diff --git a/.gitignore b/.gitignore index d22c792f43..0b6bd24070 100644 --- a/.gitignore +++ b/.gitignore @@ -124,4 +124,7 @@ devDb*.db *.xjb #neo4j -persistence-modules/neo4j/data/** \ No newline at end of file +persistence-modules/neo4j/data/** +/deep-shallow-copy/.mvn/wrapper +/deep-shallow-copy/mvnw +/deep-shallow-copy/mvnw.cmd diff --git a/algorithms-modules/algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/maximumsubarray/KadaneAlgorithm.java b/algorithms-modules/algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/maximumsubarray/KadaneAlgorithm.java index 202912a1af..15e813f680 100644 --- a/algorithms-modules/algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/maximumsubarray/KadaneAlgorithm.java +++ b/algorithms-modules/algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/maximumsubarray/KadaneAlgorithm.java @@ -5,7 +5,7 @@ import org.slf4j.LoggerFactory; public class KadaneAlgorithm { - private Logger logger = LoggerFactory.getLogger(BruteForceAlgorithm.class.getName()); + private Logger logger = LoggerFactory.getLogger(KadaneAlgorithm.class.getName()); public int maxSubArraySum(int[] arr) { @@ -14,15 +14,15 @@ public class KadaneAlgorithm { int end = 0; int maxSoFar = arr[0], maxEndingHere = arr[0]; + for (int i = 1; i < size; i++) { - - if (arr[i] > maxEndingHere + arr[i]) { - start = i; + maxEndingHere = maxEndingHere + arr[i]; + if (arr[i] > maxEndingHere) { maxEndingHere = arr[i]; - } else { - maxEndingHere = maxEndingHere + arr[i]; + if (maxSoFar < maxEndingHere) { + start = i; + } } - if (maxSoFar < maxEndingHere) { maxSoFar = maxEndingHere; end = i; diff --git a/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/maximumsubarray/KadaneAlgorithmUnitTest.java b/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/maximumsubarray/KadaneAlgorithmUnitTest.java index 8dcc81bc5b..b0ce689645 100644 --- a/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/maximumsubarray/KadaneAlgorithmUnitTest.java +++ b/algorithms-modules/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/maximumsubarray/KadaneAlgorithmUnitTest.java @@ -7,7 +7,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; class KadaneAlgorithmUnitTest { @Test - void givenArrayWithNegativeNumberWhenMaximumSubarrayThenReturns6() { + void givenArrayWithNegativeNumberWhenMaximumSubarrayThenReturnsExpectedResult() { //given int[] arr = new int[] { -3, 1, -8, 4, -1, 2, 1, -5, 5 }; //when @@ -27,7 +27,7 @@ class KadaneAlgorithmUnitTest { //then assertEquals(-1, maxSum); } - + @Test void givenArrayWithAllPosiitveNumbersWhenMaximumSubarrayThenReturnsExpectedResult() { //given @@ -39,4 +39,15 @@ class KadaneAlgorithmUnitTest { assertEquals(10, maxSum); } + @Test + void givenArrayToTestStartIndexWhenMaximumSubarrayThenReturnsExpectedResult() { + //given + int[] arr = new int[] { 1, 2, -1, 3, -6, -2 }; + //when + KadaneAlgorithm algorithm = new KadaneAlgorithm(); + int maxSum = algorithm.maxSubArraySum(arr); + //then + assertEquals(5, maxSum); + } + } \ No newline at end of file diff --git a/algorithms-modules/algorithms-miscellaneous-7/README.md b/algorithms-modules/algorithms-miscellaneous-7/README.md index ab07d655f9..82d9df9292 100644 --- a/algorithms-modules/algorithms-miscellaneous-7/README.md +++ b/algorithms-modules/algorithms-miscellaneous-7/README.md @@ -3,4 +3,5 @@ - [Algorithm to Identify and Validate a Credit Card Number](https://www.baeldung.com/java-validate-cc-number) - [Find the N Most Frequent Elements in a Java Array](https://www.baeldung.com/java-n-most-frequent-elements-array) - [Getting Pixel Array From Image in Java](https://www.baeldung.com/java-getting-pixel-array-from-image) +- [Calculate Distance Between Two Coordinates in Java](https://www.baeldung.com/java-find-distance-between-points) - More articles: [[<-- prev]](/algorithms-miscellaneous-6) diff --git a/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/latlondistance/EquirectangularApproximation.java b/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/latlondistance/EquirectangularApproximation.java new file mode 100644 index 0000000000..e42475c17e --- /dev/null +++ b/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/latlondistance/EquirectangularApproximation.java @@ -0,0 +1,19 @@ +package com.baeldung.algorithms.latlondistance; + +public class EquirectangularApproximation { + + private static final int EARTH_RADIUS = 6371; // Approx Earth radius in KM + + public static double calculateDistance(double lat1, double lon1, double lat2, double lon2) { + double lat1Rad = Math.toRadians(lat1); + double lat2Rad = Math.toRadians(lat2); + double lon1Rad = Math.toRadians(lon1); + double lon2Rad = Math.toRadians(lon2); + + double x = (lon2Rad - lon1Rad) * Math.cos((lat1Rad + lat2Rad) / 2); + double y = (lat2Rad - lat1Rad); + double distance = Math.sqrt(x * x + y * y) * EARTH_RADIUS; + + return distance; + } +} \ No newline at end of file diff --git a/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/latlondistance/HaversineDistance.java b/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/latlondistance/HaversineDistance.java new file mode 100644 index 0000000000..69074ec559 --- /dev/null +++ b/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/latlondistance/HaversineDistance.java @@ -0,0 +1,24 @@ +package com.baeldung.algorithms.latlondistance; + +public class HaversineDistance { + private static final int EARTH_RADIUS = 6371; // Approx Earth radius in KM + + public static double calculateDistance(double startLat, double startLong, + double endLat, double endLong) { + + double dLat = Math.toRadians((endLat - startLat)); + double dLong = Math.toRadians((endLong - startLong)); + + startLat = Math.toRadians(startLat); + endLat = Math.toRadians(endLat); + + double a = haversine(dLat) + Math.cos(startLat) * Math.cos(endLat) * haversine(dLong); + double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); + + return EARTH_RADIUS * c; + } + + public static double haversine(double val) { + return Math.pow(Math.sin(val / 2), 2); + } +} diff --git a/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/latlondistance/VincentyDistance.java b/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/latlondistance/VincentyDistance.java new file mode 100644 index 0000000000..7d0b0b907f --- /dev/null +++ b/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/latlondistance/VincentyDistance.java @@ -0,0 +1,53 @@ +package com.baeldung.algorithms.latlondistance; + +public class VincentyDistance { + + // Constants for WGS84 ellipsoid model of Earth + private static final double SEMI_MAJOR_AXIS_MT = 6378137; + private static final double SEMI_MINOR_AXIS_MT = 6356752.314245; + private static final double FLATTENING = 1 / 298.257223563; + private static final double ERROR_TOLERANCE = 1e-12; + + public static double calculateDistance(double latitude1, double longitude1, double latitude2, double longitude2) { + double U1 = Math.atan((1 - FLATTENING) * Math.tan(Math.toRadians(latitude1))); + double U2 = Math.atan((1 - FLATTENING) * Math.tan(Math.toRadians(latitude2))); + + double sinU1 = Math.sin(U1); + double cosU1 = Math.cos(U1); + double sinU2 = Math.sin(U2); + double cosU2 = Math.cos(U2); + + double longitudeDifference = Math.toRadians(longitude2 - longitude1); + double previousLongitudeDifference; + + double sinSigma, cosSigma, sigma, sinAlpha, cosSqAlpha, cos2SigmaM; + + do { + sinSigma = Math.sqrt(Math.pow(cosU2 * Math.sin(longitudeDifference), 2) + + Math.pow(cosU1 * sinU2 - sinU1 * cosU2 * Math.cos(longitudeDifference), 2)); + cosSigma = sinU1 * sinU2 + cosU1 * cosU2 * Math.cos(longitudeDifference); + sigma = Math.atan2(sinSigma, cosSigma); + sinAlpha = cosU1 * cosU2 * Math.sin(longitudeDifference) / sinSigma; + cosSqAlpha = 1 - Math.pow(sinAlpha, 2); + cos2SigmaM = cosSigma - 2 * sinU1 * sinU2 / cosSqAlpha; + if (Double.isNaN(cos2SigmaM)) { + cos2SigmaM = 0; + } + previousLongitudeDifference = longitudeDifference; + double C = FLATTENING / 16 * cosSqAlpha * (4 + FLATTENING * (4 - 3 * cosSqAlpha)); + longitudeDifference = Math.toRadians(longitude2 - longitude1) + (1 - C) * FLATTENING * sinAlpha * + (sigma + C * sinSigma * (cos2SigmaM + C * cosSigma * (-1 + 2 * Math.pow(cos2SigmaM, 2)))); + } while (Math.abs(longitudeDifference - previousLongitudeDifference) > ERROR_TOLERANCE); + + double uSq = cosSqAlpha * (Math.pow(SEMI_MAJOR_AXIS_MT, 2) - Math.pow(SEMI_MINOR_AXIS_MT, 2)) / Math.pow(SEMI_MINOR_AXIS_MT, 2); + + double A = 1 + uSq / 16384 * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq))); + double B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq))); + + double deltaSigma = B * sinSigma * (cos2SigmaM + B / 4 * (cosSigma * (-1 + 2 * Math.pow(cos2SigmaM, 2)) - + B / 6 * cos2SigmaM * (-3 + 4 * Math.pow(sinSigma, 2)) * (-3 + 4 * Math.pow(cos2SigmaM, 2)))); + + double distanceMt = SEMI_MINOR_AXIS_MT * A * (sigma - deltaSigma); + return distanceMt / 1000; + } +} \ No newline at end of file diff --git a/algorithms-modules/algorithms-miscellaneous-7/src/test/java/com/baeldung/algorithms/latlondistance/GeoDistanceUnitTest.java b/algorithms-modules/algorithms-miscellaneous-7/src/test/java/com/baeldung/algorithms/latlondistance/GeoDistanceUnitTest.java new file mode 100644 index 0000000000..9e72f86287 --- /dev/null +++ b/algorithms-modules/algorithms-miscellaneous-7/src/test/java/com/baeldung/algorithms/latlondistance/GeoDistanceUnitTest.java @@ -0,0 +1,26 @@ +package com.baeldung.algorithms.latlondistance; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +class GeoDistanceUnitTest { + @Test + public void testCalculateDistance() { + double lat1 = 40.714268; // New York + double lon1 = -74.005974; + double lat2 = 34.0522; // Los Angeles + double lon2 = -118.2437; + + double equirectangularDistance = EquirectangularApproximation.calculateDistance(lat1, lon1, lat2, lon2); + double haversineDistance = HaversineDistance.calculateDistance(lat1, lon1, lat2, lon2); + double vincentyDistance = VincentyDistance.calculateDistance(lat1, lon1, lat2, lon2); + + double expectedDistance = 3944; + assertTrue(Math.abs(equirectangularDistance - expectedDistance) < 100); + assertTrue(Math.abs(haversineDistance - expectedDistance) < 10); + assertTrue(Math.abs(vincentyDistance - expectedDistance) < 0.5); + + } + +} \ No newline at end of file diff --git a/apache-httpclient-2/src/main/java/com/baeldung/tlsversion/ClientTlsVersionExamples.java b/apache-httpclient-2/src/main/java/com/baeldung/tlsversion/ClientTlsVersionExamples.java index c58763b1c0..818d0c3cd9 100644 --- a/apache-httpclient-2/src/main/java/com/baeldung/tlsversion/ClientTlsVersionExamples.java +++ b/apache-httpclient-2/src/main/java/com/baeldung/tlsversion/ClientTlsVersionExamples.java @@ -1,36 +1,43 @@ package com.baeldung.tlsversion; -import javax.net.ssl.SSLSocket; - -import org.apache.http.HttpEntity; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.conn.ssl.SSLConnectionSocketFactory; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.ssl.SSLContexts; -import org.apache.http.util.EntityUtils; - import java.io.IOException; +import javax.net.ssl.SSLSocket; + +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.config.TlsConfig; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder; +import org.apache.hc.client5.http.io.HttpClientConnectionManager; +import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; +import org.apache.hc.core5.http.HttpEntity; +import org.apache.hc.core5.http.io.entity.EntityUtils; +import org.apache.hc.core5.http.ssl.TLS; +import org.apache.hc.core5.ssl.SSLContexts; +import org.apache.hc.core5.util.Timeout; + public class ClientTlsVersionExamples { - public static CloseableHttpClient setViaSocketFactory() { - SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( - SSLContexts.createDefault(), - new String[] { "TLSv1.2", "TLSv1.3" }, - null, - SSLConnectionSocketFactory.getDefaultHostnameVerifier()); + final HttpClientConnectionManager cm = PoolingHttpClientConnectionManagerBuilder.create() + .setDefaultTlsConfig(TlsConfig.custom() + .setHandshakeTimeout(Timeout.ofSeconds(30)) + .setSupportedProtocols(TLS.V_1_2, TLS.V_1_3) + .build()) + .build(); - return HttpClients.custom().setSSLSocketFactory(sslsf).build(); + return HttpClients.custom() + .setConnectionManager(cm) + .build(); } public static CloseableHttpClient setTlsVersionPerConnection() { SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(SSLContexts.createDefault()) { - @Override protected void prepareSocket(SSLSocket socket) { - String hostname = socket.getInetAddress().getHostName(); + String hostname = socket.getInetAddress() + .getHostName(); if (hostname.endsWith("internal.system.com")) { socket.setEnabledProtocols(new String[] { "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3" }); } else { @@ -39,7 +46,14 @@ public class ClientTlsVersionExamples { } }; - return HttpClients.custom().setSSLSocketFactory(sslsf).build(); + HttpClientConnectionManager connManager = PoolingHttpClientConnectionManagerBuilder.create() + .setSSLSocketFactory(sslsf) + .build(); + + return HttpClients.custom() + .setConnectionManager(connManager) + .build(); + } // To configure the TLS versions for the client, set the https.protocols system property during runtime. @@ -47,15 +61,11 @@ public class ClientTlsVersionExamples { public static CloseableHttpClient setViaSystemProperties() { return HttpClients.createSystem(); // Alternatively: - // return HttpClients.custom().useSystemProperties().build(); + //return HttpClients.custom().useSystemProperties().build(); } public static void main(String[] args) throws IOException { - // Alternatively: - // CloseableHttpClient httpClient = setTlsVersionPerConnection(); - // CloseableHttpClient httpClient = setViaSystemProperties(); - try (CloseableHttpClient httpClient = setViaSocketFactory(); - CloseableHttpResponse response = httpClient.execute(new HttpGet("https://httpbin.org/"))) { + try (CloseableHttpClient httpClient = setViaSocketFactory(); CloseableHttpResponse response = httpClient.execute(new HttpGet("https://httpbin.org/"))) { HttpEntity entity = response.getEntity(); EntityUtils.consume(entity); diff --git a/apache-httpclient/src/test/java/com/baeldung/httpclient/advancedconfig/HttpClientAdvancedConfigurationIntegrationTest.java b/apache-httpclient/src/test/java/com/baeldung/httpclient/advancedconfig/HttpClientAdvancedConfigurationIntegrationTest.java index 2235d0e9d0..3f2c1328e8 100644 --- a/apache-httpclient/src/test/java/com/baeldung/httpclient/advancedconfig/HttpClientAdvancedConfigurationIntegrationTest.java +++ b/apache-httpclient/src/test/java/com/baeldung/httpclient/advancedconfig/HttpClientAdvancedConfigurationIntegrationTest.java @@ -1,29 +1,5 @@ package com.baeldung.httpclient.advancedconfig; - -import com.github.tomakehurst.wiremock.junit.WireMockRule; -import org.apache.http.HttpHeaders; -import org.apache.http.HttpHost; -import org.apache.http.HttpResponse; -import org.apache.http.auth.AuthScope; -import org.apache.http.auth.UsernamePasswordCredentials; -import org.apache.http.client.AuthCache; -import org.apache.http.client.CredentialsProvider; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.client.protocol.HttpClientContext; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.auth.BasicScheme; -import org.apache.http.impl.client.BasicAuthCache; -import org.apache.http.impl.client.BasicCredentialsProvider; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.impl.conn.DefaultProxyRoutePlanner; -import org.junit.Rule; -import org.junit.Test; - -import java.io.IOException; - import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; import static com.github.tomakehurst.wiremock.client.WireMock.containing; import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; @@ -34,6 +10,30 @@ import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching; import static org.junit.Assert.assertEquals; +import java.io.IOException; + +import org.apache.hc.client5.http.auth.AuthCache; +import org.apache.hc.client5.http.auth.AuthScope; +import org.apache.hc.client5.http.auth.CredentialsProvider; +import org.apache.hc.client5.http.auth.StandardAuthScheme; +import org.apache.hc.client5.http.classic.HttpClient; +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.classic.methods.HttpPost; +import org.apache.hc.client5.http.impl.auth.BasicAuthCache; +import org.apache.hc.client5.http.impl.auth.BasicScheme; +import org.apache.hc.client5.http.impl.auth.CredentialsProviderBuilder; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.client5.http.impl.routing.DefaultProxyRoutePlanner; +import org.apache.hc.client5.http.protocol.HttpClientContext; +import org.apache.hc.core5.http.HttpHeaders; +import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.HttpResponse; +import org.apache.hc.core5.http.io.entity.StringEntity; +import org.junit.Rule; +import org.junit.Test; + +import com.github.tomakehurst.wiremock.junit.WireMockRule; + public class HttpClientAdvancedConfigurationIntegrationTest { @Rule @@ -59,7 +59,7 @@ public class HttpClientAdvancedConfigurationIntegrationTest { HttpResponse response = httpClient.execute(httpGet); //then - assertEquals(response.getStatusLine().getStatusCode(), 200); + assertEquals(response.getCode(), 200); } @Test @@ -82,7 +82,7 @@ public class HttpClientAdvancedConfigurationIntegrationTest { HttpResponse response = httpClient.execute(httpPost); //then - assertEquals(response.getStatusLine().getStatusCode(), 200); + assertEquals(response.getCode(), 200); } @@ -107,7 +107,7 @@ public class HttpClientAdvancedConfigurationIntegrationTest { HttpResponse response = httpclient.execute(httpGet); //then - assertEquals(response.getStatusLine().getStatusCode(), 200); + assertEquals(response.getCode(), 200); proxyMock.verify(getRequestedFor(urlEqualTo("/private"))); serviceMock.verify(getRequestedFor(urlEqualTo("/private"))); } @@ -125,14 +125,12 @@ public class HttpClientAdvancedConfigurationIntegrationTest { DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy); // Client credentials - CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); - credentialsProvider.setCredentials(new AuthScope(proxy), - new UsernamePasswordCredentials("username_admin", "secret_password")); - + CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create() + .add(new AuthScope(proxy), "username_admin", "secret_password".toCharArray()) + .build(); // Create AuthCache instance AuthCache authCache = new BasicAuthCache(); - // Generate BASIC scheme object and add it to the local auth cache BasicScheme basicAuth = new BasicScheme(); authCache.put(proxy, basicAuth); @@ -149,10 +147,11 @@ public class HttpClientAdvancedConfigurationIntegrationTest { //when final HttpGet httpGet = new HttpGet("http://localhost:8089/private"); + httpGet.setHeader("Authorization", StandardAuthScheme.BASIC); HttpResponse response = httpclient.execute(httpGet, context); //then - assertEquals(response.getStatusLine().getStatusCode(), 200); + assertEquals(response.getCode(), 200); proxyMock.verify(getRequestedFor(urlEqualTo("/private")).withHeader("Authorization", containing("Basic"))); serviceMock.verify(getRequestedFor(urlEqualTo("/private"))); } diff --git a/apache-httpclient/src/test/java/com/baeldung/httpclient/conn/HttpClientConnectionManagementLiveTest.java b/apache-httpclient/src/test/java/com/baeldung/httpclient/conn/HttpClientConnectionManagementLiveTest.java index 57a8f0a806..9d5294aa7e 100644 --- a/apache-httpclient/src/test/java/com/baeldung/httpclient/conn/HttpClientConnectionManagementLiveTest.java +++ b/apache-httpclient/src/test/java/com/baeldung/httpclient/conn/HttpClientConnectionManagementLiveTest.java @@ -1,69 +1,71 @@ package com.baeldung.httpclient.conn; -import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; +import java.net.URISyntaxException; +import java.util.Iterator; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; -import org.apache.http.HeaderElement; -import org.apache.http.HeaderElementIterator; -import org.apache.http.HttpClientConnection; -import org.apache.http.HttpException; -import org.apache.http.HttpHost; -import org.apache.http.HttpResponse; -import org.apache.http.client.ClientProtocolException; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.protocol.HttpClientContext; -import org.apache.http.config.SocketConfig; -import org.apache.http.conn.ConnectionKeepAliveStrategy; -import org.apache.http.conn.ConnectionPoolTimeoutException; -import org.apache.http.conn.ConnectionRequest; -import org.apache.http.conn.routing.HttpRoute; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.impl.conn.BasicHttpClientConnectionManager; -import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; -import org.apache.http.message.BasicHeaderElementIterator; -import org.apache.http.protocol.HTTP; -import org.apache.http.protocol.HttpContext; -import org.apache.http.protocol.HttpCoreContext; -import org.apache.http.protocol.HttpRequestExecutor; -import org.apache.http.util.EntityUtils; -import org.junit.Ignore; +import org.apache.hc.client5.http.ConnectionKeepAliveStrategy; +import org.apache.hc.client5.http.HttpRoute; +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.config.ConnectionConfig; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.client5.http.impl.io.BasicHttpClientConnectionManager; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; +import org.apache.hc.client5.http.io.ConnectionEndpoint; +import org.apache.hc.client5.http.io.LeaseRequest; +import org.apache.hc.core5.http.HeaderElement; +import org.apache.hc.core5.http.HeaderElements; +import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.HttpResponse; +import org.apache.hc.core5.http.io.entity.EntityUtils; +import org.apache.hc.core5.http.message.MessageSupport; +import org.apache.hc.core5.http.message.StatusLine; +import org.apache.hc.core5.http.protocol.BasicHttpContext; +import org.apache.hc.core5.http.protocol.HttpContext; +import org.apache.hc.core5.pool.PoolStats; +import org.apache.hc.core5.util.Args; +import org.apache.hc.core5.util.TimeValue; +import org.apache.hc.core5.util.Timeout; +import org.junit.Assert; import org.junit.Test; public class HttpClientConnectionManagementLiveTest { // Example 2.1. Getting a Connection Request for a Low Level Connection (HttpClientConnection) @Test - public final void whenLowLevelConnectionIsEstablished_thenNoExceptions() throws ConnectionPoolTimeoutException, InterruptedException, ExecutionException { - try (BasicHttpClientConnectionManager connManager = new BasicHttpClientConnectionManager()) { - HttpRoute route = new HttpRoute(new HttpHost("www.baeldung.com", 80)); - final ConnectionRequest connRequest = connManager.requestConnection(route, null); - assertNotNull(connRequest.get(1000, TimeUnit.SECONDS)); - } + public final void whenLowLevelConnectionIsEstablished_thenNoExceptions() throws ExecutionException, InterruptedException, TimeoutException { + BasicHttpClientConnectionManager connMgr = new BasicHttpClientConnectionManager(); + HttpRoute route = new HttpRoute(new HttpHost("www.baeldung.com", 443)); + final LeaseRequest connRequest = connMgr.lease("some-id", route, null); + assertNotNull(connRequest.get(Timeout.ZERO_MILLISECONDS)); + connMgr.close(); } // Example 3.1. Setting the PoolingHttpClientConnectionManager on a HttpClient @Test - public final void whenPollingConnectionManagerIsConfiguredOnHttpClient_thenNoExceptions() throws ClientProtocolException, IOException { + public final void whenPollingConnectionManagerIsConfiguredOnHttpClient_thenNoExceptions() throws IOException { PoolingHttpClientConnectionManager poolingConnManager = new PoolingHttpClientConnectionManager(); CloseableHttpClient client = HttpClients.custom() .setConnectionManager(poolingConnManager) .build(); client.execute(new HttpGet("https://www.baeldung.com")); - assertTrue(poolingConnManager.getTotalStats() .getLeased() == 1); + client.close(); + poolingConnManager.close(); } // Example 3.2. Using Two HttpClients to Connect to One Target Host Each @Test - public final void whenTwoConnectionsForTwoRequests_thenNoExceptions() throws InterruptedException { + public final void whenTwoConnectionsForTwoRequests_thenNoExceptions() throws InterruptedException, IOException { HttpGet get1 = new HttpGet("https://www.baeldung.com"); HttpGet get2 = new HttpGet("https://www.google.com"); PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); @@ -81,38 +83,52 @@ public class HttpClientConnectionManagementLiveTest { thread1.join(); thread2.join(); - assertTrue(connManager.getTotalStats() + Assert.assertTrue(connManager.getTotalStats() .getLeased() == 0); + client1.close(); + client2.close(); + connManager.close(); } // Example 4.1. Increasing the Number of Connections that Can be Open and Managed Beyond the default Limits @Test - public final void whenIncreasingConnectionPool_thenNoEceptions() { - try (PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager()) { - connManager.setMaxTotal(5); - connManager.setDefaultMaxPerRoute(4); - HttpHost host = new HttpHost("www.baeldung.com", 80); - connManager.setMaxPerRoute(new HttpRoute(host), 5); - } + public final void whenIncreasingConnectionPool_thenNoExceptions() { + PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); + connManager.setMaxTotal(5); + connManager.setDefaultMaxPerRoute(4); + HttpHost host = new HttpHost("www.baeldung.com", 80); + connManager.setMaxPerRoute(new HttpRoute(host), 5); + connManager.close(); } // Example 4.2. Using Threads to Execute Connections @Test - public final void whenExecutingSameRequestsInDifferentThreads_thenExecuteReuqest() throws InterruptedException { + public final void whenExecutingSameRequestsInDifferentThreads_thenExecuteRequest() throws InterruptedException, IOException { HttpGet get = new HttpGet("http://www.baeldung.com"); PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); CloseableHttpClient client = HttpClients.custom() .setConnectionManager(connManager) .build(); - MultiHttpClientConnThread thread1 = new MultiHttpClientConnThread(client, get); - MultiHttpClientConnThread thread2 = new MultiHttpClientConnThread(client, get); - MultiHttpClientConnThread thread3 = new MultiHttpClientConnThread(client, get); + MultiHttpClientConnThread thread1 = new MultiHttpClientConnThread(client, get, connManager); + MultiHttpClientConnThread thread2 = new MultiHttpClientConnThread(client, get, connManager); + MultiHttpClientConnThread thread3 = new MultiHttpClientConnThread(client, get, connManager); + MultiHttpClientConnThread thread4 = new MultiHttpClientConnThread(client, get, connManager); + MultiHttpClientConnThread thread5 = new MultiHttpClientConnThread(client, get, connManager); + MultiHttpClientConnThread thread6 = new MultiHttpClientConnThread(client, get, connManager); thread1.start(); thread2.start(); thread3.start(); + thread4.start(); + thread5.start(); + thread6.start(); thread1.join(); thread2.join(); thread3.join(); + thread4.join(); + thread5.join(); + thread6.join(); + client.close(); + connManager.close(); } // Example 5.1. A Custom Keep Alive Strategy @@ -120,22 +136,19 @@ public class HttpClientConnectionManagementLiveTest { public final void whenCustomizingKeepAliveStrategy_thenNoExceptions() { final ConnectionKeepAliveStrategy myStrategy = new ConnectionKeepAliveStrategy() { @Override - public long getKeepAliveDuration(final HttpResponse myResponse, final HttpContext myContext) { - final HeaderElementIterator it = new BasicHeaderElementIterator(myResponse.headerIterator(HTTP.CONN_KEEP_ALIVE)); - while (it.hasNext()) { - final HeaderElement he = it.nextElement(); - final String param = he.getName(); - final String value = he.getValue(); - if ((value != null) && param.equalsIgnoreCase("timeout")) { - return Long.parseLong(value) * 1000; + public TimeValue getKeepAliveDuration(HttpResponse response, HttpContext context) { + Args.notNull(response, "HTTP response"); + final Iterator it = MessageSupport.iterate(response, HeaderElements.KEEP_ALIVE); + final HeaderElement he = it.next(); + final String param = he.getName(); + final String value = he.getValue(); + if (value != null && param.equalsIgnoreCase("timeout")) { + try { + return TimeValue.ofSeconds(Long.parseLong(value)); + } catch (final NumberFormatException ignore) { } } - final HttpHost target = (HttpHost) myContext.getAttribute(HttpCoreContext.HTTP_TARGET_HOST); - if ("localhost".equalsIgnoreCase(target.getHostName())) { - return 10 * 1000; - } else { - return 5 * 1000; - } + return TimeValue.ofSeconds(5); } }; @@ -144,42 +157,38 @@ public class HttpClientConnectionManagementLiveTest { .setKeepAliveStrategy(myStrategy) .setConnectionManager(connManager) .build(); + connManager.close(); } - // Example 6.1. BasicHttpClientConnectionManager Connection Reuse + //Example 6.1. BasicHttpClientConnectionManager Connection Reuse @Test - public final void givenBasicHttpClientConnManager_whenConnectionReuse_thenNoExceptions() throws IOException, HttpException, InterruptedException, ExecutionException { - BasicHttpClientConnectionManager basicConnManager = new BasicHttpClientConnectionManager(); - HttpClientContext context = HttpClientContext.create(); - - // low level + public final void givenBasicHttpClientConnManager_whenConnectionReuse_thenNoExceptions() throws InterruptedException, ExecutionException, TimeoutException, IOException, URISyntaxException { + BasicHttpClientConnectionManager connMgr = new BasicHttpClientConnectionManager(); HttpRoute route = new HttpRoute(new HttpHost("www.baeldung.com", 443)); - ConnectionRequest connRequest = basicConnManager.requestConnection(route, null); - HttpClientConnection conn = connRequest.get(10, TimeUnit.SECONDS); - basicConnManager.connect(conn, route, 1000, context); - basicConnManager.routeComplete(conn, route, context); + final HttpContext context = new BasicHttpContext(); - HttpRequestExecutor exeRequest = new HttpRequestExecutor(); - context.setTargetHost((new HttpHost("www.baeldung.com", 80))); - HttpGet get = new HttpGet("http://www.baeldung.com"); - exeRequest.execute(get, conn, context); + final LeaseRequest connRequest = connMgr.lease("some-id", route, null); + final ConnectionEndpoint endpoint = connRequest.get(Timeout.ZERO_MILLISECONDS); + connMgr.connect(endpoint, Timeout.ZERO_MILLISECONDS, context); - basicConnManager.releaseConnection(conn, null, 1, TimeUnit.SECONDS); + connMgr.release(endpoint, null, TimeValue.ZERO_MILLISECONDS); - // high level CloseableHttpClient client = HttpClients.custom() - .setConnectionManager(basicConnManager) + .setConnectionManager(connMgr) .build(); - client.execute(get); + HttpGet httpGet = new HttpGet("https://www.example.com"); + client.execute(httpGet, context, response -> response); + client.close(); + connMgr.close(); } // Example 6.2. PoolingHttpClientConnectionManager: Re-Using Connections with Threads @Test - public final void whenConnectionsNeededGreaterThanMaxTotal_thenLeaseMasTotalandReuse() throws InterruptedException { - HttpGet get = new HttpGet("http://echo.200please.com"); + public final void whenConnectionsNeededGreaterThanMaxTotal_thenLeaseMasTotalandReuse() throws InterruptedException, IOException { + HttpGet get = new HttpGet("http://www.baeldung.com"); PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); - connManager.setDefaultMaxPerRoute(5); - connManager.setMaxTotal(5); + connManager.setDefaultMaxPerRoute(6); + connManager.setMaxTotal(6); CloseableHttpClient client = HttpClients.custom() .setConnectionManager(connManager) .build(); @@ -193,48 +202,71 @@ public class HttpClientConnectionManagementLiveTest { for (MultiHttpClientConnThread thread : threads) { thread.join(1000); } + client.close(); + connManager.close(); } // Example 7.1. Setting Socket Timeout to 5 Seconds @Test - public final void whenConfiguringTimeOut_thenNoExceptions() { - HttpRoute route = new HttpRoute(new HttpHost("www.baeldung.com", 80)); - try (PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager()) { - connManager.setSocketConfig(route.getTargetHost(), SocketConfig.custom() - .setSoTimeout(5000) - .build()); - assertTrue(connManager.getSocketConfig(route.getTargetHost()) - .getSoTimeout() == 5000); - } + public final void whenConfiguringTimeOut_thenNoExceptions() throws ExecutionException, InterruptedException, TimeoutException, IOException { + final HttpRoute route = new HttpRoute(new HttpHost("www.baeldung.com", 80)); + final HttpContext context = new BasicHttpContext(); + final PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); + + final ConnectionConfig connConfig = ConnectionConfig.custom() + .setSocketTimeout(5, TimeUnit.SECONDS) + .build(); + + connManager.setDefaultConnectionConfig(connConfig); + + final LeaseRequest leaseRequest = connManager.lease("id1", route, null); + final ConnectionEndpoint endpoint = leaseRequest.get(Timeout.ZERO_MILLISECONDS); + connManager.connect(endpoint, null, context); + connManager.close(); } // Example 8.1. Setting the HttpClient to Check for Stale Connections @Test - public final void whenHttpClientChecksStaleConns_thenNoExceptions() { - PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); - HttpClients.custom() - .setDefaultRequestConfig(RequestConfig.custom() - .setStaleConnectionCheckEnabled(true) - .build()) + public final void whenEvictIdealConn_thenNoExceptions() throws InterruptedException, IOException { + final PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); + connManager.setMaxTotal(100); + try (final CloseableHttpClient httpclient = HttpClients.custom() .setConnectionManager(connManager) - .build(); - } + .evictExpiredConnections() + .evictIdleConnections(TimeValue.ofSeconds(2)) + .build()) { + // create an array of URIs to perform GETs on + final String[] urisToGet = { "http://hc.apache.org/", "http://hc.apache.org/httpcomponents-core-ga/"}; - // Example 8.2. Using a Stale Connection Monitor Thread - @Test - public final void whenCustomizedIdleConnMonitor_thenNoExceptions() throws InterruptedException { - PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); - HttpClients.custom() - .setConnectionManager(connManager) - .build(); - IdleConnectionMonitorThread staleMonitor = new IdleConnectionMonitorThread(connManager); - staleMonitor.start(); - staleMonitor.join(1000); + for (final String requestURI : urisToGet) { + final HttpGet request = new HttpGet(requestURI); + + System.out.println("Executing request " + request.getMethod() + " " + request.getRequestUri()); + + httpclient.execute(request, response -> { + System.out.println("----------------------------------------"); + System.out.println(request + "->" + new StatusLine(response)); + EntityUtils.consume(response.getEntity()); + return null; + }); + } + + final PoolStats stats1 = connManager.getTotalStats(); + System.out.println("Connections kept alive: " + stats1.getAvailable()); + + // Sleep 10 sec and let the connection evict or do its job + Thread.sleep(4000); + + final PoolStats stats2 = connManager.getTotalStats(); + System.out.println("Connections kept alive: " + stats2.getAvailable()); + + connManager.close(); + } } // Example 9.1. Closing Connection and Releasing Resources - @Test(expected = IllegalStateException.class) - public final void whenClosingConnectionsandManager_thenCloseWithNoExceptions1() throws InterruptedException, ExecutionException, IOException, HttpException { + @Test + public final void whenClosingConnectionsandManager_thenCloseWithNoExceptions1() throws IOException { PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); CloseableHttpClient client = HttpClients.custom() .setConnectionManager(connManager) @@ -246,16 +278,11 @@ public class HttpClientConnectionManagementLiveTest { response.close(); client.close(); connManager.close(); - connManager.shutdown(); - - client.execute(get); - - assertTrue(response.getEntity() == null); } @Test // Example 3.2. TESTER VERSION - public final void whenTwoConnectionsForTwoRequests_thenTwoConnectionsAreLeased() throws InterruptedException { + public final void whenTwoConnectionsForTwoRequests_thenTwoConnectionsAreLeased() throws InterruptedException, IOException { HttpGet get1 = new HttpGet("https://www.baeldung.com"); HttpGet get2 = new HttpGet("https://www.google.com"); @@ -273,77 +300,11 @@ public class HttpClientConnectionManagementLiveTest { thread2.start(); thread1.join(); thread2.join(1000); - assertTrue(poolingConnManager.getTotalStats() + Assert.assertTrue(poolingConnManager.getTotalStats() .getLeased() == 2); - } - @Test - // Example 4.2 Tester Version - public final void whenExecutingSameRequestsInDifferentThreads_thenUseDefaultConnLimit() throws InterruptedException { - PoolingHttpClientConnectionManager poolingConnManager = new PoolingHttpClientConnectionManager(); - CloseableHttpClient client = HttpClients.custom() - .setConnectionManager(poolingConnManager) - .build(); - final TesterVersion_MultiHttpClientConnThread thread1 = new TesterVersion_MultiHttpClientConnThread(client, new HttpGet("http://www.google.com"), poolingConnManager); - final TesterVersion_MultiHttpClientConnThread thread2 = new TesterVersion_MultiHttpClientConnThread(client, new HttpGet("http://www.google.com"), poolingConnManager); - final TesterVersion_MultiHttpClientConnThread thread3 = new TesterVersion_MultiHttpClientConnThread(client, new HttpGet("http://www.google.com"), poolingConnManager); - thread1.start(); - thread2.start(); - thread3.start(); - thread1.join(10000); - thread2.join(10000); - thread3.join(10000); - } - - @Test - // 6.2 TESTER VERSION - public final void whenConnectionsNeededGreaterThanMaxTotal_thenReuseConnections() throws InterruptedException { - PoolingHttpClientConnectionManager poolingConnManager = new PoolingHttpClientConnectionManager(); - poolingConnManager.setDefaultMaxPerRoute(5); - poolingConnManager.setMaxTotal(5); - CloseableHttpClient client = HttpClients.custom() - .setConnectionManager(poolingConnManager) - .build(); - final MultiHttpClientConnThread[] threads = new MultiHttpClientConnThread[10]; - int countConnMade = 0; - for (int i = 0; i < threads.length; i++) { - threads[i] = new MultiHttpClientConnThread(client, new HttpGet("http://www.baeldung.com/"), poolingConnManager); - } - for (final MultiHttpClientConnThread thread : threads) { - thread.start(); - } - for (final MultiHttpClientConnThread thread : threads) { - thread.join(10000); - countConnMade++; - if (countConnMade == 0) { - assertTrue(thread.getLeasedConn() == 5); - } - } - } - - @Test - @Ignore("Very Long Running") - // 8.2 TESTER VERSION - public final void whenCustomizedIdleConnMonitor_thenEliminateIdleConns() throws InterruptedException { - PoolingHttpClientConnectionManager poolingConnManager = new PoolingHttpClientConnectionManager(); - CloseableHttpClient client = HttpClients.custom() - .setConnectionManager(poolingConnManager) - .build(); - final IdleConnectionMonitorThread staleMonitor = new IdleConnectionMonitorThread(poolingConnManager); - final HttpGet get = new HttpGet("http://google.com"); - final TesterVersion_MultiHttpClientConnThread thread1 = new TesterVersion_MultiHttpClientConnThread(client, get, poolingConnManager); - final TesterVersion_MultiHttpClientConnThread thread2 = new TesterVersion_MultiHttpClientConnThread(client, get, poolingConnManager); - final TesterVersion_MultiHttpClientConnThread thread3 = new TesterVersion_MultiHttpClientConnThread(client, get, poolingConnManager); - staleMonitor.start(); - thread1.start(); - thread1.join(); - thread2.start(); - thread2.join(); - thread3.start(); - assertTrue(poolingConnManager.getTotalStats() - .getAvailable() == 1); - thread3.join(32000); - assertTrue(poolingConnManager.getTotalStats() - .getAvailable() == 0); + client1.close(); + client2.close(); + poolingConnManager.close(); } } diff --git a/apache-httpclient/src/test/java/com/baeldung/httpclient/conn/MultiHttpClientConnThread.java b/apache-httpclient/src/test/java/com/baeldung/httpclient/conn/MultiHttpClientConnThread.java index acadd1f240..16bb49123a 100644 --- a/apache-httpclient/src/test/java/com/baeldung/httpclient/conn/MultiHttpClientConnThread.java +++ b/apache-httpclient/src/test/java/com/baeldung/httpclient/conn/MultiHttpClientConnThread.java @@ -2,12 +2,12 @@ package com.baeldung.httpclient.conn; import java.io.IOException; -import org.apache.http.HttpResponse; -import org.apache.http.client.ClientProtocolException; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; -import org.apache.http.util.EntityUtils; +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; +import org.apache.hc.core5.http.HttpEntity; +import org.apache.hc.core5.http.HttpResponse; +import org.apache.hc.core5.http.io.entity.EntityUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -45,22 +45,21 @@ public class MultiHttpClientConnThread extends Thread { try { logger.debug("Thread Running: " + getName()); - logger.debug("Thread Running: " + getName()); if (connManager != null) { logger.info("Before - Leased Connections = " + connManager.getTotalStats().getLeased()); logger.info("Before - Available Connections = " + connManager.getTotalStats().getAvailable()); } - final HttpResponse response = client.execute(get); + HttpEntity entity = client.execute(get).getEntity(); if (connManager != null) { leasedConn = connManager.getTotalStats().getLeased(); logger.info("After - Leased Connections = " + connManager.getTotalStats().getLeased()); logger.info("After - Available Connections = " + connManager.getTotalStats().getAvailable()); } + EntityUtils.consume(entity); - EntityUtils.consume(response.getEntity()); } catch (final IOException ex) { logger.error("", ex); } diff --git a/apache-httpclient/src/test/java/com/baeldung/httpclient/conn/TesterVersion_MultiHttpClientConnThread.java b/apache-httpclient/src/test/java/com/baeldung/httpclient/conn/TesterVersion_MultiHttpClientConnThread.java index a50858672e..6703d6880c 100644 --- a/apache-httpclient/src/test/java/com/baeldung/httpclient/conn/TesterVersion_MultiHttpClientConnThread.java +++ b/apache-httpclient/src/test/java/com/baeldung/httpclient/conn/TesterVersion_MultiHttpClientConnThread.java @@ -2,10 +2,9 @@ package com.baeldung.httpclient.conn; import java.io.IOException; -import org.apache.http.client.ClientProtocolException; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/apache-httpclient4/src/main/java/com/baeldung/tlsversion/ClientTlsVersionExamples.java b/apache-httpclient4/src/main/java/com/baeldung/tlsversion/ClientTlsVersionExamples.java new file mode 100644 index 0000000000..c58763b1c0 --- /dev/null +++ b/apache-httpclient4/src/main/java/com/baeldung/tlsversion/ClientTlsVersionExamples.java @@ -0,0 +1,64 @@ +package com.baeldung.tlsversion; + +import javax.net.ssl.SSLSocket; + +import org.apache.http.HttpEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.ssl.SSLContexts; +import org.apache.http.util.EntityUtils; + +import java.io.IOException; + +public class ClientTlsVersionExamples { + + public static CloseableHttpClient setViaSocketFactory() { + SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( + SSLContexts.createDefault(), + new String[] { "TLSv1.2", "TLSv1.3" }, + null, + SSLConnectionSocketFactory.getDefaultHostnameVerifier()); + + return HttpClients.custom().setSSLSocketFactory(sslsf).build(); + } + + public static CloseableHttpClient setTlsVersionPerConnection() { + SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(SSLContexts.createDefault()) { + + @Override + protected void prepareSocket(SSLSocket socket) { + String hostname = socket.getInetAddress().getHostName(); + if (hostname.endsWith("internal.system.com")) { + socket.setEnabledProtocols(new String[] { "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3" }); + } else { + socket.setEnabledProtocols(new String[] { "TLSv1.3" }); + } + } + }; + + return HttpClients.custom().setSSLSocketFactory(sslsf).build(); + } + + // To configure the TLS versions for the client, set the https.protocols system property during runtime. + // For example: java -Dhttps.protocols=TLSv1.1,TLSv1.2,TLSv1.3 -jar webClient.jar + public static CloseableHttpClient setViaSystemProperties() { + return HttpClients.createSystem(); + // Alternatively: + // return HttpClients.custom().useSystemProperties().build(); + } + + public static void main(String[] args) throws IOException { + // Alternatively: + // CloseableHttpClient httpClient = setTlsVersionPerConnection(); + // CloseableHttpClient httpClient = setViaSystemProperties(); + try (CloseableHttpClient httpClient = setViaSocketFactory(); + CloseableHttpResponse response = httpClient.execute(new HttpGet("https://httpbin.org/"))) { + + HttpEntity entity = response.getEntity(); + EntityUtils.consume(entity); + } + } +} \ No newline at end of file diff --git a/apache-httpclient4/src/test/java/com/baeldung/httpclient/advancedconfig/HttpClientAdvancedConfigurationIntegrationTest.java b/apache-httpclient4/src/test/java/com/baeldung/httpclient/advancedconfig/HttpClientAdvancedConfigurationIntegrationTest.java new file mode 100644 index 0000000000..2235d0e9d0 --- /dev/null +++ b/apache-httpclient4/src/test/java/com/baeldung/httpclient/advancedconfig/HttpClientAdvancedConfigurationIntegrationTest.java @@ -0,0 +1,161 @@ +package com.baeldung.httpclient.advancedconfig; + + +import com.github.tomakehurst.wiremock.junit.WireMockRule; +import org.apache.http.HttpHeaders; +import org.apache.http.HttpHost; +import org.apache.http.HttpResponse; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.AuthCache; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.protocol.HttpClientContext; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.auth.BasicScheme; +import org.apache.http.impl.client.BasicAuthCache; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.conn.DefaultProxyRoutePlanner; +import org.junit.Rule; +import org.junit.Test; + +import java.io.IOException; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.containing; +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; +import static com.github.tomakehurst.wiremock.client.WireMock.get; +import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.post; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching; +import static org.junit.Assert.assertEquals; + +public class HttpClientAdvancedConfigurationIntegrationTest { + + @Rule + public WireMockRule serviceMock = new WireMockRule(8089); + + @Rule + public WireMockRule proxyMock = new WireMockRule(8090); + + @Test + public void givenClientWithCustomUserAgentHeader_whenExecuteRequest_shouldReturn200() throws IOException { + //given + String userAgent = "BaeldungAgent/1.0"; + serviceMock.stubFor(get(urlEqualTo("/detail")) + .withHeader("User-Agent", equalTo(userAgent)) + .willReturn(aResponse() + .withStatus(200))); + + HttpClient httpClient = HttpClients.createDefault(); + HttpGet httpGet = new HttpGet("http://localhost:8089/detail"); + httpGet.setHeader(HttpHeaders.USER_AGENT, userAgent); + + //when + HttpResponse response = httpClient.execute(httpGet); + + //then + assertEquals(response.getStatusLine().getStatusCode(), 200); + } + + @Test + public void givenClientThatSendDataInBody_whenSendXmlInBody_shouldReturn200() throws IOException { + //given + String xmlBody = "1"; + serviceMock.stubFor(post(urlEqualTo("/person")) + .withHeader("Content-Type", equalTo("application/xml")) + .withRequestBody(equalTo(xmlBody)) + .willReturn(aResponse() + .withStatus(200))); + + HttpClient httpClient = HttpClients.createDefault(); + HttpPost httpPost = new HttpPost("http://localhost:8089/person"); + httpPost.setHeader("Content-Type", "application/xml"); + StringEntity xmlEntity = new StringEntity(xmlBody); + httpPost.setEntity(xmlEntity); + + //when + HttpResponse response = httpClient.execute(httpPost); + + //then + assertEquals(response.getStatusLine().getStatusCode(), 200); + + } + + @Test + public void givenServerThatIsBehindProxy_whenClientIsConfiguredToSendRequestViaProxy_shouldReturn200() throws IOException { + //given + proxyMock.stubFor(get(urlMatching(".*")) + .willReturn(aResponse().proxiedFrom("http://localhost:8089/"))); + + serviceMock.stubFor(get(urlEqualTo("/private")) + .willReturn(aResponse().withStatus(200))); + + + HttpHost proxy = new HttpHost("localhost", 8090); + DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy); + HttpClient httpclient = HttpClients.custom() + .setRoutePlanner(routePlanner) + .build(); + + //when + final HttpGet httpGet = new HttpGet("http://localhost:8089/private"); + HttpResponse response = httpclient.execute(httpGet); + + //then + assertEquals(response.getStatusLine().getStatusCode(), 200); + proxyMock.verify(getRequestedFor(urlEqualTo("/private"))); + serviceMock.verify(getRequestedFor(urlEqualTo("/private"))); + } + + @Test + public void givenServerThatIsBehindAuthorizationProxy_whenClientSendRequest_shouldAuthorizeProperly() throws IOException { + //given + proxyMock.stubFor(get(urlMatching("/private")) + .willReturn(aResponse().proxiedFrom("http://localhost:8089/"))); + serviceMock.stubFor(get(urlEqualTo("/private")) + .willReturn(aResponse().withStatus(200))); + + + HttpHost proxy = new HttpHost("localhost", 8090); + DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy); + + // Client credentials + CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); + credentialsProvider.setCredentials(new AuthScope(proxy), + new UsernamePasswordCredentials("username_admin", "secret_password")); + + + // Create AuthCache instance + AuthCache authCache = new BasicAuthCache(); + + // Generate BASIC scheme object and add it to the local auth cache + BasicScheme basicAuth = new BasicScheme(); + authCache.put(proxy, basicAuth); + HttpClientContext context = HttpClientContext.create(); + context.setCredentialsProvider(credentialsProvider); + context.setAuthCache(authCache); + + + HttpClient httpclient = HttpClients.custom() + .setRoutePlanner(routePlanner) + .setDefaultCredentialsProvider(credentialsProvider) + .build(); + + + //when + final HttpGet httpGet = new HttpGet("http://localhost:8089/private"); + HttpResponse response = httpclient.execute(httpGet, context); + + //then + assertEquals(response.getStatusLine().getStatusCode(), 200); + proxyMock.verify(getRequestedFor(urlEqualTo("/private")).withHeader("Authorization", containing("Basic"))); + serviceMock.verify(getRequestedFor(urlEqualTo("/private"))); + } + + +} diff --git a/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/conn/HttpClientConnectionManagementLiveTest.java b/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/conn/HttpClientConnectionManagementLiveTest.java new file mode 100644 index 0000000000..c894d72af0 --- /dev/null +++ b/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/conn/HttpClientConnectionManagementLiveTest.java @@ -0,0 +1,349 @@ +package com.baeldung.httpclient.httpclient.conn; + +import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; + +import org.apache.http.HeaderElement; +import org.apache.http.HeaderElementIterator; +import org.apache.http.HttpClientConnection; +import org.apache.http.HttpException; +import org.apache.http.HttpHost; +import org.apache.http.HttpResponse; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.protocol.HttpClientContext; +import org.apache.http.config.SocketConfig; +import org.apache.http.conn.ConnectionKeepAliveStrategy; +import org.apache.http.conn.ConnectionPoolTimeoutException; +import org.apache.http.conn.ConnectionRequest; +import org.apache.http.conn.routing.HttpRoute; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.conn.BasicHttpClientConnectionManager; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.message.BasicHeaderElementIterator; +import org.apache.http.protocol.HTTP; +import org.apache.http.protocol.HttpContext; +import org.apache.http.protocol.HttpCoreContext; +import org.apache.http.protocol.HttpRequestExecutor; +import org.apache.http.util.EntityUtils; +import org.junit.Ignore; +import org.junit.Test; + +public class HttpClientConnectionManagementLiveTest { + + // Example 2.1. Getting a Connection Request for a Low Level Connection (HttpClientConnection) + @Test + public final void whenLowLevelConnectionIsEstablished_thenNoExceptions() throws ConnectionPoolTimeoutException, InterruptedException, ExecutionException { + try (BasicHttpClientConnectionManager connManager = new BasicHttpClientConnectionManager()) { + HttpRoute route = new HttpRoute(new HttpHost("www.baeldung.com", 80)); + final ConnectionRequest connRequest = connManager.requestConnection(route, null); + assertNotNull(connRequest.get(1000, TimeUnit.SECONDS)); + } + } + + // Example 3.1. Setting the PoolingHttpClientConnectionManager on a HttpClient + @Test + public final void whenPollingConnectionManagerIsConfiguredOnHttpClient_thenNoExceptions() throws ClientProtocolException, IOException { + PoolingHttpClientConnectionManager poolingConnManager = new PoolingHttpClientConnectionManager(); + CloseableHttpClient client = HttpClients.custom() + .setConnectionManager(poolingConnManager) + .build(); + client.execute(new HttpGet("https://www.baeldung.com")); + + assertTrue(poolingConnManager.getTotalStats() + .getLeased() == 1); + } + + // Example 3.2. Using Two HttpClients to Connect to One Target Host Each + @Test + public final void whenTwoConnectionsForTwoRequests_thenNoExceptions() throws InterruptedException { + HttpGet get1 = new HttpGet("https://www.baeldung.com"); + HttpGet get2 = new HttpGet("https://www.google.com"); + PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); + CloseableHttpClient client1 = HttpClients.custom() + .setConnectionManager(connManager) + .build(); + CloseableHttpClient client2 = HttpClients.custom() + .setConnectionManager(connManager) + .build(); + + MultiHttpClientConnThread thread1 = new MultiHttpClientConnThread(client1, get1); + MultiHttpClientConnThread thread2 = new MultiHttpClientConnThread(client2, get2); + thread1.start(); + thread2.start(); + thread1.join(); + thread2.join(); + + assertTrue(connManager.getTotalStats() + .getLeased() == 0); + } + + // Example 4.1. Increasing the Number of Connections that Can be Open and Managed Beyond the default Limits + @Test + public final void whenIncreasingConnectionPool_thenNoEceptions() { + try (PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager()) { + connManager.setMaxTotal(5); + connManager.setDefaultMaxPerRoute(4); + HttpHost host = new HttpHost("www.baeldung.com", 80); + connManager.setMaxPerRoute(new HttpRoute(host), 5); + } + } + + // Example 4.2. Using Threads to Execute Connections + @Test + public final void whenExecutingSameRequestsInDifferentThreads_thenExecuteReuqest() throws InterruptedException { + HttpGet get = new HttpGet("http://www.baeldung.com"); + PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); + CloseableHttpClient client = HttpClients.custom() + .setConnectionManager(connManager) + .build(); + MultiHttpClientConnThread thread1 = new MultiHttpClientConnThread(client, get); + MultiHttpClientConnThread thread2 = new MultiHttpClientConnThread(client, get); + MultiHttpClientConnThread thread3 = new MultiHttpClientConnThread(client, get); + thread1.start(); + thread2.start(); + thread3.start(); + thread1.join(); + thread2.join(); + thread3.join(); + } + + // Example 5.1. A Custom Keep Alive Strategy + @Test + public final void whenCustomizingKeepAliveStrategy_thenNoExceptions() { + final ConnectionKeepAliveStrategy myStrategy = new ConnectionKeepAliveStrategy() { + @Override + public long getKeepAliveDuration(final HttpResponse myResponse, final HttpContext myContext) { + final HeaderElementIterator it = new BasicHeaderElementIterator(myResponse.headerIterator(HTTP.CONN_KEEP_ALIVE)); + while (it.hasNext()) { + final HeaderElement he = it.nextElement(); + final String param = he.getName(); + final String value = he.getValue(); + if ((value != null) && param.equalsIgnoreCase("timeout")) { + return Long.parseLong(value) * 1000; + } + } + final HttpHost target = (HttpHost) myContext.getAttribute(HttpCoreContext.HTTP_TARGET_HOST); + if ("localhost".equalsIgnoreCase(target.getHostName())) { + return 10 * 1000; + } else { + return 5 * 1000; + } + } + + }; + PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); + HttpClients.custom() + .setKeepAliveStrategy(myStrategy) + .setConnectionManager(connManager) + .build(); + } + + // Example 6.1. BasicHttpClientConnectionManager Connection Reuse + @Test + public final void givenBasicHttpClientConnManager_whenConnectionReuse_thenNoExceptions() throws IOException, HttpException, InterruptedException, ExecutionException { + BasicHttpClientConnectionManager basicConnManager = new BasicHttpClientConnectionManager(); + HttpClientContext context = HttpClientContext.create(); + + // low level + HttpRoute route = new HttpRoute(new HttpHost("www.baeldung.com", 443)); + ConnectionRequest connRequest = basicConnManager.requestConnection(route, null); + HttpClientConnection conn = connRequest.get(10, TimeUnit.SECONDS); + basicConnManager.connect(conn, route, 1000, context); + basicConnManager.routeComplete(conn, route, context); + + HttpRequestExecutor exeRequest = new HttpRequestExecutor(); + context.setTargetHost((new HttpHost("www.baeldung.com", 80))); + HttpGet get = new HttpGet("http://www.baeldung.com"); + exeRequest.execute(get, conn, context); + + basicConnManager.releaseConnection(conn, null, 1, TimeUnit.SECONDS); + + // high level + CloseableHttpClient client = HttpClients.custom() + .setConnectionManager(basicConnManager) + .build(); + client.execute(get); + } + + // Example 6.2. PoolingHttpClientConnectionManager: Re-Using Connections with Threads + @Test + public final void whenConnectionsNeededGreaterThanMaxTotal_thenLeaseMasTotalandReuse() throws InterruptedException { + HttpGet get = new HttpGet("http://echo.200please.com"); + PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); + connManager.setDefaultMaxPerRoute(5); + connManager.setMaxTotal(5); + CloseableHttpClient client = HttpClients.custom() + .setConnectionManager(connManager) + .build(); + MultiHttpClientConnThread[] threads = new MultiHttpClientConnThread[10]; + for (int i = 0; i < threads.length; i++) { + threads[i] = new MultiHttpClientConnThread(client, get, connManager); + } + for (MultiHttpClientConnThread thread : threads) { + thread.start(); + } + for (MultiHttpClientConnThread thread : threads) { + thread.join(1000); + } + } + + // Example 7.1. Setting Socket Timeout to 5 Seconds + @Test + public final void whenConfiguringTimeOut_thenNoExceptions() { + HttpRoute route = new HttpRoute(new HttpHost("www.baeldung.com", 80)); + try (PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager()) { + connManager.setSocketConfig(route.getTargetHost(), SocketConfig.custom() + .setSoTimeout(5000) + .build()); + assertTrue(connManager.getSocketConfig(route.getTargetHost()) + .getSoTimeout() == 5000); + } + } + + // Example 8.1. Setting the HttpClient to Check for Stale Connections + @Test + public final void whenHttpClientChecksStaleConns_thenNoExceptions() { + PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); + HttpClients.custom() + .setDefaultRequestConfig(RequestConfig.custom() + .setStaleConnectionCheckEnabled(true) + .build()) + .setConnectionManager(connManager) + .build(); + } + + // Example 8.2. Using a Stale Connection Monitor Thread + @Test + public final void whenCustomizedIdleConnMonitor_thenNoExceptions() throws InterruptedException { + PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); + HttpClients.custom() + .setConnectionManager(connManager) + .build(); + IdleConnectionMonitorThread staleMonitor = new IdleConnectionMonitorThread(connManager); + staleMonitor.start(); + staleMonitor.join(1000); + } + + // Example 9.1. Closing Connection and Releasing Resources + @Test(expected = IllegalStateException.class) + public final void whenClosingConnectionsandManager_thenCloseWithNoExceptions1() throws InterruptedException, ExecutionException, IOException, HttpException { + PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); + CloseableHttpClient client = HttpClients.custom() + .setConnectionManager(connManager) + .build(); + final HttpGet get = new HttpGet("http://google.com"); + CloseableHttpResponse response = client.execute(get); + + EntityUtils.consume(response.getEntity()); + response.close(); + client.close(); + connManager.close(); + connManager.shutdown(); + + client.execute(get); + + assertTrue(response.getEntity() == null); + } + + @Test + // Example 3.2. TESTER VERSION + public final void whenTwoConnectionsForTwoRequests_thenTwoConnectionsAreLeased() throws InterruptedException { + HttpGet get1 = new HttpGet("https://www.baeldung.com"); + HttpGet get2 = new HttpGet("https://www.google.com"); + + PoolingHttpClientConnectionManager poolingConnManager = new PoolingHttpClientConnectionManager(); + final CloseableHttpClient client1 = HttpClients.custom() + .setConnectionManager(poolingConnManager) + .build(); + final CloseableHttpClient client2 = HttpClients.custom() + .setConnectionManager(poolingConnManager) + .build(); + + final TesterVersion_MultiHttpClientConnThread thread1 = new TesterVersion_MultiHttpClientConnThread(client1, get1, poolingConnManager); + final TesterVersion_MultiHttpClientConnThread thread2 = new TesterVersion_MultiHttpClientConnThread(client2, get2, poolingConnManager); + thread1.start(); + thread2.start(); + thread1.join(); + thread2.join(1000); + assertTrue(poolingConnManager.getTotalStats() + .getLeased() == 2); + } + + @Test + // Example 4.2 Tester Version + public final void whenExecutingSameRequestsInDifferentThreads_thenUseDefaultConnLimit() throws InterruptedException { + PoolingHttpClientConnectionManager poolingConnManager = new PoolingHttpClientConnectionManager(); + CloseableHttpClient client = HttpClients.custom() + .setConnectionManager(poolingConnManager) + .build(); + final TesterVersion_MultiHttpClientConnThread thread1 = new TesterVersion_MultiHttpClientConnThread(client, new HttpGet("http://www.google.com"), poolingConnManager); + final TesterVersion_MultiHttpClientConnThread thread2 = new TesterVersion_MultiHttpClientConnThread(client, new HttpGet("http://www.google.com"), poolingConnManager); + final TesterVersion_MultiHttpClientConnThread thread3 = new TesterVersion_MultiHttpClientConnThread(client, new HttpGet("http://www.google.com"), poolingConnManager); + thread1.start(); + thread2.start(); + thread3.start(); + thread1.join(10000); + thread2.join(10000); + thread3.join(10000); + } + + @Test + // 6.2 TESTER VERSION + public final void whenConnectionsNeededGreaterThanMaxTotal_thenReuseConnections() throws InterruptedException { + PoolingHttpClientConnectionManager poolingConnManager = new PoolingHttpClientConnectionManager(); + poolingConnManager.setDefaultMaxPerRoute(5); + poolingConnManager.setMaxTotal(5); + CloseableHttpClient client = HttpClients.custom() + .setConnectionManager(poolingConnManager) + .build(); + final MultiHttpClientConnThread[] threads = new MultiHttpClientConnThread[10]; + int countConnMade = 0; + for (int i = 0; i < threads.length; i++) { + threads[i] = new MultiHttpClientConnThread(client, new HttpGet("http://www.baeldung.com/"), poolingConnManager); + } + for (final MultiHttpClientConnThread thread : threads) { + thread.start(); + } + for (final MultiHttpClientConnThread thread : threads) { + thread.join(10000); + countConnMade++; + if (countConnMade == 0) { + assertTrue(thread.getLeasedConn() == 5); + } + } + } + + @Test + @Ignore("Very Long Running") + // 8.2 TESTER VERSION + public final void whenCustomizedIdleConnMonitor_thenEliminateIdleConns() throws InterruptedException { + PoolingHttpClientConnectionManager poolingConnManager = new PoolingHttpClientConnectionManager(); + CloseableHttpClient client = HttpClients.custom() + .setConnectionManager(poolingConnManager) + .build(); + final IdleConnectionMonitorThread staleMonitor = new IdleConnectionMonitorThread(poolingConnManager); + final HttpGet get = new HttpGet("http://google.com"); + final TesterVersion_MultiHttpClientConnThread thread1 = new TesterVersion_MultiHttpClientConnThread(client, get, poolingConnManager); + final TesterVersion_MultiHttpClientConnThread thread2 = new TesterVersion_MultiHttpClientConnThread(client, get, poolingConnManager); + final TesterVersion_MultiHttpClientConnThread thread3 = new TesterVersion_MultiHttpClientConnThread(client, get, poolingConnManager); + staleMonitor.start(); + thread1.start(); + thread1.join(); + thread2.start(); + thread2.join(); + thread3.start(); + assertTrue(poolingConnManager.getTotalStats() + .getAvailable() == 1); + thread3.join(32000); + assertTrue(poolingConnManager.getTotalStats() + .getAvailable() == 0); + } +} diff --git a/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/conn/IdleConnectionMonitorThread.java b/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/conn/IdleConnectionMonitorThread.java new file mode 100644 index 0000000000..4bf97e4fa6 --- /dev/null +++ b/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/conn/IdleConnectionMonitorThread.java @@ -0,0 +1,41 @@ +package com.baeldung.httpclient.httpclient.conn; + +import java.util.concurrent.TimeUnit; + +import org.apache.http.conn.HttpClientConnectionManager; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; + +public class IdleConnectionMonitorThread extends Thread { + private final HttpClientConnectionManager connMgr; + private volatile boolean shutdown; + + IdleConnectionMonitorThread(final PoolingHttpClientConnectionManager connMgr) { + super(); + this.connMgr = connMgr; + } + + // API + + @Override + public final void run() { + try { + while (!shutdown) { + synchronized (this) { + wait(1000); + connMgr.closeExpiredConnections(); + connMgr.closeIdleConnections(30, TimeUnit.SECONDS); + } + } + } catch (final InterruptedException ex) { + shutdown(); + } + } + + private void shutdown() { + shutdown = true; + synchronized (this) { + notifyAll(); + } + } + +} diff --git a/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/conn/MultiHttpClientConnThread.java b/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/conn/MultiHttpClientConnThread.java new file mode 100644 index 0000000000..4183094621 --- /dev/null +++ b/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/conn/MultiHttpClientConnThread.java @@ -0,0 +1,69 @@ +package com.baeldung.httpclient.httpclient.conn; + +import java.io.IOException; + +import org.apache.http.HttpResponse; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.util.EntityUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MultiHttpClientConnThread extends Thread { + private final Logger logger = LoggerFactory.getLogger(getClass()); + + private final CloseableHttpClient client; + private final HttpGet get; + + private PoolingHttpClientConnectionManager connManager; + private int leasedConn; + + MultiHttpClientConnThread(final CloseableHttpClient client, final HttpGet get, final PoolingHttpClientConnectionManager connManager) { + this.client = client; + this.get = get; + this.connManager = connManager; + leasedConn = 0; + } + + MultiHttpClientConnThread(final CloseableHttpClient client, final HttpGet get) { + this.client = client; + this.get = get; + } + + // API + + final int getLeasedConn() { + return leasedConn; + } + + // + + @Override + public final void run() { + try { + logger.debug("Thread Running: " + getName()); + + logger.debug("Thread Running: " + getName()); + + if (connManager != null) { + logger.info("Before - Leased Connections = " + connManager.getTotalStats().getLeased()); + logger.info("Before - Available Connections = " + connManager.getTotalStats().getAvailable()); + } + + final HttpResponse response = client.execute(get); + + if (connManager != null) { + leasedConn = connManager.getTotalStats().getLeased(); + logger.info("After - Leased Connections = " + connManager.getTotalStats().getLeased()); + logger.info("After - Available Connections = " + connManager.getTotalStats().getAvailable()); + } + + EntityUtils.consume(response.getEntity()); + } catch (final IOException ex) { + logger.error("", ex); + } + } + +} diff --git a/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/conn/TesterVersion_MultiHttpClientConnThread.java b/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/conn/TesterVersion_MultiHttpClientConnThread.java new file mode 100644 index 0000000000..5e2710342d --- /dev/null +++ b/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/conn/TesterVersion_MultiHttpClientConnThread.java @@ -0,0 +1,46 @@ +package com.baeldung.httpclient.httpclient.conn; + +import java.io.IOException; + +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Preconditions; + +public class TesterVersion_MultiHttpClientConnThread extends Thread { + private final Logger logger = LoggerFactory.getLogger(getClass()); + + private final CloseableHttpClient client; + private final HttpGet get; + private PoolingHttpClientConnectionManager connManager; + + TesterVersion_MultiHttpClientConnThread(final CloseableHttpClient client, final HttpGet get, final PoolingHttpClientConnectionManager connManager) { + this.client = client; + this.get = get; + this.connManager = Preconditions.checkNotNull(connManager); + } + + // + + @Override + public final void run() { + try { + logger.debug("Thread Running: " + getName()); + + logger.info("Before - Leased Connections = " + connManager.getTotalStats().getLeased()); + logger.info("Before - Available Connections = " + connManager.getTotalStats().getAvailable()); + + client.execute(get); + + logger.info("After - Leased Connections = " + connManager.getTotalStats().getLeased()); + logger.info("After - Available Connections = " + connManager.getTotalStats().getAvailable()); + } catch (final IOException ex) { + logger.error("", ex); + } + } + +} diff --git a/apache-kafka-2/README.md b/apache-kafka-2/README.md index 81239d4a7b..dc675a0811 100644 --- a/apache-kafka-2/README.md +++ b/apache-kafka-2/README.md @@ -12,3 +12,4 @@ You can build the project from the command line using: *mvn clean install*, or i - [Is a Key Required as Part of Sending Messages to Kafka?](https://www.baeldung.com/java-kafka-message-key) - [Read Data From the Beginning Using Kafka Consumer API](https://www.baeldung.com/java-kafka-consumer-api-read) - [Get Partition Count for a Topic in Kafka](https://www.baeldung.com/java-kafka-partition-count-topic) +- [bootstrap-server in Kafka Configuration](https://www.baeldung.com/java-kafka-bootstrap-server) diff --git a/apache-kafka-2/src/main/java/com/baeldung/kafka/consumer/SimpleConsumerWithBootStrapServers.java b/apache-kafka-2/src/main/java/com/baeldung/kafka/consumer/SimpleConsumerWithBootStrapServers.java new file mode 100644 index 0000000000..7501b40056 --- /dev/null +++ b/apache-kafka-2/src/main/java/com/baeldung/kafka/consumer/SimpleConsumerWithBootStrapServers.java @@ -0,0 +1,39 @@ +package com.baeldung.kafka.consumer; + +import org.apache.kafka.clients.consumer.*; +import org.apache.kafka.common.serialization.LongDeserializer; +import org.apache.kafka.common.serialization.StringDeserializer; + +import java.time.Duration; +import java.util.Arrays; +import java.util.Properties; + +public class SimpleConsumerWithBootStrapServers { + + public static void main(String[] args) { + try(final Consumer consumer = createConsumer()) { + ConsumerRecords records = consumer.poll(Duration.ofMinutes(1)); + for(ConsumerRecord record : records) { + System.out.println(record.value()); + } + } + } + + private static Consumer createConsumer() { + final Properties props = new Properties(); + props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, + "localhost:9092,another-host.com:29092"); + props.put(ConsumerConfig.GROUP_ID_CONFIG, + "MySampleConsumer"); + props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, + LongDeserializer.class.getName()); + props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, + StringDeserializer.class.getName()); + // Create the consumer using props. + final Consumer consumer = new KafkaConsumer(props); + // Subscribe to the topic. + consumer.subscribe(Arrays.asList("samples")); + return consumer; + } + +} diff --git a/apache-libraries-2/README.md b/apache-libraries-2/README.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/apache-libraries-2/pom.xml b/apache-libraries-2/pom.xml new file mode 100644 index 0000000000..618ff4a188 --- /dev/null +++ b/apache-libraries-2/pom.xml @@ -0,0 +1,29 @@ + + + 4.0.0 + apache-libraries-2 + 0.0.1-SNAPSHOT + apache-libraries-2 + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + + + + + javax.validation + validation-api + ${javax.validation.validation-api.version} + + + + + + 2.0.1.Final + + + \ No newline at end of file diff --git a/apache-libraries-2/src/main/java/com/baeldung/xslt/XSLTProcessor.java b/apache-libraries-2/src/main/java/com/baeldung/xslt/XSLTProcessor.java new file mode 100644 index 0000000000..6bc0023485 --- /dev/null +++ b/apache-libraries-2/src/main/java/com/baeldung/xslt/XSLTProcessor.java @@ -0,0 +1,18 @@ +package com.baeldung.xslt; + +import javax.xml.transform.*; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; +import java.io.File; + +public class XSLTProcessor { + public static void transformXMLUsingXSLT(String inputXMLPath, String xsltPath, String outputHTMLPath) throws TransformerException { + Source xmlSource = new StreamSource(new File(inputXMLPath)); + Source xsltSource = new StreamSource(new File(xsltPath)); + Result output = new StreamResult(new File(outputHTMLPath)); + + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + Transformer transformer = transformerFactory.newTransformer(xsltSource); + transformer.transform(xmlSource, output); + } +} diff --git a/apache-libraries-2/src/main/resources/avroHttpRequest-schema.avsc b/apache-libraries-2/src/main/resources/avroHttpRequest-schema.avsc new file mode 100644 index 0000000000..18179a9cde --- /dev/null +++ b/apache-libraries-2/src/main/resources/avroHttpRequest-schema.avsc @@ -0,0 +1,47 @@ +{ + "type":"record", + "name":"AvroHttpRequest", + "namespace":"com.baeldung.avro.model", + "fields":[ + { + "name":"requestTime", + "type":"long" + }, + { + "name":"clientIdentifier", + "type":{ + "type":"record", + "name":"ClientIdentifier", + "fields":[ + { + "name":"hostName", + "type":"string" + }, + { + "name":"ipAddress", + "type":"string" + } + ] + } + }, + { + "name":"employeeNames", + "type":{ + "type":"array", + "items":"string" + }, + "default":null + }, + { + "name":"active", + "type":{ + "type":"enum", + "name":"Active", + "symbols":[ + "YES", + "NO" + ] + } + } + ] +} \ No newline at end of file diff --git a/apache-libraries-2/src/main/resources/log4j2.xml b/apache-libraries-2/src/main/resources/log4j2.xml new file mode 100644 index 0000000000..d1ea5173fa --- /dev/null +++ b/apache-libraries-2/src/main/resources/log4j2.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/apache-libraries-2/src/main/resources/logback.xml b/apache-libraries-2/src/main/resources/logback.xml new file mode 100644 index 0000000000..7d900d8ea8 --- /dev/null +++ b/apache-libraries-2/src/main/resources/logback.xml @@ -0,0 +1,13 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + \ No newline at end of file diff --git a/apache-libraries-2/src/test/java/com/baeldung/xslt/XSLTProcessorUnitTest.java b/apache-libraries-2/src/test/java/com/baeldung/xslt/XSLTProcessorUnitTest.java new file mode 100644 index 0000000000..cbfbf78c87 --- /dev/null +++ b/apache-libraries-2/src/test/java/com/baeldung/xslt/XSLTProcessorUnitTest.java @@ -0,0 +1,29 @@ +package com.baeldung.xslt; + +import org.junit.jupiter.api.Test; + +import javax.xml.transform.TransformerException; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class XSLTProcessorUnitTest { + + @Test + public void givenValidInputAndStylesheet_whenTransformingXML_thenOutputHTMLCreated() throws TransformerException, IOException { + // Given + String inputXMLPath = "src/test/resources/input.xml"; + String xsltPath = "src/test/resources/stylesheet.xslt"; + String outputHTMLPath = "src/test/resources/output.html"; + + + XSLTProcessor.transformXMLUsingXSLT(inputXMLPath, xsltPath, outputHTMLPath); + + + Path outputFile = Paths.get(outputHTMLPath); + assertTrue(Files.exists(outputFile)); + } +} diff --git a/apache-libraries-2/src/test/resources/input.xml b/apache-libraries-2/src/test/resources/input.xml new file mode 100644 index 0000000000..e283680337 --- /dev/null +++ b/apache-libraries-2/src/test/resources/input.xml @@ -0,0 +1,11 @@ + + + + John Doe + 30 + + + Jane Smith + 25 + + diff --git a/apache-libraries-2/src/test/resources/output.html b/apache-libraries-2/src/test/resources/output.html new file mode 100644 index 0000000000..b75e73ca15 --- /dev/null +++ b/apache-libraries-2/src/test/resources/output.html @@ -0,0 +1,3 @@ + +

Male person: John Doe, Age: 30

+

Female person: Jane Smith, Age: 25

diff --git a/apache-libraries-2/src/test/resources/stylesheet.xslt b/apache-libraries-2/src/test/resources/stylesheet.xslt new file mode 100644 index 0000000000..9f07852a2a --- /dev/null +++ b/apache-libraries-2/src/test/resources/stylesheet.xslt @@ -0,0 +1,22 @@ + + + + + + Male person: + + , Age: + + + + + + + Female person: + + , Age: + + + + + diff --git a/apache-poi-2/README.md b/apache-poi-2/README.md index 0132147201..65641e7c37 100644 --- a/apache-poi-2/README.md +++ b/apache-poi-2/README.md @@ -13,4 +13,5 @@ This module contains articles about Apache POI. - [Setting Formulas in Excel with Apache POI](https://www.baeldung.com/java-apache-poi-set-formulas) - [Set the Date Format Using Apache POI](https://www.baeldung.com/java-apache-poi-date-format) - [Replacing Variables in a Document Template with Java](https://www.baeldung.com/java-replace-pattern-word-document-doc-docx) +- [Lock Header Rows With Apache POI](https://www.baeldung.com/java-apache-poi-lock-header-rows) - More articles: [[<-- prev]](../apache-poi) diff --git a/aws-modules/aws-s3-update-object/pom.xml b/aws-modules/aws-s3-update-object/pom.xml new file mode 100644 index 0000000000..574a63977b --- /dev/null +++ b/aws-modules/aws-s3-update-object/pom.xml @@ -0,0 +1,42 @@ + + + 4.0.0 + aws-s3-update-object + 0.0.1-SNAPSHOT + aws-s3-update-object + Project demonstrating overwriting of S3 objects + + com.baeldung + parent-boot-2 + 0.0.1-SNAPSHOT + ../../parent-boot-2 + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-test + test + + + com.amazonaws + aws-java-sdk + ${aws-java-sdk-version} + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + 1.12.523 + + diff --git a/aws-modules/aws-s3-update-object/src/main/java/com/baeldung/awss3updateobject/AwsS3UpdateObjectApplication.java b/aws-modules/aws-s3-update-object/src/main/java/com/baeldung/awss3updateobject/AwsS3UpdateObjectApplication.java new file mode 100644 index 0000000000..24866c287b --- /dev/null +++ b/aws-modules/aws-s3-update-object/src/main/java/com/baeldung/awss3updateobject/AwsS3UpdateObjectApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.awss3updateobject; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class AwsS3UpdateObjectApplication { + + public static void main(String[] args) { + SpringApplication.run(AwsS3UpdateObjectApplication.class, args); + } + +} diff --git a/aws-modules/aws-s3-update-object/src/main/java/com/baeldung/awss3updateobject/controller/FileController.java b/aws-modules/aws-s3-update-object/src/main/java/com/baeldung/awss3updateobject/controller/FileController.java new file mode 100644 index 0000000000..e87358ef56 --- /dev/null +++ b/aws-modules/aws-s3-update-object/src/main/java/com/baeldung/awss3updateobject/controller/FileController.java @@ -0,0 +1,24 @@ +package com.baeldung.awss3updateobject.controller; + +import com.baeldung.awss3updateobject.service.FileService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +@RestController +@RequestMapping("api/v1/file") +public class FileController { + + @Autowired + FileService fileService; + + @PostMapping("/upload") + public String uploadFile(@RequestParam("file") MultipartFile multipartFile) throws Exception { + return this.fileService.uploadFile(multipartFile); + } + + @PostMapping("/update") + public String updateFile(@RequestParam("file") MultipartFile multipartFile, @RequestParam("filePath") String exitingFilePath) throws Exception { + return this.fileService.updateFile(multipartFile, exitingFilePath); + } +} diff --git a/aws-modules/aws-s3-update-object/src/main/java/com/baeldung/awss3updateobject/service/FileService.java b/aws-modules/aws-s3-update-object/src/main/java/com/baeldung/awss3updateobject/service/FileService.java new file mode 100644 index 0000000000..23eaad7913 --- /dev/null +++ b/aws-modules/aws-s3-update-object/src/main/java/com/baeldung/awss3updateobject/service/FileService.java @@ -0,0 +1,80 @@ +package com.baeldung.awss3updateobject.service; + +import com.amazonaws.auth.AWSCredentials; +import com.amazonaws.auth.AWSStaticCredentialsProvider; +import com.amazonaws.auth.BasicAWSCredentials; +import com.amazonaws.regions.Regions; +import com.amazonaws.services.s3.AmazonS3; +import com.amazonaws.services.s3.AmazonS3ClientBuilder; +import com.amazonaws.services.s3.model.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.PostConstruct; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +@Service +public class FileService { + + private static final Logger logger = LoggerFactory.getLogger(FileService.class); + + public AmazonS3 amazonS3; + + @Value("${aws.s3bucket}") + public String awsS3Bucket; + + @PostConstruct + private void init(){ + AWSCredentials credentials = new BasicAWSCredentials( + "AWS AccessKey", + "AWS secretKey" + ); + this.amazonS3 = AmazonS3ClientBuilder.standard() + .withRegion(Regions.fromName("us-east-1")) + .withCredentials(new AWSStaticCredentialsProvider(credentials)) + .build(); + } + + public String uploadFile(MultipartFile multipartFile) throws Exception { + String key = "/documents/" + multipartFile.getOriginalFilename(); + return this.uploadDocument(this.awsS3Bucket, key, multipartFile); + } + + public String updateFile(MultipartFile multipartFile, String key) throws Exception { + return this.uploadDocument(this.awsS3Bucket, key, multipartFile); + } + + private String uploadDocument(String s3bucket, String key, MultipartFile multipartFile) throws Exception { + try { + ObjectMetadata metadata = new ObjectMetadata(); + metadata.setContentType(multipartFile.getContentType()); + Map attributes = new HashMap<>(); + attributes.put("document-content-size", String.valueOf(multipartFile.getSize())); + metadata.setUserMetadata(attributes); + InputStream documentStream = multipartFile.getInputStream(); + PutObjectResult putObjectResult = this.amazonS3.putObject(new PutObjectRequest(s3bucket, key, documentStream, metadata)); + + S3Object s3Object = this.amazonS3.getObject(s3bucket, key); + logger.info("Last Modified: " + s3Object.getObjectMetadata().getLastModified()); + return key; + } catch (AmazonS3Exception ex) { + if (ex.getErrorCode().equalsIgnoreCase("NoSuchBucket")) { + String msg = String.format("No bucket found with name %s", s3bucket); + throw new Exception(msg); + } else if (ex.getErrorCode().equalsIgnoreCase("AccessDenied")) { + String msg = String.format("Access denied to S3 bucket %s", s3bucket); + throw new Exception(msg); + } + throw ex; + } catch (IOException ex) { + String msg = String.format("Error saving file %s to AWS S3 bucket %s", key, s3bucket); + throw new Exception(msg); + } + } +} diff --git a/aws-modules/aws-s3-update-object/src/main/resources/application.properties b/aws-modules/aws-s3-update-object/src/main/resources/application.properties new file mode 100644 index 0000000000..c840d970a8 --- /dev/null +++ b/aws-modules/aws-s3-update-object/src/main/resources/application.properties @@ -0,0 +1 @@ +aws.s3bucket=baeldung-documents; diff --git a/aws-modules/aws-s3-update-object/src/test/java/com/baeldung/awss3updateobject/controller/FileControllerUnitTest.java b/aws-modules/aws-s3-update-object/src/test/java/com/baeldung/awss3updateobject/controller/FileControllerUnitTest.java new file mode 100644 index 0000000000..823391c139 --- /dev/null +++ b/aws-modules/aws-s3-update-object/src/test/java/com/baeldung/awss3updateobject/controller/FileControllerUnitTest.java @@ -0,0 +1,62 @@ +package com.baeldung.awss3updateobject.controller; + +import com.baeldung.awss3updateobject.service.FileService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.multipart.MultipartFile; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; + +public class FileControllerUnitTest { + + private MockMvc mockMvc; + + @Mock + private FileService fileService; + + @InjectMocks + private FileController fileController; + + @BeforeEach + public void setUp() { + MockitoAnnotations.openMocks(this); + this.mockMvc = MockMvcBuilders.standaloneSetup(fileController).build(); + } + + @Test + public void givenValidMultipartFile_whenUploadedViaEndpoint_thenCorrectPathIsReturned() throws Exception { + MockMultipartFile multipartFile = new MockMultipartFile("file", "test.txt", "text/plain", "sample file content".getBytes()); + String expectedResult = "File Uploaded Successfully"; + + when(fileService.uploadFile(multipartFile)).thenReturn(expectedResult); + + mockMvc.perform(multipart("/api/v1/file/upload").file(multipartFile)) + .andExpect(status().isOk()) + .andExpect(content().string(expectedResult)); + } + + @Test + public void givenValidMultipartFileAndExistingPath_whenUpdatedViaEndpoint_thenSamePathIsReturned() throws Exception { + MockMultipartFile multipartFile = new MockMultipartFile("file", "test.txt", "text/plain", "updated file content".getBytes()); + String filePath = "some/path/to/file"; + String expectedResult = "File Updated Successfully"; + + when(fileService.updateFile(multipartFile, filePath)).thenReturn(expectedResult); + + mockMvc.perform(multipart("/api/v1/file/update") + .file(multipartFile) + .param("filePath", filePath)) + .andExpect(status().isOk()) + .andExpect(content().string(expectedResult)); + } +} \ No newline at end of file diff --git a/aws-modules/aws-s3-update-object/src/test/java/com/baeldung/awss3updateobject/service/FileServiceUnitTest.java b/aws-modules/aws-s3-update-object/src/test/java/com/baeldung/awss3updateobject/service/FileServiceUnitTest.java new file mode 100644 index 0000000000..90ed77b148 --- /dev/null +++ b/aws-modules/aws-s3-update-object/src/test/java/com/baeldung/awss3updateobject/service/FileServiceUnitTest.java @@ -0,0 +1,99 @@ +package com.baeldung.awss3updateobject.service; + +import com.amazonaws.services.s3.AmazonS3; +import com.amazonaws.services.s3.model.AmazonS3Exception; +import com.amazonaws.services.s3.model.PutObjectRequest; +import com.amazonaws.services.s3.model.S3Object; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.io.InputStream; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +public class FileServiceUnitTest { + + @Mock + private AmazonS3 amazonS3; + + @Mock + private MultipartFile multipartFile; + + @InjectMocks + private FileService fileService; + + @BeforeEach + public void setup() { + MockitoAnnotations.openMocks(this); + fileService = new FileService(); + fileService.awsS3Bucket = "test-bucket"; + fileService.amazonS3 = amazonS3; + } + + @Test + public void givenValidFile_whenUploaded_thenKeyMatchesDocumentPath() throws Exception { + when(multipartFile.getName()).thenReturn("testFile"); + when(multipartFile.getOriginalFilename()).thenReturn("testFile"); + when(multipartFile.getContentType()).thenReturn("application/pdf"); + when(multipartFile.getSize()).thenReturn(1024L); + when(multipartFile.getInputStream()).thenReturn(mock(InputStream.class)); + + S3Object s3Object = new S3Object(); + when(amazonS3.putObject(any())).thenReturn(null); + when(amazonS3.getObject(anyString(), anyString())).thenReturn(s3Object); + + String key = fileService.uploadFile(multipartFile); + + assertEquals("/documents/testFile", key); + } + + @Test + public void givenValidFile_whenUploadFailsDueToNoBucket_thenExceptionIsThrown() throws Exception { + when(multipartFile.getName()).thenReturn("testFile"); + when(multipartFile.getOriginalFilename()).thenReturn("testFile"); + when(multipartFile.getContentType()).thenReturn("application/pdf"); + when(multipartFile.getSize()).thenReturn(1024L); + when(multipartFile.getInputStream()).thenReturn(mock(InputStream.class)); + + AmazonS3Exception exception = new AmazonS3Exception("Test exception"); + exception.setErrorCode("NoSuchBucket"); + when(amazonS3.putObject(any(PutObjectRequest.class))).thenThrow(exception); + + assertThrows(Exception.class, () -> fileService.uploadFile(multipartFile)); + } + + @Test + public void givenExistingFile_whenUpdated_thenSameKeyIsReturned() throws Exception { + when(multipartFile.getName()).thenReturn("testFile"); + when(multipartFile.getContentType()).thenReturn("application/pdf"); + when(multipartFile.getSize()).thenReturn(1024L); + when(multipartFile.getInputStream()).thenReturn(mock(InputStream.class)); + + S3Object s3Object = new S3Object(); + when(amazonS3.putObject(any(PutObjectRequest.class))).thenReturn(null); + when(amazonS3.getObject(anyString(), anyString())).thenReturn(s3Object); + + String key = "/documents/existingFile"; + String resultKey = fileService.updateFile(multipartFile, key); + + assertEquals(key, resultKey); + } + + @Test + public void givenFileWithIOException_whenUpdated_thenExceptionIsThrown() throws Exception { + when(multipartFile.getName()).thenReturn("testFile"); + when(multipartFile.getContentType()).thenReturn("application/pdf"); + when(multipartFile.getSize()).thenReturn(1024L); + when(multipartFile.getInputStream()).thenThrow(new IOException("Test IO Exception")); + + assertThrows(Exception.class, () -> fileService.updateFile(multipartFile, "/documents/existingFile")); + } +} \ No newline at end of file diff --git a/aws-modules/aws-s3/README.md b/aws-modules/aws-s3/README.md index 3389fdf454..59c9f893d9 100644 --- a/aws-modules/aws-s3/README.md +++ b/aws-modules/aws-s3/README.md @@ -8,4 +8,5 @@ This module contains articles about Simple Storage Service (S3) on AWS - [Multipart Uploads in Amazon S3 with Java](https://www.baeldung.com/aws-s3-multipart-upload) - [Using the JetS3t Java Client With Amazon S3](https://www.baeldung.com/jets3t-amazon-s3) - [Check if a Specified Key Exists in a Given S3 Bucket Using Java](https://www.baeldung.com/java-aws-s3-check-specified-key-exists) -- [Listing All AWS S3 Objects in a Bucket Using Java](https://www.baeldung.com/java-aws-s3-list-bucket-objects) \ No newline at end of file +- [Listing All AWS S3 Objects in a Bucket Using Java](https://www.baeldung.com/java-aws-s3-list-bucket-objects) +- [Update an Existing Amazon S3 Object Using Java](https://www.baeldung.com/java-update-amazon-s3-object) diff --git a/aws-modules/aws-s3/src/main/java/com/baeldung/s3/RenameObjectService.java b/aws-modules/aws-s3/src/main/java/com/baeldung/s3/RenameObjectService.java new file mode 100644 index 0000000000..0ca586c73b --- /dev/null +++ b/aws-modules/aws-s3/src/main/java/com/baeldung/s3/RenameObjectService.java @@ -0,0 +1,79 @@ +package com.baeldung.s3; + +import java.util.List; + +import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.model.CopyObjectRequest; +import software.amazon.awssdk.services.s3.model.DeleteObjectRequest; +import software.amazon.awssdk.services.s3.model.ListObjectsV2Request; +import software.amazon.awssdk.services.s3.model.ListObjectsV2Response; +import software.amazon.awssdk.services.s3.model.S3Object; + +public class RenameObjectService { + + private S3Client s3Client; + + public RenameObjectService(S3Client s3Client) { + this.s3Client = s3Client; + } + + public RenameObjectService() { + init(); + } + + public void init() { + this.s3Client = S3Client.builder() + .region(Region.US_EAST_1) + .credentialsProvider(ProfileCredentialsProvider.create("default")) + .build(); + } + + public void renameFile(String bucketName, String keyName, String destinationKeyName) { + CopyObjectRequest copyObjRequest = CopyObjectRequest.builder() + .sourceBucket(bucketName) + .sourceKey(keyName) + .destinationBucket(destinationKeyName) + .destinationKey(bucketName) + .build(); + s3Client.copyObject(copyObjRequest); + DeleteObjectRequest deleteRequest = DeleteObjectRequest.builder() + .bucket(bucketName) + .key(keyName) + .build(); + s3Client.deleteObject(deleteRequest); + } + + public void renameFolder(String bucketName, String sourceFolderKey, String destinationFolderKey) { + ListObjectsV2Request listRequest = ListObjectsV2Request.builder() + .bucket(bucketName) + .prefix(sourceFolderKey) + .build(); + + ListObjectsV2Response listResponse = s3Client.listObjectsV2(listRequest); + List objects = listResponse.contents(); + + for (S3Object s3Object : objects) { + String newKey = destinationFolderKey + s3Object.key() + .substring(sourceFolderKey.length()); + + // Copy object to destination folder + CopyObjectRequest copyRequest = CopyObjectRequest.builder() + .sourceBucket(bucketName) + .sourceKey(s3Object.key()) + .destinationBucket(bucketName) + .destinationKey(newKey) + .build(); + s3Client.copyObject(copyRequest); + + // Delete object from source folder + DeleteObjectRequest deleteRequest = DeleteObjectRequest.builder() + .bucket(bucketName) + .key(s3Object.key()) + .build(); + s3Client.deleteObject(deleteRequest); + } + } + +} diff --git a/aws-modules/pom.xml b/aws-modules/pom.xml index 02473815b5..b94faafa86 100644 --- a/aws-modules/pom.xml +++ b/aws-modules/pom.xml @@ -19,6 +19,7 @@ aws-miscellaneous aws-reactive aws-s3 + aws-s3-update-object diff --git a/core-java-modules/core-java-arrays-convert/README.md b/core-java-modules/core-java-arrays-convert/README.md index b68773463d..dcaaaac12e 100644 --- a/core-java-modules/core-java-arrays-convert/README.md +++ b/core-java-modules/core-java-arrays-convert/README.md @@ -9,3 +9,4 @@ This module contains articles about arrays conversion in Java - [Converting a String Array Into an int Array in Java](https://www.baeldung.com/java-convert-string-array-to-int-array) - [Convert Java Array to Iterable](https://www.baeldung.com/java-array-convert-to-iterable) - [Converting an int[] to HashSet in Java](https://www.baeldung.com/java-converting-int-array-to-hashset) +- [Convert an ArrayList of String to a String Array in Java](https://www.baeldung.com/java-convert-string-arraylist-array) diff --git a/core-java-modules/core-java-arrays-convert/pom.xml b/core-java-modules/core-java-arrays-convert/pom.xml index c90b60e09a..480e1b3f07 100644 --- a/core-java-modules/core-java-arrays-convert/pom.xml +++ b/core-java-modules/core-java-arrays-convert/pom.xml @@ -20,5 +20,4 @@ ${commons-lang3.version} - \ No newline at end of file diff --git a/core-java-modules/core-java-arrays-operations-advanced/README.md b/core-java-modules/core-java-arrays-operations-advanced/README.md index e3465c9fa3..b379958f37 100644 --- a/core-java-modules/core-java-arrays-operations-advanced/README.md +++ b/core-java-modules/core-java-arrays-operations-advanced/README.md @@ -13,3 +13,4 @@ This module contains articles about advanced operations on arrays in Java. They - [Performance of System.arraycopy() vs. Arrays.copyOf()](https://www.baeldung.com/java-system-arraycopy-arrays-copyof-performance) - [Slicing Arrays in Java](https://www.baeldung.com/java-slicing-arrays) - [Combining Two or More Byte Arrays](https://www.baeldung.com/java-concatenate-byte-arrays) +- [Calculating the Sum of Two Arrays in Java](https://www.baeldung.com/java-sum-arrays-element-wise) diff --git a/core-java-modules/core-java-arrays-operations-advanced/src/main/java/com/baeldung/arraysums/SumArraysUsingForEach.java b/core-java-modules/core-java-arrays-operations-advanced/src/main/java/com/baeldung/arraysums/SumArraysUsingForEach.java new file mode 100644 index 0000000000..3c2a75a409 --- /dev/null +++ b/core-java-modules/core-java-arrays-operations-advanced/src/main/java/com/baeldung/arraysums/SumArraysUsingForEach.java @@ -0,0 +1,14 @@ +package com.baeldung.arraysums; + +public class SumArraysUsingForEach { + + public static int[] sumOfTwoArrays(int[] arr1, int[] arr2) { + int[] arr3 = new int[arr1.length]; + int counter = 0; + for (int num1 : arr1) { + arr3[counter] = num1 + arr2[counter]; + counter++; + } + return arr3; + } +} diff --git a/core-java-modules/core-java-arrays-operations-advanced/src/main/java/com/baeldung/arraysums/SumArraysUsingForLoop.java b/core-java-modules/core-java-arrays-operations-advanced/src/main/java/com/baeldung/arraysums/SumArraysUsingForLoop.java new file mode 100644 index 0000000000..32e2e939d4 --- /dev/null +++ b/core-java-modules/core-java-arrays-operations-advanced/src/main/java/com/baeldung/arraysums/SumArraysUsingForLoop.java @@ -0,0 +1,12 @@ +package com.baeldung.arraysums; + +public class SumArraysUsingForLoop { + + public static int[] sumOfTwoArrays(int[] arr1, int[] arr2) { + int[] arr3 = new int[arr1.length]; + for (int i = 0; i < arr1.length; i++) { + arr3[i] = arr1[i] + arr2[i]; + } + return arr3; + } +} diff --git a/core-java-modules/core-java-arrays-operations-advanced/src/main/java/com/baeldung/arraysums/SumArraysUsingStreams.java b/core-java-modules/core-java-arrays-operations-advanced/src/main/java/com/baeldung/arraysums/SumArraysUsingStreams.java new file mode 100644 index 0000000000..40bfda4b74 --- /dev/null +++ b/core-java-modules/core-java-arrays-operations-advanced/src/main/java/com/baeldung/arraysums/SumArraysUsingStreams.java @@ -0,0 +1,14 @@ +package com.baeldung.arraysums; + +import java.util.Arrays; +import java.util.stream.IntStream; + +public class SumArraysUsingStreams { + + public static int[] sumOfTwoArrays(int[] arr1, int[] arr2) { + IntStream range = IntStream.range(0, Math.min(arr1.length, arr2.length)); + IntStream stream3 = range.map(i -> arr1[i] + arr2[i]); + int[] arr3 = stream3.toArray(); + return arr3; + } +} diff --git a/core-java-modules/core-java-arrays-operations-advanced/src/test/java/com/baeldung/arraysums/SumArraysUsingForEachUnitTest.java b/core-java-modules/core-java-arrays-operations-advanced/src/test/java/com/baeldung/arraysums/SumArraysUsingForEachUnitTest.java new file mode 100644 index 0000000000..883b35b223 --- /dev/null +++ b/core-java-modules/core-java-arrays-operations-advanced/src/test/java/com/baeldung/arraysums/SumArraysUsingForEachUnitTest.java @@ -0,0 +1,16 @@ +package com.baeldung.arraysums; + +import com.baeldung.arraysums.SumArraysUsingForEach; +import org.junit.Test; +import static org.junit.Assert.*; + +public class SumArraysUsingForEachUnitTest { + + @Test + public void sumOfTwoArraysUsingForEach_GivenTwoEqualSizedIntArrays_ReturnsCorrectSumArray() { + int[] arr1 = { 4, 5, 1, 6, 4, 15 }; + int[] arr2 = { 3, 5, 6, 1, 9, 6 }; + int[] expected = { 7, 10, 7, 7, 13, 21 }; + assertArrayEquals(expected, SumArraysUsingForEach.sumOfTwoArrays(arr1, arr2)); + } +} diff --git a/core-java-modules/core-java-arrays-operations-advanced/src/test/java/com/baeldung/arraysums/SumArraysUsingForLoopUnitTest.java b/core-java-modules/core-java-arrays-operations-advanced/src/test/java/com/baeldung/arraysums/SumArraysUsingForLoopUnitTest.java new file mode 100644 index 0000000000..7cffd5f4ff --- /dev/null +++ b/core-java-modules/core-java-arrays-operations-advanced/src/test/java/com/baeldung/arraysums/SumArraysUsingForLoopUnitTest.java @@ -0,0 +1,16 @@ +package com.baeldung.arraysums; + +import com.baeldung.arraysums.SumArraysUsingForLoop; +import org.junit.Test; +import static org.junit.Assert.*; + +public class SumArraysUsingForLoopUnitTest { + + @Test + public void sumOfTwoArrays_GivenTwoEqualSizedIntArrays_ReturnsCorrectSumArray() { + int[] arr1 = {4, 5, 1, 6, 4, 15}; + int[] arr2 = {3, 5, 6, 1, 9, 6}; + int[] expected = {7, 10, 7, 7, 13, 21}; + assertArrayEquals(expected, SumArraysUsingForLoop.sumOfTwoArrays(arr1, arr2)); + } +} diff --git a/core-java-modules/core-java-arrays-operations-advanced/src/test/java/com/baeldung/arraysums/SumArraysUsingStreamsUnitTest.java b/core-java-modules/core-java-arrays-operations-advanced/src/test/java/com/baeldung/arraysums/SumArraysUsingStreamsUnitTest.java new file mode 100644 index 0000000000..62ea465ab0 --- /dev/null +++ b/core-java-modules/core-java-arrays-operations-advanced/src/test/java/com/baeldung/arraysums/SumArraysUsingStreamsUnitTest.java @@ -0,0 +1,16 @@ +package com.baeldung.arraysums; + +import com.baeldung.arraysums.SumArraysUsingStreams; +import org.junit.Test; +import static org.junit.Assert.*; + +public class SumArraysUsingStreamsUnitTest { + + @Test + public void sumOfTwoArraysUsingStreams_GivenTwoEqualSizedIntArrays_ReturnsCorrectSumArray() { + int[] arr1 = {4, 5, 1, 6, 4, 15}; + int[] arr2 = {3, 5, 6, 1, 9, 6}; + int[] expected = {7, 10, 7, 7, 13, 21}; + assertArrayEquals(expected, SumArraysUsingStreams.sumOfTwoArrays(arr1, arr2)); + } +} diff --git a/core-java-modules/core-java-collections-conversions-2/README.md b/core-java-modules/core-java-collections-conversions-2/README.md index fe17af0a7a..e8d008104c 100644 --- a/core-java-modules/core-java-collections-conversions-2/README.md +++ b/core-java-modules/core-java-collections-conversions-2/README.md @@ -12,4 +12,6 @@ This module contains articles about conversions among Collection types and array - [Convert a List of Integers to a List of Strings](https://www.baeldung.com/java-convert-list-integers-to-list-strings) - [Combining Two Lists Into a Map in Java](https://www.baeldung.com/java-combine-two-lists-into-map) - [Convert a List of Strings to a List of Integers](https://www.baeldung.com/java-convert-list-strings-to-integers) +- [Convert List to Long[] Array in Java](https://www.baeldung.com/java-convert-list-object-to-long-array) +- [Get the First n Elements of a List Into an Array](https://www.baeldung.com/java-take-start-elements-list-array) - More articles: [[<-- prev]](../core-java-collections-conversions) diff --git a/core-java-modules/core-java-collections-conversions-2/pom.xml b/core-java-modules/core-java-collections-conversions-2/pom.xml index 8cd0a6932b..7b7533fc39 100644 --- a/core-java-modules/core-java-collections-conversions-2/pom.xml +++ b/core-java-modules/core-java-collections-conversions-2/pom.xml @@ -43,6 +43,7 @@ 0.10.3 + 11 + 3.1.1 - \ No newline at end of file diff --git a/core-java-modules/core-java-collections-conversions-2/src/test/java/com/baeldung/arrayconversion/ArrayListToArrayUnitTest.java b/core-java-modules/core-java-collections-conversions-2/src/test/java/com/baeldung/arrayconversion/ArrayListToArrayUnitTest.java new file mode 100644 index 0000000000..63cdf22f3a --- /dev/null +++ b/core-java-modules/core-java-collections-conversions-2/src/test/java/com/baeldung/arrayconversion/ArrayListToArrayUnitTest.java @@ -0,0 +1,46 @@ +package com.baeldung.arrayconversion; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + +import java.util.List; + +import org.junit.jupiter.api.Test; + +import com.google.common.collect.Lists; + +public class ArrayListToArrayUnitTest { + private static final List INPUT_LIST = Lists.newArrayList("Michael Bolton", "Michael Jackson", "Guns and Roses", "Bryan Adams", "Air Supply"); + private static final String[] EXPECTED_ARRAY = new String[] { "Michael Bolton", "Michael Jackson", "Guns and Roses", "Bryan Adams", "Air Supply" }; + + @Test + void whenUsingForLoop_thenGetExpectedResult() { + String[] result = new String[INPUT_LIST.size()]; + for (int i = 0; i < INPUT_LIST.size(); i++) { + result[i] = INPUT_LIST.get(i); + } + assertArrayEquals(EXPECTED_ARRAY, result); + } + + @Test + void whenUsingListToArray_thenGetExpectedResult() { + String[] result = new String[INPUT_LIST.size()]; + INPUT_LIST.toArray(result); + assertArrayEquals(EXPECTED_ARRAY, result); + + String[] result2 = INPUT_LIST.toArray(new String[0]); + assertArrayEquals(EXPECTED_ARRAY, result2); + } + + @Test + void whenUsingStreamApi_thenGetExpectedResult() { + String[] result = INPUT_LIST.stream() + .toArray(String[]::new); + assertArrayEquals(EXPECTED_ARRAY, result); + } + + @Test + void whenUsingListToArrayInJava11_thenGetExpectedResult() { + String[] result = INPUT_LIST.toArray(String[]::new); + assertArrayEquals(EXPECTED_ARRAY, result); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-collections-conversions-2/src/test/java/com/baeldung/arrayconversion/ListToArrayFirstNElementsUnitTest.java b/core-java-modules/core-java-collections-conversions-2/src/test/java/com/baeldung/arrayconversion/ListToArrayFirstNElementsUnitTest.java new file mode 100644 index 0000000000..c9818613fe --- /dev/null +++ b/core-java-modules/core-java-collections-conversions-2/src/test/java/com/baeldung/arrayconversion/ListToArrayFirstNElementsUnitTest.java @@ -0,0 +1,56 @@ +package com.baeldung.arrayconversion; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + +import java.util.Iterator; +import java.util.List; + +import org.junit.jupiter.api.Test; + +import com.google.common.collect.Lists; + +public class ListToArrayFirstNElementsUnitTest { + private static final List INPUT_LIST = Lists.newArrayList("one", "two", "three", "four", "five", "six", "seven"); + private static final int n = 5; + + @Test + void whenUsingForLoop_thenGetExpectedArray() { + String[] result = new String[n]; + for (int i = 0; i < n; i++) { + result[i] = INPUT_LIST.get(i); + } + assertArrayEquals(new String[] { "one", "two", "three", "four", "five" }, result); + + String[] result2 = new String[n]; + Iterator iterator = INPUT_LIST.iterator(); + for (int i = 0; i < n && iterator.hasNext(); i++) { + result2[i] = iterator.next(); + } + assertArrayEquals(new String[] { "one", "two", "three", "four", "five" }, result2); + } + + @Test + void whenUsingSubList_thenGetExpectedArray() { + String[] result = new String[n]; + INPUT_LIST.subList(0, n) + .toArray(result); + assertArrayEquals(new String[] { "one", "two", "three", "four", "five" }, result); + + String[] result2 = INPUT_LIST.subList(0, n) + .toArray(new String[0]); + assertArrayEquals(new String[] { "one", "two", "three", "four", "five" }, result2); + + // available only for java 11+ + String[] result3 = INPUT_LIST.subList(0, n) + .toArray(String[]::new); + assertArrayEquals(new String[] { "one", "two", "three", "four", "five" }, result3); + } + + @Test + void whenUsingStream_thenGetExpectedArray() { + String[] result = INPUT_LIST.stream() + .limit(n) + .toArray(String[]::new); + assertArrayEquals(new String[] { "one", "two", "three", "four", "five" }, result); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-collections-maps-3/README.md b/core-java-modules/core-java-collections-maps-3/README.md index 68df2b9556..0d07bde8c1 100644 --- a/core-java-modules/core-java-collections-maps-3/README.md +++ b/core-java-modules/core-java-collections-maps-3/README.md @@ -9,4 +9,5 @@ This module contains articles about Map data structures in Java. - [Collections.synchronizedMap vs. ConcurrentHashMap](https://www.baeldung.com/java-synchronizedmap-vs-concurrenthashmap) - [Java HashMap Load Factor](https://www.baeldung.com/java-hashmap-load-factor) - [Converting Java Properties to HashMap](https://www.baeldung.com/java-convert-properties-to-hashmap) +- [Get Values and Keys as ArrayList From a HashMap](https://www.baeldung.com/java-values-keys-arraylists-hashmap) - More articles: [[<-- prev]](/core-java-modules/core-java-collections-maps-2) diff --git a/core-java-modules/core-java-collections-maps-3/src/test/java/com/baeldung/map/hashmap/kvtolist/MapKeysValuesToListUnitTest.java b/core-java-modules/core-java-collections-maps-3/src/test/java/com/baeldung/map/hashmap/kvtolist/MapKeysValuesToListUnitTest.java new file mode 100644 index 0000000000..39c537bac2 --- /dev/null +++ b/core-java-modules/core-java-collections-maps-3/src/test/java/com/baeldung/map/hashmap/kvtolist/MapKeysValuesToListUnitTest.java @@ -0,0 +1,72 @@ +package com.baeldung.map.hashmap.kvtolist; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.junit.jupiter.api.Test; + +public class MapKeysValuesToListUnitTest { + private static final HashMap DEV_MAP; + + static { + DEV_MAP = new HashMap<>(); + DEV_MAP.put("Kent", "Linux"); + DEV_MAP.put("Eric", "MacOS"); + DEV_MAP.put("Kevin", "Windows"); + DEV_MAP.put("Michal", "MacOS"); + DEV_MAP.put("Saajan", "Linux"); + } + + @Test + void whenUsingKeySet_thenGetExpectedResult() { + List keyList = new ArrayList<>(DEV_MAP.keySet()); + // this assertion may fail, since hashMap doesn't preserve the insertion order + // assertEquals(Lists.newArrayList("Kent", "Eric", "Kevin", "Michal", "Saajan"), keyList); + + assertThat(keyList).containsExactlyInAnyOrder("Kent", "Eric", "Kevin", "Michal", "Saajan"); + + } + + @Test + void whenUsingValues_thenGetExpectedResult() { + List valueList = new ArrayList<>(DEV_MAP.values()); + assertThat(valueList).containsExactlyInAnyOrder("Linux", "MacOS", "Windows", "MacOS", "Linux"); + } + + @Test + void whenLoopingEntries_thenGetExpectedResult() { + List keyList = new ArrayList<>(); + List valueList = new ArrayList<>(); + for (Map.Entry entry : DEV_MAP.entrySet()) { + keyList.add(entry.getKey()); + valueList.add(entry.getValue()); + } + + assertKeyAndValueList(keyList, valueList); + + } + + @Test + void whenUsingForEach_thenGetExpectedResult() { + List keyList = new ArrayList<>(); + List valueList = new ArrayList<>(); + DEV_MAP.forEach((k, v) -> { + keyList.add(k); + valueList.add(v); + }); + + assertKeyAndValueList(keyList, valueList); + } + + private void assertKeyAndValueList(List keyList, List valueList) { + assertThat(keyList).containsExactlyInAnyOrder("Kent", "Eric", "Kevin", "Michal", "Saajan"); + assertThat(valueList).containsExactlyInAnyOrder("Linux", "MacOS", "Windows", "MacOS", "Linux"); + for (int i = 0; i < keyList.size(); i++) { + assertThat(DEV_MAP).containsEntry(keyList.get(i), valueList.get(i)); + } + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-collections-maps-6/README.md b/core-java-modules/core-java-collections-maps-6/README.md index bebcdea82b..d4f432bdcb 100644 --- a/core-java-modules/core-java-collections-maps-6/README.md +++ b/core-java-modules/core-java-collections-maps-6/README.md @@ -8,3 +8,4 @@ - [How to Modify a Key in a HashMap?](https://www.baeldung.com/java-hashmap-modify-key) - [Converting String or String Array to Map in Java](https://www.baeldung.com/java-convert-string-to-map) - [Remove Duplicate Values From HashMap in Java](https://www.baeldung.com/java-hashmap-delete-duplicates) +- [Sorting Java Map in Descending Order](https://www.baeldung.com/java-sort-map-descending) diff --git a/core-java-modules/core-java-collections-set-2/pom.xml b/core-java-modules/core-java-collections-set-2/pom.xml index 680c01d8ca..d1a108f8bb 100644 --- a/core-java-modules/core-java-collections-set-2/pom.xml +++ b/core-java-modules/core-java-collections-set-2/pom.xml @@ -20,6 +20,17 @@ ${junit-platform.version} test + + org.testng + testng + 7.7.0 + test + + + com.google.guava + guava + 32.1.1-jre + diff --git a/core-java-modules/core-java-collections-set-2/src/main/java/com/baeldung/cartesianproduct/CartesianProduct.java b/core-java-modules/core-java-collections-set-2/src/main/java/com/baeldung/cartesianproduct/CartesianProduct.java new file mode 100644 index 0000000000..d4725d74f1 --- /dev/null +++ b/core-java-modules/core-java-collections-set-2/src/main/java/com/baeldung/cartesianproduct/CartesianProduct.java @@ -0,0 +1,75 @@ +package com.baeldung.cartesianproduct; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import com.google.common.collect.Sets; + +public class CartesianProduct { + public List> getCartesianProductIterative(List> sets) { + List> result = new ArrayList<>(); + if(sets == null || sets.isEmpty()) { + return result; + } + int totalSets = sets.size(); + int totalCombinations = 1 << totalSets; + for(int i = 0; i < totalCombinations; i++) { + List combination = new ArrayList<>(); + for(int j = 0; j < totalSets; j++) { + if (((i >> j) & 1) == 1) { + combination.add(sets.get(j).get(0)); + } else { + combination.add(sets.get(j).get(1)); + } + } + result.add(combination); + } + return result; + } + + public List> getCartesianProductRecursive(List> sets) { + List> result = new ArrayList<>(); + getCartesianProductRecursiveHelper(sets, 0, new ArrayList<>(), result); + return result; + } + + private void getCartesianProductRecursiveHelper(List> sets, int index, List current, List> result) { + if(index == sets.size()) { + result.add(new ArrayList<>(current)); + return; + } + List currentSet = sets.get(index); + for(Object element: currentSet) { + current.add(element); + getCartesianProductRecursiveHelper(sets, index+1, current, result); + current.remove(current.size() - 1); + } + } + + public List> getCartesianProductUsingStreams(List> sets) { + return cartesianProduct(sets,0).collect(Collectors.toList()); + } + + public Stream> cartesianProduct(List> sets, int index) { + if(index == sets.size()) { + List emptyList = new ArrayList<>(); + return Stream.of(emptyList); + } + List currentSet = sets.get(index); + return currentSet.stream().flatMap(element -> cartesianProduct(sets, index+1) + .map(list -> { + List newList = new ArrayList<>(list); + newList.add(0, element); return newList; + })); + } + + public List> getCartesianProductUsingGuava(List> sets) { + Set> cartesianProduct = Sets.cartesianProduct(sets); + List> cartesianList = new ArrayList<>(cartesianProduct); + return cartesianList; + } + +} diff --git a/core-java-modules/core-java-collections-set-2/src/test/java/com/baeldung/cartesianproduct/CartesianProductUnitTest.java b/core-java-modules/core-java-collections-set-2/src/test/java/com/baeldung/cartesianproduct/CartesianProductUnitTest.java new file mode 100644 index 0000000000..cc9c01fb5f --- /dev/null +++ b/core-java-modules/core-java-collections-set-2/src/test/java/com/baeldung/cartesianproduct/CartesianProductUnitTest.java @@ -0,0 +1,93 @@ +package com.baeldung.cartesianproduct; + +import static org.testng.Assert.assertEquals; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.testng.annotations.Test; + +public class CartesianProductUnitTest { + private CartesianProduct cp = new CartesianProduct(); + List> sets = Arrays.asList( + Arrays.asList(10, 20), + Arrays.asList("John", "Jack"), + Arrays.asList('I', 'J') + ); + + @Test + public void whenUsingStreams_thenCalculateCartesianProduct() { + List> expected = Arrays.asList( + Arrays.asList(10, "John", 'I'), + Arrays.asList(10, "John", 'J'), + Arrays.asList(10, "Jack", 'I'), + Arrays.asList(10, "Jack", 'J'), + Arrays.asList(20, "John", 'I'), + Arrays.asList(20, "John", 'J'), + Arrays.asList(20, "Jack", 'I'), + Arrays.asList(20, "Jack", 'J') + ); + List> cartesianProduct = cp.getCartesianProductUsingStreams(sets); + + assertEquals(expected, cartesianProduct); + } + + @Test + public void whenUsingRecursion_thenCalculateCartesianProduct() { + List> expected = Arrays.asList( + Arrays.asList(10, "John", 'I'), + Arrays.asList(10, "John", 'J'), + Arrays.asList(10, "Jack", 'I'), + Arrays.asList(10, "Jack", 'J'), + Arrays.asList(20, "John", 'I'), + Arrays.asList(20, "John", 'J'), + Arrays.asList(20, "Jack", 'I'), + Arrays.asList(20, "Jack", 'J') + ); + List> cartesianProduct = cp.getCartesianProductRecursive(sets); + + assertEquals(expected, cartesianProduct); + } + + @Test + public void whenUsingIterativeApproach_thenCalculateCartesianProduct() { + List> expected = Arrays.asList( + Arrays.asList(20, "Jack", 'J'), + Arrays.asList(10, "Jack", 'J'), + Arrays.asList(20, "John", 'J'), + Arrays.asList(10, "John", 'J'), + Arrays.asList(20, "Jack", 'I'), + Arrays.asList(10, "Jack", 'I'), + Arrays.asList(20, "John", 'I'), + Arrays.asList(10, "John", 'I') + ); + List> cartesianProduct = cp.getCartesianProductIterative(sets); + + assertEquals(expected, cartesianProduct); + } + + @Test + public void whenUsingGuava_thenCalculateCartesianProduct() { + List> sets = new ArrayList<>(); + sets.add(new HashSet<>(Arrays.asList(10, 20))); + sets.add(new HashSet<>(Arrays.asList("John", "Jack"))); + sets.add(new HashSet<>(Arrays.asList('I', 'J'))); + + List> expected = Arrays.asList( + Arrays.asList(20, "John", 'I'), + Arrays.asList(20, "John", 'J'), + Arrays.asList(20, "Jack", 'I'), + Arrays.asList(20, "Jack", 'J'), + Arrays.asList(10, "John", 'I'), + Arrays.asList(10, "John", 'J'), + Arrays.asList(10, "Jack", 'I'), + Arrays.asList(10, "Jack", 'J') + ); + List> cartesianProduct = cp.getCartesianProductUsingGuava(sets); + + assertEquals(expected, cartesianProduct); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-concurrency-advanced/src/main/java/com/baeldung/concurrent/phaser/LongRunningAction.java b/core-java-modules/core-java-concurrency-advanced/src/main/java/com/baeldung/concurrent/phaser/LongRunningAction.java index 44f84ad77c..093cfdbc81 100644 --- a/core-java-modules/core-java-concurrency-advanced/src/main/java/com/baeldung/concurrent/phaser/LongRunningAction.java +++ b/core-java-modules/core-java-concurrency-advanced/src/main/java/com/baeldung/concurrent/phaser/LongRunningAction.java @@ -7,31 +7,37 @@ import java.util.concurrent.Phaser; class LongRunningAction implements Runnable { - private static Logger log = LoggerFactory.getLogger(LongRunningAction.class); - private String threadName; - private Phaser ph; + private static final Logger log = LoggerFactory.getLogger(LongRunningAction.class); + private final String threadName; + private final Phaser ph; LongRunningAction(String threadName, Phaser ph) { this.threadName = threadName; this.ph = ph; + + this.randomWait(); + ph.register(); + log.info("Thread {} registered during phase {}", threadName, ph.getPhase()); } @Override public void run() { - log.info("This is phase {}", ph.getPhase()); - log.info("Thread {} before long running action", threadName); - + log.info("Thread {} BEFORE long running action in phase {}", threadName, ph.getPhase()); + ph.arriveAndAwaitAdvance(); + + randomWait(); + + log.info("Thread {} AFTER long running action in phase {}", threadName, ph.getPhase()); + ph.arriveAndDeregister(); + } + + // Simulating real work + private void randomWait() { try { - Thread.sleep(2000); + Thread.sleep((long) (Math.random() * 100)); } catch (InterruptedException e) { e.printStackTrace(); } - - log.debug("Thread {} action completed and waiting for others", threadName); - ph.arriveAndAwaitAdvance(); - log.debug("Thread {} proceeding in phase {}", threadName, ph.getPhase()); - - ph.arriveAndDeregister(); } } \ No newline at end of file diff --git a/core-java-modules/core-java-concurrency-advanced/src/test/java/com/baeldung/concurrent/phaser/PhaserUnitTest.java b/core-java-modules/core-java-concurrency-advanced/src/test/java/com/baeldung/concurrent/phaser/PhaserUnitTest.java index 384a1837c1..9cb863073e 100644 --- a/core-java-modules/core-java-concurrency-advanced/src/test/java/com/baeldung/concurrent/phaser/PhaserUnitTest.java +++ b/core-java-modules/core-java-concurrency-advanced/src/test/java/com/baeldung/concurrent/phaser/PhaserUnitTest.java @@ -7,8 +7,6 @@ import org.junit.runners.MethodSorters; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import java.util.concurrent.Phaser; import static junit.framework.TestCase.assertEquals; @@ -16,38 +14,32 @@ import static junit.framework.TestCase.assertEquals; @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class PhaserUnitTest { - private static Logger log = LoggerFactory.getLogger(PhaserUnitTest.class); + private static final Logger log = LoggerFactory.getLogger(PhaserUnitTest.class); @Test - public void givenPhaser_whenCoordinateWorksBetweenThreads_thenShouldCoordinateBetweenMultiplePhases() { - //given - ExecutorService executorService = Executors.newCachedThreadPool(); + public void givenPhaser_whenCoordinateWorksBetweenThreads_thenShouldCoordinateBetweenMultiplePhases() throws InterruptedException { Phaser ph = new Phaser(1); assertEquals(0, ph.getPhase()); - //when - executorService.submit(new LongRunningAction("thread-1", ph)); - executorService.submit(new LongRunningAction("thread-2", ph)); - executorService.submit(new LongRunningAction("thread-3", ph)); + new Thread(new LongRunningAction("thread-1", ph)).start(); + new Thread(new LongRunningAction("thread-2", ph)).start(); + new Thread(new LongRunningAction("thread-3", ph)).start(); - //then - log.debug("Thread {} waiting for others", Thread.currentThread().getName()); + log.info("Thread {} waiting for others", Thread.currentThread().getName()); ph.arriveAndAwaitAdvance(); - log.debug("Thread {} proceeding in phase {}", Thread.currentThread().getName(), ph.getPhase()); - + log.info("Thread {} proceeding in phase {}", Thread.currentThread().getName(), ph.getPhase()); assertEquals(1, ph.getPhase()); - //and - executorService.submit(new LongRunningAction("thread-4", ph)); - executorService.submit(new LongRunningAction("thread-5", ph)); + new Thread(new LongRunningAction("thread-4", ph)).start(); + new Thread(new LongRunningAction("thread-5", ph)).start(); - log.debug("Thread {} waiting for others", Thread.currentThread().getName()); + log.info("Thread {} waiting for new phase", Thread.currentThread().getName()); ph.arriveAndAwaitAdvance(); - log.debug("Thread {} proceeding in phase {}", Thread.currentThread().getName(), ph.getPhase()); - + log.info("Thread {} proceeding in phase {}", Thread.currentThread().getName(), ph.getPhase()); assertEquals(2, ph.getPhase()); - ph.arriveAndDeregister(); + Thread.sleep(1000); + assertEquals(true, ph.isTerminated()); } } diff --git a/core-java-modules/core-java-conditionals/README.md b/core-java-modules/core-java-conditionals/README.md index ae5694c3ba..828f3484f1 100644 --- a/core-java-modules/core-java-conditionals/README.md +++ b/core-java-modules/core-java-conditionals/README.md @@ -3,3 +3,4 @@ This module contains articles about Java Conditionals. ### Relevant articles: +- [Guide to the yield Keyword in Java](https://www.baeldung.com/java-yield-switch) diff --git a/core-java-modules/core-java-datetime-conversion/README.md b/core-java-modules/core-java-datetime-conversion/README.md index 11e4348838..d3a3dae728 100644 --- a/core-java-modules/core-java-datetime-conversion/README.md +++ b/core-java-modules/core-java-datetime-conversion/README.md @@ -8,3 +8,5 @@ This module contains articles about converting between Java date and time object - [Convert Date to LocalDate or LocalDateTime and Back](http://www.baeldung.com/java-date-to-localdate-and-localdatetime) - [Convert Between java.time.Instant and java.sql.Timestamp](https://www.baeldung.com/java-time-instant-to-java-sql-timestamp) - [Convert Between LocalDateTime and ZonedDateTime](https://www.baeldung.com/java-localdatetime-zoneddatetime) +- [Conversion From 12-Hour Time to 24-Hour Time in Java](https://www.baeldung.com/java-convert-time-format) +- [Convert Epoch Time to LocalDate and LocalDateTime](https://www.baeldung.com/java-convert-epoch-localdate) diff --git a/core-java-modules/core-java-datetime-conversion/src/test/java/com/baeldung/twelvehourstotwentyhours/TimeConversionUnitTest.java b/core-java-modules/core-java-datetime-conversion/src/test/java/com/baeldung/twelvehourstotwentyhours/TimeConversionUnitTest.java new file mode 100644 index 0000000000..e82af6dd19 --- /dev/null +++ b/core-java-modules/core-java-datetime-conversion/src/test/java/com/baeldung/twelvehourstotwentyhours/TimeConversionUnitTest.java @@ -0,0 +1,30 @@ +package com.baeldung.twelvehourstotwentyhours; + +import static org.junit.jupiter.api.Assertions.*; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; +import java.util.Date; +import java.util.Locale; +import org.junit.jupiter.api.Test; + +public class TimeConversionUnitTest { + + @Test + public void givenTimeInTwelveHours_whenConvertingToTwentyHours_thenConverted() throws ParseException { + SimpleDateFormat displayFormat = new SimpleDateFormat("HH:mm"); + SimpleDateFormat parseFormat = new SimpleDateFormat("hh:mm a"); + Date date = parseFormat.parse("06:00 PM"); + assertEquals("18:00", displayFormat.format(date)); + } + + @Test + public void givenTimeInTwelveHours_whenConvertingToTwentyHoursWithDateTimeFormatter_thenConverted() throws ParseException { + String time = LocalTime.parse("06:00 PM", DateTimeFormatter.ofPattern("hh:mm a", Locale.US)) + .format(DateTimeFormatter.ofPattern("HH:mm")); + assertEquals("18:00", time); + } + +} diff --git a/core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/socketexception/SslServer.java b/core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/socketexception/SslServer.java new file mode 100644 index 0000000000..ae783fa8bd --- /dev/null +++ b/core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/socketexception/SslServer.java @@ -0,0 +1,32 @@ +package com.baeldung.socketexception; + +import java.io.IOException; + +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; + +public class SslServer { + + public static void createSSLSocketWithEnabledProtocols(SSLServerSocketFactory socketFactory, int port, String[] enabledProtocols) { + SSLServerSocket serverSocket = null; + + try { + serverSocket = (SSLServerSocket) socketFactory.createServerSocket(port); + // Set the enabled protocols + serverSocket.setEnabledProtocols(enabledProtocols); + System.out.println("Server is running on port " + port); + + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (serverSocket != null) { + try { + serverSocket.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + +} diff --git a/core-java-modules/core-java-exceptions-2/src/test/java/com/baeldung/socketexception/SocketExceptionHandlingUnitTest.java b/core-java-modules/core-java-exceptions-2/src/test/java/com/baeldung/socketexception/SocketExceptionHandlingUnitTest.java index 08b21c6299..197046d273 100644 --- a/core-java-modules/core-java-exceptions-2/src/test/java/com/baeldung/socketexception/SocketExceptionHandlingUnitTest.java +++ b/core-java-modules/core-java-exceptions-2/src/test/java/com/baeldung/socketexception/SocketExceptionHandlingUnitTest.java @@ -1,25 +1,33 @@ package com.baeldung.socketexception; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import java.io.IOException; import java.net.SocketException; import java.util.concurrent.Executors; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; + import org.junit.BeforeClass; import org.junit.Test; public class SocketExceptionHandlingUnitTest { + private static final int PORT = 6699; @BeforeClass public static void runServer() throws IOException, InterruptedException { Executors.newSingleThreadExecutor() - .submit(() -> new SocketServer().start(6699)); + .submit(() -> new SocketServer().start(PORT)); Thread.sleep(100); } @Test public void givenRunningServer_whenConnectToClosedSocket_thenHandleException() throws IOException { SocketClient client = new SocketClient(); - client.startConnection("127.0.0.1", 6699); + client.startConnection("127.0.0.1", PORT); try { client.sendMessage("hi"); client.sendMessage("hi again"); @@ -28,4 +36,22 @@ public class SocketExceptionHandlingUnitTest { } } + @Test + public void givenRunningServer_whenConnectToSocket_thenHandleConnectionResetException() throws IOException { + // Enable multiple SSL/TLS protocols + String[] enabledProtocols = { "TLSv1.2", "TLSv1.3", "TLSv1.1", "TLSv1", "SSLv3", "SSLv3" }; + SSLServerSocketFactory mockFactory = mock(SSLServerSocketFactory.class); + SSLServerSocket mockServerSocket = mock(SSLServerSocket.class); + + // Set up the mock factory to return the mock server socket + when(mockFactory.createServerSocket(PORT)).thenReturn(mockServerSocket); + + // Call the method being tested + SslServer.createSSLSocketWithEnabledProtocols(mockFactory, PORT, enabledProtocols); + + // Verify that setEnabledProtocols and close were called + verify(mockServerSocket).setEnabledProtocols(enabledProtocols); + verify(mockServerSocket).close(); + } + } diff --git a/core-java-modules/core-java-io/pom.xml b/core-java-modules/core-java-io/pom.xml index a59ac619bd..8364f36874 100644 --- a/core-java-modules/core-java-io/pom.xml +++ b/core-java-modules/core-java-io/pom.xml @@ -38,9 +38,9 @@ ${fscontext.version} - javax.activation - activation - 1.1 + org.eclipse.angus + angus-activation + ${angus-activation.version} test @@ -73,10 +73,6 @@ org.apache.maven.plugins maven-javadoc-plugin ${maven-javadoc-plugin.version} - - ${maven.compiler.source} - ${maven.compiler.target} - @@ -131,13 +127,15 @@ - 3.0.0-M1 - 2.4.0 + 3.5.0 + 2.7.1 - 1.18 + 2.8.0 0.1.5 - 3.1.0 + 3.3.0 4.4.2 + 2.1.2 + 2.0.1 \ No newline at end of file diff --git a/core-java-modules/core-java-io/src/test/java/com/baeldung/mimetype/MimeTypeUnitTest.java b/core-java-modules/core-java-io/src/test/java/com/baeldung/mimetype/MimeTypeUnitTest.java index bf916e39e7..4c382d07a6 100644 --- a/core-java-modules/core-java-io/src/test/java/com/baeldung/mimetype/MimeTypeUnitTest.java +++ b/core-java-modules/core-java-io/src/test/java/com/baeldung/mimetype/MimeTypeUnitTest.java @@ -10,7 +10,7 @@ import java.net.URLConnection; import java.nio.file.Files; import java.nio.file.Path; -import javax.activation.MimetypesFileTypeMap; +import jakarta.activation.MimetypesFileTypeMap; import org.apache.tika.Tika; import org.junit.Test; diff --git a/core-java-modules/core-java-jar/src/test/java/com/baeldung/jar/JarAppUnitTest.java b/core-java-modules/core-java-jar/src/test/java/com/baeldung/jar/JarAppUnitTest.java index 707ce79624..fc40aa01c5 100644 --- a/core-java-modules/core-java-jar/src/test/java/com/baeldung/jar/JarAppUnitTest.java +++ b/core-java-modules/core-java-jar/src/test/java/com/baeldung/jar/JarAppUnitTest.java @@ -3,10 +3,14 @@ package com.baeldung.jar; import org.junit.Assert; import org.junit.jupiter.api.Test; +import java.util.regex.Pattern; + public class JarAppUnitTest { @Test public void findClassTest(){ - Assert.assertTrue(JarApp.findObjectMapperClass().endsWith("jackson-databind-2.13.3.jar")); + Pattern databindPattern = Pattern.compile(".*jackson-databind-(\\d)+\\.(\\d)+\\.(\\d)\\.jar$"); + + Assert.assertTrue(databindPattern.matcher(JarApp.findObjectMapperClass()).matches()); } } diff --git a/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/randominset/RandomInSetUtil.java b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/randominset/RandomInSetUtil.java new file mode 100644 index 0000000000..5b203db515 --- /dev/null +++ b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/randominset/RandomInSetUtil.java @@ -0,0 +1,50 @@ +package com.baeldung.randominset; + +import java.util.HashSet; +import java.util.Random; +import java.util.Set; +import java.util.concurrent.ThreadLocalRandom; + +public class RandomInSetUtil { + + public static T getByRandomClass(Set set) { + if (set == null || set.isEmpty()) { + throw new IllegalArgumentException("The Set cannot be empty."); + } + int randomIndex = new Random().nextInt(set.size()); + int i = 0; + for (T element : set) { + if (i == randomIndex) { + return element; + } + i++; + } + throw new IllegalStateException("Something went wrong while picking a random element."); + } + + public static T getByThreadLocalRandom(Set set) { + if (set == null || set.isEmpty()) { + throw new IllegalArgumentException("The Set cannot be empty."); + } + int randomIndex = ThreadLocalRandom.current().nextInt(set.size()); + int i = 0; + for (T element : set) { + if (i == randomIndex) { + return element; + } + i++; + } + throw new IllegalStateException("Something went wrong while picking a random element."); + } + + public static void main(String[] args) { + Set animals = new HashSet<>(); + animals.add("Lion"); + animals.add("Elephant"); + animals.add("Giraffe"); + + String randomAnimal = getByThreadLocalRandom(animals); + System.out.println("Randomly picked animal: " + randomAnimal); + } + +} diff --git a/core-java-modules/core-java-leetcode/src/test/java/com/baeldung/leetcode/magicsquare/GenerationUnitTest.java b/core-java-modules/core-java-lang-math-3/src/test/java/com/baeldung/magicsquare/GenerationUnitTest.java similarity index 95% rename from core-java-modules/core-java-leetcode/src/test/java/com/baeldung/leetcode/magicsquare/GenerationUnitTest.java rename to core-java-modules/core-java-lang-math-3/src/test/java/com/baeldung/magicsquare/GenerationUnitTest.java index 308c655bd1..f02200462e 100644 --- a/core-java-modules/core-java-leetcode/src/test/java/com/baeldung/leetcode/magicsquare/GenerationUnitTest.java +++ b/core-java-modules/core-java-lang-math-3/src/test/java/com/baeldung/magicsquare/GenerationUnitTest.java @@ -1,4 +1,4 @@ -package com.baeldung.leetcode.magicsquare; +package com.baeldung.magicsquare; import org.junit.jupiter.api.Test; diff --git a/core-java-modules/core-java-leetcode/src/test/java/com/baeldung/leetcode/magicsquare/MagicSquare.java b/core-java-modules/core-java-lang-math-3/src/test/java/com/baeldung/magicsquare/MagicSquare.java similarity index 96% rename from core-java-modules/core-java-leetcode/src/test/java/com/baeldung/leetcode/magicsquare/MagicSquare.java rename to core-java-modules/core-java-lang-math-3/src/test/java/com/baeldung/magicsquare/MagicSquare.java index 5e16f2e0db..b6e7ac24f5 100644 --- a/core-java-modules/core-java-leetcode/src/test/java/com/baeldung/leetcode/magicsquare/MagicSquare.java +++ b/core-java-modules/core-java-lang-math-3/src/test/java/com/baeldung/magicsquare/MagicSquare.java @@ -1,4 +1,4 @@ -package com.baeldung.leetcode.magicsquare; +package com.baeldung.magicsquare; import org.junit.platform.commons.util.StringUtils; @@ -172,7 +172,9 @@ public class MagicSquare { int value = getCell(x, y); if (value == 0) { sb.append(" "); - sb.append(".".repeat(largestNumberLength)); + for (int i = 0; i < largestNumberLength; ++i) { + sb.append("."); + } sb.append(" "); } else { sb.append(String.format(formatString, value)); diff --git a/core-java-modules/core-java-lang-math-3/src/test/java/com/baeldung/magicsquare/README.md b/core-java-modules/core-java-lang-math-3/src/test/java/com/baeldung/magicsquare/README.md new file mode 100644 index 0000000000..b2f7ece88a --- /dev/null +++ b/core-java-modules/core-java-lang-math-3/src/test/java/com/baeldung/magicsquare/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [Creating a Magic Square in Java](https://www.baeldung.com/java-magic-square) diff --git a/core-java-modules/core-java-leetcode/src/test/java/com/baeldung/leetcode/magicsquare/ValidationUnitTest.java b/core-java-modules/core-java-lang-math-3/src/test/java/com/baeldung/magicsquare/ValidationUnitTest.java similarity index 92% rename from core-java-modules/core-java-leetcode/src/test/java/com/baeldung/leetcode/magicsquare/ValidationUnitTest.java rename to core-java-modules/core-java-lang-math-3/src/test/java/com/baeldung/magicsquare/ValidationUnitTest.java index 93f36931e6..6b0ec600bb 100644 --- a/core-java-modules/core-java-leetcode/src/test/java/com/baeldung/leetcode/magicsquare/ValidationUnitTest.java +++ b/core-java-modules/core-java-lang-math-3/src/test/java/com/baeldung/magicsquare/ValidationUnitTest.java @@ -1,4 +1,4 @@ -package com.baeldung.leetcode.magicsquare; +package com.baeldung.magicsquare; import org.junit.jupiter.api.Test; diff --git a/core-java-modules/core-java-lang-oop-generics/README.md b/core-java-modules/core-java-lang-oop-generics/README.md index 720ba9dcfd..3e33ba5315 100644 --- a/core-java-modules/core-java-lang-oop-generics/README.md +++ b/core-java-modules/core-java-lang-oop-generics/README.md @@ -9,3 +9,4 @@ This module contains articles about generics in Java - [Super Type Tokens in Java Generics](https://www.baeldung.com/java-super-type-tokens) - [Java Warning “unchecked conversion”](https://www.baeldung.com/java-unchecked-conversion) - [Java Warning “Unchecked Cast”](https://www.baeldung.com/java-warning-unchecked-cast) +- [What Does the Holder Class Do in Java?](https://www.baeldung.com/java-holder-class) diff --git a/core-java-modules/core-java-lang-oop-inheritance/README.md b/core-java-modules/core-java-lang-oop-inheritance/README.md index c87bdf13d7..430f88e717 100644 --- a/core-java-modules/core-java-lang-oop-inheritance/README.md +++ b/core-java-modules/core-java-lang-oop-inheritance/README.md @@ -12,3 +12,4 @@ This module contains articles about inheritance in Java - [Guide to Inheritance in Java](https://www.baeldung.com/java-inheritance) - [Object Type Casting in Java](https://www.baeldung.com/java-type-casting) - [Variable and Method Hiding in Java](https://www.baeldung.com/java-variable-method-hiding) +- [Inner Classes Vs. Subclasses in Java](https://www.baeldung.com/java-inner-classes-vs-subclasses) diff --git a/core-java-modules/core-java-lang-oop-inheritance/src/main/java/com/baeldung/subclassinnerclass/EmailNotifier.java b/core-java-modules/core-java-lang-oop-inheritance/src/main/java/com/baeldung/subclassinnerclass/EmailNotifier.java new file mode 100644 index 0000000000..9f3e140926 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-inheritance/src/main/java/com/baeldung/subclassinnerclass/EmailNotifier.java @@ -0,0 +1,22 @@ +package com.baeldung.subclassinnerclass; + +public class EmailNotifier extends Notifier { + @Override + void notify(Message e) { + // connect to the email connector + EmailConnector emailConnector = new EmailConnector(); + emailConnector.connect(); + // send email + } + + // Inner class for email connection + static class EmailConnector { + private String emailHost; + private int emailPort; + // Getter Setters + + private void connect() { + // connect to the smtp server + } + } +} diff --git a/core-java-modules/core-java-lang-oop-inheritance/src/main/java/com/baeldung/subclassinnerclass/Message.java b/core-java-modules/core-java-lang-oop-inheritance/src/main/java/com/baeldung/subclassinnerclass/Message.java new file mode 100644 index 0000000000..35d751b288 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-inheritance/src/main/java/com/baeldung/subclassinnerclass/Message.java @@ -0,0 +1,6 @@ +package com.baeldung.subclassinnerclass; + +public class Message { + private int message; + // getter setter and other atteibutes +} diff --git a/core-java-modules/core-java-lang-oop-inheritance/src/main/java/com/baeldung/subclassinnerclass/NotificationService.java b/core-java-modules/core-java-lang-oop-inheritance/src/main/java/com/baeldung/subclassinnerclass/NotificationService.java new file mode 100644 index 0000000000..2ebbbde961 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-inheritance/src/main/java/com/baeldung/subclassinnerclass/NotificationService.java @@ -0,0 +1,17 @@ +package com.baeldung.subclassinnerclass; + +public class NotificationService { + void notifyMessages() { + // Sending a Text Message + Message textMessage = new Message(); + Notifier textNotifier = new TextMessageNotifier(); + + textNotifier.notify(textMessage); + + // Sending an Email Message + Message emailMessage = new Message(); + Notifier emailNotifier = new EmailNotifier(); + + emailNotifier.notify(emailMessage); + } +} diff --git a/core-java-modules/core-java-lang-oop-inheritance/src/main/java/com/baeldung/subclassinnerclass/Notifier.java b/core-java-modules/core-java-lang-oop-inheritance/src/main/java/com/baeldung/subclassinnerclass/Notifier.java new file mode 100644 index 0000000000..aff0372af3 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-inheritance/src/main/java/com/baeldung/subclassinnerclass/Notifier.java @@ -0,0 +1,5 @@ +package com.baeldung.subclassinnerclass; + +public abstract class Notifier { + abstract void notify(Message e); +} diff --git a/core-java-modules/core-java-lang-oop-inheritance/src/main/java/com/baeldung/subclassinnerclass/TextMessageNotifier.java b/core-java-modules/core-java-lang-oop-inheritance/src/main/java/com/baeldung/subclassinnerclass/TextMessageNotifier.java new file mode 100644 index 0000000000..8b64b4331d --- /dev/null +++ b/core-java-modules/core-java-lang-oop-inheritance/src/main/java/com/baeldung/subclassinnerclass/TextMessageNotifier.java @@ -0,0 +1,14 @@ +package com.baeldung.subclassinnerclass; + +public class TextMessageNotifier extends Notifier { + @Override + void notify(Message e) { + // Provide text message specific implementation here + } + + // Inner class for text message connection + private static class SMSConnector { + private String smsHost; + // Getter Setters + } +} diff --git a/core-java-modules/core-java-lang-oop-inheritance/src/test/java/com/baeldung/subclassinnerclass/InnerClassUnitTest.java b/core-java-modules/core-java-lang-oop-inheritance/src/test/java/com/baeldung/subclassinnerclass/InnerClassUnitTest.java new file mode 100644 index 0000000000..27577a546f --- /dev/null +++ b/core-java-modules/core-java-lang-oop-inheritance/src/test/java/com/baeldung/subclassinnerclass/InnerClassUnitTest.java @@ -0,0 +1,16 @@ +package com.baeldung.subclassinnerclass; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import org.junit.Test; + +public class InnerClassUnitTest { + @Test + public void givenInnerStaticClassWhenInstantiatedThenOuterClassIsInstantiated() { + Notifier emailNotifier = new EmailNotifier(); + EmailNotifier.EmailConnector emailConnector = new EmailNotifier.EmailConnector(); + + assertThat(emailNotifier).hasSameClassAs(new EmailNotifier()); + assertThat(emailConnector).isInstanceOf(EmailNotifier.EmailConnector.class); + } +} diff --git a/core-java-modules/core-java-lang-oop-inheritance/src/test/java/com/baeldung/subclassinnerclass/SubClassUnitTest.java b/core-java-modules/core-java-lang-oop-inheritance/src/test/java/com/baeldung/subclassinnerclass/SubClassUnitTest.java new file mode 100644 index 0000000000..25e6f5b8a4 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-inheritance/src/test/java/com/baeldung/subclassinnerclass/SubClassUnitTest.java @@ -0,0 +1,18 @@ +package com.baeldung.subclassinnerclass; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import org.junit.Test; + +public class SubClassUnitTest { + @Test + public void givenSubclassWhenInstantiatedThenSubclassObjectIsPossible() { + Notifier emailNotifier = new EmailNotifier(); + assertThat(emailNotifier).hasSameClassAs(new EmailNotifier()); + assertThat(emailNotifier).isExactlyInstanceOf(EmailNotifier.class); + + Notifier textMessageNotifier = new TextMessageNotifier(); + assertThat(textMessageNotifier).isInstanceOf(Notifier.class); + assertThat(textMessageNotifier).isExactlyInstanceOf(TextMessageNotifier.class); + } +} diff --git a/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/deepcopyarraylist/Course.java b/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/deepcopyarraylist/Course.java index f8367cfd50..75edca087f 100644 --- a/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/deepcopyarraylist/Course.java +++ b/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/deepcopyarraylist/Course.java @@ -1,6 +1,7 @@ package com.baeldung.deepcopyarraylist; import java.io.Serializable; +import java.util.Objects; public class Course implements Serializable, Cloneable { @@ -39,4 +40,23 @@ public class Course implements Serializable, Cloneable { throw new IllegalStateException(e); } } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + + if (o == null || getClass() != o.getClass()) + return false; + + Course that = (Course) o; + + return Objects.equals(courseId,that.courseId) + && Objects.equals(courseName,that.courseName); + } + + @Override + public int hashCode() { + return Objects.hash(courseId,courseName); + } } diff --git a/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/deepcopyarraylist/Student.java b/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/deepcopyarraylist/Student.java index 0b3f1ba4a9..ce9f773bc7 100644 --- a/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/deepcopyarraylist/Student.java +++ b/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/deepcopyarraylist/Student.java @@ -2,6 +2,7 @@ package com.baeldung.deepcopyarraylist; import java.io.Serializable; import java.util.List; +import java.util.Objects; import java.util.stream.Collectors; import org.apache.commons.lang3.SerializationUtils; @@ -100,4 +101,23 @@ public class Student implements Serializable, Cloneable { student.course = this.course.clone(); return student; } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + + Student that = (Student) o; + + return Objects.equals(studentId,that.studentId) && + Objects.equals(studentName, that.studentName) && + Objects.equals(course, that.course); + } + + @Override + public int hashCode() { + return Objects.hash(studentId,studentName,course); + } } diff --git a/core-java-modules/core-java-lang-oop-patterns/src/test/java/com/baeldung/deepcopyarraylist/DeepCopyArrayListUnitTest.java b/core-java-modules/core-java-lang-oop-patterns/src/test/java/com/baeldung/deepcopyarraylist/DeepCopyArrayListUnitTest.java index 625c7e8385..d7e4c0ff64 100644 --- a/core-java-modules/core-java-lang-oop-patterns/src/test/java/com/baeldung/deepcopyarraylist/DeepCopyArrayListUnitTest.java +++ b/core-java-modules/core-java-lang-oop-patterns/src/test/java/com/baeldung/deepcopyarraylist/DeepCopyArrayListUnitTest.java @@ -19,8 +19,10 @@ public class DeepCopyArrayListUnitTest { List deepCopy = Student.deepCopyUsingCloneable(students); - Assertions.assertNotEquals(students.get(0), deepCopy.get(0)); - Assertions.assertNotEquals(students.get(1), deepCopy.get(1)); + Assertions.assertEquals(students.get(0), deepCopy.get(0)); + Assertions.assertNotSame(students.get(0),deepCopy.get(0)); + Assertions.assertEquals(students.get(1), deepCopy.get(1)); + Assertions.assertNotSame(students.get(1),deepCopy.get(1)); } @@ -37,8 +39,10 @@ public class DeepCopyArrayListUnitTest { List deepCopy = Student.deepCopyUsingCopyConstructor(students); - Assertions.assertNotEquals(students.get(0), deepCopy.get(0)); - Assertions.assertNotEquals(students.get(1), deepCopy.get(1)); + Assertions.assertEquals(students.get(0), deepCopy.get(0)); + Assertions.assertNotSame(students.get(0),deepCopy.get(0)); + Assertions.assertEquals(students.get(1), deepCopy.get(1)); + Assertions.assertNotSame(students.get(1),deepCopy.get(1)); } @Test @@ -54,8 +58,10 @@ public class DeepCopyArrayListUnitTest { List deepCopy = Student.deepCopyUsingSerialization(students); - Assertions.assertNotEquals(students.get(0), deepCopy.get(0)); - Assertions.assertNotEquals(students.get(1), deepCopy.get(1)); + Assertions.assertEquals(students.get(0), deepCopy.get(0)); + Assertions.assertNotSame(students.get(0),deepCopy.get(0)); + Assertions.assertEquals(students.get(1), deepCopy.get(1)); + Assertions.assertNotSame(students.get(1),deepCopy.get(1)); } @Test @@ -71,7 +77,9 @@ public class DeepCopyArrayListUnitTest { List deepCopy = Student.deepCopyUsingJackson(students); - Assertions.assertNotEquals(students.get(0), deepCopy.get(0)); - Assertions.assertNotEquals(students.get(1), deepCopy.get(1)); + Assertions.assertEquals(students.get(0), deepCopy.get(0)); + Assertions.assertNotSame(students.get(0),deepCopy.get(0)); + Assertions.assertEquals(students.get(1), deepCopy.get(1)); + Assertions.assertNotSame(students.get(1),deepCopy.get(1)); } } diff --git a/core-java-modules/core-java-lang-oop-types/pom.xml b/core-java-modules/core-java-lang-oop-types/pom.xml index a5b492f5ca..a9909598eb 100644 --- a/core-java-modules/core-java-lang-oop-types/pom.xml +++ b/core-java-modules/core-java-lang-oop-types/pom.xml @@ -27,7 +27,7 @@ - 1.15 + 1.16.0 \ No newline at end of file diff --git a/core-java-modules/core-java-lang-operators/src/test/java/com/baeldung/modulo/ModuloUnitTest.java b/core-java-modules/core-java-lang-operators/src/test/java/com/baeldung/modulo/ModuloUnitTest.java index 8b3685adf3..0a9418cb17 100644 --- a/core-java-modules/core-java-lang-operators/src/test/java/com/baeldung/modulo/ModuloUnitTest.java +++ b/core-java-modules/core-java-lang-operators/src/test/java/com/baeldung/modulo/ModuloUnitTest.java @@ -1,54 +1,77 @@ package com.baeldung.modulo; +import static org.junit.Assert.assertEquals; + import org.junit.Test; import static org.assertj.core.api.Java6Assertions.*; public class ModuloUnitTest { - @Test - public void whenIntegerDivision_thenLosesRemainder(){ - assertThat(11 / 4).isEqualTo(2); - } - - @Test - public void whenDoubleDivision_thenKeepsRemainder(){ - assertThat(11 / 4.0).isEqualTo(2.75); - } - - @Test - public void whenModulo_thenReturnsRemainder(){ - assertThat(11 % 4).isEqualTo(3); - } - - @Test(expected = ArithmeticException.class) - public void whenDivisionByZero_thenArithmeticException(){ - double result = 1 / 0; - } - - @Test(expected = ArithmeticException.class) - public void whenModuloByZero_thenArithmeticException(){ - double result = 1 % 0; - } - - @Test - public void whenDivisorIsOddAndModulusIs2_thenResultIs1(){ - assertThat(3 % 2).isEqualTo(1); - } - - @Test - public void whenDivisorIsEvenAndModulusIs2_thenResultIs0(){ - assertThat(4 % 2).isEqualTo(0); - } - - @Test - public void whenItemsIsAddedToCircularQueue_thenNoArrayIndexOutOfBounds(){ - int QUEUE_CAPACITY= 10; - int[] circularQueue = new int[QUEUE_CAPACITY]; - int itemsInserted = 0; - for (int value = 0; value < 1000; value++) { - int writeIndex = ++itemsInserted % QUEUE_CAPACITY; - circularQueue[writeIndex] = value; + @Test + public void whenIntegerDivision_thenLosesRemainder() { + assertThat(11 / 4).isEqualTo(2); + } + + @Test + public void whenDoubleDivision_thenKeepsRemainder() { + assertThat(11 / 4.0).isEqualTo(2.75); + } + + @Test + public void whenModulo_thenReturnsRemainder() { + assertThat(11 % 4).isEqualTo(3); + } + + @Test(expected = ArithmeticException.class) + public void whenDivisionByZero_thenArithmeticException() { + double result = 1 / 0; + } + + @Test(expected = ArithmeticException.class) + public void whenModuloByZero_thenArithmeticException() { + double result = 1 % 0; + } + + @Test + public void whenDivisorIsOddAndModulusIs2_thenResultIs1() { + assertThat(3 % 2).isEqualTo(1); + } + + @Test + public void whenDivisorIsEvenAndModulusIs2_thenResultIs0() { + assertThat(4 % 2).isEqualTo(0); + } + + @Test + public void whenDividendIsNegativeAndModulusIs2_thenResultIsNegative() { + assertEquals(-1, -9 % 2); + } + + @Test + public void whenDividendIsNegativeAndRemainderIsCheckedForNegativeValue_thenResultIsPositive() { + int remainder = -9 % 2; + + if (remainder < 0) { + remainder += 2; + } + assertEquals(1, remainder); + } + + @Test + public void whenDividendIsNegativeAndUsesMathClass_thenResultIsPositive() { + int remainder = Math.floorMod(-9, 2); + assertEquals(1, remainder); + } + + @Test + public void whenItemsIsAddedToCircularQueue_thenNoArrayIndexOutOfBounds() { + int QUEUE_CAPACITY = 10; + int[] circularQueue = new int[QUEUE_CAPACITY]; + int itemsInserted = 0; + for (int value = 0; value < 1000; value++) { + int writeIndex = ++itemsInserted % QUEUE_CAPACITY; + circularQueue[writeIndex] = value; + } } - } } diff --git a/core-java-modules/core-java-lang/src/test/java/com/baeldung/comparator/Java8ComparatorUnitTest.java b/core-java-modules/core-java-lang/src/test/java/com/baeldung/comparator/Java8ComparatorUnitTest.java index dac05a85b1..612fd7e097 100644 --- a/core-java-modules/core-java-lang/src/test/java/com/baeldung/comparator/Java8ComparatorUnitTest.java +++ b/core-java-modules/core-java-lang/src/test/java/com/baeldung/comparator/Java8ComparatorUnitTest.java @@ -30,13 +30,13 @@ public class Java8ComparatorUnitTest { System.out.println("************** Java 8 Comaparator **************"); Comparator byRanking = (Player player1, Player player2) -> Integer.compare(player1.getRanking(), player2.getRanking()); - System.out.println("Before Sorting : " + footballTeam); Collections.sort(footballTeam, byRanking); - System.out.println("After Sorting : " + footballTeam); - assertEquals(footballTeam.get(0) - .getName(), "Steven"); - assertEquals(footballTeam.get(2) - .getRanking(), 67); + assertEquals(footballTeam.get(0).getName(), "Steven"); + assertEquals(footballTeam.get(0).getRanking(), 45); + assertEquals(footballTeam.get(1).getName(), "John"); + assertEquals(footballTeam.get(1).getRanking(), 59); + assertEquals(footballTeam.get(2).getName(), "Roger"); + assertEquals(footballTeam.get(2).getRanking(), 67); } @Test @@ -45,24 +45,24 @@ public class Java8ComparatorUnitTest { System.out.println("********* byRanking *********"); Comparator byRanking = Comparator.comparing(Player::getRanking); - System.out.println("Before Sorting : " + footballTeam); Collections.sort(footballTeam, byRanking); - System.out.println("After Sorting : " + footballTeam); - assertEquals(footballTeam.get(0) - .getName(), "Steven"); - assertEquals(footballTeam.get(2) - .getRanking(), 67); - + assertEquals(footballTeam.get(0).getName(), "Steven"); + assertEquals(footballTeam.get(0).getRanking(), 45); + assertEquals(footballTeam.get(1).getName(), "John"); + assertEquals(footballTeam.get(1).getRanking(), 59); + assertEquals(footballTeam.get(2).getName(), "Roger"); + assertEquals(footballTeam.get(2).getRanking(), 67); + System.out.println("********* byAge *********"); Comparator byAge = Comparator.comparing(Player::getAge); - System.out.println("Before Sorting : " + footballTeam); Collections.sort(footballTeam, byAge); - System.out.println("After Sorting : " + footballTeam); - assertEquals(footballTeam.get(0) - .getName(), "Roger"); - assertEquals(footballTeam.get(2) - .getRanking(), 45); + assertEquals(footballTeam.get(0).getName(), "Roger"); + assertEquals(footballTeam.get(0).getAge(), 20); + assertEquals(footballTeam.get(1).getName(), "John"); + assertEquals(footballTeam.get(1).getAge(), 22); + assertEquals(footballTeam.get(2).getName(), "Steven"); + assertEquals(footballTeam.get(2).getAge(), 24); } } diff --git a/core-java-modules/core-java-leetcode/pom.xml b/core-java-modules/core-java-leetcode/pom.xml deleted file mode 100644 index eb91308c64..0000000000 --- a/core-java-modules/core-java-leetcode/pom.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - 4.0.0 - core-java-leetcode - core-java-leetcode - jar - - - com.baeldung - parent-modules - 1.0.0-SNAPSHOT - ../../pom.xml - - - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - ${maven-compiler-plugin.version} - - ${maven.compiler.source.version} - ${maven.compiler.target.version} - - - - - - - 11 - 11 - - - diff --git a/core-java-modules/core-java-regex-2/src/test/java/com/baeldung/regex/squarebrackets/ExtractTextBetweenSquareBracketsUnitTest.java b/core-java-modules/core-java-regex-2/src/test/java/com/baeldung/regex/squarebrackets/ExtractTextBetweenSquareBracketsUnitTest.java new file mode 100644 index 0000000000..2ea80a1f69 --- /dev/null +++ b/core-java-modules/core-java-regex-2/src/test/java/com/baeldung/regex/squarebrackets/ExtractTextBetweenSquareBracketsUnitTest.java @@ -0,0 +1,98 @@ +package com.baeldung.regex.squarebrackets; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.junit.jupiter.api.Test; + +import com.google.common.collect.Lists; + +public class ExtractTextBetweenSquareBracketsUnitTest { + static final String INPUT1 = "some text [THE IMPORTANT MESSAGE] something else"; + static final String EXPECTED1 = "THE IMPORTANT MESSAGE"; + + static final String INPUT2 = "[La La Land], [The last Emperor], and [Life of Pi] are all great movies."; + static final List EXPECTED2 = Lists.newArrayList("La La Land", "The last Emperor", "Life of Pi"); + + @Test + void whenUsingDotStarOnInput1_thenGetExpectedResult() { + String result = null; + String rePattern = "\\[(.*)]"; + Pattern p = Pattern.compile(rePattern); + Matcher m = p.matcher(INPUT1); + if (m.find()) { + result = m.group(1); + } + assertThat(result).isEqualTo(EXPECTED1); + } + + @Test + void whenUsingCharClassOnInput1_thenGetExpectedResult() { + String result = null; + String rePattern = "\\[([^]]*)"; + Pattern p = Pattern.compile(rePattern); + Matcher m = p.matcher(INPUT1); + if (m.find()) { + result = m.group(1); + } + assertThat(result).isEqualTo(EXPECTED1); + } + + @Test + void whenUsingSplitOnInput1_thenGetExpectedResult() { + String[] strArray = INPUT1.split("[\\[\\]]", -1); + String result = strArray.length == 3 ? strArray[1] : null; + + assertThat(result).isEqualTo(EXPECTED1); + } + + @Test + void whenUsingSplitWithLimit_thenGetExpectedResult() { + String[] strArray = "[THE IMPORTANT MESSAGE]".split("[\\[\\]]"); + assertThat(strArray).hasSize(2) + .containsExactly("", "THE IMPORTANT MESSAGE"); + + strArray = "[THE IMPORTANT MESSAGE]".split("[\\[\\]]", -1); + assertThat(strArray).hasSize(3) + .containsExactly("", "THE IMPORTANT MESSAGE", ""); + } + + @Test + void whenUsingNonGreedyOnInput2_thenGetExpectedResult() { + List result = new ArrayList<>(); + String rePattern = "\\[(.*?)]"; + Pattern p = Pattern.compile(rePattern); + Matcher m = p.matcher(INPUT2); + while (m.find()) { + result.add(m.group(1)); + } + assertThat(result).isEqualTo(EXPECTED2); + } + + @Test + void whenUsingCharClassOnInput2_thenGetExpectedResult() { + List result = new ArrayList<>(); + String rePattern = "\\[([^]]*)"; + Pattern p = Pattern.compile(rePattern); + Matcher m = p.matcher(INPUT2); + while (m.find()) { + result.add(m.group(1)); + } + assertThat(result).isEqualTo(EXPECTED2); + } + + @Test + void whenUsingSplitInput2_thenGetExpectedResult() { + List result = new ArrayList<>(); + String[] strArray = INPUT2.split("[\\[\\]]", -1); + for (int i = 1; i < strArray.length; i += 2) { + result.add(strArray[i]); + } + assertThat(result).isEqualTo(EXPECTED2); + } + +} \ No newline at end of file diff --git a/core-java-modules/core-java-security-2/src/test/java/com/baeldung/trustedcert/CertificatesUnitTest.java b/core-java-modules/core-java-security-2/src/test/java/com/baeldung/trustedcert/CertificatesUnitTest.java index b013ff4ed1..4f40c3c195 100644 --- a/core-java-modules/core-java-security-2/src/test/java/com/baeldung/trustedcert/CertificatesUnitTest.java +++ b/core-java-modules/core-java-security-2/src/test/java/com/baeldung/trustedcert/CertificatesUnitTest.java @@ -28,9 +28,6 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; -import org.junit.jupiter.api.Disabled; - -@Disabled //fixing in https://team.baeldung.com/browse/JAVA-23897 public class CertificatesUnitTest { private static final String GODADDY_CA_ALIAS = "godaddyrootg2ca [jdk]"; diff --git a/core-java-modules/core-java-security-3/pom.xml b/core-java-modules/core-java-security-3/pom.xml index ad9feeb36a..b979b56658 100644 --- a/core-java-modules/core-java-security-3/pom.xml +++ b/core-java-modules/core-java-security-3/pom.xml @@ -33,7 +33,7 @@ com.google.guava guava - ${google-guava.version} + ${guava.version} org.springframework.security @@ -47,7 +47,6 @@ 1.15 2.3.1 6.0.3 - 31.0.1-jre \ No newline at end of file diff --git a/core-java-modules/core-java-security-algorithms/pom.xml b/core-java-modules/core-java-security-algorithms/pom.xml index 0dde9f861a..0204203fd7 100644 --- a/core-java-modules/core-java-security-algorithms/pom.xml +++ b/core-java-modules/core-java-security-algorithms/pom.xml @@ -13,28 +13,4 @@ 0.0.1-SNAPSHOT - - - commons-codec - commons-codec - ${commons-codec.version} - - - org.bouncycastle - bcprov-jdk15on - ${bouncycastle.version} - - - javax.xml.bind - jaxb-api - ${jaxb-api.version} - - - - - 1.60 - 1.11 - 2.3.1 - - \ No newline at end of file diff --git a/core-java-modules/core-java-streams-4/pom.xml b/core-java-modules/core-java-streams-4/pom.xml index fe791ebd42..0b9b3569f1 100644 --- a/core-java-modules/core-java-streams-4/pom.xml +++ b/core-java-modules/core-java-streams-4/pom.xml @@ -39,7 +39,7 @@ org.assertj assertj-core - 3.23.1 + ${assertj.version} test @@ -55,7 +55,7 @@ org.apache.commons commons-lang3 - 3.12.0 + ${commons-lang3.version} test @@ -81,7 +81,7 @@ com.google.guava guava - ${google.guava.version} + ${guava.version} com.oath.cyclops @@ -114,6 +114,7 @@ + 3.23.1 3.1 12 12 @@ -123,7 +124,6 @@ 1.0.0-alpha-4 3.5.1 4.4 - 31.1-jre 10.4.1 diff --git a/core-java-modules/core-java-streams/pom.xml b/core-java-modules/core-java-streams/pom.xml index b0794829c2..c7282dda21 100644 --- a/core-java-modules/core-java-streams/pom.xml +++ b/core-java-modules/core-java-streams/pom.xml @@ -14,33 +14,6 @@ - - org.openjdk.jmh - jmh-core - ${jmh-core.version} - - - org.openjdk.jmh - jmh-generator-annprocess - ${jmh-generator.version} - provided - - - org.apache.commons - commons-lang3 - ${commons-lang3.version} - - - log4j - log4j - ${log4j.version} - - - org.projectlombok - lombok - ${lombok.version} - provided - com.codepoetics protonpack @@ -57,17 +30,7 @@ ${streamex.version} - org.aspectj - aspectjrt - ${asspectj.version} - - - org.aspectj - aspectjweaver - ${asspectj.version} - - - pl.touk + com.pivovarit throwing-function ${throwing-function.version} @@ -96,15 +59,13 @@ - 0.9.0 - 1.15 - 0.6.5 - 2.10 - 1.3 - 1.8.9 - 3.1 - 1.8 - 1.8 + 0.10.4 + 1.16 + 0.8.1 + 1.5.1 + + 17 + 17 \ No newline at end of file diff --git a/core-java-modules/core-java-streams/src/test/java/com/baeldung/stream/filter/StreamFilterUnitTest.java b/core-java-modules/core-java-streams/src/test/java/com/baeldung/stream/filter/StreamFilterUnitTest.java index 5ad875f61e..3f3922e015 100644 --- a/core-java-modules/core-java-streams/src/test/java/com/baeldung/stream/filter/StreamFilterUnitTest.java +++ b/core-java-modules/core-java-streams/src/test/java/com/baeldung/stream/filter/StreamFilterUnitTest.java @@ -1,8 +1,8 @@ package com.baeldung.stream.filter; import org.junit.jupiter.api.Test; -import pl.touk.throwing.ThrowingPredicate; -import pl.touk.throwing.exception.WrappedException; +import com.pivovarit.function.ThrowingPredicate; +import com.pivovarit.function.exception.WrappedException; import java.io.IOException; import java.util.Arrays; @@ -156,5 +156,4 @@ public class StreamFilterUnitTest { }) .collect(Collectors.toList())).isInstanceOf(RuntimeException.class); } - -} +} \ No newline at end of file diff --git a/core-java-modules/core-java-string-apis-2/pom.xml b/core-java-modules/core-java-string-apis-2/pom.xml index 51ab3bc1f8..814d301532 100644 --- a/core-java-modules/core-java-string-apis-2/pom.xml +++ b/core-java-modules/core-java-string-apis-2/pom.xml @@ -22,7 +22,7 @@ org.apache.commons commons-lang3 - ${commons.lang3.version} + ${commons-lang3.version} com.ibm.icu @@ -42,8 +42,6 @@ - 3.12.0 - 31.1-jre 61.1 diff --git a/core-java-modules/core-java-string-conversions-3/README.md b/core-java-modules/core-java-string-conversions-3/README.md index 96799d1660..4b348dd555 100644 --- a/core-java-modules/core-java-string-conversions-3/README.md +++ b/core-java-modules/core-java-string-conversions-3/README.md @@ -1,3 +1,4 @@ ## Relevant Articles - [Object.toString() vs String.valueOf()](https://www.baeldung.com/java-object-tostring-vs-string-valueof) - [Convert String to Int Using Encapsulation](https://www.baeldung.com/java-encapsulation-convert-string-to-int) +- [HashMap with Multiple Values for the Same Key](https://www.baeldung.com/java-hashmap-multiple-values-per-key) diff --git a/core-java-modules/pom.xml b/core-java-modules/pom.xml index a6f0382186..e9bb86e500 100644 --- a/core-java-modules/pom.xml +++ b/core-java-modules/pom.xml @@ -108,7 +108,6 @@ core-java-lang-operators-2 core-java-lang-syntax core-java-lang-syntax-2 - core-java-leetcode core-java-locale core-java-networking core-java-networking-2 diff --git a/di-modules/avaje/README.md b/di-modules/avaje/README.md index ea914e551f..f0fa9f058e 100644 --- a/di-modules/avaje/README.md +++ b/di-modules/avaje/README.md @@ -4,4 +4,4 @@ This module contains articles about Avaje ### Relevant articles: -- [Introduction to Avaje Inject](https://www.baeldung.com/avaje-inject/intro) \ No newline at end of file +- [Introduction to Avaje Inject](https://www.baeldung.com/avaje-inject) diff --git a/docker-modules/docker-caching/multi-module-caching/pom.xml b/docker-modules/docker-caching/multi-module-caching/pom.xml index b64cf1a8b8..60f14a17e5 100644 --- a/docker-modules/docker-caching/multi-module-caching/pom.xml +++ b/docker-modules/docker-caching/multi-module-caching/pom.xml @@ -27,7 +27,7 @@ UTF-8 1.8 - 31.1-jre + 32.1.2-jre \ No newline at end of file diff --git a/docker-modules/docker-caching/single-module-caching/pom.xml b/docker-modules/docker-caching/single-module-caching/pom.xml index a388c7563f..0e5174b7ca 100644 --- a/docker-modules/docker-caching/single-module-caching/pom.xml +++ b/docker-modules/docker-caching/single-module-caching/pom.xml @@ -49,7 +49,7 @@ 8 8 UTF-8 - 31.1-jre + 32.1.2-jre \ No newline at end of file diff --git a/jackson-modules/jackson-conversions/src/test/java/com/baeldung/jackson/date/JacksonDateUnitTest.java b/jackson-modules/jackson-conversions/src/test/java/com/baeldung/jackson/date/JacksonDateUnitTest.java index 047d53ab62..4dc9e40292 100644 --- a/jackson-modules/jackson-conversions/src/test/java/com/baeldung/jackson/date/JacksonDateUnitTest.java +++ b/jackson-modules/jackson-conversions/src/test/java/com/baeldung/jackson/date/JacksonDateUnitTest.java @@ -20,6 +20,7 @@ import org.joda.time.DateTimeZone; import org.junit.Test; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.util.StdDateFormat; @@ -67,6 +68,8 @@ public class JacksonDateUnitTest { ObjectMapper objectMapper = new ObjectMapper(); objectMapper.findAndRegisterModules(); objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + objectMapper.enable(SerializationFeature.WRITE_DATES_WITH_ZONE_ID); + objectMapper.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE); ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")); String converted = objectMapper.writeValueAsString(now); diff --git a/javaxval-2/README.md b/javaxval-2/README.md index b7603d9e84..3ae53ebd94 100644 --- a/javaxval-2/README.md +++ b/javaxval-2/README.md @@ -7,4 +7,5 @@ This module contains articles about Bean Validation. - [Guide to ParameterMessageInterpolator](https://www.baeldung.com/hibernate-parametermessageinterpolator) - [Hibernate Validator Annotation Processor in Depth](https://www.baeldung.com/hibernate-validator-annotation-processor) - [Object Validation After Deserialization](https://www.baeldung.com/java-object-validation-deserialization) +- [Java Validation List Annotations](https://www.baeldung.com/java-validation-list-annotations) - More articles: [[<-- prev]](../javaxval) diff --git a/javaxval-2/src/main/java/com/baeldung/javaxval/listvalidation/AllLevels.java b/javaxval-2/src/main/java/com/baeldung/javaxval/listvalidation/AllLevels.java new file mode 100644 index 0000000000..b6660c225a --- /dev/null +++ b/javaxval-2/src/main/java/com/baeldung/javaxval/listvalidation/AllLevels.java @@ -0,0 +1,4 @@ +package com.baeldung.javaxval.listvalidation; + +public interface AllLevels { +} diff --git a/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/listvalidation/domain/JobAspirant.java b/javaxval-2/src/main/java/com/baeldung/javaxval/listvalidation/JobAspirant.java similarity index 79% rename from spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/listvalidation/domain/JobAspirant.java rename to javaxval-2/src/main/java/com/baeldung/javaxval/listvalidation/JobAspirant.java index 4191625b4f..31c8d69639 100644 --- a/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/listvalidation/domain/JobAspirant.java +++ b/javaxval-2/src/main/java/com/baeldung/javaxval/listvalidation/JobAspirant.java @@ -1,12 +1,7 @@ -package com.baeldung.listvalidation.domain; +package com.baeldung.javaxval.listvalidation; -import com.baeldung.listvalidation.groups.AllLevels; -import com.baeldung.listvalidation.groups.Junior; -import com.baeldung.listvalidation.groups.MidSenior; -import com.baeldung.listvalidation.groups.Senior; -import org.springframework.lang.Nullable; +import jakarta.validation.constraints.*; -import javax.validation.constraints.*; import java.util.Date; public class JobAspirant { @@ -14,7 +9,6 @@ public class JobAspirant { @Size(min = 5, message = "Name should have at least 5 characters", groups = AllLevels.class), @Size(max = 20, message = "Name should have at most 20 characters", groups = AllLevels.class) }) - @Pattern.List({ @Pattern(regexp = "^[\\p{Alpha} ]*$", message = "Name should contain only alphabets and space", groups = AllLevels.class), @Pattern(regexp = "^[^\\s].*$", message = "Name should not start with space", groups = AllLevels.class), @@ -22,18 +16,8 @@ public class JobAspirant { @Pattern(regexp = "^((?! ).)*$", message = "Name should not contain consecutive spaces", groups = AllLevels.class), @Pattern(regexp = "^[^a-z].*$", message = "Name should not start with a lower case character", groups = AllLevels.class) }) - - private String name; - public Integer getExperience() { - return experience; - } - - public void setExperience(Integer experience) { - this.experience = experience; - } - @Min.List({ @Min(value = 15, message = "Years of experience cannot be less than 15 Years", groups = Senior.class), @Min(value = 10, message = "Years of experience cannot be less than 10 Years", groups = MidSenior.class), @@ -47,18 +31,16 @@ public class JobAspirant { private Integer experience; @AssertTrue.List({ - @AssertTrue(message = "Terms and Conditions consent missing for Senior Level Job Application", groups = Senior.class), - @AssertTrue(message = "Terms and Conditions consent missing for Mid-Senior Level Job Application", groups = MidSenior.class), - @AssertTrue(message = "Terms and Conditions consent missing for Junior Level Job Application", groups = Junior.class) + @AssertTrue(message = "Terms and Conditions consent missing for Senior Level Job", groups = Senior.class), + @AssertTrue(message = "Terms and Conditions consent missing for Mid-Senior Level Job", groups = MidSenior.class), + @AssertTrue(message = "Terms and Conditions consent missing for Junior Level Job", groups = Junior.class) }) - @Nullable private Boolean agreement; - @Nullable @Future.List({ - @Future(message = "Active passport is mandatory for Senior Level Job Application", groups = Senior.class), - @Future(message = "Active passport is mandatory for Mid-Senior Level Job Application", groups = MidSenior.class), - @Future(message = "Active passport is mandatory for Junior Level Job Application", groups = Junior.class) + @Future(message = "Active passport is mandatory for Senior Level Job", groups = Senior.class), + @Future(message = "Active passport is mandatory for Mid-Senior Level Job", groups = MidSenior.class), + @Future(message = "Active passport is mandatory for Junior Level Job", groups = Junior.class) }) private Date passportExpiryDate; @@ -70,8 +52,6 @@ public class JobAspirant { @Pattern(regexp = "^(Junior)$", message = "Job level should be Junior" ,flags = Pattern.Flag.CASE_INSENSITIVE, groups = Junior.class) }) -// @Pattern(regexp = "^(Senior|MidSenior|Junior)$", message = "Job level should be Senior, MidSenior or Junior" -// ,flags = Pattern.Flag.CASE_INSENSITIVE, groups = AllLevels.class) private String jobLevel; public String getJobLevel() { @@ -104,4 +84,12 @@ public class JobAspirant { public void setPassportExpiryDate(Date passportExpiryDate) { this.passportExpiryDate = passportExpiryDate; } + + public Integer getExperience() { + return experience; + } + + public void setExperience(Integer experience) { + this.experience = experience; + } } diff --git a/javaxval-2/src/main/java/com/baeldung/javaxval/listvalidation/Junior.java b/javaxval-2/src/main/java/com/baeldung/javaxval/listvalidation/Junior.java new file mode 100644 index 0000000000..e881f4d6cd --- /dev/null +++ b/javaxval-2/src/main/java/com/baeldung/javaxval/listvalidation/Junior.java @@ -0,0 +1,4 @@ +package com.baeldung.javaxval.listvalidation; + +public interface Junior { +} diff --git a/javaxval-2/src/main/java/com/baeldung/javaxval/listvalidation/MidSenior.java b/javaxval-2/src/main/java/com/baeldung/javaxval/listvalidation/MidSenior.java new file mode 100644 index 0000000000..f3a6bb67f8 --- /dev/null +++ b/javaxval-2/src/main/java/com/baeldung/javaxval/listvalidation/MidSenior.java @@ -0,0 +1,4 @@ +package com.baeldung.javaxval.listvalidation; + +public interface MidSenior { +} diff --git a/javaxval-2/src/main/java/com/baeldung/javaxval/listvalidation/Senior.java b/javaxval-2/src/main/java/com/baeldung/javaxval/listvalidation/Senior.java new file mode 100644 index 0000000000..be3cf00d9c --- /dev/null +++ b/javaxval-2/src/main/java/com/baeldung/javaxval/listvalidation/Senior.java @@ -0,0 +1,4 @@ +package com.baeldung.javaxval.listvalidation; + +public interface Senior { +} diff --git a/javaxval-2/src/test/java/com/baeldung/javaxval/listvalidation/JobAspirantUnitTest.java b/javaxval-2/src/test/java/com/baeldung/javaxval/listvalidation/JobAspirantUnitTest.java new file mode 100644 index 0000000000..cee020c69f --- /dev/null +++ b/javaxval-2/src/test/java/com/baeldung/javaxval/listvalidation/JobAspirantUnitTest.java @@ -0,0 +1,209 @@ +package com.baeldung.javaxval.listvalidation; + +import jakarta.validation.ConstraintViolation; +import jakarta.validation.Validation; +import jakarta.validation.Validator; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; + +public class JobAspirantUnitTest { + private static Validator validator; + @BeforeClass + public static void setupValidatorInstance() { + validator = Validation.buildDefaultValidatorFactory().getValidator(); + } + @Test + public void givenJobLevelJunior_whenInValidMinExperience_thenExpectErrors() throws ParseException { + JobAspirant jobAspirant = getJobAspirant("Junior", "John Adam", "2025-12-31", 3, true); + Set> violations = validator.validate(jobAspirant, Junior.class); + assertThat(violations.size()).isEqualTo(1); + violations.forEach(action -> { + assertThat(action.getPropertyPath().toString()).isEqualTo("experience"); + assertThat(action.getMessage()).isEqualTo("Years of experience cannot be less than 5 Years"); + }); + } + @Test + public void givenJobLevelMidSenior_whenInvalidMinExperience_thenExpectErrors() throws ParseException { + JobAspirant jobAspirant = getJobAspirant("MidSenior", "John Adam", "2025-12-31", 8, true); + Set> violations = validator.validate(jobAspirant, MidSenior.class); + assertThat(violations.size()).isEqualTo(1); + violations.forEach(action -> { + assertThat(action.getPropertyPath().toString()).isEqualTo("experience"); + assertThat(action.getMessage()).isEqualTo("Years of experience cannot be less than 10 Years"); + }); + } + @Test + public void givenJobLevelSenior_whenInvalidMinExperience_thenExpectErrors() throws ParseException { + JobAspirant jobAspirant = getJobAspirant("Senior", "John Adam", "2025-12-31", 13, true); + Set> violations = validator.validate(jobAspirant, Senior.class); + assertThat(violations.size()).isEqualTo(1); + violations.forEach(action -> { + assertThat(action.getPropertyPath().toString()).isEqualTo("experience"); + assertThat(action.getMessage()).isEqualTo("Years of experience cannot be less than 15 Years"); + }); + } + @Test + public void givenJobLevelJunior_whenInValidMaxExperience_thenExpectErrors() throws ParseException { + JobAspirant jobAspirant = getJobAspirant("Junior", "John Adam", "2025-12-31", 11, true); + Set> violations = validator.validate(jobAspirant, Junior.class); + assertThat(violations.size()).isEqualTo(1); + violations.forEach(action -> { + assertThat(action.getPropertyPath().toString()).isEqualTo("experience"); + assertThat(action.getMessage()).isEqualTo("Years of experience cannot be more than 10 Years"); + }); + } + @Test + public void givenJobLevelMidSenior_whenInvalidMaxExperience_thenExpectErrors() throws ParseException { + JobAspirant jobAspirant = getJobAspirant("MidSenior", "John Adam", "2025-12-31", 16, true); + Set> violations = validator.validate(jobAspirant, MidSenior.class); + assertThat(violations.size()).isEqualTo(1); + violations.forEach(action -> { + assertThat(action.getPropertyPath().toString()).isEqualTo("experience"); + assertThat(action.getMessage()).isEqualTo("Years of experience cannot be more than 15 Years"); + }); + } + @Test + public void givenJobLevelSenior_whenInvalidMaxExperience_thenExpectErrors() throws ParseException { + JobAspirant jobAspirant = getJobAspirant("Senior", "John Adam", "2025-12-31", 23, true); + Set> violations = validator.validate(jobAspirant, Senior.class); + assertThat(violations.size()).isEqualTo(1); + violations.forEach(action -> { + assertThat(action.getPropertyPath().toString()).isEqualTo("experience"); + assertThat(action.getMessage()).isEqualTo("Years of experience cannot be more than 20 Years"); + }); + } + @Test + public void whenInvalidName_thenExpectErrors() throws ParseException { + JobAspirant jobAspirant = getJobAspirant("Senior", "John Adam", "2025-12-31", 17, true); + Set> violations = validator.validate(jobAspirant, Senior.class, AllLevels.class); + assertThat(violations.size()).isEqualTo(1); + violations.forEach(action -> { + assertThat(action.getPropertyPath().toString()).isEqualTo("name"); + assertThat(action.getMessage()).isEqualTo("Name should not contain consecutive spaces"); + }); + } + @Test + public void givenJuniorLevel_whenInvalidAgreement_thenExpectErrors() throws ParseException { + JobAspirant jobAspirant = getJobAspirant("Junior", "John Adam", "2025-12-31", 7, false); + Set> violations = validator.validate(jobAspirant, Junior.class); + assertThat(violations.size()).isEqualTo(1); + violations.forEach(action -> { + assertThat(action.getPropertyPath().toString()).isEqualTo("agreement"); + assertThat(action.getMessage()).isEqualTo("Terms and Conditions consent missing for Junior Level Job"); + }); + } + @Test + public void givenSeniorLevel_whenInvalidAgreement_thenExpectErrors() throws ParseException { + JobAspirant jobAspirant = getJobAspirant("Senior", "John Adam", "2025-12-31", 17, false); + Set> violations = validator.validate(jobAspirant, Senior.class); + assertThat(violations.size()).isEqualTo(1); + violations.forEach(action -> { + assertThat(action.getPropertyPath().toString()).isEqualTo("agreement"); + assertThat(action.getMessage()).isEqualTo("Terms and Conditions consent missing for Senior Level Job"); + }); + } + @Test + public void givenJobLevelMidSenior_whenInvalidPassport_thenExpectErrors() throws ParseException { + JobAspirant jobAspirant = getJobAspirant("MidSenior", "John Adam", "2021-12-31", 12, true); + Set> violations = validator.validate(jobAspirant, MidSenior.class); + assertThat(violations.size()).isEqualTo(1); + violations.forEach(action -> { + assertThat(action.getPropertyPath().toString()).isEqualTo("passportExpiryDate"); + assertThat(action.getMessage()).isEqualTo("Active passport is mandatory for Mid-Senior Level Job"); + }); + } + @Test + public void givenJobLevelSenior_whenInvalidPassport_thenExpectErrors() throws ParseException { + JobAspirant jobAspirant = getJobAspirant("Senior", "John Adam", "2021-12-31", 18, true); + Set> violations = validator.validate(jobAspirant, Senior.class); + assertThat(violations.size()).isEqualTo(1); + violations.forEach(action -> { + assertThat(action.getPropertyPath().toString()).isEqualTo("passportExpiryDate"); + assertThat(action.getMessage()).isEqualTo("Active passport is mandatory for Senior Level Job"); + }); + } + @Test + public void givenJobLevelSenior_whenAllFieldsValid_thenNoErrors() throws ParseException { + JobAspirant jobAspirant = getJobAspirant("Senior", "John Adam", "2025-12-31", 17, true); + Set> violations = validator.validate(jobAspirant, Senior.class, AllLevels.class); + assertThat(violations.size()).isEqualTo(0); + } + @Test + public void givenJobLevelMidSenior_whenAllFieldsValid_thenNoErrors() throws ParseException { + JobAspirant jobAspirant = getJobAspirant("MidSenior", "John Adam", "2025-12-31", 12, true); + Set> violations = validator.validate(jobAspirant, MidSenior.class, AllLevels.class); + assertThat(violations.size()).isEqualTo(0); + } + @Test + public void givenJobLevelJunior_whenAllFieldsValid_thenNoErrors() throws ParseException { + JobAspirant jobAspirant = getJobAspirant("Junior", "John Adam", "2025-12-31", 7, true); + Set> violations = validator.validate(jobAspirant, Junior.class, AllLevels.class); + assertThat(violations.size()).isEqualTo(0); + } + @Test + public void givenJobLevelJunior_whenAllFieldsInValid_thenExpectErrors() throws ParseException { + JobAspirant jobAspirant = getJobAspirant("Junior", " John Adam", "2022-12-31", 3, false); + Set> violations = validator.validate(jobAspirant, Junior.class, AllLevels.class); + assertThat(violations.size()).isEqualTo(4); + violations.forEach(action -> { + String fieldName = action.getPropertyPath().toString(); + switch(fieldName) { + case "name": + assertThat(action.getMessage()).isEqualTo("Name should not start with space"); + break; + case "passportExpiryDate": + assertThat(action.getMessage()).isEqualTo("Active passport is mandatory for Junior Level Job"); + break; + case "experience": + assertThat(action.getMessage()).isEqualTo("Years of experience cannot be less than 5 Years"); + break; + case "agreement": + assertThat(action.getMessage()).isEqualTo("Terms and Conditions consent missing for Junior Level Job"); + break; + } + }); + } + @Test + public void givenJobLevelSenior_whenAllFieldsInValid_thenExpectErrors() throws ParseException { + JobAspirant jobAspirant = getJobAspirant("Senior", "John Adam ", "2022-12-31", 12, false); + Set> violations = validator.validate(jobAspirant, Senior.class, AllLevels.class); + assertThat(violations.size()).isEqualTo(4); + violations.forEach(action -> { + String fieldName = action.getPropertyPath().toString(); + switch(fieldName) { + case "name": + assertThat(action.getMessage()).isEqualTo("Name should not end with space"); + break; + case "passportExpiryDate": + assertThat(action.getMessage()).isEqualTo("Active passport is mandatory for Senior Level Job"); + break; + case "experience": + assertThat(action.getMessage()).isEqualTo("Years of experience cannot be less than 15 Years"); + break; + case "agreement": + assertThat(action.getMessage()).isEqualTo("Terms and Conditions consent missing for Senior Level Job"); + break; + } + }); + } + private JobAspirant getJobAspirant(String jobLevel, String name, String passportExpDate, int exp, boolean agmt) throws ParseException { + JobAspirant jobAspirant = new JobAspirant(); + jobAspirant.setName(name); + jobAspirant.setPassportExpiryDate(convertStringToDate(passportExpDate)); + jobAspirant.setJobLevel(jobLevel); + jobAspirant.setExperience(exp); + jobAspirant.setAgreement(agmt); + return jobAspirant; + } + private Date convertStringToDate(String date) throws ParseException { + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); + return formatter.parse(date); + } +} diff --git a/json-modules/json-2/README.md b/json-modules/json-2/README.md index a29484d9fc..f41a7047fa 100644 --- a/json-modules/json-2/README.md +++ b/json-modules/json-2/README.md @@ -13,5 +13,6 @@ This module contains articles about JSON. - [Getting a Value in JSONObject](https://www.baeldung.com/java-jsonobject-get-value) - [Pretty-Print a JSON in Java](https://www.baeldung.com/java-json-pretty-print) - [Remove Whitespaces From a JSON in Java](https://www.baeldung.com/java-json-minify-remove-whitespaces) +- [Programmatic Generation of JSON Schemas in Java](https://www.baeldung.com/java-json-schema-create-automatically) - More Articles: [[<-- prev]](/json-modules/json) diff --git a/json-modules/json-2/pom.xml b/json-modules/json-2/pom.xml index 82fe689ebf..7253088516 100644 --- a/json-modules/json-2/pom.xml +++ b/json-modules/json-2/pom.xml @@ -1,7 +1,7 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 json-2 0.0.1-SNAPSHOT @@ -123,6 +123,26 @@ javax.annotation-api 1.3.2 + + com.github.victools + jsonschema-generator + ${jsonschema-generator.version} + + + com.github.victools + jsonschema-module-jackson + ${jsonschema-generator.version} + + + jakarta.validation + jakarta.validation-api + ${jakarta.validation.version} + + + com.github.victools + jsonschema-module-jakarta-validation + ${jsonschema-generator.version} + @@ -162,6 +182,55 @@ + + + com.github.victools + jsonschema-maven-plugin + ${jsonschema-generator.version} + + + + generate + + + + + + com.baeldung.jsonschemageneration.plugin + + + com.baeldung.jsonschemageneration.plugin.Person + + DRAFT_2020_12 + src/main/resources/schemas + {1}/{0}.json + true + + PLAIN_JSON + + + + + SCHEMA_VERSION_INDICATOR + + + + Jackson + + + + + + JakartaValidation + + + + + + + + + @@ -173,6 +242,8 @@ 0.1.1 0.4.2 0.13.0 + 4.31.1 + 3.0.2 \ No newline at end of file diff --git a/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/configuration/AdvancedArticle.java b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/configuration/AdvancedArticle.java new file mode 100644 index 0000000000..07e00bba0f --- /dev/null +++ b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/configuration/AdvancedArticle.java @@ -0,0 +1,70 @@ +package com.baeldung.jsonschemageneration.configuration; + +import java.sql.Timestamp; +import java.util.Date; +import java.util.UUID; + +enum Area { + JAVA("JAVA"), KOTLIN("KOTLIN"), SCALA("SCALA"), LINUX("LINUX"); + + private final String area; + + Area(String area) { + this.area = area; + } + + public String getArea() { + return area; + } +} + +public class AdvancedArticle { + private UUID id; + private String title; + + private String content; + + @AllowedTypes({ Timestamp.class, Date.class }) + private Object createdAt; + private Area area; + + public Area getArea() { + return area; + } + + public void setArea(Area area) { + this.area = area; + } + + public Object getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Object createdAt) { + this.createdAt = createdAt; + } + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } +} diff --git a/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/configuration/AdvancedConfigurationSchemaGenerator.java b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/configuration/AdvancedConfigurationSchemaGenerator.java new file mode 100644 index 0000000000..3fbf6bac6e --- /dev/null +++ b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/configuration/AdvancedConfigurationSchemaGenerator.java @@ -0,0 +1,39 @@ +package com.baeldung.jsonschemageneration.configuration; + +import com.fasterxml.jackson.databind.JsonNode; +import com.github.victools.jsonschema.generator.Option; +import com.github.victools.jsonschema.generator.OptionPreset; +import com.github.victools.jsonschema.generator.SchemaGenerator; +import com.github.victools.jsonschema.generator.SchemaGeneratorConfig; +import com.github.victools.jsonschema.generator.SchemaGeneratorConfigBuilder; +import com.github.victools.jsonschema.generator.SchemaVersion; + +import java.util.Optional; +import java.util.UUID; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class AdvancedConfigurationSchemaGenerator { + public static void main(String[] args) { + + SchemaGeneratorConfigBuilder configBuilder = new SchemaGeneratorConfigBuilder(SchemaVersion.DRAFT_2020_12, OptionPreset.PLAIN_JSON); + + configBuilder.forFields().withInstanceAttributeOverride((node, field, context) -> node.put("readOnly", field.getDeclaredType().isInstanceOf(UUID.class))); + + configBuilder.forFields() + .withTargetTypeOverridesResolver(field -> Optional.ofNullable(field.getAnnotationConsideringFieldAndGetterIfSupported(AllowedTypes.class)) + .map(AllowedTypes::value) + .map(Stream::of) + .map(stream -> stream.map(subtype -> field.getContext().resolve(subtype))) + .map(stream -> stream.collect(Collectors.toList())) + .orElse(null)); + + SchemaGeneratorConfig config = configBuilder.with(Option.EXTRA_OPEN_API_FORMAT_VALUES).build(); + + SchemaGenerator generator = new SchemaGenerator(config); + JsonNode jsonSchema = generator.generateSchema(AdvancedArticle.class); + + System.out.println(jsonSchema.toPrettyString()); + } + +} diff --git a/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/configuration/AllowedTypes.java b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/configuration/AllowedTypes.java new file mode 100644 index 0000000000..9c2ae2780d --- /dev/null +++ b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/configuration/AllowedTypes.java @@ -0,0 +1,13 @@ +package com.baeldung.jsonschemageneration.configuration; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface AllowedTypes { + Class[] value(); +} + diff --git a/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/configuration/IndividualConfigurationSchemaGenerator.java b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/configuration/IndividualConfigurationSchemaGenerator.java new file mode 100644 index 0000000000..3e1b556311 --- /dev/null +++ b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/configuration/IndividualConfigurationSchemaGenerator.java @@ -0,0 +1,44 @@ +package com.baeldung.jsonschemageneration.configuration; + +import com.baeldung.jsonschemageneration.recursive.Author; +import com.fasterxml.jackson.databind.JsonNode; +import com.github.victools.jsonschema.generator.Option; +import com.github.victools.jsonschema.generator.OptionPreset; +import com.github.victools.jsonschema.generator.SchemaGenerator; +import com.github.victools.jsonschema.generator.SchemaGeneratorConfig; +import com.github.victools.jsonschema.generator.SchemaGeneratorConfigBuilder; +import com.github.victools.jsonschema.generator.SchemaVersion; + +import javax.annotation.Nullable; +import javax.validation.constraints.NotNull; +import java.time.Instant; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class IndividualConfigurationSchemaGenerator { + public static void main(String[] args) { + + SchemaGeneratorConfigBuilder configBuilder = new SchemaGeneratorConfigBuilder(SchemaVersion.DRAFT_2020_12, OptionPreset.PLAIN_JSON); + + configBuilder.forFields().withRequiredCheck(field -> field.getAnnotationConsideringFieldAndGetter(Nullable.class) == null).withArrayUniqueItemsResolver(scope -> scope.getType().getErasedType() == (List.class) ? true : null); + + configBuilder.forMethods().withRequiredCheck(method -> method.getAnnotationConsideringFieldAndGetter(NotNull.class) != null); + + configBuilder.forTypesInGeneral() + .withArrayUniqueItemsResolver(scope -> scope.getType().getErasedType() == (List.class) ? true : null) + .withDefaultResolver(scope -> scope.getType().getErasedType() == List.class ? Collections.EMPTY_LIST : null) + .withDefaultResolver(scope -> scope.getType().getErasedType() == Date.class ? Date.from(Instant.now()) : null) + .withEnumResolver(scope -> scope.getType().getErasedType().isEnum() ? Stream.of(scope.getType().getErasedType().getEnumConstants()).map(v -> ((Enum) v).name()).collect(Collectors.toList()) : null); + + SchemaGeneratorConfig config = configBuilder.with(Option.EXTRA_OPEN_API_FORMAT_VALUES).build(); + + SchemaGenerator generator = new SchemaGenerator(config); + JsonNode jsonSchema = generator.generateSchema(Author.class); + + System.out.println(jsonSchema.toPrettyString()); + } + +} diff --git a/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/modules/JacksonModuleSchemaGenerator.java b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/modules/JacksonModuleSchemaGenerator.java new file mode 100644 index 0000000000..eda5015400 --- /dev/null +++ b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/modules/JacksonModuleSchemaGenerator.java @@ -0,0 +1,68 @@ +package com.baeldung.jsonschemageneration.modules; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.JsonNode; +import com.github.victools.jsonschema.generator.SchemaGenerator; +import com.github.victools.jsonschema.generator.SchemaGeneratorConfigBuilder; +import com.github.victools.jsonschema.module.jackson.JacksonModule; + +import java.util.Date; +import java.util.List; +import java.util.UUID; + +import static com.github.victools.jsonschema.generator.Option.EXTRA_OPEN_API_FORMAT_VALUES; +import static com.github.victools.jsonschema.generator.OptionPreset.PLAIN_JSON; +import static com.github.victools.jsonschema.generator.SchemaVersion.DRAFT_2020_12; +import static com.github.victools.jsonschema.module.jackson.JacksonOption.RESPECT_JSONPROPERTY_REQUIRED; + +public class JacksonModuleSchemaGenerator { + public static void main(String[] args) { + + JacksonModule module = new JacksonModule(RESPECT_JSONPROPERTY_REQUIRED); + SchemaGeneratorConfigBuilder configBuilder = new SchemaGeneratorConfigBuilder(DRAFT_2020_12, PLAIN_JSON).with(module).with(EXTRA_OPEN_API_FORMAT_VALUES); + + SchemaGenerator generator = new SchemaGenerator(configBuilder.build()); + JsonNode jsonSchema = generator.generateSchema(Person.class); + + System.out.println(jsonSchema.toPrettyString()); + } + + static class Person { + + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + UUID id; + + @JsonProperty(access = JsonProperty.Access.READ_WRITE, required = true) + String name; + + @JsonProperty(access = JsonProperty.Access.READ_WRITE, required = true) + String surname; + + @JsonProperty(access = JsonProperty.Access.READ_WRITE, required = true) + Address address; + + @JsonIgnore + String fullName; + + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + Date createdAt; + + @JsonProperty(access = JsonProperty.Access.READ_WRITE) + List friends; + + } + + static class Address { + + @JsonProperty() + String street; + + @JsonProperty(required = true) + String city; + + @JsonProperty(required = true) + String country; + } + +} diff --git a/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/modules/JakartaValidationModuleSchemaGenerator.java b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/modules/JakartaValidationModuleSchemaGenerator.java new file mode 100644 index 0000000000..ca19d35357 --- /dev/null +++ b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/modules/JakartaValidationModuleSchemaGenerator.java @@ -0,0 +1,63 @@ +package com.baeldung.jsonschemageneration.modules; + +import com.fasterxml.jackson.databind.JsonNode; +import com.github.victools.jsonschema.generator.SchemaGenerator; +import com.github.victools.jsonschema.generator.SchemaGeneratorConfigBuilder; +import com.github.victools.jsonschema.module.jakarta.validation.JakartaValidationModule; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Null; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; + +import java.util.Date; +import java.util.List; +import java.util.UUID; + +import static com.github.victools.jsonschema.generator.OptionPreset.PLAIN_JSON; +import static com.github.victools.jsonschema.generator.SchemaVersion.DRAFT_2020_12; +import static com.github.victools.jsonschema.module.jakarta.validation.JakartaValidationOption.INCLUDE_PATTERN_EXPRESSIONS; +import static com.github.victools.jsonschema.module.jakarta.validation.JakartaValidationOption.NOT_NULLABLE_FIELD_IS_REQUIRED; + +public class JakartaValidationModuleSchemaGenerator { + public static void main(String[] args) { + + JakartaValidationModule module = new JakartaValidationModule(NOT_NULLABLE_FIELD_IS_REQUIRED, INCLUDE_PATTERN_EXPRESSIONS); + SchemaGeneratorConfigBuilder configBuilder = new SchemaGeneratorConfigBuilder(DRAFT_2020_12, PLAIN_JSON).with(module); + + SchemaGenerator generator = new SchemaGenerator(configBuilder.build()); + JsonNode jsonSchema = generator.generateSchema(Person.class); + + System.out.println(jsonSchema.toPrettyString()); + } + + static class Person { + + @NotNull UUID id; + + @NotNull String name; + + @NotNull @Email @Pattern(regexp = "\\b[A-Za-z0-9._%+-]+@baeldung\\.com\\b") String email; + + @NotNull String surname; + + @NotNull Address address; + + @Null String fullName; + + @NotNull Date createdAt; + + @Size(max = 10) List friends; + + } + + static class Address { + + @Null String street; + + @NotNull String city; + + @NotNull String country; + } + +} diff --git a/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/plugin/Person.java b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/plugin/Person.java new file mode 100644 index 0000000000..f87dcd5981 --- /dev/null +++ b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/plugin/Person.java @@ -0,0 +1,61 @@ +package com.baeldung.jsonschemageneration.plugin; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Null; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; + +import java.util.Date; +import java.util.List; +import java.util.UUID; + +public class Person { + + @NotNull + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + UUID id; + + @NotNull + @JsonProperty(access = JsonProperty.Access.READ_WRITE, required = true) + String name; + + @NotNull + @JsonProperty(access = JsonProperty.Access.READ_WRITE, required = true) + @Email @Pattern(regexp = "\\b[A-Za-z0-9._%+-]+@baeldung\\.com\\b") String email; + + @NotNull + @JsonProperty(access = JsonProperty.Access.READ_WRITE, required = true) + + String surname; + + @NotNull + @JsonProperty(access = JsonProperty.Access.READ_WRITE, required = true) + Address address; + + @Null String fullName; + + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + Date createdAt; + + @Size(max = 10) + @JsonProperty(access = JsonProperty.Access.READ_WRITE) + List friends; + +} + +class Address { + + @Null + @JsonProperty + String street; + + @NotNull + @JsonProperty(required = true) + String city; + + @NotNull + @JsonProperty(required = true) + String country; +} \ No newline at end of file diff --git a/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/recursive/Author.java b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/recursive/Author.java new file mode 100644 index 0000000000..a19afb3f6f --- /dev/null +++ b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/recursive/Author.java @@ -0,0 +1,12 @@ +package com.baeldung.jsonschemageneration.recursive; + +import java.util.List; +import java.util.UUID; + +public class Author { + private UUID id; + private String name; + private String role; + + private List articles; +} diff --git a/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/recursive/AuthoredArticle.java b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/recursive/AuthoredArticle.java new file mode 100644 index 0000000000..3ab7464aaf --- /dev/null +++ b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/recursive/AuthoredArticle.java @@ -0,0 +1,68 @@ +package com.baeldung.jsonschemageneration.recursive; + +import java.util.Date; +import java.util.UUID; + +enum Area { + JAVA("JAVA"), KOTLIN("KOTLIN"), SCALA("SCALA"), LINUX("LINUX"); + + private final String area; + + Area(String area) { + this.area = area; + } + + public String getArea() { + return area; + } +} + +public class AuthoredArticle { + private UUID id; + private String title; + private String content; + private Date createdAt; + private Area area; + + private Author author; + + public Area getArea() { + return area; + } + + public void setArea(Area area) { + this.area = area; + } + + public Date getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } +} diff --git a/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/recursive/RecursiveSchemaGenerator.java b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/recursive/RecursiveSchemaGenerator.java new file mode 100644 index 0000000000..2047dac53f --- /dev/null +++ b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/recursive/RecursiveSchemaGenerator.java @@ -0,0 +1,23 @@ +package com.baeldung.jsonschemageneration.recursive; + +import com.fasterxml.jackson.databind.JsonNode; +import com.github.victools.jsonschema.generator.Option; +import com.github.victools.jsonschema.generator.OptionPreset; +import com.github.victools.jsonschema.generator.SchemaGenerator; +import com.github.victools.jsonschema.generator.SchemaGeneratorConfig; +import com.github.victools.jsonschema.generator.SchemaGeneratorConfigBuilder; +import com.github.victools.jsonschema.generator.SchemaVersion; + +public class RecursiveSchemaGenerator { + public static void main(String[] args) { + + SchemaGeneratorConfigBuilder configBuilder = new SchemaGeneratorConfigBuilder(SchemaVersion.DRAFT_2020_12, OptionPreset.PLAIN_JSON); + SchemaGeneratorConfig config = configBuilder.with(Option.EXTRA_OPEN_API_FORMAT_VALUES).without(Option.FLATTENED_ENUMS_FROM_TOSTRING).build(); + + SchemaGenerator generator = new SchemaGenerator(config); + JsonNode jsonSchema = generator.generateSchema(AuthoredArticle.class); + + System.out.println(jsonSchema.toPrettyString()); + } + +} diff --git a/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/simple/Article.java b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/simple/Article.java new file mode 100644 index 0000000000..480dc2e425 --- /dev/null +++ b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/simple/Article.java @@ -0,0 +1,66 @@ +package com.baeldung.jsonschemageneration.simple; + +import java.util.Date; +import java.util.UUID; + +enum Area { + JAVA("JAVA"), KOTLIN("KOTLIN"), SCALA("SCALA"), LINUX("LINUX"); + + private final String area; + + Area(String area) { + this.area = area; + } + + public String getArea() { + return area; + } +} + +public class Article { + private UUID id; + private String title; + private String content; + private Date createdAt; + private Area area; + + public Area getArea() { + return area; + } + + public void setArea(Area area) { + this.area = area; + } + + public Date getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } +} diff --git a/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/simple/SimpleSchemaGenerator.java b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/simple/SimpleSchemaGenerator.java new file mode 100644 index 0000000000..daea643b1b --- /dev/null +++ b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/simple/SimpleSchemaGenerator.java @@ -0,0 +1,23 @@ +package com.baeldung.jsonschemageneration.simple; + +import com.fasterxml.jackson.databind.JsonNode; +import com.github.victools.jsonschema.generator.Option; +import com.github.victools.jsonschema.generator.OptionPreset; +import com.github.victools.jsonschema.generator.SchemaGenerator; +import com.github.victools.jsonschema.generator.SchemaGeneratorConfig; +import com.github.victools.jsonschema.generator.SchemaGeneratorConfigBuilder; +import com.github.victools.jsonschema.generator.SchemaVersion; + +public class SimpleSchemaGenerator { + public static void main(String[] args) { + + SchemaGeneratorConfigBuilder configBuilder = new SchemaGeneratorConfigBuilder(SchemaVersion.DRAFT_2020_12, OptionPreset.PLAIN_JSON); + SchemaGeneratorConfig config = configBuilder.with(Option.EXTRA_OPEN_API_FORMAT_VALUES).without(Option.FLATTENED_ENUMS_FROM_TOSTRING).build(); + + SchemaGenerator generator = new SchemaGenerator(config); + JsonNode jsonSchema = generator.generateSchema(Article.class); + + System.out.println(jsonSchema.toPrettyString()); + } + +} diff --git a/json-modules/json-2/src/main/resources/schemas/com/baeldung/jsonschemageneration/plugin/Person.json b/json-modules/json-2/src/main/resources/schemas/com/baeldung/jsonschemageneration/plugin/Person.json new file mode 100644 index 0000000000..d52a527684 --- /dev/null +++ b/json-modules/json-2/src/main/resources/schemas/com/baeldung/jsonschemageneration/plugin/Person.json @@ -0,0 +1,54 @@ +{ + "$defs" : { + "Address" : { + "type" : "object", + "properties" : { + "city" : { + "type" : "string" + }, + "country" : { + "type" : "string" + }, + "street" : { + "type" : [ "string", "null" ] + } + }, + "required" : [ "city", "country" ], + "additionalProperties" : false + } + }, + "type" : "object", + "properties" : { + "address" : { + "$ref" : "#/$defs/Address" + }, + "createdAt" : { + "type" : "string", + "readOnly" : true + }, + "email" : { + "type" : "string", + "format" : "email", + "pattern" : "\\b[A-Za-z0-9._%+-]+@baeldung\\.com\\b" + }, + "friends" : { + "maxItems" : 10, + "type" : "array", + "items" : { + "$ref" : "#" + } + }, + "id" : { + "type" : "string", + "readOnly" : true + }, + "name" : { + "type" : "string" + }, + "surname" : { + "type" : "string" + } + }, + "required" : [ "address", "email", "id", "name", "surname" ], + "additionalProperties" : false +} \ No newline at end of file diff --git a/json-modules/json-arrays/README.md b/json-modules/json-arrays/README.md new file mode 100644 index 0000000000..f119467046 --- /dev/null +++ b/json-modules/json-arrays/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [How to Check if a Value Exists in a JSON Array for a Particular Key](https://www.baeldung.com/java-json-array-check-key-value-pair) diff --git a/json-modules/json-arrays/pom.xml b/json-modules/json-arrays/pom.xml new file mode 100644 index 0000000000..0eefbc86fc --- /dev/null +++ b/json-modules/json-arrays/pom.xml @@ -0,0 +1,47 @@ + + + 4.0.0 + org.baeldung + json-arrays + json-arrays + + + com.baeldung + json-modules + 1.0.0-SNAPSHOT + + + + + org.json + json + ${json.version} + + + com.google.code.gson + gson + ${gson.version} + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + + + javax.json.bind + javax.json.bind-api + ${jsonb-api.version} + + + + + 1.0 + 20230227 + 2.8.5 + 1.1.2 + 2.28.0 + + + diff --git a/json-modules/json-arrays/src/test/java/com.baeldung.checkforkey/CheckForKeyUnitTest.java b/json-modules/json-arrays/src/test/java/com.baeldung.checkforkey/CheckForKeyUnitTest.java new file mode 100644 index 0000000000..6e1cbb7ab0 --- /dev/null +++ b/json-modules/json-arrays/src/test/java/com.baeldung.checkforkey/CheckForKeyUnitTest.java @@ -0,0 +1,47 @@ +package com.baeldung.checkforkey; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Objects; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +import org.junit.jupiter.api.Test; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; + +public class CheckForKeyUnitTest { + + private final String exampleJson = "[{\"colour\":\"red\"},{\"colour\":\"blue\"},{\"colour\":\"green\"}]"; + + @Test + public void givenJsonArray_whenUsingJackson_thenDetectKeyInArray() throws JsonProcessingException { + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode tree = objectMapper.readTree(exampleJson); + + Stream s = StreamSupport.stream(tree.spliterator(), false); + boolean result = s.map(entry -> entry.get("colour")) + .filter(Objects::nonNull) + .anyMatch(colour -> "green".equals(colour.asText())); + assertTrue(result); + } + + @Test + public void givenJsonArray_whenUsingGson_thenDetectKeyInArray() { + Gson gson = new Gson(); + JsonArray parsed = gson.fromJson(exampleJson, JsonArray.class); + + Stream s = StreamSupport.stream(parsed.spliterator(), false); + boolean result = s.map(entry -> entry.getAsJsonObject() + .get("colour")) + .filter(Objects::nonNull) + .anyMatch(colour -> "green".equals(colour.getAsString())); + assertTrue(result); + } + +} diff --git a/json-modules/pom.xml b/json-modules/pom.xml index 82314e0edf..306b404049 100644 --- a/json-modules/pom.xml +++ b/json-modules/pom.xml @@ -16,6 +16,7 @@ json json-2 + json-arrays json-conversion json-path gson diff --git a/kubernetes-modules/README.md b/kubernetes-modules/README.md new file mode 100644 index 0000000000..cb52c12465 --- /dev/null +++ b/kubernetes-modules/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [Guide to Eclipse JKube](https://www.baeldung.com/ops/eclipse-jkube) diff --git a/lombok-modules/lombok-2/pom.xml b/lombok-modules/lombok-2/pom.xml index 88fbaf530f..ea562ad896 100644 --- a/lombok-modules/lombok-2/pom.xml +++ b/lombok-modules/lombok-2/pom.xml @@ -25,10 +25,58 @@ jackson-databind ${jackson.version} + + com.google.code.gson + gson + ${gson.version} + + + javax.annotation + javax.annotation-api + ${javax.annotation} + + + io.swagger + swagger-annotations + ${swagger.annotation} + org.springframework.boot spring-boot-starter-web + + + + org.openapitools + openapi-generator-maven-plugin + ${openapi.version} + + + + generate + + + ${project.basedir}/src/main/resources/bookapi.yml + java + com.baeldung.openapi.model + + @lombok.Data @lombok.NoArgsConstructor @lombok.AllArgsConstructor + + false + false + false + + + + + + + + 4.2.3 + 2.10.1 + 1.3.2 + 1.6.2 + \ No newline at end of file diff --git a/lombok-modules/lombok-2/src/main/java/com/baeldung/lombok/openapiandlombook/Book.java b/lombok-modules/lombok-2/src/main/java/com/baeldung/lombok/openapiandlombook/Book.java new file mode 100644 index 0000000000..2da2e74a40 --- /dev/null +++ b/lombok-modules/lombok-2/src/main/java/com/baeldung/lombok/openapiandlombook/Book.java @@ -0,0 +1,12 @@ +package com.baeldung.lombok.openapiandlombook; + +@lombok.Data +@lombok.NoArgsConstructor +@lombok.AllArgsConstructor +public class Book { + + private Long id; + private String name; + private String author; + +} diff --git a/lombok-modules/lombok-2/src/main/resources/bookapi.yml b/lombok-modules/lombok-2/src/main/resources/bookapi.yml new file mode 100644 index 0000000000..e9b63b2f85 --- /dev/null +++ b/lombok-modules/lombok-2/src/main/resources/bookapi.yml @@ -0,0 +1,39 @@ +openapi: 3.0.2 +info: + version: 1.0.0 + title: Book Store + license: + name: MIT +paths: + /books: + get: + tags: + - book + summary: Get All Books + responses: + 200: + description: successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/Book' + + 404: + description: Book not found + content: { } +components: + schemas: + Book: + type: object + required: + - id + - name + - author + properties: + id: + type: integer + format: int64 + name: + type: string + author: + type: string diff --git a/lombok-modules/lombok/pom.xml b/lombok-modules/lombok/pom.xml index 6ba90f33b5..a04233bc2b 100644 --- a/lombok-modules/lombok/pom.xml +++ b/lombok-modules/lombok/pom.xml @@ -43,7 +43,6 @@ - edge-SNAPSHOT 1.0.0.Final 1.18.20.0 23.0.0 diff --git a/lombok-modules/pom.xml b/lombok-modules/pom.xml index 5100ed1790..46d91462fb 100644 --- a/lombok-modules/pom.xml +++ b/lombok-modules/pom.xml @@ -16,7 +16,7 @@ - + lombok lombok-2 diff --git a/mapstruct/src/main/java/com/baeldung/expression/dto/LicenseDto.java b/mapstruct/src/main/java/com/baeldung/expression/dto/LicenseDto.java new file mode 100644 index 0000000000..cd6e9bad68 --- /dev/null +++ b/mapstruct/src/main/java/com/baeldung/expression/dto/LicenseDto.java @@ -0,0 +1,21 @@ +package com.baeldung.expression.dto; + +import java.time.LocalDateTime; +import java.util.UUID; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; + +@AllArgsConstructor +@Data +@Builder +public class LicenseDto { + + private UUID id; + + private LocalDateTime startDate; + + private LocalDateTime endDate; + +} diff --git a/mapstruct/src/main/java/com/baeldung/expression/mapper/LicenseMapper.java b/mapstruct/src/main/java/com/baeldung/expression/mapper/LicenseMapper.java new file mode 100644 index 0000000000..100588b45d --- /dev/null +++ b/mapstruct/src/main/java/com/baeldung/expression/mapper/LicenseMapper.java @@ -0,0 +1,43 @@ +package com.baeldung.expression.mapper; + +import java.time.Duration; +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; + +import org.mapstruct.AfterMapping; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.MappingTarget; + +import com.baeldung.expression.dto.LicenseDto; +import com.baeldung.expression.model.License; + +@Mapper +public interface LicenseMapper { + + @Mapping(target = "startDate", expression = "java(mapStartDate(licenseDto))") + @Mapping(target = "endDate", ignore = true) + @Mapping(target = "active", constant = "true") + @Mapping(target = "renewalRequired", conditionExpression = "java(isEndDateInTwoWeeks(licenseDto))", source = ".") + License toLicense(LicenseDto licenseDto); + + @AfterMapping + default void afterMapping(LicenseDto licenseDto, @MappingTarget License license) { + OffsetDateTime endDate = licenseDto.getEndDate() != null ? licenseDto.getEndDate() + .atOffset(ZoneOffset.UTC) : OffsetDateTime.now() + .plusYears(1); + license.setEndDate(endDate); + } + + default OffsetDateTime mapStartDate(LicenseDto licenseDto) { + return licenseDto.getStartDate() != null ? licenseDto.getStartDate() + .atOffset(ZoneOffset.UTC) : OffsetDateTime.now(); + } + + default boolean isEndDateInTwoWeeks(LicenseDto licenseDto) { + return licenseDto.getEndDate() != null && Duration.between(licenseDto.getEndDate(), LocalDateTime.now()) + .toDays() <= 14; + } + +} diff --git a/mapstruct/src/main/java/com/baeldung/expression/model/License.java b/mapstruct/src/main/java/com/baeldung/expression/model/License.java new file mode 100644 index 0000000000..9e87be03d4 --- /dev/null +++ b/mapstruct/src/main/java/com/baeldung/expression/model/License.java @@ -0,0 +1,21 @@ +package com.baeldung.expression.model; + +import java.time.OffsetDateTime; +import java.util.UUID; + +import lombok.Data; + +@Data +public class License { + + private UUID id; + + private OffsetDateTime startDate; + + private OffsetDateTime endDate; + + private boolean active; + + private boolean renewalRequired; + +} diff --git a/mapstruct/src/test/java/com/baeldung/expression/mapper/LicenseMapperUnitTest.java b/mapstruct/src/test/java/com/baeldung/expression/mapper/LicenseMapperUnitTest.java new file mode 100644 index 0000000000..98f704e61c --- /dev/null +++ b/mapstruct/src/test/java/com/baeldung/expression/mapper/LicenseMapperUnitTest.java @@ -0,0 +1,64 @@ +package com.baeldung.expression.mapper; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.time.LocalDate; +import java.time.LocalDateTime; + +import org.junit.jupiter.api.Test; +import org.mapstruct.factory.Mappers; + +import com.baeldung.expression.dto.LicenseDto; +import com.baeldung.expression.model.License; + +class LicenseMapperUnitTest { + + LicenseMapper licenseMapper = Mappers.getMapper(LicenseMapper.class); + + @Test + void givenLicenseDtoWithStartDateAndWithoutEndDate_WhenMapperMethodIsInvoked_ThenLicenseShouldBePopulatedWithDefaultEndDate() { + License license = licenseMapper.toLicense(LicenseDto.builder() + .startDate(LocalDateTime.now()) + .build()); + assertThat(license).isNotNull(); + assertThat(license.getEndDate() + .toLocalDate()).isEqualTo(LocalDate.now() + .plusYears(1)); + } + + @Test + void givenLicenseDtoWithEndDateAndWithoutStartDate_WhenMapperMethodIsInvoked_ThenLicenseShouldBePopulatedWithDefaultStartDate() { + License license = licenseMapper.toLicense(LicenseDto.builder() + .endDate(LocalDateTime.now() + .plusYears(2)) + .build()); + assertThat(license).isNotNull(); + assertThat(license.getStartDate() + .toLocalDate()).isEqualTo(LocalDate.now()); + } + + @Test + void givenLicenseDtoWithoutStartDateAndEndDate_WhenMapperMethodIsInvoked_ThenLicenseShouldBePopulatedWithDefaultDetails() { + License license = licenseMapper.toLicense(LicenseDto.builder() + .build()); + assertThat(license).isNotNull(); + assertThat(license.getStartDate() + .toLocalDate()).isEqualTo(LocalDate.now()); + assertThat(license.getEndDate() + .toLocalDate()).isEqualTo(LocalDate.now() + .plusYears(1)); + assertThat(license.isActive()).isTrue(); + assertThat(license.isRenewalRequired()).isFalse(); + } + + @Test + void givenLicenseDtoWithEndDateInTwoWeeks_WhenMapperMethodIsInvoked_ThenLicenseShouldBePopulatedWithRenewalRequiredSetToTrue() { + License license = licenseMapper.toLicense(LicenseDto.builder() + .endDate(LocalDateTime.now() + .plusDays(10)) + .build()); + assertThat(license).isNotNull(); + assertThat(license.isRenewalRequired()).isTrue(); + } + +} \ No newline at end of file diff --git a/maven-modules/maven-build-optimization/.mvn/jvm.config.txt b/maven-modules/maven-build-optimization/.mvn/jvm.config.txt new file mode 100644 index 0000000000..37dd0076c2 --- /dev/null +++ b/maven-modules/maven-build-optimization/.mvn/jvm.config.txt @@ -0,0 +1 @@ +-XX:-TieredCompilation -XX:TieredStopAtLevel=1 \ No newline at end of file diff --git a/maven-modules/maven-build-optimization/.profiler/profiler-report-2023-08-05-19-34-46.html b/maven-modules/maven-build-optimization/.profiler/profiler-report-2023-08-05-19-34-46.html new file mode 100644 index 0000000000..807679bbf6 --- /dev/null +++ b/maven-modules/maven-build-optimization/.profiler/profiler-report-2023-08-05-19-34-46.html @@ -0,0 +1,2542 @@ + + + + + Maven Profiler Report + + + +
+

maven-build-optimization (21,91 s)

+

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

+ + +
+

maven-build-optimization (18,81 s)

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

Artifact Downloading (168,3 s)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ArtifactDuration
org.codehaus.plexus:plexus-utils:jar:3.3.01,649 s
javax.inject:javax.inject:jar:11,646 s
org.codehaus.plexus:plexus-resources:jar:1.2.01,643 s
org.apache.maven.doxia:doxia-integration-tools:jar:1.11.11,640 s
org.eclipse.sisu:org.eclipse.sisu.inject:jar:0.3.51,636 s
javax.enterprise:cdi-api:jar:1.21,634 s
javax.annotation:javax.annotation-api:jar:1.21,632 s
org.eclipse.sisu:org.eclipse.sisu.plexus:jar:0.3.51,630 s
org.apache.maven:maven-plugin-api:jar:3.1.01,627 s
org.apache.maven.reporting:maven-reporting-impl:jar:3.2.01,623 s
org.apache.maven.reporting:maven-reporting-api:jar:3.1.11,620 s
commons-collections:commons-collections:jar:3.2.21,618 s
oro:oro:jar:2.0.81,616 s
dom4j:dom4j:jar:1.11,613 s
commons-logging:commons-logging:jar:1.11,611 s
commons-chain:commons-chain:jar:1.11,607 s
commons-digester:commons-digester:jar:1.81,604 s
commons-beanutils:commons-beanutils:jar:1.7.01,602 s
org.apache.velocity:velocity-tools:jar:2.01,600 s
commons-lang:commons-lang:jar:2.41,597 s
org.apache.velocity:velocity:jar:1.71,595 s
org.codehaus.plexus:plexus-velocity:jar:1.21,592 s
org.codehaus.plexus:plexus-container-default:jar:1.0-alpha-301,589 s
org.codehaus.plexus:plexus-i18n:jar:1.0-beta-101,586 s
org.apache.maven.doxia:doxia-module-xhtml5:jar:1.11.11,583 s
org.apache.maven.doxia:doxia-module-xhtml:jar:1.11.11,578 s
org.apache.maven.doxia:doxia-skin-model:jar:1.11.11,572 s
org.apache.httpcomponents:httpcore:jar:4.4.141,569 s
org.apache.commons:commons-text:jar:1.31,566 s
org.apache.maven.doxia:doxia-core:jar:1.11.11,563 s
org.apache.maven.doxia:doxia-site-renderer:jar:1.11.11,560 s
org.apache.maven.doxia:doxia-decoration-model:jar:1.11.11,556 s
org.apache.maven.doxia:doxia-logging-api:jar:1.11.11,553 s
org.apache.maven.doxia:doxia-sink-api:jar:1.11.11,551 s
org.slf4j:jul-to-slf4j:jar:1.7.361,549 s
org.slf4j:slf4j-api:jar:1.7.361,546 s
net.sourceforge.pmd:pmd-jsp:jar:6.49.01,543 s
org.mozilla:rhino:jar:1.7.141,540 s
net.sourceforge.pmd:pmd-javascript:jar:6.49.01,537 s
net.sourceforge.pmd:pmd-java:jar:6.49.01,535 s
net.sourceforge.saxon:saxon:jar:dom:9.1.0.81,533 s
com.google.code.gson:gson:jar:2.8.91,530 s
org.ow2.asm:asm:jar:9.31,528 s
net.sourceforge.saxon:saxon:jar:9.1.0.81,524 s
com.beust:jcommander:jar:1.481,521 s
org.antlr:antlr4-runtime:jar:4.7.21,519 s
net.sourceforge.pmd:pmd-core:jar:6.49.01,516 s
org.apache.commons:commons-lang3:jar:3.12.01,513 s
commons-io:commons-io:jar:2.11.01,511 s
org.apache.maven.shared:maven-common-artifact-filters:jar:3.3.11,508 s
org.codehaus.plexus:plexus-component-annotations:jar:2.1.11,504 s
org.apache.maven:maven-artifact:jar:3.01,501 s
org.codehaus.plexus:plexus-classworlds:jar:2.2.31,498 s
org.sonatype.sisu:sisu-guice:jar:noaop:2.1.71,495 s
org.sonatype.sisu:sisu-inject-bean:jar:1.4.21,481 s
org.sonatype.sisu:sisu-inject-plexus:jar:1.4.21,472 s
org.sonatype.aether:aether-util:jar:1.71,468 s
org.sonatype.aether:aether-api:jar:1.71,465 s
org.sonatype.aether:aether-spi:jar:1.71,462 s
org.sonatype.aether:aether-impl:jar:1.71,459 s
org.apache.maven:maven-aether-provider:jar:3.01,455 s
org.apache.maven:maven-model-builder:jar:3.01,453 s
org.apache.maven:maven-repository-metadata:jar:3.01,450 s
org.apache.maven:maven-settings-builder:jar:3.01,447 s
org.apache.maven:maven-settings:jar:3.01,444 s
org.apache.maven:maven-model:jar:3.01,441 s
org.apache.maven:maven-core:jar:3.01,437 s
org.apache.maven.shared:maven-artifact-transfer:jar:0.13.11,434 s
org.apache.maven.surefire:surefire-logger-api:jar:2.22.21,110 s
org.objenesis:objenesis:jar:3.21,107 s
net.bytebuddy:byte-buddy-agent:jar:1.12.81,104 s
net.bytebuddy:byte-buddy:jar:1.12.81,102 s
org.mockito:mockito-core:jar:4.4.01,097 s
org.hamcrest:hamcrest-all:jar:1.31,094 s
org.hamcrest:hamcrest:jar:2.21,092 s
org.assertj:assertj-core:jar:3.21.01,090 s
org.hamcrest:hamcrest-core:jar:1.31,087 s
junit:junit:jar:4.13.21,081 s
org.junit.vintage:junit-vintage-engine:jar:5.9.21,072 s
org.junit.platform:junit-platform-commons:jar:1.9.21,053 s
org.opentest4j:opentest4j:jar:1.2.01,046 s
org.junit.jupiter:junit-jupiter-api:jar:5.9.21,043 s
org.junit.jupiter:junit-jupiter-params:jar:5.9.21,041 s
org.apiguardian:apiguardian-api:jar:1.1.21,037 s
org.junit.platform:junit-platform-engine:jar:1.9.21,034 s
org.junit.jupiter:junit-jupiter-engine:jar:5.9.21,030 s
org.slf4j:jcl-over-slf4j:jar:1.7.321,027 s
ch.qos.logback:logback-core:jar:1.2.71,025 s
ch.qos.logback:logback-classic:jar:1.2.71,021 s
org.slf4j:slf4j-api:jar:1.7.321,018 s
com.vackosar.gitflowincrementalbuilder:gitflow-incremental-builder:pom:3.12.2912,3 ms
com.jcraft:jsch.agentproxy.sshagent:jar:0.0.9714,0 ms
net.java.dev.jna:jna-platform:jar:4.1.0709,2 ms
net.java.dev.jna:jna:jar:4.1.0700,3 ms
com.jcraft:jsch.agentproxy.pageant:jar:0.0.9696,9 ms
com.jcraft:jsch.agentproxy.jsch:jar:0.0.9691,3 ms
com.jcraft:jsch.agentproxy.usocket-nc:jar:0.0.9687,5 ms
com.jcraft:jsch.agentproxy.usocket-jna:jar:0.0.9681,7 ms
com.jcraft:jsch.agentproxy.core:jar:0.0.9677,3 ms
com.jcraft:jsch.agentproxy.connector-factory:jar:0.0.9673,1 ms
com.jcraft:jzlib:jar:1.1.1669,0 ms
com.jcraft:jsch:jar:0.1.55665,4 ms
org.eclipse.jgit:org.eclipse.jgit.ssh.jsch:jar:5.10.0.202012080955-r662,5 ms
com.googlecode.javaewah:JavaEWAH:jar:1.1.7659,3 ms
org.eclipse.jgit:org.eclipse.jgit:jar:5.10.0.202012080955-r656,1 ms
com.vackosar.gitflowincrementalbuilder:gitflow-incremental-builder:jar:3.12.2653,0 ms
org.apache.maven:maven-model:jar:3.0.3435,3 ms
org.apache.maven:maven-plugin-api:jar:3.0.3430,5 ms
org.sonatype.plexus:plexus-cipher:jar:1.4427,8 ms
org.sonatype.plexus:plexus-sec-dispatcher:jar:1.3424,9 ms
org.codehaus.plexus:plexus-component-annotations:jar:1.5.5421,3 ms
org.codehaus.plexus:plexus-classworlds:jar:2.4418,1 ms
org.codehaus.plexus:plexus-utils:jar:2.0.6414,4 ms
org.codehaus.plexus:plexus-interpolation:jar:1.14411,1 ms
org.sonatype.sisu:sisu-guice:jar:no_aop:2.9.4403,0 ms
org.sonatype.sisu:sisu-inject-bean:jar:2.1.1396,1 ms
org.sonatype.sisu:sisu-inject-plexus:jar:2.1.1392,9 ms
org.sonatype.aether:aether-util:jar:1.11388,1 ms
org.sonatype.aether:aether-api:jar:1.11385,0 ms
org.sonatype.aether:aether-impl:jar:1.11381,0 ms
org.sonatype.aether:aether-spi:jar:1.11377,5 ms
org.apache.maven:maven-aether-provider:jar:3.0.3374,7 ms
org.apache.maven:maven-model-builder:jar:3.0.3371,9 ms
org.apache.maven:maven-artifact:jar:3.0.3369,1 ms
org.apache.maven:maven-repository-metadata:jar:3.0.3365,9 ms
org.apache.maven:maven-settings-builder:jar:3.0.3361,7 ms
org.apache.maven:maven-settings:jar:3.0.3358,7 ms
org.apache.maven:maven-core:jar:3.0.3355,7 ms
org.codehaus.plexus:plexus-utils:jar:3.0.15320,8 ms
com.google.code.findbugs:jsr305:jar:2.0.1312,4 ms
org.apache.maven.shared:maven-shared-utils:jar:0.4309,8 ms
commons-codec:commons-codec:jar:1.6307,2 ms
org.apache.maven:maven-artifact:jar:2.2.1304,6 ms
backport-util-concurrent:backport-util-concurrent:jar:3.1302,0 ms
org.apache.maven:maven-repository-metadata:jar:2.2.1298,3 ms
org.apache.maven:maven-artifact-manager:jar:2.2.1294,0 ms
org.apache.maven:maven-model:jar:2.2.1291,5 ms
classworlds:classworlds:jar:1.1-alpha-2288,9 ms
junit:junit:jar:3.8.1286,4 ms
org.codehaus.plexus:plexus-container-default:jar:1.0-alpha-9-stable-1282,9 ms
org.codehaus.plexus:plexus-interpolation:jar:1.11278,9 ms
org.apache.maven:maven-plugin-registry:jar:2.2.1276,5 ms
org.apache.maven:maven-profile:jar:2.2.1273,8 ms
org.apache.maven:maven-settings:jar:2.2.1271,4 ms
org.apache.maven:maven-project:jar:2.2.1268,8 ms
org.apache.maven:maven-plugin-api:jar:2.2.1265,4 ms
commons-io:commons-io:jar:2.6111,6 ms
org.apache.maven.shared:maven-shared-utils:jar:3.3.4109,0 ms
org.apache.velocity:velocity:pom:1.6.297,59 ms
commons-collections:commons-collections:pom:3.2.284,54 ms
org.apache:apache:pom:576,39 ms
org.eclipse.aether:aether-impl:pom:0.9.0.M277,00 ms
org.eclipse.sisu:org.eclipse.sisu.inject:pom:0.3.572,70 ms
org.eclipse.aether:aether-util:pom:0.9.0.M271,60 ms
org.codehaus.plexus:plexus-container-default:pom:1.0-alpha-3070,94 ms
org.codehaus.plexus:plexus-utils:pom:2.0.669,83 ms
org.mozilla:rhino:pom:1.7.1468,12 ms
org.eclipse.jgit:org.eclipse.jgit-parent:pom:5.10.0.202012080955-r67,22 ms
org.codehaus.plexus:plexus:pom:2.0.767,22 ms
oro:oro:pom:2.0.866,76 ms
org.slf4j:slf4j-api:pom:1.7.3262,58 ms
commons-collections:commons-collections:pom:2.062,45 ms
org.eclipse.jgit:org.eclipse.jgit.ssh.jsch:pom:5.10.0.202012080955-r61,11 ms
org.sonatype.aether:aether-impl:pom:1.1161,37 ms
org.codehaus.plexus:plexus-container-default:pom:1.0-alpha-9-stable-161,22 ms
com.google.code.findbugs:jsr305:pom:2.0.160,24 ms
com.jcraft:jsch:pom:0.1.4959,02 ms
org.codehaus.plexus:plexus-classworlds:pom:1.2-alpha-958,04 ms
ch.qos.logback:logback-classic:pom:1.2.757,91 ms
org.sonatype.sisu:sisu-guice:pom:2.1.757,63 ms
commons-io:commons-io:pom:2.557,02 ms
commons-beanutils:commons-beanutils:pom:1.657,12 ms
javax.inject:javax.inject:pom:157,82 ms
com.jcraft:jzlib:pom:1.1.156,09 ms
org.jboss.weld:weld-parent:pom:2656,42 ms
org.apache.maven:maven:pom:2.2.155,59 ms
org.apache.maven:maven-project:pom:2.2.155,15 ms
org.slf4j:slf4j-parent:pom:1.7.3255,55 ms
ch.qos.logback:logback-core:pom:1.2.755,62 ms
org.junit.jupiter:junit-jupiter-params:pom:5.9.255,39 ms
org.apache.maven:maven-plugin-api:pom:3.055,91 ms
org.sonatype.oss:oss-parent:pom:355,16 ms
org.apache.maven:maven:pom:3.1.055,12 ms
org.apache:apache:pom:1453,84 ms
org.assertj:assertj-core:pom:3.21.053,16 ms
org.apache.maven.doxia:doxia-logging-api:pom:1.11.153,83 ms
commons-codec:commons-codec:pom:1.652,94 ms
org.apache:apache:pom:1352,42 ms
ch.qos.logback:logback-parent:pom:1.2.752,44 ms
net.sourceforge.pmd:pmd-javascript:pom:6.49.052,50 ms
org.apache.maven:maven-model:pom:3.1.052,30 ms
org.apache.maven:maven-settings:pom:3.1.052,33 ms
com.jcraft:jsch.agentproxy.core:pom:0.0.951,97 ms
org.apache.maven:maven-parent:pom:3551,64 ms
org.apache:apache:pom:651,83 ms
org.codehaus.plexus:plexus-utils:pom:3.3.051,78 ms
org.sonatype.aether:aether-api:pom:1.751,32 ms
org.apache.velocity:velocity:pom:1.751,33 ms
org.apache.maven.shared:maven-artifact-transfer:pom:0.13.150,31 ms
org.junit:junit-bom:pom:5.7.150,17 ms
org.apache.httpcomponents:httpcore:pom:4.4.1450,00 ms
xml-apis:xml-apis:pom:1.0.b250,17 ms
org.apache.maven.reporting:maven-reporting-impl:pom:3.2.050,00 ms
org.apache.maven:maven-core:pom:3.1.050,88 ms
org.apache.maven:maven-core:pom:3.0.348,45 ms
org.apache.maven:maven-parent:pom:3648,84 ms
org.apache.commons:commons-parent:pom:4748,48 ms
net.sourceforge.pmd:pmd-java:pom:6.49.048,23 ms
org.apache.maven.doxia:doxia-core:pom:1.11.148,46 ms
commons-chain:commons-chain:pom:1.148,33 ms
org.eclipse.jgit:org.eclipse.jgit:pom:5.10.0.202012080955-r47,77 ms
com.googlecode.javaewah:JavaEWAH:pom:1.1.747,41 ms
com.jcraft:jsch:pom:0.1.5547,14 ms
org.apache.maven.plugins:maven-clean-plugin:pom:3.2.047,30 ms
org.apache:apache:pom:2547,29 ms
org.apache.maven:maven-profile:pom:2.2.147,30 ms
org.apache.maven:maven-artifact:pom:3.047,23 ms
org.commonjava.maven.plugins:directory-maven-plugin:pom:0.3.146,74 ms
org.apache.maven.plugins:maven-pmd-plugin:jar:3.19.046,85 ms
org.sonatype.sisu:sisu-parent:pom:2.1.146,14 ms
org.apache.maven.doxia:doxia-site-renderer:pom:1.11.146,37 ms
org.apache.httpcomponents:httpcomponents-parent:pom:1146,78 ms
log4j:log4j:pom:1.2.1246,66 ms
commons-digester:commons-digester:pom:1.646,89 ms
org.sonatype.oss:oss-parent:pom:645,87 ms
org.apache.maven:maven-parent:pom:1545,51 ms
org.apache.maven.plugins:maven-install-plugin:pom:2.5.245,87 ms
org.apache.maven:maven-settings-builder:pom:3.0.345,01 ms
org.sonatype.sisu:sisu-inject-bean:pom:2.1.145,81 ms
org.hamcrest:hamcrest-core:pom:1.345,43 ms
org.hamcrest:hamcrest:pom:2.245,94 ms
net.bytebuddy:byte-buddy-agent:pom:1.12.845,38 ms
org.codehaus.plexus:plexus-classworlds:pom:2.2.345,57 ms
net.sourceforge.pmd:pmd:pom:6.49.045,12 ms
org.sonatype.oss:oss-parent:pom:945,17 ms
com.beust:jcommander:pom:1.4845,36 ms
org.apache.maven.doxia:doxia-skin-model:pom:1.11.145,26 ms
avalon-framework:avalon-framework:pom:4.1.345,37 ms
org.apache.commons:commons-parent:pom:4244,20 ms
org.apache.maven:maven-settings:pom:3.0.344,16 ms
org.apache.maven:maven-model:pom:2.2.144,03 ms
org.codehaus.plexus:plexus:pom:6.544,63 ms
org.apache.commons:commons-parent:pom:3944,23 ms
org.slf4j:slf4j-parent:pom:1.7.3644,75 ms
org.ow2.asm:asm:pom:9.344,39 ms
logkit:logkit:pom:1.0.144,09 ms
org.apache.maven.reporting:maven-reporting-api:pom:3.1.144,16 ms
org.apache.maven.shared:maven-shared-components:pom:1544,84 ms
com.jcraft:jsch.agentproxy:pom:0.0.943,31 ms
net.java.dev.jna:jna-platform:pom:4.1.043,11 ms
org.commonjava.maven.plugins:directory-maven-plugin:jar:0.3.143,95 ms
org.apache.maven.plugins:maven-install-plugin:jar:2.5.243,19 ms
org.apache.maven.shared:maven-shared-components:pom:3443,48 ms
org.sonatype.forge:forge-parent:pom:743,50 ms
org.apache.maven:maven-model-builder:pom:3.0.343,32 ms
org.codehaus.plexus:plexus-containers:pom:1.0.343,70 ms
org.junit.jupiter:junit-jupiter-engine:pom:5.9.243,63 ms
net.bytebuddy:byte-buddy-parent:pom:1.12.843,82 ms
org.apache:apache:pom:2143,91 ms
org.apache.httpcomponents:httpcomponents-core:pom:4.4.1443,69 ms
org.apache.maven.doxia:doxia-modules:pom:1.11.143,31 ms
org.codehaus.plexus:plexus-components:pom:1.1.1243,70 ms
commons-collections:commons-collections:pom:3.143,62 ms
org.apache.velocity:velocity-tools:pom:2.043,88 ms
commons-collections:commons-collections:pom:3.243,92 ms
org.eclipse.sisu:sisu-inject:pom:0.3.543,24 ms
org.apache.maven:maven-model-builder:pom:3.1.043,18 ms
org.apache.httpcomponents:httpclient:pom:4.5.1343,56 ms
org.apache.maven.doxia:doxia-integration-tools:pom:1.11.143,28 ms
org.sonatype.oss:oss-parent:pom:542,01 ms
org.apache.maven.plugins:maven-plugins:pom:3542,47 ms
org.apache.maven.plugins:maven-clean-plugin:jar:3.2.042,26 ms
org.apache.maven.plugins:maven-plugins:pom:3742,31 ms
commons-io:commons-io:pom:2.642,61 ms
org.sonatype.sisu.inject:guice-plexus:pom:2.1.142,22 ms
org.sonatype.aether:aether-util:pom:1.1142,96 ms
org.codehaus.plexus:plexus:pom:2.0.242,03 ms
org.apache.maven:maven-parent:pom:2342,40 ms
org.junit:junit-bom:pom:5.8.042,55 ms
org.objenesis:objenesis-parent:pom:3.242,08 ms
org.sonatype.sisu:sisu-inject-bean:pom:1.4.242,36 ms
org.apache.maven:maven-model-builder:pom:3.042,71 ms
org.codehaus.plexus:plexus-container-default:pom:2.1.042,77 ms
org.apache.commons:commons-text:pom:1.342,56 ms
org.apache.commons:commons-parent:pom:4542,72 ms
org.codehaus.plexus:plexus-interpolation:pom:1.1642,98 ms
org.codehaus.plexus:plexus:pom:3.342,67 ms
com.jcraft:jsch.agentproxy.pageant:pom:0.0.941,70 ms
org.apache.maven.plugins:maven-plugins:pom:2541,58 ms
org.apache.maven.shared:maven-shared-utils:pom:3.3.441,60 ms
org.apache.maven:maven-model:pom:3.0.341,28 ms
org.sonatype.plexus:plexus-sec-dispatcher:pom:1.341,49 ms
org.sonatype.forge:forge-parent:pom:441,12 ms
org.codehaus.plexus:plexus:pom:3.3.141,32 ms
org.junit:junit-bom:pom:5.9.241,89 ms
org.hamcrest:hamcrest-all:pom:1.341,23 ms
org.apache.maven:maven-repository-metadata:pom:3.041,58 ms
org.ow2:ow2:pom:1.541,73 ms
org.apache.geronimo.genesis:genesis-default-flava:pom:2.041,83 ms
org.codehaus.plexus:plexus-i18n:pom:1.0-beta-1041,30 ms
org.apache.commons:commons-parent:pom:941,92 ms
commons-logging:commons-logging:pom:1.041,40 ms
dom4j:dom4j:pom:1.141,17 ms
javax.annotation:javax.annotation-api:pom:1.241,69 ms
org.codehaus.plexus:plexus:pom:3.0.141,86 ms
com.jcraft:jsch.agentproxy.connector-factory:pom:0.0.940,94 ms
com.jcraft:jsch.agentproxy.jsch:pom:0.0.940,90 ms
org.sonatype.sisu:sisu-inject-plexus:pom:2.1.140,48 ms
org.sonatype.aether:aether-parent:pom:1.1140,15 ms
classworlds:classworlds:pom:1.1-alpha-240,71 ms
org.apache.maven:maven-aether-provider:pom:3.040,45 ms
org.sonatype.aether:aether-spi:pom:1.740,35 ms
org.apache:apache:pom:1640,00 ms
org.junit:junit-bom:pom:5.7.240,99 ms
org.antlr:antlr4-master:pom:4.7.240,97 ms
org.apache.commons:commons-lang3:pom:3.8.140,64 ms
com.google.code.gson:gson-parent:pom:2.8.940,24 ms
org.apache.xbean:xbean-reflect:pom:3.740,35 ms
org.apache.geronimo.genesis:genesis-java5-flava:pom:2.040,09 ms
org.apache.maven.doxia:doxia-module-xhtml5:pom:1.11.140,48 ms
com.jcraft:jsch.agentproxy.sshagent:pom:0.0.939,63 ms
org.apache.maven:maven-parent:pom:2439,98 ms
org.apache.maven.plugins:maven-pmd-plugin:pom:3.19.039,32 ms
org.apache.maven:maven-parent:pom:3739,06 ms
org.apache:apache:pom:2339,62 ms
org.codehaus.plexus:plexus-interpolation:pom:1.1439,03 ms
org.sonatype.sisu.inject:guice-bean:pom:2.1.139,53 ms
org.sonatype.sisu:sisu-inject:pom:2.1.139,26 ms
org.sonatype.sisu:sisu-guice:pom:2.9.439,61 ms
org.apache.maven:maven-settings:pom:2.2.139,79 ms
org.junit.platform:junit-platform-commons:pom:1.9.239,25 ms
org.apache.maven:maven:pom:3.039,95 ms
org.sonatype.sisu:sisu-parent:pom:1.4.239,06 ms
org.slf4j:slf4j-api:pom:1.7.3639,61 ms
commons-collections:commons-collections:pom:3.2.139,98 ms
org.apache.maven:maven-plugin-api:pom:3.1.039,75 ms
org.eclipse.sisu:org.eclipse.sisu.plexus:pom:0.3.539,14 ms
org.apache.httpcomponents:httpcore:pom:4.4.1339,01 ms
org.apache.maven.reporting:maven-reporting-api:pom:3.039,80 ms
org.apache.maven.doxia:doxia:pom:1.039,41 ms
org.codehaus.plexus:plexus-resources:pom:1.2.039,79 ms
net.java.dev.jna:jna:pom:4.1.038,09 ms
org.apache.maven:maven:pom:3.0.338,51 ms
org.apache:apache:pom:2738,99 ms
org.sonatype.plexus:plexus-cipher:pom:1.438,91 ms
org.apache.maven:maven-artifact:pom:3.0.338,26 ms
org.apache:apache:pom:938,99 ms
org.junit.jupiter:junit-jupiter-api:pom:5.9.238,90 ms
junit:junit:pom:4.13.238,54 ms
org.assertj:assertj-parent-pom:pom:2.2.1338,07 ms
org.apache.maven:maven-parent:pom:3338,50 ms
org.apache.maven:maven-model:pom:3.038,40 ms
org.codehaus.plexus:plexus-containers:pom:2.1.138,59 ms
org.codehaus.plexus:plexus:pom:2.0.638,25 ms
org.apache.maven.shared:maven-common-artifact-filters:pom:3.1.038,98 ms
org.apache.maven:maven-parent:pom:3038,45 ms
org.apache.commons:commons-parent:pom:5238,74 ms
org.apache.geronimo.genesis:genesis:pom:2.038,35 ms
org.codehaus.plexus:plexus:pom:1.0.1038,11 ms
commons-logging:commons-logging:pom:1.138,41 ms
javax.enterprise:cdi-api:pom:1.238,86 ms
org.eclipse.aether:aether-spi:pom:0.9.0.M238,01 ms
org.apache.httpcomponents:httpcomponents-client:pom:4.5.1338,87 ms
org.apache.commons:commons-parent:pom:3438,24 ms
org.apache.maven:maven-parent:pom:1038,57 ms
com.jcraft:jsch.agentproxy.usocket-jna:pom:0.0.937,73 ms
com.jcraft:jsch.agentproxy.usocket-nc:pom:0.0.937,70 ms
org.apache.maven:maven-parent:pom:3437,84 ms
org.apache.maven:maven-aether-provider:pom:3.0.337,14 ms
org.codehaus.plexus:plexus-utils:pom:1.5.1537,16 ms
org.apache.maven:maven-repository-metadata:pom:2.2.137,94 ms
org.apache.maven:maven-plugin-registry:pom:2.2.137,76 ms
org.hamcrest:hamcrest-parent:pom:1.337,16 ms
org.apache.maven.surefire:surefire:pom:2.22.237,51 ms
org.codehaus.plexus:plexus:pom:5.137,75 ms
org.codehaus.plexus:plexus-component-annotations:pom:2.1.137,62 ms
org.slf4j:slf4j-api:pom:1.7.537,15 ms
net.sourceforge.pmd:pmd-core:pom:6.49.037,11 ms
com.google.code.gson:gson:pom:2.8.937,75 ms
org.apache.maven.doxia:doxia-sink-api:pom:1.11.137,14 ms
org.codehaus.plexus:plexus-containers:pom:2.1.037,25 ms
org.apache.xbean:xbean:pom:3.737,25 ms
com.google:google:pom:137,52 ms
org.apache.maven.doxia:doxia-module-xhtml:pom:1.11.137,70 ms
org.codehaus.plexus:plexus-containers:pom:1.0-alpha-3037,07 ms
org.codehaus.plexus:plexus-components:pom:4.037,10 ms
org.eclipse.aether:aether:pom:0.9.0.M237,23 ms
org.apache:apache:pom:1836,22 ms
org.codehaus.plexus:plexus-components:pom:1.1.1836,26 ms
org.codehaus.plexus:plexus-component-annotations:pom:1.5.536,67 ms
org.apache.maven:maven-repository-metadata:pom:3.0.336,72 ms
org.codehaus.plexus:plexus-classworlds:pom:2.436,29 ms
org.sonatype.sisu.inject:guice-parent:pom:2.9.436,18 ms
org.sonatype.aether:aether-api:pom:1.1136,69 ms
org.sonatype.aether:aether-spi:pom:1.1136,84 ms
org.apache.maven:maven-plugin-api:pom:2.2.136,35 ms
org.apache.maven:maven-artifact-manager:pom:2.2.136,45 ms
org.apache.commons:commons-parent:pom:2236,60 ms
org.codehaus.plexus:plexus-utils:pom:3.0.1536,29 ms
org.junit.platform:junit-platform-engine:pom:1.9.236,04 ms
org.mockito:mockito-core:pom:4.4.036,15 ms
org.objenesis:objenesis:pom:3.236,89 ms
org.apache.maven:maven-settings:pom:3.036,73 ms
org.sonatype.sisu.inject:guice-plexus:pom:1.4.236,89 ms
org.apache.maven.shared:maven-shared-utils:pom:3.1.036,08 ms
org.apache.maven.shared:maven-common-artifact-filters:pom:3.3.136,16 ms
net.sourceforge.pmd:pmd-jsp:pom:6.49.036,48 ms
org.apache.maven.doxia:doxia:pom:1.11.136,98 ms
com.google.collections:google-collections:pom:1.036,84 ms
org.apache.maven:maven-repository-metadata:pom:3.1.036,82 ms
org.eclipse.sisu:sisu-plexus:pom:0.3.536,74 ms
net.java:jvnet-parent:pom:336,83 ms
org.codehaus.plexus:plexus-classworlds:pom:2.4.236,24 ms
org.apache.httpcomponents:httpcomponents-core:pom:4.4.1336,86 ms
org.apache:apache:pom:736,60 ms
org.codehaus.plexus:plexus-container-default:pom:1.0-alpha-936,51 ms
org.sonatype.forge:forge-parent:pom:635,58 ms
org.apache.maven:maven-parent:pom:1135,64 ms
org.codehaus.plexus:plexus:pom:1.0.435,29 ms
org.codehaus.plexus:plexus-utils:pom:1.0.435,69 ms
backport-util-concurrent:backport-util-concurrent:pom:3.135,38 ms
org.apache.maven.shared:maven-shared-utils:pom:0.435,84 ms
org.slf4j:jcl-over-slf4j:pom:1.7.3235,15 ms
org.opentest4j:opentest4j:pom:1.2.035,58 ms
net.bytebuddy:byte-buddy:pom:1.12.835,52 ms
org.sonatype.sisu:sisu-inject-plexus:pom:1.4.235,46 ms
org.sonatype.sisu:sisu-inject:pom:1.4.235,22 ms
org.apache.maven.shared:maven-shared-components:pom:3635,28 ms
org.apache:apache:pom:2635,25 ms
org.apache.commons:commons-lang3:pom:3.12.035,54 ms
org.antlr:antlr4-runtime:pom:4.7.235,18 ms
net.sourceforge.saxon:saxon:pom:9.1.0.835,76 ms
org.apache:apache:pom:1935,50 ms
org.codehaus.plexus:plexus-classworlds:pom:2.6.035,71 ms
org.apache.maven.doxia:doxia-sitetools:pom:1.11.135,39 ms
commons-digester:commons-digester:pom:1.835,20 ms
commons-logging:commons-logging:pom:1.235,75 ms
commons-codec:commons-codec:pom:1.1135,24 ms
org.apache.maven:maven-parent:pom:1635,28 ms
org.sonatype.oss:oss-parent:pom:734,14 ms
org.codehaus.plexus:plexus-containers:pom:1.5.534,23 ms
org.codehaus.plexus:plexus-components:pom:1.1.1434,12 ms
junit:junit:pom:3.8.134,09 ms
org.apache.maven.shared:maven-shared-components:pom:1934,01 ms
org.sonatype.forge:forge-parent:pom:1034,20 ms
org.apiguardian:apiguardian-api:pom:1.1.234,54 ms
org.junit.vintage:junit-vintage-engine:pom:5.9.234,23 ms
org.apache.maven.surefire:surefire-logger-api:pom:2.22.234,84 ms
org.apache.maven:maven-core:pom:3.034,67 ms
org.sonatype.aether:aether-parent:pom:1.734,08 ms
org.sonatype.aether:aether-util:pom:1.734,82 ms
org.sonatype.aether:aether-impl:pom:1.734,32 ms
org.slf4j:slf4j-parent:pom:1.7.534,23 ms
commons-io:commons-io:pom:2.11.034,39 ms
org.slf4j:jul-to-slf4j:pom:1.7.3634,66 ms
org.apache.maven.doxia:doxia-decoration-model:pom:1.11.134,92 ms
org.codehaus.plexus:plexus:pom:1.0.1134,91 ms
org.codehaus.plexus:plexus-velocity:pom:1.234,82 ms
org.codehaus.plexus:plexus:pom:4.034,51 ms
org.apache:apache:pom:434,13 ms
commons-beanutils:commons-beanutils:pom:1.7.034,92 ms
org.apache.maven:maven-settings-builder:pom:3.1.034,20 ms
org.apache.maven:maven-artifact:pom:3.1.034,42 ms
org.codehaus.plexus:plexus-classworlds:pom:2.5.234,87 ms
org.eclipse.aether:aether-api:pom:0.9.0.M234,42 ms
org.codehaus.plexus:plexus-components:pom:6.634,12 ms
org.codehaus.plexus:plexus:pom:834,82 ms
org.sonatype.spice:spice-parent:pom:1233,99 ms
org.apache.maven:maven-plugin-api:pom:3.0.333,53 ms
org.codehaus.plexus:plexus-interpolation:pom:1.1133,07 ms
org.apache.maven:maven-artifact:pom:2.2.133,82 ms
org.apache.maven:maven-settings-builder:pom:3.033,79 ms
org.apache.maven.shared:maven-shared-components:pom:3333,07 ms
org.apache.maven.shared:maven-shared-components:pom:3033,90 ms
org.apache.commons:commons-lang3:pom:3.733,77 ms
commons-lang:commons-lang:pom:2.433,27 ms
commons-logging:commons-logging:pom:1.0.333,41 ms
commons-collections:commons-collections:pom:2.133,89 ms
org.apache.maven:maven-aether-provider:pom:3.1.033,63 ms
org.sonatype.spice:spice-parent:pom:1732,83 ms
org.sonatype.sisu.inject:guice-bean:pom:1.4.232,52 ms
org.codehaus.plexus:plexus-components:pom:1.332,73 ms
org.apache.maven.doxia:doxia-sink-api:pom:1.032,06 ms
org.codehaus.plexus:plexus-interpolation:pom:1.2632,64 ms
+
+ +
+ + + + diff --git a/maven-modules/maven-build-optimization/README.md b/maven-modules/maven-build-optimization/README.md new file mode 100644 index 0000000000..c1764b67ac --- /dev/null +++ b/maven-modules/maven-build-optimization/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [How to Speed Up Maven Build](https://www.baeldung.com/maven-fast-build) diff --git a/maven-modules/maven-build-optimization/pom.xml b/maven-modules/maven-build-optimization/pom.xml new file mode 100644 index 0000000000..f0da31ceda --- /dev/null +++ b/maven-modules/maven-build-optimization/pom.xml @@ -0,0 +1,62 @@ + + + 4.0.0 + maven-build-optimization + 0.0.1-SNAPSHOT + maven-build-optimization + pom + + + com.baeldung + maven-modules + 0.0.1-SNAPSHOT + + + + + + org.apache.maven.plugins + maven-profiler-plugin + ${profiler.version} + + + org.apache.maven.plugins + maven-failsafe-plugin + ${failsafe.version} + + + + integration-test + verify + + + + + + + + + + skipITs + + + + org.apache.maven.plugins + maven-failsafe-plugin + + true + + + + + + + + + 3.1.2 + 1.7 + + + \ No newline at end of file diff --git a/maven-modules/pom.xml b/maven-modules/pom.xml index f7bba3a8ff..e139a4b921 100644 --- a/maven-modules/pom.xml +++ b/maven-modules/pom.xml @@ -20,6 +20,7 @@ dependency-exclusion host-maven-repo-example maven-archetype + maven-build-optimization maven-builder-plugin maven-classifier maven-copy-files diff --git a/pants/README.md b/pants/README.md new file mode 100644 index 0000000000..a37d2e3d31 --- /dev/null +++ b/pants/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [Introduction to the Pants Build Tool](https://www.baeldung.com/ops/pants-build-tool-guide) diff --git a/parent-boot-3/README.md b/parent-boot-3/README.md index 738d97bdfd..d0b11d44d8 100644 --- a/parent-boot-3/README.md +++ b/parent-boot-3/README.md @@ -1,3 +1,3 @@ -## Parent Boot 2 +## Parent Boot 3 This is a parent module for all projects using Spring Boot 3. diff --git a/persistence-modules/core-java-persistence-2/README.md b/persistence-modules/core-java-persistence-2/README.md index afabf9ecb3..f9da4947a7 100644 --- a/persistence-modules/core-java-persistence-2/README.md +++ b/persistence-modules/core-java-persistence-2/README.md @@ -9,3 +9,4 @@ - [Get the Number of Rows in a ResultSet](https://www.baeldung.com/java-resultset-number-of-rows) - [Converting a JDBC ResultSet to JSON in Java](https://www.baeldung.com/java-jdbc-convert-resultset-to-json) - [Guide to MicroStream](https://www.baeldung.com/microstream-intro) +- [Executing SQL Script File in Java](https://www.baeldung.com/java-run-sql-script) diff --git a/persistence-modules/core-java-persistence-2/pom.xml b/persistence-modules/core-java-persistence-2/pom.xml index 0bec7a808f..2013bdb6af 100644 --- a/persistence-modules/core-java-persistence-2/pom.xml +++ b/persistence-modules/core-java-persistence-2/pom.xml @@ -70,6 +70,16 @@ ${assertj.version} test + + org.mybatis + mybatis + ${mybatis.version} + + + org.springframework + spring-jdbc + ${spring-jdbc.version} + @@ -80,6 +90,8 @@ 20220320 07.00.00-MS-GA 2.1.214 + 5.3.29 + 3.5.7 \ No newline at end of file diff --git a/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/script/MyBatisScriptUtility.java b/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/script/MyBatisScriptUtility.java new file mode 100644 index 0000000000..8a9bbb6e20 --- /dev/null +++ b/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/script/MyBatisScriptUtility.java @@ -0,0 +1,13 @@ +package com.baeldung.script; + +import org.apache.ibatis.jdbc.ScriptRunner; +import java.sql.Connection; + +public class MyBatisScriptUtility { + public static void runScript(String path, Connection connection) throws Exception { + ScriptRunner scriptRunner = new ScriptRunner(connection); + scriptRunner.setSendFullScript(false); + scriptRunner.setStopOnError(true); + scriptRunner.runScript(new java.io.FileReader(path)); + } +} diff --git a/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/script/SpringScriptUtility.java b/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/script/SpringScriptUtility.java new file mode 100644 index 0000000000..cf70dfa890 --- /dev/null +++ b/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/script/SpringScriptUtility.java @@ -0,0 +1,29 @@ +package com.baeldung.script; + +import org.springframework.core.io.PathResource; +import org.springframework.core.io.support.EncodedResource; +import org.springframework.jdbc.datasource.init.ScriptUtils; + +import java.sql.Connection; + +public class SpringScriptUtility { + public static void runScript(String path, Connection connection) { + boolean continueOrError = false; + boolean ignoreFailedDrops = false; + String commentPrefix = "--"; + String separator = ";"; + String blockCommentStartDelimiter = "/*"; + String blockCommentEndDelimiter = "*/"; + + ScriptUtils.executeSqlScript( + connection, + new EncodedResource(new PathResource(path)), + continueOrError, + ignoreFailedDrops, + commentPrefix, + separator, + blockCommentStartDelimiter, + blockCommentEndDelimiter + ); + } +} diff --git a/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/script/SqlScriptBatchExecutor.java b/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/script/SqlScriptBatchExecutor.java new file mode 100644 index 0000000000..b9da968abe --- /dev/null +++ b/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/script/SqlScriptBatchExecutor.java @@ -0,0 +1,74 @@ +package com.baeldung.script; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class SqlScriptBatchExecutor { + private static final Log logger = LogFactory.getLog(SqlScriptBatchExecutor.class); + private static final Pattern COMMENT_PATTERN = Pattern.compile("--.*|/\\*(.|[\\r\\n])*?\\*/"); + public static void executeBatchedSQL(String scriptFilePath, Connection connection, int batchSize) throws Exception { + List sqlStatements = parseSQLScript(scriptFilePath); + executeSQLBatches(connection, sqlStatements, batchSize); + } + private static List parseSQLScript(String scriptFilePath) throws IOException { + List sqlStatements = new ArrayList<>(); + + try (BufferedReader reader = new BufferedReader(new FileReader(scriptFilePath))) { + StringBuilder currentStatement = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + Matcher commentMatcher = COMMENT_PATTERN.matcher(line); + line = commentMatcher.replaceAll(""); + line = line.trim(); + + if (line.isEmpty()) { + continue; + } + + currentStatement.append(line).append(" "); + + if (line.endsWith(";")) { + sqlStatements.add(currentStatement.toString()); + logger.info(currentStatement.toString()); + currentStatement.setLength(0); + } + } + } catch (IOException e) { + throw e; + } + return sqlStatements; + } + + private static void executeSQLBatches(Connection connection, List sqlStatements, int batchSize) + throws SQLException { + int count = 0; + Statement statement = connection.createStatement(); + + for (String sql : sqlStatements) { + statement.addBatch(sql); + count++; + + if (count % batchSize == 0) { + logger.info("Executing batch"); + statement.executeBatch(); + statement.clearBatch(); + } + } + // Execute any remaining statements + if (count % batchSize != 0) { + statement.executeBatch(); + } + connection.commit(); + } +} diff --git a/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/script/MyBatisScriptUtilityUnitTest.java b/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/script/MyBatisScriptUtilityUnitTest.java new file mode 100644 index 0000000000..98f82cfbd5 --- /dev/null +++ b/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/script/MyBatisScriptUtilityUnitTest.java @@ -0,0 +1,46 @@ +package com.baeldung.script; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.jupiter.api.AfterAll; + +import java.io.File; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.Statement; + +public class MyBatisScriptUtilityUnitTest { + private static final Log logger = LogFactory.getLog(MyBatisScriptUtilityUnitTest.class); + private static Connection connection = null; + private static final String JDBC_URL = "jdbc:h2:mem:testdb1"; + private static final String USERNAME = "user"; + private static final String PASSWORD = "password"; + + @Before + public void prepareConnection() throws Exception { + connection = DriverManager.getConnection(JDBC_URL, USERNAME, PASSWORD); + } + + @AfterAll + public static void closeConnection() throws Exception { + connection.close(); + } + + @Test + public void givenConnectionObject_whenSQLFile_thenExecute() throws Exception { + String path = new File(ClassLoader.getSystemClassLoader() + .getResource("employee.sql").getFile()).toPath().toString(); + MyBatisScriptUtility.runScript(path, connection); + + Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery("SELECT COUNT(1) FROM employees"); + if (resultSet.next()) { + int count = resultSet.getInt(1); + Assert.assertEquals("Incorrect number of records inserted", 20, count); + } + } +} diff --git a/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/script/SpringScriptUtilityUnitTest.java b/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/script/SpringScriptUtilityUnitTest.java new file mode 100644 index 0000000000..be6e39ca31 --- /dev/null +++ b/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/script/SpringScriptUtilityUnitTest.java @@ -0,0 +1,47 @@ +package com.baeldung.script; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.jupiter.api.AfterAll; + +import java.io.File; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.Statement; + +public class SpringScriptUtilityUnitTest { + private static final Log logger = LogFactory.getLog(SpringScriptUtilityUnitTest.class); + + private static Connection connection = null; + private static final String JDBC_URL = "jdbc:h2:mem:testdb2"; + private static final String USERNAME = "user"; + private static final String PASSWORD = "password"; + + @Before + public void prepareConnection() throws Exception { + connection = DriverManager.getConnection(JDBC_URL, USERNAME, PASSWORD); + } + + @AfterAll + public static void closeConnection() throws Exception { + connection.close(); + } + + @Test + public void givenConnectionObject_whenSQLFile_thenExecute() throws Exception { + String path = new File(ClassLoader.getSystemClassLoader() + .getResource("employee.sql").getFile()).toPath().toString(); + SpringScriptUtility.runScript(path, connection); + + Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery("SELECT COUNT(1) FROM employees"); + if (resultSet.next()) { + int count = resultSet.getInt(1); + Assert.assertEquals("Incorrect number of records inserted", 20, count); + } + } +} diff --git a/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/script/SqlScriptBatchExecutorUnitTest.java b/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/script/SqlScriptBatchExecutorUnitTest.java new file mode 100644 index 0000000000..3b1210fd00 --- /dev/null +++ b/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/script/SqlScriptBatchExecutorUnitTest.java @@ -0,0 +1,47 @@ +package com.baeldung.script; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.jupiter.api.AfterAll; + +import java.io.File; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.Statement; + +public class SqlScriptBatchExecutorUnitTest { + private static final Log logger = LogFactory.getLog(SqlScriptBatchExecutorUnitTest.class); + private static Connection connection = null; + private static final String JDBC_URL = "jdbc:h2:mem:testdb3"; + private static final String USERNAME = "user"; + private static final String PASSWORD = "password"; + + @Before + public void prepareConnection() throws Exception { + connection = DriverManager.getConnection(JDBC_URL, USERNAME, PASSWORD); + } + + @AfterAll + public static void closeConnection() throws Exception { + connection.close(); + } + + @Test + public void givenConnectionObject_whenSQLFile_thenExecute() throws Exception { + String path = new File(ClassLoader.getSystemClassLoader() + .getResource("employee.sql").getFile()).toPath().toString(); + SqlScriptBatchExecutor.executeBatchedSQL(path, connection, 10); + Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery("SELECT COUNT(1) FROM employees"); + + if (resultSet.next()) { + int count = resultSet.getInt(1); + Assert.assertEquals("Incorrect number of records inserted", 20, count); + } + } + +} diff --git a/persistence-modules/core-java-persistence-2/src/test/resources/employee.sql b/persistence-modules/core-java-persistence-2/src/test/resources/employee.sql new file mode 100644 index 0000000000..c532458163 --- /dev/null +++ b/persistence-modules/core-java-persistence-2/src/test/resources/employee.sql @@ -0,0 +1,75 @@ +/** +Script Name : Create employees script +Author: Parthiv Pradhan + +**/ + +-- Create the employees table if it doesn't exist +CREATE TABLE employees ( + id INT PRIMARY KEY, + first_name VARCHAR(50), + last_name VARCHAR(50), + department VARCHAR(50), + salary DECIMAL(10, 2) +); + +-- Insert employee records +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (1, 'John', 'Doe', 'HR', 50000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (2, 'Jane', 'Smith', 'IT', 60000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (3, 'Michael', 'Johnson', 'Finance', 55000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (4, 'Emily', 'Williams', 'Marketing', 52000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (5, 'David', 'Brown', 'IT', 65000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (6, 'Sarah', 'Miller', 'Finance', 58000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (7, 'Robert', 'Jones', 'HR', 53000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (8, 'Jessica', 'Davis', 'Marketing', 51000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (9, 'William', 'Wilson', 'IT', 59000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (10, 'Jennifer', 'Taylor', 'Finance', 57000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (11, 'Daniel', 'Anderson', 'Marketing', 54000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (12, 'Linda', 'Martinez', 'HR', 52000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (13, 'Christopher', 'Lopez', 'IT', 62000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (14, 'Karen', 'Hernandez', 'Finance', 56000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (15, 'Mark', 'Garcia', 'Marketing', 53000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (16, 'Patricia', 'Lee', 'HR', 51000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (17, 'Anthony', 'Clark', 'IT', 60000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (18, 'Maria', 'Lewis', 'Finance', 59000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (19, 'Paul', 'Walker', 'Marketing', 55000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (20, 'Ruth', 'Young', 'HR', 54000.00); diff --git a/persistence-modules/hibernate-annotations/src/main/java/com/baeldung/hibernate/joincolumn/Email.java b/persistence-modules/hibernate-annotations/src/main/java/com/baeldung/hibernate/joincolumn/Email.java index 096faf7984..c25820300e 100644 --- a/persistence-modules/hibernate-annotations/src/main/java/com/baeldung/hibernate/joincolumn/Email.java +++ b/persistence-modules/hibernate-annotations/src/main/java/com/baeldung/hibernate/joincolumn/Email.java @@ -18,7 +18,7 @@ public class Email { private String address; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "employee_id") + @JoinColumn(name = "employee_id", referencedColumnName = "id") private OfficialEmployee employee; public Long getId() { diff --git a/persistence-modules/hibernate-enterprise/pom.xml b/persistence-modules/hibernate-enterprise/pom.xml index eaa7b0e765..954f8f40d3 100644 --- a/persistence-modules/hibernate-enterprise/pom.xml +++ b/persistence-modules/hibernate-enterprise/pom.xml @@ -82,7 +82,6 @@ 8.0.32 2.6.0 0.9 - 1.14.2
\ No newline at end of file diff --git a/persistence-modules/spring-boot-persistence-h2/src/main/resources/application-lazy-load-no-trans-off.properties b/persistence-modules/spring-boot-persistence-h2/src/main/resources/application-lazy-load-no-trans-off.properties index b030527cca..df322cd15e 100644 --- a/persistence-modules/spring-boot-persistence-h2/src/main/resources/application-lazy-load-no-trans-off.properties +++ b/persistence-modules/spring-boot-persistence-h2/src/main/resources/application-lazy-load-no-trans-off.properties @@ -5,7 +5,7 @@ spring.datasource.password= spring.jpa.hibernate.ddl-auto=create-drop spring.h2.console.enabled=true spring.h2.console.path=/h2-console -spring.sql.init.data-locations=data-trans.sql +spring.sql.init.data-locations=classpath:data-trans.sql logging.level.org.hibernate.SQL=INFO logging.level.org.hibernate.type=INFO diff --git a/persistence-modules/spring-boot-persistence-h2/src/main/resources/application-lazy-load-no-trans-on.properties b/persistence-modules/spring-boot-persistence-h2/src/main/resources/application-lazy-load-no-trans-on.properties index 972a7bb0f3..e5c488f3be 100644 --- a/persistence-modules/spring-boot-persistence-h2/src/main/resources/application-lazy-load-no-trans-on.properties +++ b/persistence-modules/spring-boot-persistence-h2/src/main/resources/application-lazy-load-no-trans-on.properties @@ -5,7 +5,7 @@ spring.datasource.password= spring.jpa.hibernate.ddl-auto=create-drop spring.h2.console.enabled=true spring.h2.console.path=/h2-console -spring.sql.init.data-locations=data-trans.sql +spring.sql.init.data-locations=classpath:data-trans.sql logging.level.org.hibernate.SQL=INFO logging.level.org.hibernate.type=INFO diff --git a/persistence-modules/spring-data-shardingsphere/src/test/java/com/baeldung/shardingsphere/OrderServiceIntegrationTest.java b/persistence-modules/spring-data-shardingsphere/src/test/java/com/baeldung/shardingsphere/OrderServiceLiveTest.java similarity index 98% rename from persistence-modules/spring-data-shardingsphere/src/test/java/com/baeldung/shardingsphere/OrderServiceIntegrationTest.java rename to persistence-modules/spring-data-shardingsphere/src/test/java/com/baeldung/shardingsphere/OrderServiceLiveTest.java index 938d250058..139081182f 100644 --- a/persistence-modules/spring-data-shardingsphere/src/test/java/com/baeldung/shardingsphere/OrderServiceIntegrationTest.java +++ b/persistence-modules/spring-data-shardingsphere/src/test/java/com/baeldung/shardingsphere/OrderServiceLiveTest.java @@ -21,7 +21,7 @@ import java.util.List; @Testcontainers @SpringBootTest -class OrderServiceIntegrationTest { +class OrderServiceLiveTest { @Container static MySQLContainer mySQLContainer1 = new MySQLContainer<>("mysql:8.0.23") diff --git a/pom.xml b/pom.xml index 17daf26278..12fbc3c4f0 100644 --- a/pom.xml +++ b/pom.xml @@ -346,7 +346,7 @@ core-java-modules/core-java-serialization core-java-modules/core-java-lang core-java-modules/core-java-lang-math-3 - core-java-modules/core-java-collections-conversions-2 + core-java-modules/core-java-streams-2 @@ -427,7 +427,6 @@ spring-security-modules/spring-security-ldap - spring-soap spring-swagger-codegen video-tutorials
@@ -524,7 +523,7 @@ core-java-modules/core-java-serialization core-java-modules/core-java-lang core-java-modules/core-java-lang-math-3 - core-java-modules/core-java-collections-conversions-2 + core-java-modules/core-java-streams-2 @@ -594,7 +593,6 @@ spring-security-modules/spring-security-ldap - spring-soap spring-swagger-codegen video-tutorials @@ -703,7 +701,6 @@ osgi spring-katharsis logging-modules - spring-boot-documentation spring-boot-modules apache-httpclient apache-httpclient4 @@ -758,6 +755,7 @@ algorithms-modules apache-libraries + apache-libraries-2 apache-poi apache-velocity di-modules @@ -789,7 +787,7 @@ kubernetes-modules libraries-concurrency jhipster-6 - + libraries-testing maven-modules optaplanner persistence-modules @@ -907,7 +905,8 @@ spring-kafka - + spring-native + spring-soap spring-security-modules spring-protobuf spring-quartz @@ -976,7 +975,6 @@ osgi spring-katharsis logging-modules - spring-boot-documentation spring-boot-modules apache-httpclient apache-httpclient4 @@ -1025,6 +1023,7 @@ algorithms-modules apache-libraries + apache-libraries-2 apache-poi apache-velocity di-modules @@ -1060,7 +1059,7 @@ kubernetes-modules libraries-concurrency jhipster-6 - + libraries-testing maven-modules optaplanner persistence-modules @@ -1179,7 +1178,8 @@ spring-kafka - + spring-native + spring-soap spring-security-modules spring-protobuf spring-quartz @@ -1261,7 +1261,7 @@ 2.2 1.3 4.4.0 - 1.12.13 + 1.14.6 @@ -1278,9 +1278,9 @@ 1.36 2.21.0 4.4 - 2.11.0 + 2.13.0 2.6 - 3.12.0 + 3.13.0 1.5.0 3.3.2 4.0.1 @@ -1288,7 +1288,7 @@ 2.3.3 1.2 2.15.2 - 1.4 + 1.5 1.9.2 5.9.2 1.3.2 @@ -1300,7 +1300,7 @@ 3.19.0 1.18.28 2.1.214 - 31.1-jre + 32.1.2-jre 3.2.2 diff --git a/spring-boot-documentation/pom.xml b/spring-boot-documentation/pom.xml deleted file mode 100644 index d718f33a99..0000000000 --- a/spring-boot-documentation/pom.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - 4.0.0 - com.baeldung.spring-boot-documentation - spring-boot-documentation - 1.0.0-SNAPSHOT - spring-boot-documentation - pom - - - com.baeldung - parent-boot-3 - 0.0.1-SNAPSHOT - ../parent-boot-3 - - - - springwolf - - - - - - org.junit - junit-bom - ${junit-jupiter.version} - pom - import - - - org.springframework.boot - spring-boot-dependencies - ${spring-boot.version} - pom - import - - - - - - 3.3.2 - - - diff --git a/spring-boot-documentation/springwolf/pom.xml b/spring-boot-documentation/springwolf/pom.xml deleted file mode 100644 index 4bd9f24065..0000000000 --- a/spring-boot-documentation/springwolf/pom.xml +++ /dev/null @@ -1,82 +0,0 @@ - - - 4.0.0 - springwolf - 0.0.1-SNAPSHOT - springwolf - Documentation Spring Event Driven API Using AsyncAPI and Springwolf - - - com.baeldung.spring-boot-documentation - spring-boot-documentation - 1.0.0-SNAPSHOT - - - - - org.springframework.boot - spring-boot-starter - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.kafka - spring-kafka - - - io.swagger.core.v3 - swagger-core-jakarta - ${swagger-core.version} - - - io.github.springwolf - springwolf-kafka - ${springwolf-kafka.version} - - - io.github.springwolf - springwolf-ui - ${springwolf-ui.version} - - - org.projectlombok - lombok - ${lombok.version} - - - org.springframework.kafka - spring-kafka-test - test - - - org.testcontainers - junit-jupiter - ${testcontainers-kafka.version} - test - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - com.baeldung.boot.documentation.springwolf.SpringwolfApplication - - - - - - - 2.2.11 - 0.12.1 - 0.8.0 - 1.18.3 - - - diff --git a/spring-boot-modules/pom.xml b/spring-boot-modules/pom.xml index de14e26027..251dba0316 100644 --- a/spring-boot-modules/pom.xml +++ b/spring-boot-modules/pom.xml @@ -44,7 +44,7 @@ spring-boot-graphql spring-boot-groovy - + spring-boot-jasypt spring-boot-jsp spring-boot-keycloak spring-boot-keycloak-2 @@ -91,12 +91,14 @@ spring-boot-3-native spring-boot-3-observation spring-boot-3-test-pitfalls + spring-boot-3-testcontainers spring-boot-resilience4j spring-boot-properties spring-boot-properties-2 spring-boot-properties-3 spring-boot-properties-4 spring-boot-properties-migrator-demo + spring-boot-documentation diff --git a/spring-boot-modules/spring-boot-3-testcontainers/README.md b/spring-boot-modules/spring-boot-3-testcontainers/README.md new file mode 100644 index 0000000000..5616cce48b --- /dev/null +++ b/spring-boot-modules/spring-boot-3-testcontainers/README.md @@ -0,0 +1 @@ +## Relevant Articles diff --git a/spring-boot-modules/spring-boot-3-testcontainers/pom.xml b/spring-boot-modules/spring-boot-3-testcontainers/pom.xml new file mode 100644 index 0000000000..173fb8795c --- /dev/null +++ b/spring-boot-modules/spring-boot-3-testcontainers/pom.xml @@ -0,0 +1,102 @@ + + + 4.0.0 + spring-boot-3-testcontainers + 0.0.1-SNAPSHOT + spring-boot-3-testcontainers + Testcontainer Improvements in Spring Boot 3 + + + com.baeldung + parent-boot-3 + 0.0.1-SNAPSHOT + ../../parent-boot-3 + + + + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-devtools + runtime + true + + + org.springframework.boot + spring-boot-starter-test + + + org.springframework.boot + spring-boot-starter-data-mongodb + + + + org.springframework.boot + spring-boot-testcontainers + + + + org.testcontainers + mongodb + ${testcontainers.version} + test + + + org.testcontainers + testcontainers + ${testcontainers.version} + test + + + org.testcontainers + junit-jupiter + ${testcontainers.version} + test + + + + io.rest-assured + rest-assured + ${rest-assured.version} + test + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + 3.0.0-M7 + 1.18.3 + 5.3.1 + + + \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-testcontainers/src/main/java/com/baeldung/testcontainers/Application.java b/spring-boot-modules/spring-boot-3-testcontainers/src/main/java/com/baeldung/testcontainers/Application.java new file mode 100644 index 0000000000..9a00bfebf2 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-testcontainers/src/main/java/com/baeldung/testcontainers/Application.java @@ -0,0 +1,14 @@ +package com.baeldung.testcontainers; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.data.mongodb.repository.config.EnableMongoRepositories; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/spring-boot-modules/spring-boot-3-testcontainers/src/main/java/com/baeldung/testcontainers/support/MiddleEarthCharacter.java b/spring-boot-modules/spring-boot-3-testcontainers/src/main/java/com/baeldung/testcontainers/support/MiddleEarthCharacter.java new file mode 100644 index 0000000000..4780a2f66a --- /dev/null +++ b/spring-boot-modules/spring-boot-3-testcontainers/src/main/java/com/baeldung/testcontainers/support/MiddleEarthCharacter.java @@ -0,0 +1,13 @@ +package com.baeldung.testcontainers.support; + +import java.util.UUID; + +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; + +@Document("characters") +public record MiddleEarthCharacter(@Id String id, String name, String race) { + public MiddleEarthCharacter(String name, String race) { + this(UUID.randomUUID().toString(), name, race); + } +} diff --git a/spring-boot-modules/spring-boot-3-testcontainers/src/main/java/com/baeldung/testcontainers/support/MiddleEarthCharactersController.java b/spring-boot-modules/spring-boot-3-testcontainers/src/main/java/com/baeldung/testcontainers/support/MiddleEarthCharactersController.java new file mode 100644 index 0000000000..3b7bfddbef --- /dev/null +++ b/spring-boot-modules/spring-boot-3-testcontainers/src/main/java/com/baeldung/testcontainers/support/MiddleEarthCharactersController.java @@ -0,0 +1,30 @@ +package com.baeldung.testcontainers.support; + +import java.util.List; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("characters") +public class MiddleEarthCharactersController { + private final MiddleEarthCharactersRepository repository; + + public MiddleEarthCharactersController(MiddleEarthCharactersRepository repository) { + this.repository = repository; + } + + @GetMapping + public List findByRace(@RequestParam String race) { + return repository.findAllByRace(race); + } + + @PostMapping + public MiddleEarthCharacter save(@RequestBody MiddleEarthCharacter character) { + return repository.save(character); + } +} diff --git a/spring-boot-modules/spring-boot-3-testcontainers/src/main/java/com/baeldung/testcontainers/support/MiddleEarthCharactersRepository.java b/spring-boot-modules/spring-boot-3-testcontainers/src/main/java/com/baeldung/testcontainers/support/MiddleEarthCharactersRepository.java new file mode 100644 index 0000000000..a668650670 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-testcontainers/src/main/java/com/baeldung/testcontainers/support/MiddleEarthCharactersRepository.java @@ -0,0 +1,11 @@ +package com.baeldung.testcontainers.support; + +import java.util.List; + +import org.springframework.data.mongodb.repository.MongoRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface MiddleEarthCharactersRepository extends MongoRepository { + List findAllByRace(String race); +} diff --git a/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/DynamicPropertiesIntegrationTest.java b/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/DynamicPropertiesIntegrationTest.java new file mode 100644 index 0000000000..8689b10110 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/DynamicPropertiesIntegrationTest.java @@ -0,0 +1,59 @@ +package com.baeldung.testcontainers; + +import static io.restassured.RestAssured.when; +import static org.hamcrest.Matchers.hasItems; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.DEFINED_PORT; +import static org.springframework.test.annotation.DirtiesContext.ClassMode.AFTER_CLASS; + +import java.util.List; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; +import org.testcontainers.containers.MongoDBContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.DockerImageName; + +import com.baeldung.testcontainers.support.MiddleEarthCharacter; +import com.baeldung.testcontainers.support.MiddleEarthCharactersRepository; + +@Testcontainers +@SpringBootTest(webEnvironment = DEFINED_PORT) +@DirtiesContext(classMode = AFTER_CLASS) +class DynamicPropertiesIntegrationTest { + @Container + static MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:4.0.10")); + + @DynamicPropertySource + static void setProperties(DynamicPropertyRegistry registry) { + registry.add("spring.data.mongodb.uri", mongoDBContainer::getReplicaSetUrl); + } + + @Autowired + private MiddleEarthCharactersRepository repository; + + @BeforeEach + void beforeEach() { + repository.deleteAll(); + } + + @Test + void whenRequestingHobbits_thenReturnFrodoAndSam() { + repository.saveAll(List.of( + new MiddleEarthCharacter("Frodo", "hobbit"), + new MiddleEarthCharacter("Samwise", "hobbit"), + new MiddleEarthCharacter("Aragon", "human"), + new MiddleEarthCharacter("Gandalf", "wizzard") + )); + + when().get("/characters?race=hobbit") + .then().statusCode(200) + .and().body("name", hasItems("Frodo", "Samwise")); + } + +} diff --git a/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/LocalDevApplication.java b/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/LocalDevApplication.java new file mode 100644 index 0000000000..a94c0f772a --- /dev/null +++ b/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/LocalDevApplication.java @@ -0,0 +1,29 @@ +package com.baeldung.testcontainers; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.devtools.restart.RestartScope; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.boot.testcontainers.service.connection.ServiceConnection; +import org.springframework.context.annotation.Bean; +import org.testcontainers.containers.MongoDBContainer; +import org.testcontainers.utility.DockerImageName; + +class LocalDevApplication { + + public static void main(String[] args) { + SpringApplication.from(Application::main) + .with(LocalDevTestcontainersConfig.class) + .run(args); + } + + @TestConfiguration(proxyBeanMethods = false) + static class LocalDevTestcontainersConfig { + @Bean + @RestartScope + @ServiceConnection + public MongoDBContainer mongoDBContainer() { + return new MongoDBContainer(DockerImageName.parse("mongo:4.0.10")); + } + } + +} diff --git a/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/ServiceConnectionIntegrationTest.java b/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/ServiceConnectionIntegrationTest.java new file mode 100644 index 0000000000..500d6d2e61 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/ServiceConnectionIntegrationTest.java @@ -0,0 +1,55 @@ +package com.baeldung.testcontainers; + +import static io.restassured.RestAssured.when; +import static org.hamcrest.Matchers.hasItems; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.DEFINED_PORT; +import static org.springframework.test.annotation.DirtiesContext.ClassMode.AFTER_CLASS; + +import java.util.List; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.testcontainers.service.connection.ServiceConnection; +import org.springframework.test.annotation.DirtiesContext; +import org.testcontainers.containers.MongoDBContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.DockerImageName; + +import com.baeldung.testcontainers.support.MiddleEarthCharacter; +import com.baeldung.testcontainers.support.MiddleEarthCharactersRepository; + +@Testcontainers +@SpringBootTest(webEnvironment = DEFINED_PORT) +@DirtiesContext(classMode = AFTER_CLASS) +class ServiceConnectionIntegrationTest { + + @Container + @ServiceConnection + static MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:4.0.10")); + + @Autowired + private MiddleEarthCharactersRepository repository; + + @BeforeEach + void beforeEach() { + repository.deleteAll(); + } + + @Test + void whenRequestingHobbits_thenReturnFrodoAndSam() { + repository.saveAll(List.of( + new MiddleEarthCharacter("Frodo", "hobbit"), + new MiddleEarthCharacter("Samwise", "hobbit"), + new MiddleEarthCharacter("Aragon", "human"), + new MiddleEarthCharacter("Gandalf", "wizzard") + )); + + when().get("/characters?race=hobbit") + .then().statusCode(200) + .and().body("name", hasItems("Frodo", "Samwise")); + } + +} diff --git a/spring-boot-documentation/README.md b/spring-boot-modules/spring-boot-documentation/README.md similarity index 100% rename from spring-boot-documentation/README.md rename to spring-boot-modules/spring-boot-documentation/README.md diff --git a/spring-boot-documentation/springwolf/docker-compose.yml b/spring-boot-modules/spring-boot-documentation/docker-compose.yml similarity index 100% rename from spring-boot-documentation/springwolf/docker-compose.yml rename to spring-boot-modules/spring-boot-documentation/docker-compose.yml diff --git a/spring-boot-modules/spring-boot-documentation/pom.xml b/spring-boot-modules/spring-boot-documentation/pom.xml new file mode 100644 index 0000000000..587ad8473b --- /dev/null +++ b/spring-boot-modules/spring-boot-documentation/pom.xml @@ -0,0 +1,102 @@ + + + 4.0.0 + com.baeldung.spring-boot-documentation + spring-boot-documentation + 1.0.0-SNAPSHOT + spring-boot-documentation + Documentation Spring Event Driven API Using AsyncAPI and Springwolf + pom + + + com.baeldung + parent-boot-3 + 0.0.1-SNAPSHOT + ../../parent-boot-3/pom.xml + + + + + + org.junit + junit-bom + ${junit-jupiter.version} + pom + import + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} + pom + import + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.kafka + spring-kafka + + + io.swagger.core.v3 + swagger-core-jakarta + ${swagger-core.version} + + + io.github.springwolf + springwolf-kafka + ${springwolf-kafka.version} + + + io.github.springwolf + springwolf-ui + ${springwolf-ui.version} + + + org.projectlombok + lombok + ${lombok.version} + + + org.springframework.kafka + spring-kafka-test + test + + + org.testcontainers + junit-jupiter + ${testcontainers-kafka.version} + test + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + com.baeldung.boot.documentation.springwolf.SpringwolfApplication + + + + + + + 3.3.2 + 2.2.11 + 0.12.1 + 0.8.0 + 1.18.3 + + + diff --git a/spring-boot-documentation/springwolf/src/main/java/com/baeldung/boot/documentation/springwolf/SpringwolfApplication.java b/spring-boot-modules/spring-boot-documentation/src/main/java/com/baeldung/boot/documentation/springwolf/SpringwolfApplication.java similarity index 100% rename from spring-boot-documentation/springwolf/src/main/java/com/baeldung/boot/documentation/springwolf/SpringwolfApplication.java rename to spring-boot-modules/spring-boot-documentation/src/main/java/com/baeldung/boot/documentation/springwolf/SpringwolfApplication.java diff --git a/spring-boot-documentation/springwolf/src/main/java/com/baeldung/boot/documentation/springwolf/adapter/incoming/IncomingConsumer.java b/spring-boot-modules/spring-boot-documentation/src/main/java/com/baeldung/boot/documentation/springwolf/adapter/incoming/IncomingConsumer.java similarity index 100% rename from spring-boot-documentation/springwolf/src/main/java/com/baeldung/boot/documentation/springwolf/adapter/incoming/IncomingConsumer.java rename to spring-boot-modules/spring-boot-documentation/src/main/java/com/baeldung/boot/documentation/springwolf/adapter/incoming/IncomingConsumer.java diff --git a/spring-boot-documentation/springwolf/src/main/java/com/baeldung/boot/documentation/springwolf/adapter/outgoing/OutgoingProducer.java b/spring-boot-modules/spring-boot-documentation/src/main/java/com/baeldung/boot/documentation/springwolf/adapter/outgoing/OutgoingProducer.java similarity index 100% rename from spring-boot-documentation/springwolf/src/main/java/com/baeldung/boot/documentation/springwolf/adapter/outgoing/OutgoingProducer.java rename to spring-boot-modules/spring-boot-documentation/src/main/java/com/baeldung/boot/documentation/springwolf/adapter/outgoing/OutgoingProducer.java diff --git a/spring-boot-documentation/springwolf/src/main/java/com/baeldung/boot/documentation/springwolf/dto/IncomingPayloadDto.java b/spring-boot-modules/spring-boot-documentation/src/main/java/com/baeldung/boot/documentation/springwolf/dto/IncomingPayloadDto.java similarity index 100% rename from spring-boot-documentation/springwolf/src/main/java/com/baeldung/boot/documentation/springwolf/dto/IncomingPayloadDto.java rename to spring-boot-modules/spring-boot-documentation/src/main/java/com/baeldung/boot/documentation/springwolf/dto/IncomingPayloadDto.java diff --git a/spring-boot-documentation/springwolf/src/main/java/com/baeldung/boot/documentation/springwolf/dto/OutgoingPayloadDto.java b/spring-boot-modules/spring-boot-documentation/src/main/java/com/baeldung/boot/documentation/springwolf/dto/OutgoingPayloadDto.java similarity index 100% rename from spring-boot-documentation/springwolf/src/main/java/com/baeldung/boot/documentation/springwolf/dto/OutgoingPayloadDto.java rename to spring-boot-modules/spring-boot-documentation/src/main/java/com/baeldung/boot/documentation/springwolf/dto/OutgoingPayloadDto.java diff --git a/spring-boot-documentation/springwolf/src/main/java/com/baeldung/boot/documentation/springwolf/service/ProcessorService.java b/spring-boot-modules/spring-boot-documentation/src/main/java/com/baeldung/boot/documentation/springwolf/service/ProcessorService.java similarity index 100% rename from spring-boot-documentation/springwolf/src/main/java/com/baeldung/boot/documentation/springwolf/service/ProcessorService.java rename to spring-boot-modules/spring-boot-documentation/src/main/java/com/baeldung/boot/documentation/springwolf/service/ProcessorService.java diff --git a/spring-boot-documentation/springwolf/src/main/resources/application.properties b/spring-boot-modules/spring-boot-documentation/src/main/resources/application.properties similarity index 100% rename from spring-boot-documentation/springwolf/src/main/resources/application.properties rename to spring-boot-modules/spring-boot-documentation/src/main/resources/application.properties diff --git a/spring-boot-documentation/springwolf/src/test/java/com/baeldung/boot/documentation/springwolf/ApiIntegrationTest.java b/spring-boot-modules/spring-boot-documentation/src/test/java/com/baeldung/boot/documentation/springwolf/ApiIntegrationTest.java similarity index 100% rename from spring-boot-documentation/springwolf/src/test/java/com/baeldung/boot/documentation/springwolf/ApiIntegrationTest.java rename to spring-boot-modules/spring-boot-documentation/src/test/java/com/baeldung/boot/documentation/springwolf/ApiIntegrationTest.java diff --git a/spring-boot-documentation/springwolf/src/test/resources/asyncapi.json b/spring-boot-modules/spring-boot-documentation/src/test/resources/asyncapi.json similarity index 100% rename from spring-boot-documentation/springwolf/src/test/resources/asyncapi.json rename to spring-boot-modules/spring-boot-documentation/src/test/resources/asyncapi.json diff --git a/spring-boot-modules/spring-boot-jasypt/pom.xml b/spring-boot-modules/spring-boot-jasypt/pom.xml index 8595b9c639..b83162fb04 100644 --- a/spring-boot-modules/spring-boot-jasypt/pom.xml +++ b/spring-boot-modules/spring-boot-jasypt/pom.xml @@ -50,4 +50,11 @@ 2.0.0 + + + spring-milestone + Spring Milestone + https://repo.spring.io/milestone + + \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/SecurityConfig.java b/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/SecurityConfig.java index 1ad22d9397..3423f8eb2b 100644 --- a/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/SecurityConfig.java +++ b/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/SecurityConfig.java @@ -2,6 +2,7 @@ package com.baeldung.keycloak; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.Order; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; @@ -27,18 +28,30 @@ class SecurityConfig { return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl()); } + @Order(1) @Bean - public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + public SecurityFilterChain clientFilterChain(HttpSecurity http) throws Exception { http.authorizeRequests() - .antMatchers("/customers*") - .hasRole("USER") + .antMatchers("/") + .permitAll() .anyRequest() - .permitAll(); + .authenticated(); http.oauth2Login() .and() .logout() .addLogoutHandler(keycloakLogoutHandler) .logoutSuccessUrl("/"); + return http.build(); + } + + @Order(2) + @Bean + public SecurityFilterChain resourceServerFilterChain(HttpSecurity http) throws Exception { + http.authorizeRequests() + .antMatchers("/customers*") + .hasRole("USER") + .anyRequest() + .authenticated(); http.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt); return http.build(); } diff --git a/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/configurationproperties/ImmutableCredentials.java b/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/configurationproperties/ImmutableCredentials.java index 72c45afbb2..d7e948ca9a 100644 --- a/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/configurationproperties/ImmutableCredentials.java +++ b/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/configurationproperties/ImmutableCredentials.java @@ -1,6 +1,7 @@ package com.baeldung.configurationproperties; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.bind.ConstructorBinding; @ConfigurationProperties(prefix = "mail.credentials") public class ImmutableCredentials { @@ -9,12 +10,19 @@ public class ImmutableCredentials { private final String username; private final String password; + @ConstructorBinding public ImmutableCredentials(String authMethod, String username, String password) { this.authMethod = authMethod; this.username = username; this.password = password; } + public ImmutableCredentials(String username, String password) { + this.username = username; + this.password = password; + this.authMethod = "Default"; + } + public String getAuthMethod() { return authMethod; } diff --git a/spring-boot-modules/spring-boot-telegram/.gitignore b/spring-boot-modules/spring-boot-telegram/.gitignore new file mode 100644 index 0000000000..a8e6c9dbce --- /dev/null +++ b/spring-boot-modules/spring-boot-telegram/.gitignore @@ -0,0 +1,35 @@ +HELP.md +target/ +.mvn +mvnw +mvnw.cmd +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/spring-boot-modules/spring-boot-telegram/README.md b/spring-boot-modules/spring-boot-telegram/README.md new file mode 100644 index 0000000000..4cd6560bc0 --- /dev/null +++ b/spring-boot-modules/spring-boot-telegram/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [Creating a Telegram Bot with Spring Boot](https://www.baeldung.com/spring-boot-telegram-bot) diff --git a/spring-boot-modules/spring-boot-telegram/pom.xml b/spring-boot-modules/spring-boot-telegram/pom.xml new file mode 100644 index 0000000000..b960137449 --- /dev/null +++ b/spring-boot-modules/spring-boot-telegram/pom.xml @@ -0,0 +1,45 @@ + + + 4.0.0 + com.baelding + spring-boot-telegram + 0.0.1-SNAPSHOT + spring-boot-telegram + Demo project for Spring Boot with Spring Data Redis + + + com.baeldung + parent-boot-3 + 0.0.1-SNAPSHOT + ../../parent-boot-3 + + + + + org.telegram + telegrambots-spring-boot-starter + 6.7.0 + + + org.telegram + telegrambots-abilities + 6.7.0 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + 17 + + + diff --git a/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/Constants.java b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/Constants.java new file mode 100644 index 0000000000..5c529bf15c --- /dev/null +++ b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/Constants.java @@ -0,0 +1,9 @@ +package com.baeldung.telegram; + +public class Constants { + + public static final String START_DESCRIPTION = "Starts the bot"; + + public static final String CHAT_STATES = "chatStates"; + public static final String START_TEXT = "Welcome to Baeldung Pizza Bot.\nPlease enter your name"; +} diff --git a/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/KeyboardFactory.java b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/KeyboardFactory.java new file mode 100644 index 0000000000..367c5a4c7c --- /dev/null +++ b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/KeyboardFactory.java @@ -0,0 +1,30 @@ +package com.baeldung.telegram; + +import org.telegram.telegrambots.meta.api.objects.replykeyboard.ReplyKeyboard; +import org.telegram.telegrambots.meta.api.objects.replykeyboard.ReplyKeyboardMarkup; +import org.telegram.telegrambots.meta.api.objects.replykeyboard.buttons.KeyboardRow; + +import java.util.List; + +public class KeyboardFactory { +public static ReplyKeyboard getPizzaToppingsKeyboard() { + KeyboardRow row = new KeyboardRow(); + row.add("Margherita"); + row.add("Pepperoni"); + return new ReplyKeyboardMarkup(List.of(row)); +} + + public static ReplyKeyboard getPizzaOrDrinkKeyboard(){ + KeyboardRow row = new KeyboardRow(); + row.add("Pizza"); + row.add("Drink"); + return new ReplyKeyboardMarkup(List.of(row)); + } + + public static ReplyKeyboard getYesOrNo() { + KeyboardRow row = new KeyboardRow(); + row.add("Yes"); + row.add("No"); + return new ReplyKeyboardMarkup(List.of(row)); + } +} diff --git a/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/PizzaBot.java b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/PizzaBot.java new file mode 100644 index 0000000000..802cb586d7 --- /dev/null +++ b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/PizzaBot.java @@ -0,0 +1,48 @@ +package com.baeldung.telegram; + +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; +import org.telegram.abilitybots.api.bot.AbilityBot; +import org.telegram.abilitybots.api.bot.BaseAbilityBot; +import org.telegram.abilitybots.api.objects.Ability; +import org.telegram.abilitybots.api.objects.Flag; +import org.telegram.abilitybots.api.objects.Reply; +import org.telegram.telegrambots.meta.api.objects.Update; + +import java.util.function.BiConsumer; + +import static org.telegram.abilitybots.api.objects.Locality.USER; +import static org.telegram.abilitybots.api.objects.Privacy.PUBLIC; +import static org.telegram.abilitybots.api.util.AbilityUtils.getChatId; + +@Component +public class PizzaBot extends AbilityBot { + + private final ResponseHandler responseHandler; + + public PizzaBot(Environment environment) { + super(environment.getProperty("BOT_TOKEN"), "baeldungbot"); + responseHandler = new ResponseHandler(silent, db); + } + +public Ability startBot() { + return Ability + .builder() + .name("start") + .info(Constants.START_DESCRIPTION) + .locality(USER) + .privacy(PUBLIC) + .action(ctx -> responseHandler.replyToStart(ctx.chatId())) + .build(); +} + +public Reply replyToButtons() { + BiConsumer action = (abilityBot, upd) -> responseHandler.replyToButtons(getChatId(upd), upd.getMessage()); + return Reply.of(action, Flag.TEXT,upd -> responseHandler.userIsActive(getChatId(upd))); +} + +@Override +public long creatorId() { + return 1L; +} +} diff --git a/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/ResponseHandler.java b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/ResponseHandler.java new file mode 100644 index 0000000000..862edc962c --- /dev/null +++ b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/ResponseHandler.java @@ -0,0 +1,132 @@ +package com.baeldung.telegram; + +import org.telegram.abilitybots.api.db.DBContext; +import org.telegram.abilitybots.api.sender.SilentSender; +import org.telegram.telegrambots.meta.api.methods.send.SendMessage; +import org.telegram.telegrambots.meta.api.objects.Message; +import org.telegram.telegrambots.meta.api.objects.replykeyboard.ReplyKeyboard; +import org.telegram.telegrambots.meta.api.objects.replykeyboard.ReplyKeyboardRemove; + +import java.util.Map; + +import static com.baeldung.telegram.Constants.START_TEXT; +import static com.baeldung.telegram.UserState.*; + +public class ResponseHandler { + private final SilentSender sender; + private final Map chatStates; + + public ResponseHandler(SilentSender sender, DBContext db) { + this.sender = sender; + chatStates = db.getMap(Constants.CHAT_STATES); + } + + public void replyToStart(long chatId) { + SendMessage message = new SendMessage(); + message.setChatId(chatId); + message.setText(START_TEXT); + sender.execute(message); + chatStates.put(chatId, AWAITING_NAME); + } + +public void replyToButtons(long chatId, Message message) { + if (message.getText().equalsIgnoreCase("/stop")) { + stopChat(chatId); + } + + switch (chatStates.get(chatId)) { + case AWAITING_NAME -> replyToName(chatId, message); + case FOOD_DRINK_SELECTION -> replyToFoodDrinkSelection(chatId, message); + case PIZZA_TOPPINGS -> replyToPizzaToppings(chatId, message); + case AWAITING_CONFIRMATION -> replyToOrder(chatId, message); + default -> unexpectedMessage(chatId); + } +} + + private void unexpectedMessage(long chatId) { + SendMessage sendMessage = new SendMessage(); + sendMessage.setChatId(chatId); + sendMessage.setText("I did not expect that."); + sender.execute(sendMessage); + } + +private void stopChat(long chatId) { + SendMessage sendMessage = new SendMessage(); + sendMessage.setChatId(chatId); + sendMessage.setText("Thank you for your order. See you soon!\nPress /start to order again"); + chatStates.remove(chatId); + sendMessage.setReplyMarkup(new ReplyKeyboardRemove(true)); + sender.execute(sendMessage); +} + + private void replyToOrder(long chatId, Message message) { + SendMessage sendMessage = new SendMessage(); + sendMessage.setChatId(chatId); + if ("yes".equalsIgnoreCase(message.getText())) { + sendMessage.setText("We will deliver it soon. Thank you!\nOrder another?"); + sendMessage.setReplyMarkup(KeyboardFactory.getPizzaOrDrinkKeyboard()); + sender.execute(sendMessage); + chatStates.put(chatId, FOOD_DRINK_SELECTION); + } else if ("no".equalsIgnoreCase(message.getText())) { + stopChat(chatId); + } else { + sendMessage.setText("Please select yes or no"); + sendMessage.setReplyMarkup(KeyboardFactory.getYesOrNo()); + sender.execute(sendMessage); + } + } + + private void replyToPizzaToppings(long chatId, Message message) { + if ("margherita".equalsIgnoreCase(message.getText())) { + promptWithKeyboardForState(chatId, "You selected Margherita Pizza.\nWe will deliver it soon. Thank you!\nOrder again?", + KeyboardFactory.getYesOrNo(), AWAITING_CONFIRMATION); + } else if ("pepperoni".equalsIgnoreCase(message.getText())) { + promptWithKeyboardForState(chatId, "We finished the Pepperoni Pizza.\nSelect another Topping", + KeyboardFactory.getPizzaToppingsKeyboard(), PIZZA_TOPPINGS); + } else { + SendMessage sendMessage = new SendMessage(); + sendMessage.setChatId(chatId); + sendMessage.setText("We don't sell " + message.getText() + " Pizza.\nSelect the toppings!"); + sendMessage.setReplyMarkup(KeyboardFactory.getPizzaToppingsKeyboard()); + sender.execute(sendMessage); + } + } + + private void promptWithKeyboardForState(long chatId, String text, ReplyKeyboard YesOrNo, UserState awaitingReorder) { + SendMessage sendMessage = new SendMessage(); + sendMessage.setChatId(chatId); + sendMessage.setText(text); + sendMessage.setReplyMarkup(YesOrNo); + sender.execute(sendMessage); + chatStates.put(chatId, awaitingReorder); + } + +private void replyToFoodDrinkSelection(long chatId, Message message) { + SendMessage sendMessage = new SendMessage(); + sendMessage.setChatId(chatId); + if ("drink".equalsIgnoreCase(message.getText())) { + sendMessage.setText("We don't sell drinks.\nBring your own drink!! :)"); + sendMessage.setReplyMarkup(KeyboardFactory.getPizzaOrDrinkKeyboard()); + sender.execute(sendMessage); + } else if ("pizza".equalsIgnoreCase(message.getText())) { + sendMessage.setText("We love Pizza in here.\nSelect the toppings!"); + sendMessage.setReplyMarkup(KeyboardFactory.getPizzaToppingsKeyboard()); + sender.execute(sendMessage); + chatStates.put(chatId, UserState.PIZZA_TOPPINGS); + } else { + sendMessage.setText("We don't sell " + message.getText() + ". Please select from the options below."); + sendMessage.setReplyMarkup(KeyboardFactory.getPizzaOrDrinkKeyboard()); + sender.execute(sendMessage); + } +} + +private void replyToName(long chatId, Message message) { + promptWithKeyboardForState(chatId, "Hello " + message.getText() + ". What would you like to have?", + KeyboardFactory.getPizzaOrDrinkKeyboard(), + UserState.FOOD_DRINK_SELECTION); +} + + public boolean userIsActive(Long chatId) { + return chatStates.containsKey(chatId); + } +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/SpringBootTelegramApplication.java b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/SpringBootTelegramApplication.java new file mode 100644 index 0000000000..041478f42b --- /dev/null +++ b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/SpringBootTelegramApplication.java @@ -0,0 +1,24 @@ +package com.baeldung.telegram; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ConfigurableApplicationContext; +import org.telegram.abilitybots.api.bot.AbilityBot; +import org.telegram.telegrambots.meta.TelegramBotsApi; +import org.telegram.telegrambots.meta.exceptions.TelegramApiException; +import org.telegram.telegrambots.updatesreceivers.DefaultBotSession; + +@SpringBootApplication +public class SpringBootTelegramApplication { + + public static void main(String[] args) { + ConfigurableApplicationContext ctx = SpringApplication.run(SpringBootTelegramApplication.class, args); + try { + TelegramBotsApi botsApi = new TelegramBotsApi(DefaultBotSession.class); + botsApi.registerBot(ctx.getBean("pizzaBot", AbilityBot.class)); + } catch (TelegramApiException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/UserState.java b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/UserState.java new file mode 100644 index 0000000000..a0b53a6a02 --- /dev/null +++ b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/UserState.java @@ -0,0 +1,5 @@ +package com.baeldung.telegram; + +public enum UserState { + AWAITING_NAME, FOOD_DRINK_SELECTION, PIZZA_TOPPINGS, AWAITING_CONFIRMATION +} diff --git a/spring-boot-modules/spring-boot-telegram/src/main/resources/application.properties b/spring-boot-modules/spring-boot-telegram/src/main/resources/application.properties new file mode 100644 index 0000000000..6b2753c3a8 --- /dev/null +++ b/spring-boot-modules/spring-boot-telegram/src/main/resources/application.properties @@ -0,0 +1,2 @@ +server.port=8081 +BOT_TOKEN=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/listvalidation/SpringJobApplicationDemoApp.java b/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/listvalidation/SpringJobApplicationDemoApp.java deleted file mode 100644 index a7967c73cb..0000000000 --- a/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/listvalidation/SpringJobApplicationDemoApp.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.baeldung.listvalidation; - - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class SpringJobApplicationDemoApp { - public static void main(String[] args) { - SpringApplication.run(SpringJobApplicationDemoApp.class, args); - } -} diff --git a/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/listvalidation/controller/ApplyJobController.java b/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/listvalidation/controller/ApplyJobController.java deleted file mode 100644 index e3877f09b0..0000000000 --- a/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/listvalidation/controller/ApplyJobController.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.baeldung.listvalidation.controller; - -import com.baeldung.listvalidation.domain.JobAspirant; -import com.baeldung.listvalidation.groups.AllLevels; -import com.baeldung.listvalidation.groups.Junior; -import com.baeldung.listvalidation.groups.MidSenior; -import com.baeldung.listvalidation.groups.Senior; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.validation.FieldError; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.MethodArgumentNotValidException; -import org.springframework.web.bind.annotation.*; - -import java.util.HashMap; -import java.util.Map; - -@RestController -public class ApplyJobController { - @PostMapping("/applyLevelJunior") - public ResponseEntity applyLevelJunior(@Validated({Junior.class, AllLevels.class}) @RequestBody JobAspirant user) { - - return ResponseEntity.ok("Application submitted successfully"); - } - - @PostMapping("/applyLevelMidSenior") - public ResponseEntity applyLevelMidSenior(@Validated({MidSenior.class, AllLevels.class}) @RequestBody JobAspirant user) { - - return ResponseEntity.ok("Application submitted successfully"); - } - - @PostMapping("/applyLevelSenior") - public ResponseEntity applyLevelSenior(@Validated({Senior.class, AllLevels.class}) @RequestBody JobAspirant user) { - - return ResponseEntity.ok("Application submitted successfully"); - } - - @ResponseStatus(HttpStatus.BAD_REQUEST) - @ExceptionHandler(MethodArgumentNotValidException.class) - public Map handleValidationExceptions(MethodArgumentNotValidException ex) { - Map errors = new HashMap<>(); - ex.getBindingResult().getAllErrors().forEach((error) -> { - String fieldName = ((FieldError) error).getField(); - String errorMessage = error.getDefaultMessage(); - errors.put(fieldName, errorMessage); - }); - return errors; - } -} diff --git a/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/listvalidation/groups/AllLevels.java b/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/listvalidation/groups/AllLevels.java deleted file mode 100644 index 8e3f8cc7ef..0000000000 --- a/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/listvalidation/groups/AllLevels.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.baeldung.listvalidation.groups; - -public interface AllLevels { -} diff --git a/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/listvalidation/groups/Junior.java b/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/listvalidation/groups/Junior.java deleted file mode 100644 index 8aca819f18..0000000000 --- a/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/listvalidation/groups/Junior.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.baeldung.listvalidation.groups; - -public interface Junior { -} diff --git a/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/listvalidation/groups/MidSenior.java b/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/listvalidation/groups/MidSenior.java deleted file mode 100644 index ddea95f5e2..0000000000 --- a/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/listvalidation/groups/MidSenior.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.baeldung.listvalidation.groups; - -public interface MidSenior { -} diff --git a/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/listvalidation/groups/Senior.java b/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/listvalidation/groups/Senior.java deleted file mode 100644 index d09d3ea5d5..0000000000 --- a/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/listvalidation/groups/Senior.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.baeldung.listvalidation.groups; - -public interface Senior { -} diff --git a/spring-boot-modules/spring-boot-validation/src/test/java/com/baeldung/listvalidation/application/ApplyJobControllerIntegrationTest.java b/spring-boot-modules/spring-boot-validation/src/test/java/com/baeldung/listvalidation/application/ApplyJobControllerIntegrationTest.java deleted file mode 100644 index 978110633c..0000000000 --- a/spring-boot-modules/spring-boot-validation/src/test/java/com/baeldung/listvalidation/application/ApplyJobControllerIntegrationTest.java +++ /dev/null @@ -1,289 +0,0 @@ -package com.baeldung.listvalidation.application; - - -import org.json.JSONObject; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.http.MediaType; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import org.springframework.test.web.servlet.result.MockMvcResultMatchers; - -import java.nio.charset.StandardCharsets; -import java.util.Map; - -@RunWith(SpringRunner.class) -@WebMvcTest -@AutoConfigureMockMvc -public class ApplyJobControllerIntegrationTest { - - @Autowired - private MockMvc mockMvc; - private static final String[] CORRECT_PASSPORT_EXPIRY_DATES = {"2025-01-01", "2026-02-29", "2024-03-31"}; - private static final String[] INCORRECT_PASSPORT_EXPIRY_DATES = {"2020-01-01", "2021-02-29", "2022-03-31"}; - - private static final Map MAP_OF_JOB_LEVEL_TO_PASSPORT_ERRMSG = Map.of( - "Junior", "Active passport is mandatory for Junior Level Job Application" - , "MidSenior", "Active passport is mandatory for Mid-Senior Level Job Application" - , "Senior", "Active passport is mandatory for Senior Level Job Application" - ); - private static final Map MAP_OF_JOB_LEVEL_TO_AGREEMENT_ERRMSG = Map.of( - "Junior", "Terms and Conditions consent missing for Junior Level Job Application" - , "MidSenior", "Terms and Conditions consent missing for Mid-Senior Level Job Application" - , "Senior", "Terms and Conditions consent missing for Senior Level Job Application" - ); - private static final String[] USERS_INCORRECT_NAMES = {"Bob", "bob Marley", "Bob John Federik Marley", "Bob M@rley" - , " Bob Marley", "Bob Marley ", "Bob Marley"}; - - private static final String[] USERS_CORRECT_NAMES = {"Bob Marley", "Bob John Marley", "Bobby"}; - - private static final Map MAP_OF_JOBLEVEL_TO_INCORRECT_MIN_EXPERIENCES = Map.of( - "Junior", new String[]{"1", "2", "3", "4"} - , "MidSenior", new String[]{"6", "7", "8", "9"} - , "Senior", new String[]{"11", "12", "13", "14"} - ); - private static final Map MAP_OF_JOBLEVEL_TO_MIN_ERRMSG = Map.of( - "Junior", "Years of experience cannot be less than 5 Years" - , "MidSenior", "Years of experience cannot be less than 10 Years" - , "Senior", "Years of experience cannot be less than 15 Years" - ); - private static final Map MAP_OF_JOBLEVEL_TO_MAX_ERRMSG = Map.of( - "Junior", "Years of experience cannot be more than 10 Years" - , "MidSenior", "Years of experience cannot be more than 15 Years" - , "Senior", "Years of experience cannot be more than 20 Years" - ); - private static final Map MAP_OF_JOBLEVEL_TO_INCORRECT_MAX_EXPERIENCES = Map.of( - "Junior", new String[]{"11", "14", "20", "30"} - , "MidSenior", new String[]{"16", "20", "25", "40"} - , "Senior", new String[]{"21", "25", "30", "35"} - ); - private static final Map MAP_OF_INCORRECT_NAMES_TO_ERRMSG = Map.of( - "Bob", "Name should have at least 5 characters" - , "bob Marley", "Name should not start with a lower case character" - , "Bob John Federik Marley", "Name should have at most 20 characters" - , "Bob M@rley", "Name should contain only alphabets and space" - , " Bob Marley", "Name should not start with space" - , "Bob Marley ", "Name should not end with space" - , "Bob Marley", "Name should not contain consecutive spaces" - ); - - private static final Map MAP_OF_JOBLEVEL_TO_CORRECT_EXPERIENCES = Map.of( - "Junior", new String[]{"6", "7", "8", "9", "10"} - , "MidSenior", new String[]{"11", "12", "13", "14", "15"} - , "Senior", new String[]{"16", "17", "18", "19", "20"} - ); - - - private static String[] USERS_VALID_NAMES_INVALID_MAXEXP_VALIDPSPT_VALIDAGMT_JSONS = null; - private static String[] USERS_VALID_NAMES_INVALID_MINEXP_VALIDPSPT_VALIDAGMT_JSONS = null; - private static String[] USERS_INVALID_NAMES_INVALID_MAXEXP_VALIDPSPT_VALIDAGMT_JSONS = null; - private static String[] USERS_INVALID_NAMES_INVALID_MINEXP_VALIDPSPT_VALIDAGMT_JSONS = null; - private static String[] USERS_ALL_FIELDS_VALID_EXCEPT_FOR_PSPT_AND_AGMT_JSONS = null; - private static String[] USERS_ALL_FIELDS_VALID_JSONS = null; - - @Before - public void prepareAllValidFieldsExceptForPsptAndAgmt() { - USERS_ALL_FIELDS_VALID_EXCEPT_FOR_PSPT_AND_AGMT_JSONS = new String[USERS_CORRECT_NAMES.length - * MAP_OF_JOBLEVEL_TO_CORRECT_EXPERIENCES.size() * 5 * INCORRECT_PASSPORT_EXPIRY_DATES.length]; - int i = 0; - for (String user : USERS_CORRECT_NAMES) { - for (String jobLevel : MAP_OF_JOBLEVEL_TO_CORRECT_EXPERIENCES.keySet()) { - for (String experience : MAP_OF_JOBLEVEL_TO_CORRECT_EXPERIENCES.get(jobLevel)) { - for (String passportExpiryDate : INCORRECT_PASSPORT_EXPIRY_DATES) { - USERS_ALL_FIELDS_VALID_EXCEPT_FOR_PSPT_AND_AGMT_JSONS[i++] = "{\"name\": \"" + user - + "\", \"experience\": \"" + experience + "\", \"jobLevel\": \"" + jobLevel - + "\", \"passportExpiryDate\": \"" + passportExpiryDate - + "\", \"agreement\": \"" + false + "\"}"; - } - } - } - } - - } - @Before - public void prepareUserWithAllFieldsValid() { - USERS_ALL_FIELDS_VALID_JSONS = new String[USERS_CORRECT_NAMES.length - * MAP_OF_JOBLEVEL_TO_CORRECT_EXPERIENCES.size() * 5 * CORRECT_PASSPORT_EXPIRY_DATES.length]; - int i = 0; - for (String user : USERS_CORRECT_NAMES) { - for (String jobLevel : MAP_OF_JOBLEVEL_TO_CORRECT_EXPERIENCES.keySet()) { - for (String experience : MAP_OF_JOBLEVEL_TO_CORRECT_EXPERIENCES.get(jobLevel)) { - for (String passportExpiryDate : CORRECT_PASSPORT_EXPIRY_DATES) { - USERS_ALL_FIELDS_VALID_JSONS[i++] = "{\"name\": \"" + user - + "\", \"experience\": \"" + experience + "\", \"jobLevel\": \"" + jobLevel - + "\", \"passportExpiryDate\": \"" + passportExpiryDate - + "\", \"agreement\": \"" + true + "\"}"; - } - } - } - } - } - @Before - public void prepareUsersInvalidNamesInValidMaxExpValidPassportValidAgreementJsons() { - USERS_INVALID_NAMES_INVALID_MAXEXP_VALIDPSPT_VALIDAGMT_JSONS = new String[USERS_INCORRECT_NAMES.length - * MAP_OF_JOBLEVEL_TO_INCORRECT_MAX_EXPERIENCES.size() * 4 * CORRECT_PASSPORT_EXPIRY_DATES.length]; - int i = 0; - for (String user : USERS_INCORRECT_NAMES) { - for (String jobLevel : MAP_OF_JOBLEVEL_TO_INCORRECT_MAX_EXPERIENCES.keySet()) { - for (String experience : MAP_OF_JOBLEVEL_TO_INCORRECT_MAX_EXPERIENCES.get(jobLevel)) { - for (String passportExpiryDate : CORRECT_PASSPORT_EXPIRY_DATES) { - USERS_INVALID_NAMES_INVALID_MAXEXP_VALIDPSPT_VALIDAGMT_JSONS[i++] = "{\"name\": \"" + user - + "\", \"experience\": \"" + experience + "\", \"jobLevel\": \"" + jobLevel - + "\", \"passportExpiryDate\": \"" + passportExpiryDate - + "\", \"agreement\": \"" + true + "\"}"; - } - } - } - } - } - @Before - public void prepareUsersCorrectNamesIncorrectMinExpJsons() { - USERS_VALID_NAMES_INVALID_MINEXP_VALIDPSPT_VALIDAGMT_JSONS = new String[USERS_CORRECT_NAMES.length - * MAP_OF_JOBLEVEL_TO_INCORRECT_MIN_EXPERIENCES.size() * 4 * CORRECT_PASSPORT_EXPIRY_DATES.length]; - int i = 0; - for (String user : USERS_CORRECT_NAMES) { - for (String jobLevel : MAP_OF_JOBLEVEL_TO_INCORRECT_MIN_EXPERIENCES.keySet()) { - for (String experience : MAP_OF_JOBLEVEL_TO_INCORRECT_MIN_EXPERIENCES.get(jobLevel)) { - for (String passportExpiryDate : CORRECT_PASSPORT_EXPIRY_DATES) { - USERS_VALID_NAMES_INVALID_MINEXP_VALIDPSPT_VALIDAGMT_JSONS[i++] = "{\"name\": \"" + user - + "\", \"experience\": \"" + experience + "\", \"jobLevel\": \"" + jobLevel - + "\", \"passportExpiryDate\": \"" + passportExpiryDate - + "\", \"agreement\": \"" + true + "\"}"; - } - } - } - } - } - @Before - public void prepareUsersIncorrectNamesIncorrectMinExpJsons() { - USERS_INVALID_NAMES_INVALID_MINEXP_VALIDPSPT_VALIDAGMT_JSONS = new String[USERS_INCORRECT_NAMES.length - * MAP_OF_JOBLEVEL_TO_INCORRECT_MIN_EXPERIENCES.size() * 4 * CORRECT_PASSPORT_EXPIRY_DATES.length]; - int i = 0; - for (String user : USERS_INCORRECT_NAMES) { - for (String jobLevel : MAP_OF_JOBLEVEL_TO_INCORRECT_MIN_EXPERIENCES.keySet()) { - for (String experience : MAP_OF_JOBLEVEL_TO_INCORRECT_MIN_EXPERIENCES.get(jobLevel)) { - for (String passportExpiryDate : CORRECT_PASSPORT_EXPIRY_DATES) { - USERS_INVALID_NAMES_INVALID_MINEXP_VALIDPSPT_VALIDAGMT_JSONS[i++] = "{\"name\": \"" + user - + "\", \"experience\": \"" + experience + "\", \"jobLevel\": \"" + jobLevel - + "\", \"passportExpiryDate\": \"" + passportExpiryDate - + "\", \"agreement\": \"" + true + "\"}"; - } - } - } - } - } - @Before - public void prepareUsersCorrectNamesIncorrectMaxExpJsons() { - USERS_VALID_NAMES_INVALID_MAXEXP_VALIDPSPT_VALIDAGMT_JSONS = new String[USERS_CORRECT_NAMES.length - * MAP_OF_JOBLEVEL_TO_INCORRECT_MAX_EXPERIENCES.size() * 4 * CORRECT_PASSPORT_EXPIRY_DATES.length]; - int i = 0; - for (String user : USERS_CORRECT_NAMES) { - for (String jobLevel : MAP_OF_JOBLEVEL_TO_INCORRECT_MAX_EXPERIENCES.keySet()) { - for (String experience : MAP_OF_JOBLEVEL_TO_INCORRECT_MAX_EXPERIENCES.get(jobLevel)) { - for (String passportExpiryDate : CORRECT_PASSPORT_EXPIRY_DATES) { - USERS_VALID_NAMES_INVALID_MAXEXP_VALIDPSPT_VALIDAGMT_JSONS[i++] = "{\"name\": \"" + user - + "\", \"experience\": \"" + experience + "\", \"jobLevel\": \"" + jobLevel - + "\", \"passportExpiryDate\": \"" + passportExpiryDate - + "\", \"agreement\": \"" + true + "\"}"; - } - } - } - } - } - @Test - public void whenAllFieldsValidExceptForPsptAndAgmt_thenBadRequestResponse() throws Exception { - String[] users = USERS_ALL_FIELDS_VALID_EXCEPT_FOR_PSPT_AND_AGMT_JSONS; - for (String user : users) { - JSONObject jsonObject = new JSONObject(user); - String jobLevel = jsonObject.getString("jobLevel"); - mockMvc.perform(MockMvcRequestBuilders.post("/applyLevel" + jobLevel) - .content(user) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.status().isBadRequest()) - .andExpect(MockMvcResultMatchers.content() - .json("{\"agreement\":\"" + MAP_OF_JOB_LEVEL_TO_AGREEMENT_ERRMSG.get(jobLevel) - + "\",\"passportExpiryDate\":\"" + MAP_OF_JOB_LEVEL_TO_PASSPORT_ERRMSG.get(jobLevel) + "\"}")); - } - } - @Test - public void whenUserWithAllFieldsValid_thenCorrectResponse() throws Exception { - MediaType textPlainUtf8 = new MediaType(MediaType.TEXT_PLAIN, StandardCharsets.UTF_8); - String[] users = USERS_ALL_FIELDS_VALID_JSONS; - for (String user : users) { - JSONObject jsonObject = new JSONObject(user); - String jobLevel = jsonObject.getString("jobLevel"); - mockMvc.perform(MockMvcRequestBuilders.post("/applyLevel" + jobLevel) - .content(user) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().contentType(textPlainUtf8)) - .andExpect(MockMvcResultMatchers.content().string("Application submitted successfully")); - } - } - @Test - public void whenValidUserNamesInValidMaxExpValidPsptValidAgmt_thenBadRequestResponse() throws Exception { - String[] users = USERS_VALID_NAMES_INVALID_MAXEXP_VALIDPSPT_VALIDAGMT_JSONS; - for (String user : users) { - JSONObject jsonObject = new JSONObject(user); - String jobLevel = jsonObject.getString("jobLevel"); - mockMvc.perform(MockMvcRequestBuilders.post("/applyLevel" + jobLevel) - .content(user) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.status().isBadRequest()) - .andExpect(MockMvcResultMatchers.content() - .json("{\"experience\":\"" + MAP_OF_JOBLEVEL_TO_MAX_ERRMSG.get(jobLevel) - + "\"}")); - } - } - @Test - public void whenInvalidUserNamesInValidMaxExpValidPsptValidAgmt_thenBadRequestResponse() throws Exception { - String[] users = USERS_INVALID_NAMES_INVALID_MAXEXP_VALIDPSPT_VALIDAGMT_JSONS; - for (String user : users) { - JSONObject jsonObject = new JSONObject(user); - String jobLevel = jsonObject.getString("jobLevel"); - String name = jsonObject.getString("name"); - mockMvc.perform(MockMvcRequestBuilders.post("/applyLevel" + jobLevel) - .content(user) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.status().isBadRequest()) - .andExpect(MockMvcResultMatchers.content() - .json("{\"name\":\"" + MAP_OF_INCORRECT_NAMES_TO_ERRMSG.get(name) - + "\",\"experience\":\"" + MAP_OF_JOBLEVEL_TO_MAX_ERRMSG.get(jobLevel) + "\"}")); - } - } - @Test - public void whenValidUserNamesInValidMinExpValidPsptValidAgmt_thenBadRequestResponse() throws Exception { - String[] users = USERS_VALID_NAMES_INVALID_MINEXP_VALIDPSPT_VALIDAGMT_JSONS; - for (String user : users) { - JSONObject jsonObject = new JSONObject(user); - String jobLevel = jsonObject.getString("jobLevel"); - mockMvc.perform(MockMvcRequestBuilders.post("/applyLevel" + jobLevel) - .content(user) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.status().isBadRequest()) - .andExpect(MockMvcResultMatchers.content() - .json("{\"experience\":\"" + MAP_OF_JOBLEVEL_TO_MIN_ERRMSG.get(jobLevel) + "\"}")); - } - } - @Test - public void whenInValidUserNamesInValidMinExpValidPsptValidAgmt_thenBadRequestResponse() throws Exception { - String[] users = USERS_INVALID_NAMES_INVALID_MINEXP_VALIDPSPT_VALIDAGMT_JSONS; - for (String user : users) { - JSONObject jsonObject = new JSONObject(user); - String jobLevel = jsonObject.getString("jobLevel"); - String name = jsonObject.getString("name"); - mockMvc.perform(MockMvcRequestBuilders.post("/applyLevel" + jobLevel) - .content(user) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.status().isBadRequest()) - .andExpect(MockMvcResultMatchers.content() - .json("{\"name\":\"" + MAP_OF_INCORRECT_NAMES_TO_ERRMSG.get(name) - + "\",\"experience\":\"" + MAP_OF_JOBLEVEL_TO_MIN_ERRMSG.get(jobLevel) + "\"}")); - } - } -} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/application-config/book-service.properties b/spring-cloud-modules/spring-cloud-bootstrap/application-config/book-service.properties index 2ea30b9ab7..597899bd16 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/application-config/book-service.properties +++ b/spring-cloud-modules/spring-cloud-bootstrap/application-config/book-service.properties @@ -10,8 +10,8 @@ eureka.client.registryFetchIntervalSeconds = 5 management.security.sessions=never -logging.level.org.springframework.web.=debug -logging.level.org.springframework.security=debug +logging.level.org.springframework.web.=INFO +logging.level.org.springframework.security=INFO spring.redis.host=localhost spring.redis.port=6379 diff --git a/spring-cloud-modules/spring-cloud-bootstrap/application-config/gateway.properties b/spring-cloud-modules/spring-cloud-bootstrap/application-config/gateway.properties index 42e114450d..44d5267d10 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/application-config/gateway.properties +++ b/spring-cloud-modules/spring-cloud-bootstrap/application-config/gateway.properties @@ -6,8 +6,8 @@ eureka.client.registryFetchIntervalSeconds = 5 management.security.sessions=always -logging.level.org.springframework.web.=debug -logging.level.org.springframework.security=debug +logging.level.org.springframework.web.=INFO +logging.level.org.springframework.security=INFO spring.redis.host=localhost spring.redis.port=6379 diff --git a/spring-cloud-modules/spring-cloud-bootstrap/application-config/rating-service.properties b/spring-cloud-modules/spring-cloud-bootstrap/application-config/rating-service.properties index 059b87e4e7..89f8ee40fe 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/application-config/rating-service.properties +++ b/spring-cloud-modules/spring-cloud-bootstrap/application-config/rating-service.properties @@ -10,8 +10,8 @@ eureka.client.registryFetchIntervalSeconds = 5 management.security.sessions=never -logging.level.org.springframework.web.=debug -logging.level.org.springframework.security=debug +logging.level.org.springframework.web.=INFO +logging.level.org.springframework.security=INFO spring.redis.host=localhost spring.redis.port=6379 diff --git a/spring-cloud-modules/spring-cloud-bootstrap/application-config/zipkin.properties b/spring-cloud-modules/spring-cloud-bootstrap/application-config/zipkin.properties index ca3aed2263..1a689123cb 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/application-config/zipkin.properties +++ b/spring-cloud-modules/spring-cloud-bootstrap/application-config/zipkin.properties @@ -4,4 +4,4 @@ server.port=9411 eureka.client.region = default eureka.client.registryFetchIntervalSeconds = 5 -logging.level.org.springframework.web=debug +logging.level.org.springframework.web=INFO diff --git a/spring-cloud-modules/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/pom.xml b/spring-cloud-modules/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/pom.xml index ba923c4ae6..3e2b1632c7 100644 --- a/spring-cloud-modules/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/pom.xml +++ b/spring-cloud-modules/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/pom.xml @@ -46,7 +46,6 @@ 1.3.1.RELEASE Edgware.SR6 5.2.12.Final - 1.11.20 3.1.0 diff --git a/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/resources/logback-test.xml b/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..fb1f109a18 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/resources/logback-test.xml @@ -0,0 +1,17 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-openfeign-2/src/main/resources/application.properties b/spring-cloud-modules/spring-cloud-openfeign-2/src/main/resources/application.properties index aa0dc6a382..0a31d79ee0 100644 --- a/spring-cloud-modules/spring-cloud-openfeign-2/src/main/resources/application.properties +++ b/spring-cloud-modules/spring-cloud-openfeign-2/src/main/resources/application.properties @@ -4,7 +4,7 @@ feign.okhttp.enabled=true server.port=8085 spring.main.allow-bean-definition-overriding=true -logging.level.com.baeldung.cloud.openfeign.client=DEBUG +logging.level.com.baeldung.cloud.openfeign.client=INFO feign.hystrix.enabled=true spring.cloud.openfeign.client.config.postClient.url=https://jsonplaceholder.typicode.com/posts/ \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-rabbit/src/test/resources/logback-test.xml b/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-rabbit/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..233cfa7e23 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-rabbit/src/test/resources/logback-test.xml @@ -0,0 +1,17 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-task/springcloudtasksink/src/test/resources/logback-test.xml b/spring-cloud-modules/spring-cloud-task/springcloudtasksink/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..2a5eefdd1f --- /dev/null +++ b/spring-cloud-modules/spring-cloud-task/springcloudtasksink/src/test/resources/logback-test.xml @@ -0,0 +1,15 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-zuul-fallback/spring-cloud-zuul-fallback-weather-service/src/test/resources/logback-test.xml b/spring-cloud-modules/spring-cloud-zuul-fallback/spring-cloud-zuul-fallback-weather-service/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..4ff950099a --- /dev/null +++ b/spring-cloud-modules/spring-cloud-zuul-fallback/spring-cloud-zuul-fallback-weather-service/src/test/resources/logback-test.xml @@ -0,0 +1,17 @@ + + + + + # Pattern of log message for console appender + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + + \ No newline at end of file diff --git a/spring-integration/src/test/resources/logback-test.xml b/spring-integration/src/test/resources/logback-test.xml index 8f1be4eb7a..98bfc86d71 100644 --- a/spring-integration/src/test/resources/logback-test.xml +++ b/spring-integration/src/test/resources/logback-test.xml @@ -9,6 +9,8 @@ + + diff --git a/spring-native/pom.xml b/spring-native/pom.xml index 55f17c833f..97eb33c1c7 100644 --- a/spring-native/pom.xml +++ b/spring-native/pom.xml @@ -17,17 +17,27 @@ - spring-release - Spring release - https://repo.spring.io/release + spring-milestone + Spring Milestone + https://repo.spring.io/milestone + + + spring-snapshot + Spring Snapshot + https://repo.spring.io/snapshot - spring-release - Spring release - https://repo.spring.io/release + spring-plugins-snapshot + Spring Plugins Snapshot + https://repo.spring.io/plugins-snapshot + + + spring-plugins-milestone + Spring Plugins Milestone + https://repo.spring.io/plugins-milestone diff --git a/spring-soap/.gitignore b/spring-soap/.gitignore index cce17abdb9..2b04fd0719 100644 --- a/spring-soap/.gitignore +++ b/spring-soap/.gitignore @@ -1,2 +1,4 @@ /target/ sun-jaxb.episode + +**/gen/** \ No newline at end of file diff --git a/spring-soap/pom.xml b/spring-soap/pom.xml index 8188178d61..594eb3dd19 100644 --- a/spring-soap/pom.xml +++ b/spring-soap/pom.xml @@ -30,6 +30,22 @@ spring-boot-starter-test test + + + jakarta.xml.bind + jakarta.xml.bind-api + 4.0.0 + + + + org.glassfish.jaxb + jaxb-runtime + + + + javax.xml.bind + jaxb-api + @@ -42,7 +58,7 @@ org.codehaus.mojo jaxb2-maven-plugin - 1.6 + 3.1.0 xjc @@ -52,8 +68,10 @@ - ${project.basedir}/src/main/resources/ - ${project.basedir}/src/main/java + + src/main/resources/countries.xsd + + src/main/java false @@ -61,7 +79,7 @@ org.jvnet.jaxb2.maven2 maven-jaxb2-plugin - 0.14.0 + 0.15.3 @@ -83,4 +101,7 @@ + + 17 + \ No newline at end of file diff --git a/spring-soap/src/main/java/com/baeldung/springsoap/CountryEndpoint.java b/spring-soap/src/main/java/com/baeldung/springsoap/CountryEndpoint.java index 745131767a..49020cec21 100644 --- a/spring-soap/src/main/java/com/baeldung/springsoap/CountryEndpoint.java +++ b/spring-soap/src/main/java/com/baeldung/springsoap/CountryEndpoint.java @@ -1,12 +1,14 @@ package com.baeldung.springsoap; -import com.baeldung.springsoap.gen.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.ws.server.endpoint.annotation.Endpoint; import org.springframework.ws.server.endpoint.annotation.PayloadRoot; import org.springframework.ws.server.endpoint.annotation.RequestPayload; import org.springframework.ws.server.endpoint.annotation.ResponsePayload; +import com.baeldung.springsoap.client.gen.GetCountryRequest; +import com.baeldung.springsoap.client.gen.GetCountryResponse; + @Endpoint public class CountryEndpoint { diff --git a/spring-soap/src/main/java/com/baeldung/springsoap/CountryRepository.java b/spring-soap/src/main/java/com/baeldung/springsoap/CountryRepository.java index 8a0f58a64e..183027cdb6 100644 --- a/spring-soap/src/main/java/com/baeldung/springsoap/CountryRepository.java +++ b/spring-soap/src/main/java/com/baeldung/springsoap/CountryRepository.java @@ -1,12 +1,15 @@ package com.baeldung.springsoap; -import com.baeldung.springsoap.gen.*; +import java.util.HashMap; +import java.util.Map; + +import javax.annotation.PostConstruct; + import org.springframework.stereotype.Component; import org.springframework.util.Assert; -import javax.annotation.PostConstruct; -import java.util.HashMap; -import java.util.Map; +import com.baeldung.springsoap.client.gen.Country; +import com.baeldung.springsoap.client.gen.Currency; @Component public class CountryRepository { diff --git a/spring-soap/src/main/java/com/baeldung/springsoap/WebServiceConfig.java b/spring-soap/src/main/java/com/baeldung/springsoap/WebServiceConfig.java index 930a961208..57636e9891 100644 --- a/spring-soap/src/main/java/com/baeldung/springsoap/WebServiceConfig.java +++ b/spring-soap/src/main/java/com/baeldung/springsoap/WebServiceConfig.java @@ -17,11 +17,11 @@ import org.springframework.xml.xsd.XsdSchema; public class WebServiceConfig extends WsConfigurerAdapter { @Bean - public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) { + public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) { MessageDispatcherServlet servlet = new MessageDispatcherServlet(); servlet.setApplicationContext(applicationContext); servlet.setTransformWsdlLocations(true); - return new ServletRegistrationBean(servlet, "/ws/*"); + return new ServletRegistrationBean<>(servlet, "/ws/*"); } @Bean(name = "countries") diff --git a/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/Country.java b/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/Country.java deleted file mode 100644 index bb196d625d..0000000000 --- a/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/Country.java +++ /dev/null @@ -1,139 +0,0 @@ - -package com.baeldung.springsoap.client.gen; - -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlSchemaType; -import javax.xml.bind.annotation.XmlType; - - -/** - *

Java class for country complex type. - * - *

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

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

Java class for currency. - * - *

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

- *

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

Java class for anonymous complex type. - * - *

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

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

Java class for anonymous complex type. - * - *

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

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

An ObjectFactory allows you to programatically - * construct new instances of the Java representation - * for XML content. The Java representation of XML - * content can consist of schema derived interfaces - * and classes representing the binding of schema - * type definitions, element declarations and model - * groups. Factory methods for each of these are - * provided in this class. - * - */ -@XmlRegistry -public class ObjectFactory { - - - /** - * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: com.baeldung.springsoap.client.gen - * - */ - public ObjectFactory() { - } - - /** - * Create an instance of {@link GetCountryRequest } - * - */ - public GetCountryRequest createGetCountryRequest() { - return new GetCountryRequest(); - } - - /** - * Create an instance of {@link GetCountryResponse } - * - */ - public GetCountryResponse createGetCountryResponse() { - return new GetCountryResponse(); - } - - /** - * Create an instance of {@link Country } - * - */ - public Country createCountry() { - return new Country(); - } - -} diff --git a/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/package-info.java b/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/package-info.java deleted file mode 100644 index 9432e0c328..0000000000 --- a/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/package-info.java +++ /dev/null @@ -1,2 +0,0 @@ -@javax.xml.bind.annotation.XmlSchema(namespace = "http://www.baeldung.com/springsoap/gen", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED) -package com.baeldung.springsoap.client.gen; diff --git a/spring-soap/src/test/java/com/baeldung/springsoap/ApplicationIntegrationTest.java b/spring-soap/src/test/java/com/baeldung/springsoap/ApplicationIntegrationTest.java index 3b071c286f..1150b8d91b 100644 --- a/spring-soap/src/test/java/com/baeldung/springsoap/ApplicationIntegrationTest.java +++ b/spring-soap/src/test/java/com/baeldung/springsoap/ApplicationIntegrationTest.java @@ -1,18 +1,19 @@ package com.baeldung.springsoap; -import com.baeldung.springsoap.gen.GetCountryRequest; +import static org.assertj.core.api.Assertions.assertThat; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.oxm.jaxb.Jaxb2Marshaller; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.util.ClassUtils; import org.springframework.ws.client.core.WebServiceTemplate; -import static org.assertj.core.api.Assertions.assertThat; +import com.baeldung.springsoap.client.gen.GetCountryRequest; @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) @@ -20,7 +21,8 @@ public class ApplicationIntegrationTest { private Jaxb2Marshaller marshaller = new Jaxb2Marshaller(); - @LocalServerPort private int port = 0; + @LocalServerPort + private int port = 0; @Before public void init() throws Exception { @@ -34,6 +36,8 @@ public class ApplicationIntegrationTest { GetCountryRequest request = new GetCountryRequest(); request.setName("Spain"); - assertThat(ws.marshalSendAndReceive("http://localhost:" + port + "/ws", request)).isNotNull(); + Object response = ws.marshalSendAndReceive("http://localhost:" + port + "/ws", request); + + assertThat(response).isNotNull(); } } diff --git a/web-modules/pom.xml b/web-modules/pom.xml index c009837186..8c3d3456b6 100644 --- a/web-modules/pom.xml +++ b/web-modules/pom.xml @@ -26,7 +26,7 @@ jee-7 jooby linkrest - + ninja ratpack