Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
9b625d1445
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,36 +1,43 @@
|
||||||
package com.baeldung.tlsversion;
|
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 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 class ClientTlsVersionExamples {
|
||||||
|
|
||||||
public static CloseableHttpClient setViaSocketFactory() {
|
public static CloseableHttpClient setViaSocketFactory() {
|
||||||
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
|
final HttpClientConnectionManager cm = PoolingHttpClientConnectionManagerBuilder.create()
|
||||||
SSLContexts.createDefault(),
|
.setDefaultTlsConfig(TlsConfig.custom()
|
||||||
new String[] { "TLSv1.2", "TLSv1.3" },
|
.setHandshakeTimeout(Timeout.ofSeconds(30))
|
||||||
null,
|
.setSupportedProtocols(TLS.V_1_2, TLS.V_1_3)
|
||||||
SSLConnectionSocketFactory.getDefaultHostnameVerifier());
|
.build())
|
||||||
|
.build();
|
||||||
|
|
||||||
return HttpClients.custom().setSSLSocketFactory(sslsf).build();
|
return HttpClients.custom()
|
||||||
|
.setConnectionManager(cm)
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CloseableHttpClient setTlsVersionPerConnection() {
|
public static CloseableHttpClient setTlsVersionPerConnection() {
|
||||||
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(SSLContexts.createDefault()) {
|
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(SSLContexts.createDefault()) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void prepareSocket(SSLSocket socket) {
|
protected void prepareSocket(SSLSocket socket) {
|
||||||
String hostname = socket.getInetAddress().getHostName();
|
String hostname = socket.getInetAddress()
|
||||||
|
.getHostName();
|
||||||
if (hostname.endsWith("internal.system.com")) {
|
if (hostname.endsWith("internal.system.com")) {
|
||||||
socket.setEnabledProtocols(new String[] { "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3" });
|
socket.setEnabledProtocols(new String[] { "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3" });
|
||||||
} else {
|
} 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.
|
// 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() {
|
public static CloseableHttpClient setViaSystemProperties() {
|
||||||
return HttpClients.createSystem();
|
return HttpClients.createSystem();
|
||||||
// Alternatively:
|
// Alternatively:
|
||||||
// return HttpClients.custom().useSystemProperties().build();
|
//return HttpClients.custom().useSystemProperties().build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) throws IOException {
|
public static void main(String[] args) throws IOException {
|
||||||
// Alternatively:
|
try (CloseableHttpClient httpClient = setViaSocketFactory(); CloseableHttpResponse response = httpClient.execute(new HttpGet("https://httpbin.org/"))) {
|
||||||
// CloseableHttpClient httpClient = setTlsVersionPerConnection();
|
|
||||||
// CloseableHttpClient httpClient = setViaSystemProperties();
|
|
||||||
try (CloseableHttpClient httpClient = setViaSocketFactory();
|
|
||||||
CloseableHttpResponse response = httpClient.execute(new HttpGet("https://httpbin.org/"))) {
|
|
||||||
|
|
||||||
HttpEntity entity = response.getEntity();
|
HttpEntity entity = response.getEntity();
|
||||||
EntityUtils.consume(entity);
|
EntityUtils.consume(entity);
|
||||||
|
|
|
@ -1,69 +1,71 @@
|
||||||
package com.baeldung.httpclient.conn;
|
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.assertNotNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
import org.apache.http.HeaderElement;
|
import org.apache.hc.client5.http.ConnectionKeepAliveStrategy;
|
||||||
import org.apache.http.HeaderElementIterator;
|
import org.apache.hc.client5.http.HttpRoute;
|
||||||
import org.apache.http.HttpClientConnection;
|
import org.apache.hc.client5.http.classic.methods.HttpGet;
|
||||||
import org.apache.http.HttpException;
|
import org.apache.hc.client5.http.config.ConnectionConfig;
|
||||||
import org.apache.http.HttpHost;
|
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
|
||||||
import org.apache.http.HttpResponse;
|
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
|
||||||
import org.apache.http.client.ClientProtocolException;
|
import org.apache.hc.client5.http.impl.classic.HttpClients;
|
||||||
import org.apache.http.client.config.RequestConfig;
|
import org.apache.hc.client5.http.impl.io.BasicHttpClientConnectionManager;
|
||||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
|
||||||
import org.apache.http.client.methods.HttpGet;
|
import org.apache.hc.client5.http.io.ConnectionEndpoint;
|
||||||
import org.apache.http.client.protocol.HttpClientContext;
|
import org.apache.hc.client5.http.io.LeaseRequest;
|
||||||
import org.apache.http.config.SocketConfig;
|
import org.apache.hc.core5.http.HeaderElement;
|
||||||
import org.apache.http.conn.ConnectionKeepAliveStrategy;
|
import org.apache.hc.core5.http.HeaderElements;
|
||||||
import org.apache.http.conn.ConnectionPoolTimeoutException;
|
import org.apache.hc.core5.http.HttpHost;
|
||||||
import org.apache.http.conn.ConnectionRequest;
|
import org.apache.hc.core5.http.HttpResponse;
|
||||||
import org.apache.http.conn.routing.HttpRoute;
|
import org.apache.hc.core5.http.io.entity.EntityUtils;
|
||||||
import org.apache.http.impl.client.CloseableHttpClient;
|
import org.apache.hc.core5.http.message.MessageSupport;
|
||||||
import org.apache.http.impl.client.HttpClients;
|
import org.apache.hc.core5.http.message.StatusLine;
|
||||||
import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
|
import org.apache.hc.core5.http.protocol.BasicHttpContext;
|
||||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
import org.apache.hc.core5.http.protocol.HttpContext;
|
||||||
import org.apache.http.message.BasicHeaderElementIterator;
|
import org.apache.hc.core5.pool.PoolStats;
|
||||||
import org.apache.http.protocol.HTTP;
|
import org.apache.hc.core5.util.Args;
|
||||||
import org.apache.http.protocol.HttpContext;
|
import org.apache.hc.core5.util.TimeValue;
|
||||||
import org.apache.http.protocol.HttpCoreContext;
|
import org.apache.hc.core5.util.Timeout;
|
||||||
import org.apache.http.protocol.HttpRequestExecutor;
|
import org.junit.Assert;
|
||||||
import org.apache.http.util.EntityUtils;
|
|
||||||
import org.junit.Ignore;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
public class HttpClientConnectionManagementLiveTest {
|
public class HttpClientConnectionManagementLiveTest {
|
||||||
|
|
||||||
// Example 2.1. Getting a Connection Request for a Low Level Connection (HttpClientConnection)
|
// Example 2.1. Getting a Connection Request for a Low Level Connection (HttpClientConnection)
|
||||||
@Test
|
@Test
|
||||||
public final void whenLowLevelConnectionIsEstablished_thenNoExceptions() throws ConnectionPoolTimeoutException, InterruptedException, ExecutionException {
|
public final void whenLowLevelConnectionIsEstablished_thenNoExceptions() throws ExecutionException, InterruptedException, TimeoutException {
|
||||||
try (BasicHttpClientConnectionManager connManager = new BasicHttpClientConnectionManager()) {
|
BasicHttpClientConnectionManager connMgr = new BasicHttpClientConnectionManager();
|
||||||
HttpRoute route = new HttpRoute(new HttpHost("www.baeldung.com", 80));
|
HttpRoute route = new HttpRoute(new HttpHost("www.baeldung.com", 443));
|
||||||
final ConnectionRequest connRequest = connManager.requestConnection(route, null);
|
final LeaseRequest connRequest = connMgr.lease("some-id", route, null);
|
||||||
assertNotNull(connRequest.get(1000, TimeUnit.SECONDS));
|
assertNotNull(connRequest.get(Timeout.ZERO_MILLISECONDS));
|
||||||
}
|
connMgr.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Example 3.1. Setting the PoolingHttpClientConnectionManager on a HttpClient
|
// Example 3.1. Setting the PoolingHttpClientConnectionManager on a HttpClient
|
||||||
@Test
|
@Test
|
||||||
public final void whenPollingConnectionManagerIsConfiguredOnHttpClient_thenNoExceptions() throws ClientProtocolException, IOException {
|
public final void whenPollingConnectionManagerIsConfiguredOnHttpClient_thenNoExceptions() throws IOException {
|
||||||
PoolingHttpClientConnectionManager poolingConnManager = new PoolingHttpClientConnectionManager();
|
PoolingHttpClientConnectionManager poolingConnManager = new PoolingHttpClientConnectionManager();
|
||||||
CloseableHttpClient client = HttpClients.custom()
|
CloseableHttpClient client = HttpClients.custom()
|
||||||
.setConnectionManager(poolingConnManager)
|
.setConnectionManager(poolingConnManager)
|
||||||
.build();
|
.build();
|
||||||
client.execute(new HttpGet("https://www.baeldung.com"));
|
client.execute(new HttpGet("https://www.baeldung.com"));
|
||||||
|
|
||||||
assertTrue(poolingConnManager.getTotalStats()
|
assertTrue(poolingConnManager.getTotalStats()
|
||||||
.getLeased() == 1);
|
.getLeased() == 1);
|
||||||
|
client.close();
|
||||||
|
poolingConnManager.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Example 3.2. Using Two HttpClients to Connect to One Target Host Each
|
// Example 3.2. Using Two HttpClients to Connect to One Target Host Each
|
||||||
@Test
|
@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 get1 = new HttpGet("https://www.baeldung.com");
|
||||||
HttpGet get2 = new HttpGet("https://www.google.com");
|
HttpGet get2 = new HttpGet("https://www.google.com");
|
||||||
PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();
|
PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();
|
||||||
|
@ -81,38 +83,52 @@ public class HttpClientConnectionManagementLiveTest {
|
||||||
thread1.join();
|
thread1.join();
|
||||||
thread2.join();
|
thread2.join();
|
||||||
|
|
||||||
assertTrue(connManager.getTotalStats()
|
Assert.assertTrue(connManager.getTotalStats()
|
||||||
.getLeased() == 0);
|
.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
|
// Example 4.1. Increasing the Number of Connections that Can be Open and Managed Beyond the default Limits
|
||||||
@Test
|
@Test
|
||||||
public final void whenIncreasingConnectionPool_thenNoEceptions() {
|
public final void whenIncreasingConnectionPool_thenNoExceptions() {
|
||||||
try (PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager()) {
|
PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();
|
||||||
connManager.setMaxTotal(5);
|
connManager.setMaxTotal(5);
|
||||||
connManager.setDefaultMaxPerRoute(4);
|
connManager.setDefaultMaxPerRoute(4);
|
||||||
HttpHost host = new HttpHost("www.baeldung.com", 80);
|
HttpHost host = new HttpHost("www.baeldung.com", 80);
|
||||||
connManager.setMaxPerRoute(new HttpRoute(host), 5);
|
connManager.setMaxPerRoute(new HttpRoute(host), 5);
|
||||||
}
|
connManager.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Example 4.2. Using Threads to Execute Connections
|
// Example 4.2. Using Threads to Execute Connections
|
||||||
@Test
|
@Test
|
||||||
public final void whenExecutingSameRequestsInDifferentThreads_thenExecuteReuqest() throws InterruptedException {
|
public final void whenExecutingSameRequestsInDifferentThreads_thenExecuteRequest() throws InterruptedException, IOException {
|
||||||
HttpGet get = new HttpGet("http://www.baeldung.com");
|
HttpGet get = new HttpGet("http://www.baeldung.com");
|
||||||
PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();
|
PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();
|
||||||
CloseableHttpClient client = HttpClients.custom()
|
CloseableHttpClient client = HttpClients.custom()
|
||||||
.setConnectionManager(connManager)
|
.setConnectionManager(connManager)
|
||||||
.build();
|
.build();
|
||||||
MultiHttpClientConnThread thread1 = new MultiHttpClientConnThread(client, get);
|
MultiHttpClientConnThread thread1 = new MultiHttpClientConnThread(client, get, connManager);
|
||||||
MultiHttpClientConnThread thread2 = new MultiHttpClientConnThread(client, get);
|
MultiHttpClientConnThread thread2 = new MultiHttpClientConnThread(client, get, connManager);
|
||||||
MultiHttpClientConnThread thread3 = new MultiHttpClientConnThread(client, get);
|
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();
|
thread1.start();
|
||||||
thread2.start();
|
thread2.start();
|
||||||
thread3.start();
|
thread3.start();
|
||||||
|
thread4.start();
|
||||||
|
thread5.start();
|
||||||
|
thread6.start();
|
||||||
thread1.join();
|
thread1.join();
|
||||||
thread2.join();
|
thread2.join();
|
||||||
thread3.join();
|
thread3.join();
|
||||||
|
thread4.join();
|
||||||
|
thread5.join();
|
||||||
|
thread6.join();
|
||||||
|
client.close();
|
||||||
|
connManager.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Example 5.1. A Custom Keep Alive Strategy
|
// Example 5.1. A Custom Keep Alive Strategy
|
||||||
|
@ -120,22 +136,19 @@ public class HttpClientConnectionManagementLiveTest {
|
||||||
public final void whenCustomizingKeepAliveStrategy_thenNoExceptions() {
|
public final void whenCustomizingKeepAliveStrategy_thenNoExceptions() {
|
||||||
final ConnectionKeepAliveStrategy myStrategy = new ConnectionKeepAliveStrategy() {
|
final ConnectionKeepAliveStrategy myStrategy = new ConnectionKeepAliveStrategy() {
|
||||||
@Override
|
@Override
|
||||||
public long getKeepAliveDuration(final HttpResponse myResponse, final HttpContext myContext) {
|
public TimeValue getKeepAliveDuration(HttpResponse response, HttpContext context) {
|
||||||
final HeaderElementIterator it = new BasicHeaderElementIterator(myResponse.headerIterator(HTTP.CONN_KEEP_ALIVE));
|
Args.notNull(response, "HTTP response");
|
||||||
while (it.hasNext()) {
|
final Iterator<HeaderElement> it = MessageSupport.iterate(response, HeaderElements.KEEP_ALIVE);
|
||||||
final HeaderElement he = it.nextElement();
|
final HeaderElement he = it.next();
|
||||||
final String param = he.getName();
|
final String param = he.getName();
|
||||||
final String value = he.getValue();
|
final String value = he.getValue();
|
||||||
if ((value != null) && param.equalsIgnoreCase("timeout")) {
|
if (value != null && param.equalsIgnoreCase("timeout")) {
|
||||||
return Long.parseLong(value) * 1000;
|
try {
|
||||||
|
return TimeValue.ofSeconds(Long.parseLong(value));
|
||||||
|
} catch (final NumberFormatException ignore) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final HttpHost target = (HttpHost) myContext.getAttribute(HttpCoreContext.HTTP_TARGET_HOST);
|
return TimeValue.ofSeconds(5);
|
||||||
if ("localhost".equalsIgnoreCase(target.getHostName())) {
|
|
||||||
return 10 * 1000;
|
|
||||||
} else {
|
|
||||||
return 5 * 1000;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -144,42 +157,38 @@ public class HttpClientConnectionManagementLiveTest {
|
||||||
.setKeepAliveStrategy(myStrategy)
|
.setKeepAliveStrategy(myStrategy)
|
||||||
.setConnectionManager(connManager)
|
.setConnectionManager(connManager)
|
||||||
.build();
|
.build();
|
||||||
|
connManager.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Example 6.1. BasicHttpClientConnectionManager Connection Reuse
|
//Example 6.1. BasicHttpClientConnectionManager Connection Reuse
|
||||||
@Test
|
@Test
|
||||||
public final void givenBasicHttpClientConnManager_whenConnectionReuse_thenNoExceptions() throws IOException, HttpException, InterruptedException, ExecutionException {
|
public final void givenBasicHttpClientConnManager_whenConnectionReuse_thenNoExceptions() throws InterruptedException, ExecutionException, TimeoutException, IOException, URISyntaxException {
|
||||||
BasicHttpClientConnectionManager basicConnManager = new BasicHttpClientConnectionManager();
|
BasicHttpClientConnectionManager connMgr = new BasicHttpClientConnectionManager();
|
||||||
HttpClientContext context = HttpClientContext.create();
|
|
||||||
|
|
||||||
// low level
|
|
||||||
HttpRoute route = new HttpRoute(new HttpHost("www.baeldung.com", 443));
|
HttpRoute route = new HttpRoute(new HttpHost("www.baeldung.com", 443));
|
||||||
ConnectionRequest connRequest = basicConnManager.requestConnection(route, null);
|
final HttpContext context = new BasicHttpContext();
|
||||||
HttpClientConnection conn = connRequest.get(10, TimeUnit.SECONDS);
|
|
||||||
basicConnManager.connect(conn, route, 1000, context);
|
|
||||||
basicConnManager.routeComplete(conn, route, context);
|
|
||||||
|
|
||||||
HttpRequestExecutor exeRequest = new HttpRequestExecutor();
|
final LeaseRequest connRequest = connMgr.lease("some-id", route, null);
|
||||||
context.setTargetHost((new HttpHost("www.baeldung.com", 80)));
|
final ConnectionEndpoint endpoint = connRequest.get(Timeout.ZERO_MILLISECONDS);
|
||||||
HttpGet get = new HttpGet("http://www.baeldung.com");
|
connMgr.connect(endpoint, Timeout.ZERO_MILLISECONDS, context);
|
||||||
exeRequest.execute(get, conn, context);
|
|
||||||
|
|
||||||
basicConnManager.releaseConnection(conn, null, 1, TimeUnit.SECONDS);
|
connMgr.release(endpoint, null, TimeValue.ZERO_MILLISECONDS);
|
||||||
|
|
||||||
// high level
|
|
||||||
CloseableHttpClient client = HttpClients.custom()
|
CloseableHttpClient client = HttpClients.custom()
|
||||||
.setConnectionManager(basicConnManager)
|
.setConnectionManager(connMgr)
|
||||||
.build();
|
.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
|
// Example 6.2. PoolingHttpClientConnectionManager: Re-Using Connections with Threads
|
||||||
@Test
|
@Test
|
||||||
public final void whenConnectionsNeededGreaterThanMaxTotal_thenLeaseMasTotalandReuse() throws InterruptedException {
|
public final void whenConnectionsNeededGreaterThanMaxTotal_thenLeaseMasTotalandReuse() throws InterruptedException, IOException {
|
||||||
HttpGet get = new HttpGet("http://echo.200please.com");
|
HttpGet get = new HttpGet("http://www.baeldung.com");
|
||||||
PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();
|
PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();
|
||||||
connManager.setDefaultMaxPerRoute(5);
|
connManager.setDefaultMaxPerRoute(6);
|
||||||
connManager.setMaxTotal(5);
|
connManager.setMaxTotal(6);
|
||||||
CloseableHttpClient client = HttpClients.custom()
|
CloseableHttpClient client = HttpClients.custom()
|
||||||
.setConnectionManager(connManager)
|
.setConnectionManager(connManager)
|
||||||
.build();
|
.build();
|
||||||
|
@ -193,48 +202,71 @@ public class HttpClientConnectionManagementLiveTest {
|
||||||
for (MultiHttpClientConnThread thread : threads) {
|
for (MultiHttpClientConnThread thread : threads) {
|
||||||
thread.join(1000);
|
thread.join(1000);
|
||||||
}
|
}
|
||||||
|
client.close();
|
||||||
|
connManager.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Example 7.1. Setting Socket Timeout to 5 Seconds
|
// Example 7.1. Setting Socket Timeout to 5 Seconds
|
||||||
@Test
|
@Test
|
||||||
public final void whenConfiguringTimeOut_thenNoExceptions() {
|
public final void whenConfiguringTimeOut_thenNoExceptions() throws ExecutionException, InterruptedException, TimeoutException, IOException {
|
||||||
HttpRoute route = new HttpRoute(new HttpHost("www.baeldung.com", 80));
|
final HttpRoute route = new HttpRoute(new HttpHost("www.baeldung.com", 80));
|
||||||
try (PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager()) {
|
final HttpContext context = new BasicHttpContext();
|
||||||
connManager.setSocketConfig(route.getTargetHost(), SocketConfig.custom()
|
final PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();
|
||||||
.setSoTimeout(5000)
|
|
||||||
.build());
|
final ConnectionConfig connConfig = ConnectionConfig.custom()
|
||||||
assertTrue(connManager.getSocketConfig(route.getTargetHost())
|
.setSocketTimeout(5, TimeUnit.SECONDS)
|
||||||
.getSoTimeout() == 5000);
|
.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
|
// Example 8.1. Setting the HttpClient to Check for Stale Connections
|
||||||
@Test
|
@Test
|
||||||
public final void whenHttpClientChecksStaleConns_thenNoExceptions() {
|
public final void whenEvictIdealConn_thenNoExceptions() throws InterruptedException, IOException {
|
||||||
PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();
|
final PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();
|
||||||
HttpClients.custom()
|
connManager.setMaxTotal(100);
|
||||||
.setDefaultRequestConfig(RequestConfig.custom()
|
try (final CloseableHttpClient httpclient = HttpClients.custom()
|
||||||
.setStaleConnectionCheckEnabled(true)
|
|
||||||
.build())
|
|
||||||
.setConnectionManager(connManager)
|
.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
|
for (final String requestURI : urisToGet) {
|
||||||
@Test
|
final HttpGet request = new HttpGet(requestURI);
|
||||||
public final void whenCustomizedIdleConnMonitor_thenNoExceptions() throws InterruptedException {
|
|
||||||
PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();
|
System.out.println("Executing request " + request.getMethod() + " " + request.getRequestUri());
|
||||||
HttpClients.custom()
|
|
||||||
.setConnectionManager(connManager)
|
httpclient.execute(request, response -> {
|
||||||
.build();
|
System.out.println("----------------------------------------");
|
||||||
IdleConnectionMonitorThread staleMonitor = new IdleConnectionMonitorThread(connManager);
|
System.out.println(request + "->" + new StatusLine(response));
|
||||||
staleMonitor.start();
|
EntityUtils.consume(response.getEntity());
|
||||||
staleMonitor.join(1000);
|
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
|
// Example 9.1. Closing Connection and Releasing Resources
|
||||||
@Test(expected = IllegalStateException.class)
|
@Test
|
||||||
public final void whenClosingConnectionsandManager_thenCloseWithNoExceptions1() throws InterruptedException, ExecutionException, IOException, HttpException {
|
public final void whenClosingConnectionsandManager_thenCloseWithNoExceptions1() throws IOException {
|
||||||
PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();
|
PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();
|
||||||
CloseableHttpClient client = HttpClients.custom()
|
CloseableHttpClient client = HttpClients.custom()
|
||||||
.setConnectionManager(connManager)
|
.setConnectionManager(connManager)
|
||||||
|
@ -246,16 +278,11 @@ public class HttpClientConnectionManagementLiveTest {
|
||||||
response.close();
|
response.close();
|
||||||
client.close();
|
client.close();
|
||||||
connManager.close();
|
connManager.close();
|
||||||
connManager.shutdown();
|
|
||||||
|
|
||||||
client.execute(get);
|
|
||||||
|
|
||||||
assertTrue(response.getEntity() == null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
// Example 3.2. TESTER VERSION
|
// 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 get1 = new HttpGet("https://www.baeldung.com");
|
||||||
HttpGet get2 = new HttpGet("https://www.google.com");
|
HttpGet get2 = new HttpGet("https://www.google.com");
|
||||||
|
|
||||||
|
@ -273,77 +300,11 @@ public class HttpClientConnectionManagementLiveTest {
|
||||||
thread2.start();
|
thread2.start();
|
||||||
thread1.join();
|
thread1.join();
|
||||||
thread2.join(1000);
|
thread2.join(1000);
|
||||||
assertTrue(poolingConnManager.getTotalStats()
|
Assert.assertTrue(poolingConnManager.getTotalStats()
|
||||||
.getLeased() == 2);
|
.getLeased() == 2);
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
client1.close();
|
||||||
// Example 4.2 Tester Version
|
client2.close();
|
||||||
public final void whenExecutingSameRequestsInDifferentThreads_thenUseDefaultConnLimit() throws InterruptedException {
|
poolingConnManager.close();
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,12 @@ package com.baeldung.httpclient.conn;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import org.apache.http.HttpResponse;
|
import org.apache.hc.client5.http.classic.methods.HttpGet;
|
||||||
import org.apache.http.client.ClientProtocolException;
|
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
|
||||||
import org.apache.http.client.methods.HttpGet;
|
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
|
||||||
import org.apache.http.impl.client.CloseableHttpClient;
|
import org.apache.hc.core5.http.HttpEntity;
|
||||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
import org.apache.hc.core5.http.HttpResponse;
|
||||||
import org.apache.http.util.EntityUtils;
|
import org.apache.hc.core5.http.io.entity.EntityUtils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
@ -45,22 +45,21 @@ public class MultiHttpClientConnThread extends Thread {
|
||||||
try {
|
try {
|
||||||
logger.debug("Thread Running: " + getName());
|
logger.debug("Thread Running: " + getName());
|
||||||
|
|
||||||
logger.debug("Thread Running: " + getName());
|
|
||||||
|
|
||||||
if (connManager != null) {
|
if (connManager != null) {
|
||||||
logger.info("Before - Leased Connections = " + connManager.getTotalStats().getLeased());
|
logger.info("Before - Leased Connections = " + connManager.getTotalStats().getLeased());
|
||||||
logger.info("Before - Available Connections = " + connManager.getTotalStats().getAvailable());
|
logger.info("Before - Available Connections = " + connManager.getTotalStats().getAvailable());
|
||||||
}
|
}
|
||||||
|
|
||||||
final HttpResponse response = client.execute(get);
|
HttpEntity entity = client.execute(get).getEntity();
|
||||||
|
|
||||||
if (connManager != null) {
|
if (connManager != null) {
|
||||||
leasedConn = connManager.getTotalStats().getLeased();
|
leasedConn = connManager.getTotalStats().getLeased();
|
||||||
logger.info("After - Leased Connections = " + connManager.getTotalStats().getLeased());
|
logger.info("After - Leased Connections = " + connManager.getTotalStats().getLeased());
|
||||||
logger.info("After - Available Connections = " + connManager.getTotalStats().getAvailable());
|
logger.info("After - Available Connections = " + connManager.getTotalStats().getAvailable());
|
||||||
}
|
}
|
||||||
|
EntityUtils.consume(entity);
|
||||||
|
|
||||||
EntityUtils.consume(response.getEntity());
|
|
||||||
} catch (final IOException ex) {
|
} catch (final IOException ex) {
|
||||||
logger.error("", ex);
|
logger.error("", ex);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,9 @@ package com.baeldung.httpclient.conn;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import org.apache.http.client.ClientProtocolException;
|
import org.apache.hc.client5.http.classic.methods.HttpGet;
|
||||||
import org.apache.http.client.methods.HttpGet;
|
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
|
||||||
import org.apache.http.impl.client.CloseableHttpClient;
|
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
|
||||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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)
|
- [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)
|
- [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)
|
- [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)
|
||||||
|
|
|
@ -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)
|
- [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)
|
- [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)
|
- [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)
|
- More articles: [[<-- prev]](../apache-poi)
|
||||||
|
|
|
@ -2,26 +2,21 @@
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<parent>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-parent</artifactId>
|
|
||||||
<version>3.1.2</version>
|
|
||||||
<relativePath/> <!-- lookup parent from repository -->
|
|
||||||
</parent>
|
|
||||||
<groupId>com.baeldung</groupId>
|
|
||||||
<artifactId>aws-s3-update-object</artifactId>
|
<artifactId>aws-s3-update-object</artifactId>
|
||||||
<version>0.0.1-SNAPSHOT</version>
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
<name>aws-s3-update-object</name>
|
<name>aws-s3-update-object</name>
|
||||||
<description>Project demonstrating overwriting of S3 objects</description>
|
<description>Project demonstrating overwriting of S3 objects</description>
|
||||||
<properties>
|
<parent>
|
||||||
<java.version>17</java.version>
|
<groupId>com.baeldung</groupId>
|
||||||
</properties>
|
<artifactId>parent-boot-2</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<relativePath>../../parent-boot-2</relativePath>
|
||||||
|
</parent>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-web</artifactId>
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-test</artifactId>
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
@ -30,10 +25,9 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.amazonaws</groupId>
|
<groupId>com.amazonaws</groupId>
|
||||||
<artifactId>aws-java-sdk</artifactId>
|
<artifactId>aws-java-sdk</artifactId>
|
||||||
<version>1.12.523</version>
|
<version>${aws-java-sdk-version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
|
@ -42,5 +36,7 @@
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
<properties>
|
||||||
|
<aws-java-sdk-version>1.12.523</aws-java-sdk-version>
|
||||||
|
</properties>
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -7,13 +7,13 @@ import com.amazonaws.regions.Regions;
|
||||||
import com.amazonaws.services.s3.AmazonS3;
|
import com.amazonaws.services.s3.AmazonS3;
|
||||||
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
|
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
|
||||||
import com.amazonaws.services.s3.model.*;
|
import com.amazonaws.services.s3.model.*;
|
||||||
import jakarta.annotation.PostConstruct;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
|
@ -11,6 +11,7 @@ import org.springframework.test.web.servlet.MockMvc;
|
||||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.mockito.Mockito.*;
|
import static org.mockito.Mockito.*;
|
||||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
|
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.status;
|
||||||
|
@ -34,28 +35,28 @@ public class FileControllerUnitTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void givenValidMultipartFile_whenUploadedViaEndpoint_thenCorrectPathIsReturned() throws Exception {
|
public void givenValidMultipartFile_whenUploadedViaEndpoint_thenCorrectPathIsReturned() throws Exception {
|
||||||
MockMultipartFile multipartFile = new MockMultipartFile("multipartFile", "test.txt",
|
MockMultipartFile multipartFile = new MockMultipartFile("file", "test.txt", "text/plain", "sample file content".getBytes());
|
||||||
"text/plain", "test data".getBytes());
|
String expectedResult = "File Uploaded Successfully";
|
||||||
|
|
||||||
when(fileService.uploadFile(any(MultipartFile.class))).thenReturn("/documents/test.txt");
|
when(fileService.uploadFile(multipartFile)).thenReturn(expectedResult);
|
||||||
|
|
||||||
mockMvc.perform(multipart("/file/upload").file(multipartFile))
|
mockMvc.perform(multipart("/api/v1/file/upload").file(multipartFile))
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andExpect(content().string("/documents/test.txt"));
|
.andExpect(content().string(expectedResult));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void givenValidMultipartFileAndExistingPath_whenUpdatedViaEndpoint_thenSamePathIsReturned() throws Exception {
|
public void givenValidMultipartFileAndExistingPath_whenUpdatedViaEndpoint_thenSamePathIsReturned() throws Exception {
|
||||||
MockMultipartFile multipartFile = new MockMultipartFile("multipartFile", "test.txt",
|
MockMultipartFile multipartFile = new MockMultipartFile("file", "test.txt", "text/plain", "updated file content".getBytes());
|
||||||
"text/plain", "test update data".getBytes());
|
String filePath = "some/path/to/file";
|
||||||
String existingFilePath = "/documents/existingFile.txt";
|
String expectedResult = "File Updated Successfully";
|
||||||
|
|
||||||
when(fileService.updateFile(any(MultipartFile.class), eq(existingFilePath))).thenReturn(existingFilePath);
|
when(fileService.updateFile(multipartFile, filePath)).thenReturn(expectedResult);
|
||||||
|
|
||||||
mockMvc.perform(multipart("/file/update")
|
mockMvc.perform(multipart("/api/v1/file/update")
|
||||||
.file(multipartFile)
|
.file(multipartFile)
|
||||||
.param("exitingFilePath", existingFilePath))
|
.param("filePath", filePath))
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andExpect(content().string(existingFilePath));
|
.andExpect(content().string(expectedResult));
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -41,6 +41,7 @@ public class FileServiceUnitTest {
|
||||||
@Test
|
@Test
|
||||||
public void givenValidFile_whenUploaded_thenKeyMatchesDocumentPath() throws Exception {
|
public void givenValidFile_whenUploaded_thenKeyMatchesDocumentPath() throws Exception {
|
||||||
when(multipartFile.getName()).thenReturn("testFile");
|
when(multipartFile.getName()).thenReturn("testFile");
|
||||||
|
when(multipartFile.getOriginalFilename()).thenReturn("testFile");
|
||||||
when(multipartFile.getContentType()).thenReturn("application/pdf");
|
when(multipartFile.getContentType()).thenReturn("application/pdf");
|
||||||
when(multipartFile.getSize()).thenReturn(1024L);
|
when(multipartFile.getSize()).thenReturn(1024L);
|
||||||
when(multipartFile.getInputStream()).thenReturn(mock(InputStream.class));
|
when(multipartFile.getInputStream()).thenReturn(mock(InputStream.class));
|
||||||
|
@ -57,6 +58,7 @@ public class FileServiceUnitTest {
|
||||||
@Test
|
@Test
|
||||||
public void givenValidFile_whenUploadFailsDueToNoBucket_thenExceptionIsThrown() throws Exception {
|
public void givenValidFile_whenUploadFailsDueToNoBucket_thenExceptionIsThrown() throws Exception {
|
||||||
when(multipartFile.getName()).thenReturn("testFile");
|
when(multipartFile.getName()).thenReturn("testFile");
|
||||||
|
when(multipartFile.getOriginalFilename()).thenReturn("testFile");
|
||||||
when(multipartFile.getContentType()).thenReturn("application/pdf");
|
when(multipartFile.getContentType()).thenReturn("application/pdf");
|
||||||
when(multipartFile.getSize()).thenReturn(1024L);
|
when(multipartFile.getSize()).thenReturn(1024L);
|
||||||
when(multipartFile.getInputStream()).thenReturn(mock(InputStream.class));
|
when(multipartFile.getInputStream()).thenReturn(mock(InputStream.class));
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
<module>aws-miscellaneous</module>
|
<module>aws-miscellaneous</module>
|
||||||
<module>aws-reactive</module>
|
<module>aws-reactive</module>
|
||||||
<module>aws-s3</module>
|
<module>aws-s3</module>
|
||||||
|
<module>aws-s3-update-object</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
|
|
|
@ -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)
|
- [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)
|
- [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)
|
- [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)
|
||||||
|
|
|
@ -12,4 +12,5 @@ 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)
|
- [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)
|
- [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 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)
|
||||||
- More articles: [[<-- prev]](../core-java-collections-conversions)
|
- More articles: [[<-- prev]](../core-java-collections-conversions)
|
||||||
|
|
|
@ -8,3 +8,4 @@
|
||||||
- [How to Modify a Key in a HashMap?](https://www.baeldung.com/java-hashmap-modify-key)
|
- [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)
|
- [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)
|
- [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)
|
||||||
|
|
|
@ -3,3 +3,4 @@
|
||||||
This module contains articles about Java Conditionals.
|
This module contains articles about Java Conditionals.
|
||||||
|
|
||||||
### Relevant articles:
|
### Relevant articles:
|
||||||
|
- [Guide to the yield Keyword in Java](https://www.baeldung.com/java-yield-switch)
|
||||||
|
|
|
@ -8,3 +8,4 @@ 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 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 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)
|
- [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)
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,25 +1,33 @@
|
||||||
package com.baeldung.socketexception;
|
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.io.IOException;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
import javax.net.ssl.SSLServerSocket;
|
||||||
|
import javax.net.ssl.SSLServerSocketFactory;
|
||||||
|
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
public class SocketExceptionHandlingUnitTest {
|
public class SocketExceptionHandlingUnitTest {
|
||||||
|
private static final int PORT = 6699;
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void runServer() throws IOException, InterruptedException {
|
public static void runServer() throws IOException, InterruptedException {
|
||||||
Executors.newSingleThreadExecutor()
|
Executors.newSingleThreadExecutor()
|
||||||
.submit(() -> new SocketServer().start(6699));
|
.submit(() -> new SocketServer().start(PORT));
|
||||||
Thread.sleep(100);
|
Thread.sleep(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void givenRunningServer_whenConnectToClosedSocket_thenHandleException() throws IOException {
|
public void givenRunningServer_whenConnectToClosedSocket_thenHandleException() throws IOException {
|
||||||
SocketClient client = new SocketClient();
|
SocketClient client = new SocketClient();
|
||||||
client.startConnection("127.0.0.1", 6699);
|
client.startConnection("127.0.0.1", PORT);
|
||||||
try {
|
try {
|
||||||
client.sendMessage("hi");
|
client.sendMessage("hi");
|
||||||
client.sendMessage("hi again");
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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> T getByRandomClass(Set<T> 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> T getByThreadLocalRandom(Set<T> 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<String> animals = new HashSet<>();
|
||||||
|
animals.add("Lion");
|
||||||
|
animals.add("Elephant");
|
||||||
|
animals.add("Giraffe");
|
||||||
|
|
||||||
|
String randomAnimal = getByThreadLocalRandom(animals);
|
||||||
|
System.out.println("Randomly picked animal: " + randomAnimal);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
## Relevant Articles
|
||||||
|
- [Creating a Magic Square in Java](https://www.baeldung.com/java-magic-square)
|
|
@ -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)
|
- [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 conversion”](https://www.baeldung.com/java-unchecked-conversion)
|
||||||
- [Java Warning “Unchecked Cast”](https://www.baeldung.com/java-warning-unchecked-cast)
|
- [Java Warning “Unchecked Cast”](https://www.baeldung.com/java-warning-unchecked-cast)
|
||||||
|
- [What Does the Holder<T> Class Do in Java?](https://www.baeldung.com/java-holder-class)
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
package com.baeldung.subclassinnerclass;
|
package com.baeldung.subclassinnerclass;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
|
|
||||||
public class EmailNotifier extends Notifier {
|
public class EmailNotifier extends Notifier {
|
||||||
@Override
|
@Override
|
||||||
void notify(Message e) {
|
void notify(Message e) {
|
||||||
// Provide email specific implementation here
|
// connect to the email connector
|
||||||
|
EmailConnector emailConnector = new EmailConnector();
|
||||||
|
emailConnector.connect();
|
||||||
|
// send email
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inner class for email connection
|
// Inner class for email connection
|
||||||
|
@ -13,5 +14,9 @@ public class EmailNotifier extends Notifier {
|
||||||
private String emailHost;
|
private String emailHost;
|
||||||
private int emailPort;
|
private int emailPort;
|
||||||
// Getter Setters
|
// Getter Setters
|
||||||
|
|
||||||
|
private void connect() {
|
||||||
|
// connect to the smtp server
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package com.baeldung.deepcopyarraylist;
|
package com.baeldung.deepcopyarraylist;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
public class Course implements Serializable, Cloneable {
|
public class Course implements Serializable, Cloneable {
|
||||||
|
|
||||||
|
@ -39,4 +40,23 @@ public class Course implements Serializable, Cloneable {
|
||||||
throw new IllegalStateException(e);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package com.baeldung.deepcopyarraylist;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.apache.commons.lang3.SerializationUtils;
|
import org.apache.commons.lang3.SerializationUtils;
|
||||||
|
@ -100,4 +101,23 @@ public class Student implements Serializable, Cloneable {
|
||||||
student.course = this.course.clone();
|
student.course = this.course.clone();
|
||||||
return student;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,8 +19,10 @@ public class DeepCopyArrayListUnitTest {
|
||||||
|
|
||||||
List<Student> deepCopy = Student.deepCopyUsingCloneable(students);
|
List<Student> deepCopy = Student.deepCopyUsingCloneable(students);
|
||||||
|
|
||||||
Assertions.assertNotEquals(students.get(0), deepCopy.get(0));
|
Assertions.assertEquals(students.get(0), deepCopy.get(0));
|
||||||
Assertions.assertNotEquals(students.get(1), deepCopy.get(1));
|
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<Student> deepCopy = Student.deepCopyUsingCopyConstructor(students);
|
List<Student> deepCopy = Student.deepCopyUsingCopyConstructor(students);
|
||||||
|
|
||||||
Assertions.assertNotEquals(students.get(0), deepCopy.get(0));
|
Assertions.assertEquals(students.get(0), deepCopy.get(0));
|
||||||
Assertions.assertNotEquals(students.get(1), deepCopy.get(1));
|
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
|
@Test
|
||||||
|
@ -54,8 +58,10 @@ public class DeepCopyArrayListUnitTest {
|
||||||
|
|
||||||
List<Student> deepCopy = Student.deepCopyUsingSerialization(students);
|
List<Student> deepCopy = Student.deepCopyUsingSerialization(students);
|
||||||
|
|
||||||
Assertions.assertNotEquals(students.get(0), deepCopy.get(0));
|
Assertions.assertEquals(students.get(0), deepCopy.get(0));
|
||||||
Assertions.assertNotEquals(students.get(1), deepCopy.get(1));
|
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
|
@Test
|
||||||
|
@ -71,7 +77,9 @@ public class DeepCopyArrayListUnitTest {
|
||||||
|
|
||||||
List<Student> deepCopy = Student.deepCopyUsingJackson(students);
|
List<Student> deepCopy = Student.deepCopyUsingJackson(students);
|
||||||
|
|
||||||
Assertions.assertNotEquals(students.get(0), deepCopy.get(0));
|
Assertions.assertEquals(students.get(0), deepCopy.get(0));
|
||||||
Assertions.assertNotEquals(students.get(1), deepCopy.get(1));
|
Assertions.assertNotSame(students.get(0),deepCopy.get(0));
|
||||||
|
Assertions.assertEquals(students.get(1), deepCopy.get(1));
|
||||||
|
Assertions.assertNotSame(students.get(1),deepCopy.get(1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,13 +30,13 @@ public class Java8ComparatorUnitTest {
|
||||||
System.out.println("************** Java 8 Comaparator **************");
|
System.out.println("************** Java 8 Comaparator **************");
|
||||||
Comparator<Player> byRanking = (Player player1, Player player2) -> Integer.compare(player1.getRanking(), player2.getRanking());
|
Comparator<Player> byRanking = (Player player1, Player player2) -> Integer.compare(player1.getRanking(), player2.getRanking());
|
||||||
|
|
||||||
System.out.println("Before Sorting : " + footballTeam);
|
|
||||||
Collections.sort(footballTeam, byRanking);
|
Collections.sort(footballTeam, byRanking);
|
||||||
System.out.println("After Sorting : " + footballTeam);
|
assertEquals(footballTeam.get(0).getName(), "Steven");
|
||||||
assertEquals(footballTeam.get(0)
|
assertEquals(footballTeam.get(0).getRanking(), 45);
|
||||||
.getName(), "Steven");
|
assertEquals(footballTeam.get(1).getName(), "John");
|
||||||
assertEquals(footballTeam.get(2)
|
assertEquals(footballTeam.get(1).getRanking(), 59);
|
||||||
.getRanking(), 67);
|
assertEquals(footballTeam.get(2).getName(), "Roger");
|
||||||
|
assertEquals(footballTeam.get(2).getRanking(), 67);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -45,24 +45,24 @@ public class Java8ComparatorUnitTest {
|
||||||
System.out.println("********* byRanking *********");
|
System.out.println("********* byRanking *********");
|
||||||
Comparator<Player> byRanking = Comparator.comparing(Player::getRanking);
|
Comparator<Player> byRanking = Comparator.comparing(Player::getRanking);
|
||||||
|
|
||||||
System.out.println("Before Sorting : " + footballTeam);
|
|
||||||
Collections.sort(footballTeam, byRanking);
|
Collections.sort(footballTeam, byRanking);
|
||||||
System.out.println("After Sorting : " + footballTeam);
|
assertEquals(footballTeam.get(0).getName(), "Steven");
|
||||||
assertEquals(footballTeam.get(0)
|
assertEquals(footballTeam.get(0).getRanking(), 45);
|
||||||
.getName(), "Steven");
|
assertEquals(footballTeam.get(1).getName(), "John");
|
||||||
assertEquals(footballTeam.get(2)
|
assertEquals(footballTeam.get(1).getRanking(), 59);
|
||||||
.getRanking(), 67);
|
assertEquals(footballTeam.get(2).getName(), "Roger");
|
||||||
|
assertEquals(footballTeam.get(2).getRanking(), 67);
|
||||||
|
|
||||||
System.out.println("********* byAge *********");
|
System.out.println("********* byAge *********");
|
||||||
Comparator<Player> byAge = Comparator.comparing(Player::getAge);
|
Comparator<Player> byAge = Comparator.comparing(Player::getAge);
|
||||||
|
|
||||||
System.out.println("Before Sorting : " + footballTeam);
|
|
||||||
Collections.sort(footballTeam, byAge);
|
Collections.sort(footballTeam, byAge);
|
||||||
System.out.println("After Sorting : " + footballTeam);
|
assertEquals(footballTeam.get(0).getName(), "Roger");
|
||||||
assertEquals(footballTeam.get(0)
|
assertEquals(footballTeam.get(0).getAge(), 20);
|
||||||
.getName(), "Roger");
|
assertEquals(footballTeam.get(1).getName(), "John");
|
||||||
assertEquals(footballTeam.get(2)
|
assertEquals(footballTeam.get(1).getAge(), 22);
|
||||||
.getRanking(), 45);
|
assertEquals(footballTeam.get(2).getName(), "Steven");
|
||||||
|
assertEquals(footballTeam.get(2).getAge(), 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
## Relevant Articles
|
## Relevant Articles
|
||||||
- [Object.toString() vs String.valueOf()](https://www.baeldung.com/java-object-tostring-vs-string-valueof)
|
- [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)
|
- [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)
|
||||||
|
|
|
@ -4,4 +4,4 @@ This module contains articles about Avaje
|
||||||
|
|
||||||
### Relevant articles:
|
### Relevant articles:
|
||||||
|
|
||||||
- [Introduction to Avaje Inject](https://www.baeldung.com/avaje-inject/intro)
|
- [Introduction to Avaje Inject](https://www.baeldung.com/avaje-inject)
|
||||||
|
|
|
@ -7,4 +7,5 @@ This module contains articles about Bean Validation.
|
||||||
- [Guide to ParameterMessageInterpolator](https://www.baeldung.com/hibernate-parametermessageinterpolator)
|
- [Guide to ParameterMessageInterpolator](https://www.baeldung.com/hibernate-parametermessageinterpolator)
|
||||||
- [Hibernate Validator Annotation Processor in Depth](https://www.baeldung.com/hibernate-validator-annotation-processor)
|
- [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)
|
- [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)
|
- More articles: [[<-- prev]](../javaxval)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
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">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<artifactId>json-2</artifactId>
|
<artifactId>json-2</artifactId>
|
||||||
<version>0.0.1-SNAPSHOT</version>
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
@ -123,6 +123,26 @@
|
||||||
<artifactId>javax.annotation-api</artifactId>
|
<artifactId>javax.annotation-api</artifactId>
|
||||||
<version>1.3.2</version>
|
<version>1.3.2</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.victools</groupId>
|
||||||
|
<artifactId>jsonschema-generator</artifactId>
|
||||||
|
<version>${jsonschema-generator.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.victools</groupId>
|
||||||
|
<artifactId>jsonschema-module-jackson</artifactId>
|
||||||
|
<version>${jsonschema-generator.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>jakarta.validation</groupId>
|
||||||
|
<artifactId>jakarta.validation-api</artifactId>
|
||||||
|
<version>${jakarta.validation.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.victools</groupId>
|
||||||
|
<artifactId>jsonschema-module-jakarta-validation</artifactId>
|
||||||
|
<version>${jsonschema-generator.version}</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
@ -162,6 +182,55 @@
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</pluginManagement>
|
</pluginManagement>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>com.github.victools</groupId>
|
||||||
|
<artifactId>jsonschema-maven-plugin</artifactId>
|
||||||
|
<version>${jsonschema-generator.version}</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>generate</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
<configuration>
|
||||||
|
<packageNames>
|
||||||
|
<packageName>com.baeldung.jsonschemageneration.plugin</packageName>
|
||||||
|
</packageNames>
|
||||||
|
<classNames>
|
||||||
|
<className>com.baeldung.jsonschemageneration.plugin.Person</className>
|
||||||
|
</classNames>
|
||||||
|
<schemaVersion>DRAFT_2020_12</schemaVersion>
|
||||||
|
<schemaFilePath>src/main/resources/schemas</schemaFilePath>
|
||||||
|
<schemaFileName>{1}/{0}.json</schemaFileName>
|
||||||
|
<failIfNoClassesMatch>true</failIfNoClassesMatch>
|
||||||
|
<options>
|
||||||
|
<preset>PLAIN_JSON</preset>
|
||||||
|
<enabled>
|
||||||
|
<option>DEFINITIONS_FOR_ALL_OBJECTS</option>
|
||||||
|
<option>FORBIDDEN_ADDITIONAL_PROPERTIES_BY_DEFAULT</option>
|
||||||
|
</enabled>
|
||||||
|
<disabled>SCHEMA_VERSION_INDICATOR</disabled>
|
||||||
|
</options>
|
||||||
|
<modules>
|
||||||
|
<module>
|
||||||
|
<name>Jackson</name>
|
||||||
|
<options>
|
||||||
|
<option>RESPECT_JSONPROPERTY_REQUIRED</option>
|
||||||
|
</options>
|
||||||
|
</module>
|
||||||
|
<module>
|
||||||
|
<name>JakartaValidation</name>
|
||||||
|
<options>
|
||||||
|
<option>NOT_NULLABLE_FIELD_IS_REQUIRED</option>
|
||||||
|
<option>INCLUDE_PATTERN_EXPRESSIONS</option>
|
||||||
|
</options>
|
||||||
|
</module>
|
||||||
|
</modules>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
|
@ -173,6 +242,8 @@
|
||||||
<jackson-jsonld.version>0.1.1</jackson-jsonld.version>
|
<jackson-jsonld.version>0.1.1</jackson-jsonld.version>
|
||||||
<hydra-jsonld.version>0.4.2</hydra-jsonld.version>
|
<hydra-jsonld.version>0.4.2</hydra-jsonld.version>
|
||||||
<jsonld-java.version>0.13.0</jsonld-java.version>
|
<jsonld-java.version>0.13.0</jsonld-java.version>
|
||||||
|
<jsonschema-generator.version>4.31.1</jsonschema-generator.version>
|
||||||
|
<jakarta.validation.version>3.0.2</jakarta.validation.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
</project>
|
</project>
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
|
@ -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());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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<Person> friends;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Address {
|
||||||
|
|
||||||
|
@JsonProperty()
|
||||||
|
String street;
|
||||||
|
|
||||||
|
@JsonProperty(required = true)
|
||||||
|
String city;
|
||||||
|
|
||||||
|
@JsonProperty(required = true)
|
||||||
|
String country;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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<Person> friends;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Address {
|
||||||
|
|
||||||
|
@Null String street;
|
||||||
|
|
||||||
|
@NotNull String city;
|
||||||
|
|
||||||
|
@NotNull String country;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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<Person> friends;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class Address {
|
||||||
|
|
||||||
|
@Null
|
||||||
|
@JsonProperty
|
||||||
|
String street;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@JsonProperty(required = true)
|
||||||
|
String city;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@JsonProperty(required = true)
|
||||||
|
String country;
|
||||||
|
}
|
|
@ -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<AuthoredArticle> articles;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
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">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>org.baeldung</groupId>
|
||||||
|
<artifactId>json-arrays</artifactId>
|
||||||
|
<name>json-arrays</name>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>com.baeldung</groupId>
|
||||||
|
<artifactId>json-modules</artifactId>
|
||||||
|
<version>1.0.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.json</groupId>
|
||||||
|
<artifactId>json</artifactId>
|
||||||
|
<version>${json.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.code.gson</groupId>
|
||||||
|
<artifactId>gson</artifactId>
|
||||||
|
<version>${gson.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-databind</artifactId>
|
||||||
|
<version>${jackson.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.json.bind</groupId>
|
||||||
|
<artifactId>javax.json.bind-api</artifactId>
|
||||||
|
<version>${jsonb-api.version}</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<jsonb-api.version>1.0</jsonb-api.version>
|
||||||
|
<json.version>20230227</json.version>
|
||||||
|
<gson.version>2.8.5</gson.version>
|
||||||
|
<javax.version>1.1.2</javax.version>
|
||||||
|
<json-unit-assertj.version>2.28.0</json-unit-assertj.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
</project>
|
|
@ -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<JsonNode> 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<JsonElement> 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -16,6 +16,7 @@
|
||||||
<modules>
|
<modules>
|
||||||
<module>json</module>
|
<module>json</module>
|
||||||
<module>json-2</module>
|
<module>json-2</module>
|
||||||
|
<module>json-arrays</module>
|
||||||
<module>json-conversion</module>
|
<module>json-conversion</module>
|
||||||
<module>json-path</module>
|
<module>json-path</module>
|
||||||
<module>gson</module>
|
<module>gson</module>
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
## Relevant Articles
|
||||||
|
- [Guide to Eclipse JKube](https://www.baeldung.com/ops/eclipse-jkube)
|
|
@ -25,10 +25,58 @@
|
||||||
<artifactId>jackson-databind</artifactId>
|
<artifactId>jackson-databind</artifactId>
|
||||||
<version>${jackson.version}</version>
|
<version>${jackson.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.code.gson</groupId>
|
||||||
|
<artifactId>gson</artifactId>
|
||||||
|
<version>${gson.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.annotation</groupId>
|
||||||
|
<artifactId>javax.annotation-api</artifactId>
|
||||||
|
<version>${javax.annotation}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.swagger</groupId>
|
||||||
|
<artifactId>swagger-annotations</artifactId>
|
||||||
|
<version>${swagger.annotation}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-web</artifactId>
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.openapitools</groupId>
|
||||||
|
<artifactId>openapi-generator-maven-plugin</artifactId>
|
||||||
|
<version>${openapi.version}</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>generate</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<inputSpec>${project.basedir}/src/main/resources/bookapi.yml</inputSpec>
|
||||||
|
<generatorName>java</generatorName>
|
||||||
|
<modelPackage>com.baeldung.openapi.model</modelPackage>
|
||||||
|
<configOptions>
|
||||||
|
<additionalModelTypeAnnotations>@lombok.Data @lombok.NoArgsConstructor @lombok.AllArgsConstructor</additionalModelTypeAnnotations>
|
||||||
|
</configOptions>
|
||||||
|
<generateApis>false</generateApis>
|
||||||
|
<generateSupportingFiles>false</generateSupportingFiles>
|
||||||
|
<generateApiDocumentation>false</generateApiDocumentation>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
<properties>
|
||||||
|
<openapi.version>4.2.3</openapi.version>
|
||||||
|
<gson.version>2.10.1</gson.version>
|
||||||
|
<javax.annotation>1.3.2</javax.annotation>
|
||||||
|
<swagger.annotation>1.6.2</swagger.annotation>
|
||||||
|
</properties>
|
||||||
|
|
||||||
</project>
|
</project>
|
|
@ -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;
|
||||||
|
|
||||||
|
}
|
|
@ -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
|
|
@ -43,7 +43,6 @@
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<lombok.version>edge-SNAPSHOT</lombok.version>
|
|
||||||
<hibernate-jpa-2.1-api.version>1.0.0.Final</hibernate-jpa-2.1-api.version>
|
<hibernate-jpa-2.1-api.version>1.0.0.Final</hibernate-jpa-2.1-api.version>
|
||||||
<delombok-maven-plugin.version>1.18.20.0</delombok-maven-plugin.version>
|
<delombok-maven-plugin.version>1.18.20.0</delombok-maven-plugin.version>
|
||||||
<annotations.version>23.0.0</annotations.version>
|
<annotations.version>23.0.0</annotations.version>
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<modules>
|
<modules>
|
||||||
<!--<module>lombok</module>--> <!-- Fixing in JAVA-24006 -->
|
<module>lombok</module>
|
||||||
<module>lombok-2</module>
|
<module>lombok-2</module>
|
||||||
<!-- <module>lombok-custom</module>--> <!-- this module uses legacy jdk-8 features (tools.jar), so can't upgrade to jdk9 or above-->
|
<!-- <module>lombok-custom</module>--> <!-- this module uses legacy jdk-8 features (tools.jar), so can't upgrade to jdk9 or above-->
|
||||||
</modules>
|
</modules>
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
## Relevant Articles
|
||||||
|
- [How to Speed Up Maven Build](https://www.baeldung.com/maven-fast-build)
|
|
@ -0,0 +1,2 @@
|
||||||
|
## Relevant Articles
|
||||||
|
- [Introduction to the Pants Build Tool](https://www.baeldung.com/ops/pants-build-tool-guide)
|
|
@ -70,6 +70,16 @@
|
||||||
<version>${assertj.version}</version>
|
<version>${assertj.version}</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mybatis</groupId>
|
||||||
|
<artifactId>mybatis</artifactId>
|
||||||
|
<version>${mybatis.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-jdbc</artifactId>
|
||||||
|
<version>${spring-jdbc.version}</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
|
@ -80,6 +90,8 @@
|
||||||
<json.version>20220320</json.version>
|
<json.version>20220320</json.version>
|
||||||
<microstream.storage.version>07.00.00-MS-GA</microstream.storage.version>
|
<microstream.storage.version>07.00.00-MS-GA</microstream.storage.version>
|
||||||
<h2.version>2.1.214</h2.version>
|
<h2.version>2.1.214</h2.version>
|
||||||
|
<spring-jdbc.version>5.3.29</spring-jdbc.version>
|
||||||
|
<mybatis.version>3.5.7</mybatis.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
</project>
|
</project>
|
|
@ -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));
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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<String> sqlStatements = parseSQLScript(scriptFilePath);
|
||||||
|
executeSQLBatches(connection, sqlStatements, batchSize);
|
||||||
|
}
|
||||||
|
private static List<String> parseSQLScript(String scriptFilePath) throws IOException {
|
||||||
|
List<String> 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<String> 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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
|
@ -82,7 +82,6 @@
|
||||||
<mysql.version>8.0.32</mysql.version>
|
<mysql.version>8.0.32</mysql.version>
|
||||||
<mariaDB4j.version>2.6.0</mariaDB4j.version>
|
<mariaDB4j.version>2.6.0</mariaDB4j.version>
|
||||||
<geodb.version>0.9</geodb.version>
|
<geodb.version>0.9</geodb.version>
|
||||||
<byte-buddy.version>1.14.2</byte-buddy.version>
|
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
</project>
|
</project>
|
|
@ -5,7 +5,7 @@ spring.datasource.password=
|
||||||
spring.jpa.hibernate.ddl-auto=create-drop
|
spring.jpa.hibernate.ddl-auto=create-drop
|
||||||
spring.h2.console.enabled=true
|
spring.h2.console.enabled=true
|
||||||
spring.h2.console.path=/h2-console
|
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.SQL=INFO
|
||||||
logging.level.org.hibernate.type=INFO
|
logging.level.org.hibernate.type=INFO
|
||||||
|
|
|
@ -5,7 +5,7 @@ spring.datasource.password=
|
||||||
spring.jpa.hibernate.ddl-auto=create-drop
|
spring.jpa.hibernate.ddl-auto=create-drop
|
||||||
spring.h2.console.enabled=true
|
spring.h2.console.enabled=true
|
||||||
spring.h2.console.path=/h2-console
|
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.SQL=INFO
|
||||||
logging.level.org.hibernate.type=INFO
|
logging.level.org.hibernate.type=INFO
|
||||||
|
|
10
pom.xml
10
pom.xml
|
@ -427,7 +427,6 @@
|
||||||
<!-- <module>spring-roo</module> --> <!-- Not supported JAVA-17327 -->
|
<!-- <module>spring-roo</module> --> <!-- Not supported JAVA-17327 -->
|
||||||
|
|
||||||
<module>spring-security-modules/spring-security-ldap</module>
|
<module>spring-security-modules/spring-security-ldap</module>
|
||||||
<module>spring-soap</module>
|
|
||||||
<module>spring-swagger-codegen</module>
|
<module>spring-swagger-codegen</module>
|
||||||
<module>video-tutorials</module>
|
<module>video-tutorials</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
@ -594,7 +593,6 @@
|
||||||
<!-- <module>spring-roo</module> --> <!-- Not supported JAVA-17327 -->
|
<!-- <module>spring-roo</module> --> <!-- Not supported JAVA-17327 -->
|
||||||
|
|
||||||
<module>spring-security-modules/spring-security-ldap</module>
|
<module>spring-security-modules/spring-security-ldap</module>
|
||||||
<module>spring-soap</module>
|
|
||||||
<module>spring-swagger-codegen</module>
|
<module>spring-swagger-codegen</module>
|
||||||
<module>video-tutorials</module>
|
<module>video-tutorials</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
@ -908,6 +906,7 @@
|
||||||
<module>spring-kafka</module>
|
<module>spring-kafka</module>
|
||||||
|
|
||||||
<module>spring-native</module>
|
<module>spring-native</module>
|
||||||
|
<module>spring-soap</module>
|
||||||
<module>spring-security-modules</module>
|
<module>spring-security-modules</module>
|
||||||
<module>spring-protobuf</module>
|
<module>spring-protobuf</module>
|
||||||
<module>spring-quartz</module>
|
<module>spring-quartz</module>
|
||||||
|
@ -1180,6 +1179,7 @@
|
||||||
<module>spring-kafka</module>
|
<module>spring-kafka</module>
|
||||||
|
|
||||||
<module>spring-native</module>
|
<module>spring-native</module>
|
||||||
|
<module>spring-soap</module>
|
||||||
<module>spring-security-modules</module>
|
<module>spring-security-modules</module>
|
||||||
<module>spring-protobuf</module>
|
<module>spring-protobuf</module>
|
||||||
<module>spring-quartz</module>
|
<module>spring-quartz</module>
|
||||||
|
@ -1261,7 +1261,7 @@
|
||||||
<hamcrest.version>2.2</hamcrest.version>
|
<hamcrest.version>2.2</hamcrest.version>
|
||||||
<hamcrest-all.version>1.3</hamcrest-all.version>
|
<hamcrest-all.version>1.3</hamcrest-all.version>
|
||||||
<mockito.version>4.4.0</mockito.version>
|
<mockito.version>4.4.0</mockito.version>
|
||||||
<byte-buddy.version>1.12.13</byte-buddy.version>
|
<byte-buddy.version>1.14.6</byte-buddy.version>
|
||||||
|
|
||||||
<!-- logging -->
|
<!-- logging -->
|
||||||
<!-- overwriting in the slf4j and logback in the hibernate-jpa, spring-data-eclipselink. When updated to the latest version remove the version from that module-->
|
<!-- overwriting in the slf4j and logback in the hibernate-jpa, spring-data-eclipselink. When updated to the latest version remove the version from that module-->
|
||||||
|
@ -1278,7 +1278,7 @@
|
||||||
<jmh-generator.version>1.36</jmh-generator.version>
|
<jmh-generator.version>1.36</jmh-generator.version>
|
||||||
<maven-failsafe-plugin.version>2.21.0</maven-failsafe-plugin.version>
|
<maven-failsafe-plugin.version>2.21.0</maven-failsafe-plugin.version>
|
||||||
<commons-collections4.version>4.4</commons-collections4.version>
|
<commons-collections4.version>4.4</commons-collections4.version>
|
||||||
<commons-io.version>2.11.0</commons-io.version>
|
<commons-io.version>2.13.0</commons-io.version>
|
||||||
<commons-lang.version>2.6</commons-lang.version>
|
<commons-lang.version>2.6</commons-lang.version>
|
||||||
<commons-lang3.version>3.13.0</commons-lang3.version>
|
<commons-lang3.version>3.13.0</commons-lang3.version>
|
||||||
<commons-cli.version>1.5.0</commons-cli.version>
|
<commons-cli.version>1.5.0</commons-cli.version>
|
||||||
|
@ -1288,7 +1288,7 @@
|
||||||
<javax.servlet.jsp-api.version>2.3.3</javax.servlet.jsp-api.version>
|
<javax.servlet.jsp-api.version>2.3.3</javax.servlet.jsp-api.version>
|
||||||
<jstl.version>1.2</jstl.version>
|
<jstl.version>1.2</jstl.version>
|
||||||
<jackson.version>2.15.2</jackson.version>
|
<jackson.version>2.15.2</jackson.version>
|
||||||
<commons-fileupload.version>1.4</commons-fileupload.version>
|
<commons-fileupload.version>1.5</commons-fileupload.version>
|
||||||
<junit-platform.version>1.9.2</junit-platform.version>
|
<junit-platform.version>1.9.2</junit-platform.version>
|
||||||
<junit-jupiter.version>5.9.2</junit-jupiter.version>
|
<junit-jupiter.version>5.9.2</junit-jupiter.version>
|
||||||
<junit-platform-surefire-provider.version>1.3.2</junit-platform-surefire-provider.version>
|
<junit-platform-surefire-provider.version>1.3.2</junit-platform-surefire-provider.version>
|
||||||
|
|
|
@ -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/
|
|
@ -0,0 +1,45 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>com.baelding</groupId>
|
||||||
|
<artifactId>spring-boot-telegram</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<name>spring-boot-telegram</name>
|
||||||
|
<description>Demo project for Spring Boot with Spring Data Redis</description>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>com.baeldung</groupId>
|
||||||
|
<artifactId>parent-boot-3</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<relativePath>../../parent-boot-3</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.telegram</groupId>
|
||||||
|
<artifactId>telegrambots-spring-boot-starter</artifactId>
|
||||||
|
<version>6.7.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.telegram</groupId>
|
||||||
|
<artifactId>telegrambots-abilities</artifactId>
|
||||||
|
<version>6.7.0</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<java.version>17</java.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
</project>
|
|
@ -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";
|
||||||
|
}
|
|
@ -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));
|
||||||
|
}
|
||||||
|
}
|
|
@ -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<BaseAbilityBot, Update> 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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<Long, UserState> 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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
package com.baeldung.telegram;
|
||||||
|
|
||||||
|
public enum UserState {
|
||||||
|
AWAITING_NAME, FOOD_DRINK_SELECTION, PIZZA_TOPPINGS, AWAITING_CONFIRMATION
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
server.port=8081
|
||||||
|
BOT_TOKEN=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
|
@ -10,8 +10,8 @@ eureka.client.registryFetchIntervalSeconds = 5
|
||||||
|
|
||||||
management.security.sessions=never
|
management.security.sessions=never
|
||||||
|
|
||||||
logging.level.org.springframework.web.=debug
|
logging.level.org.springframework.web.=INFO
|
||||||
logging.level.org.springframework.security=debug
|
logging.level.org.springframework.security=INFO
|
||||||
|
|
||||||
spring.redis.host=localhost
|
spring.redis.host=localhost
|
||||||
spring.redis.port=6379
|
spring.redis.port=6379
|
||||||
|
|
|
@ -6,8 +6,8 @@ eureka.client.registryFetchIntervalSeconds = 5
|
||||||
|
|
||||||
management.security.sessions=always
|
management.security.sessions=always
|
||||||
|
|
||||||
logging.level.org.springframework.web.=debug
|
logging.level.org.springframework.web.=INFO
|
||||||
logging.level.org.springframework.security=debug
|
logging.level.org.springframework.security=INFO
|
||||||
|
|
||||||
spring.redis.host=localhost
|
spring.redis.host=localhost
|
||||||
spring.redis.port=6379
|
spring.redis.port=6379
|
||||||
|
|
|
@ -10,8 +10,8 @@ eureka.client.registryFetchIntervalSeconds = 5
|
||||||
|
|
||||||
management.security.sessions=never
|
management.security.sessions=never
|
||||||
|
|
||||||
logging.level.org.springframework.web.=debug
|
logging.level.org.springframework.web.=INFO
|
||||||
logging.level.org.springframework.security=debug
|
logging.level.org.springframework.security=INFO
|
||||||
|
|
||||||
spring.redis.host=localhost
|
spring.redis.host=localhost
|
||||||
spring.redis.port=6379
|
spring.redis.port=6379
|
||||||
|
|
|
@ -4,4 +4,4 @@ server.port=9411
|
||||||
eureka.client.region = default
|
eureka.client.region = default
|
||||||
eureka.client.registryFetchIntervalSeconds = 5
|
eureka.client.registryFetchIntervalSeconds = 5
|
||||||
|
|
||||||
logging.level.org.springframework.web=debug
|
logging.level.org.springframework.web=INFO
|
||||||
|
|
|
@ -46,7 +46,6 @@
|
||||||
<spring-cloud-dataflow-dependencies.version>1.3.1.RELEASE</spring-cloud-dataflow-dependencies.version>
|
<spring-cloud-dataflow-dependencies.version>1.3.1.RELEASE</spring-cloud-dataflow-dependencies.version>
|
||||||
<spring-cloud-dependencies.version>Edgware.SR6</spring-cloud-dependencies.version>
|
<spring-cloud-dependencies.version>Edgware.SR6</spring-cloud-dependencies.version>
|
||||||
<hibernate.compatible.version>5.2.12.Final</hibernate.compatible.version>
|
<hibernate.compatible.version>5.2.12.Final</hibernate.compatible.version>
|
||||||
<byte-buddy.version>1.11.20</byte-buddy.version>
|
|
||||||
<rest-assured.version>3.1.0</rest-assured.version>
|
<rest-assured.version>3.1.0</rest-assured.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<configuration>
|
||||||
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<encoder>
|
||||||
|
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
|
||||||
|
</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<logger name="com.netflix.config" level="WARN"/>
|
||||||
|
|
||||||
|
<logger name="org.springframework.boot.test.context" level="WARN"/>
|
||||||
|
|
||||||
|
<root level="INFO">
|
||||||
|
<appender-ref ref="STDOUT" />
|
||||||
|
</root>
|
||||||
|
</configuration>
|
|
@ -4,7 +4,7 @@ feign.okhttp.enabled=true
|
||||||
|
|
||||||
server.port=8085
|
server.port=8085
|
||||||
spring.main.allow-bean-definition-overriding=true
|
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
|
feign.hystrix.enabled=true
|
||||||
|
|
||||||
spring.cloud.openfeign.client.config.postClient.url=https://jsonplaceholder.typicode.com/posts/
|
spring.cloud.openfeign.client.config.postClient.url=https://jsonplaceholder.typicode.com/posts/
|
|
@ -0,0 +1,17 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<configuration>
|
||||||
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<encoder>
|
||||||
|
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
|
||||||
|
</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<logger name="org.springframework.boot.test.context" level="WARN"/>
|
||||||
|
|
||||||
|
<logger name="org.springframework.test.context.support" level="WARN"/>
|
||||||
|
|
||||||
|
<root level="INFO">
|
||||||
|
<appender-ref ref="STDOUT" />
|
||||||
|
</root>
|
||||||
|
</configuration>
|
|
@ -0,0 +1,15 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<configuration>
|
||||||
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<encoder>
|
||||||
|
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
|
||||||
|
</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<logger name="org.springframework.boot.test.context" level="WARN"/>
|
||||||
|
|
||||||
|
<root level="INFO">
|
||||||
|
<appender-ref ref="STDOUT" />
|
||||||
|
</root>
|
||||||
|
</configuration>
|
|
@ -0,0 +1,17 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<configuration>
|
||||||
|
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<layout class="ch.qos.logback.classic.PatternLayout">
|
||||||
|
# Pattern of log message for console appender
|
||||||
|
<Pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern>
|
||||||
|
</layout>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<logger name="org.springframework.boot.test.context" level="WARN"/>
|
||||||
|
|
||||||
|
<logger name="org.springframework.boot.test.autoconfigure.web.servlet" level="WARN"/>
|
||||||
|
|
||||||
|
<root level="INFO">
|
||||||
|
<appender-ref ref="stdout" />
|
||||||
|
</root>
|
||||||
|
</configuration>
|
|
@ -9,6 +9,8 @@
|
||||||
|
|
||||||
<logger name="org.springframework" level="ERROR"/>
|
<logger name="org.springframework" level="ERROR"/>
|
||||||
|
|
||||||
|
<logger name="org.springframework.integration.config" level="INFO"/>
|
||||||
|
|
||||||
<root level="INFO">
|
<root level="INFO">
|
||||||
<appender-ref ref="stdout" />
|
<appender-ref ref="stdout" />
|
||||||
</root>
|
</root>
|
||||||
|
|
|
@ -1,2 +1,4 @@
|
||||||
/target/
|
/target/
|
||||||
sun-jaxb.episode
|
sun-jaxb.episode
|
||||||
|
|
||||||
|
**/gen/**
|
|
@ -30,6 +30,22 @@
|
||||||
<artifactId>spring-boot-starter-test</artifactId>
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>jakarta.xml.bind</groupId>
|
||||||
|
<artifactId>jakarta.xml.bind-api</artifactId>
|
||||||
|
<version>4.0.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.glassfish.jaxb</groupId>
|
||||||
|
<artifactId>jaxb-runtime</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.xml.bind</groupId>
|
||||||
|
<artifactId>jaxb-api</artifactId>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
@ -42,7 +58,7 @@
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
<artifactId>jaxb2-maven-plugin</artifactId>
|
<artifactId>jaxb2-maven-plugin</artifactId>
|
||||||
<version>1.6</version>
|
<version>3.1.0</version>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<id>xjc</id>
|
<id>xjc</id>
|
||||||
|
@ -52,8 +68,10 @@
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
<configuration>
|
<configuration>
|
||||||
<schemaDirectory>${project.basedir}/src/main/resources/</schemaDirectory>
|
<sources>
|
||||||
<outputDirectory>${project.basedir}/src/main/java</outputDirectory>
|
<source>src/main/resources/countries.xsd</source>
|
||||||
|
</sources>
|
||||||
|
<outputDirectory>src/main/java</outputDirectory>
|
||||||
<clearOutputDir>false</clearOutputDir>
|
<clearOutputDir>false</clearOutputDir>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
@ -61,7 +79,7 @@
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.jvnet.jaxb2.maven2</groupId>
|
<groupId>org.jvnet.jaxb2.maven2</groupId>
|
||||||
<artifactId>maven-jaxb2-plugin</artifactId>
|
<artifactId>maven-jaxb2-plugin</artifactId>
|
||||||
<version>0.14.0</version>
|
<version>0.15.3</version>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<goals>
|
<goals>
|
||||||
|
@ -83,4 +101,7 @@
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<java.version>17</java.version>
|
||||||
|
</properties>
|
||||||
</project>
|
</project>
|
|
@ -1,12 +1,14 @@
|
||||||
package com.baeldung.springsoap;
|
package com.baeldung.springsoap;
|
||||||
|
|
||||||
import com.baeldung.springsoap.gen.*;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.ws.server.endpoint.annotation.Endpoint;
|
import org.springframework.ws.server.endpoint.annotation.Endpoint;
|
||||||
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
|
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
|
||||||
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
|
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
|
||||||
import org.springframework.ws.server.endpoint.annotation.ResponsePayload;
|
import org.springframework.ws.server.endpoint.annotation.ResponsePayload;
|
||||||
|
|
||||||
|
import com.baeldung.springsoap.client.gen.GetCountryRequest;
|
||||||
|
import com.baeldung.springsoap.client.gen.GetCountryResponse;
|
||||||
|
|
||||||
@Endpoint
|
@Endpoint
|
||||||
public class CountryEndpoint {
|
public class CountryEndpoint {
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
package com.baeldung.springsoap;
|
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.stereotype.Component;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import com.baeldung.springsoap.client.gen.Country;
|
||||||
import java.util.HashMap;
|
import com.baeldung.springsoap.client.gen.Currency;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class CountryRepository {
|
public class CountryRepository {
|
||||||
|
|
|
@ -17,11 +17,11 @@ import org.springframework.xml.xsd.XsdSchema;
|
||||||
public class WebServiceConfig extends WsConfigurerAdapter {
|
public class WebServiceConfig extends WsConfigurerAdapter {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) {
|
public ServletRegistrationBean<MessageDispatcherServlet> messageDispatcherServlet(ApplicationContext applicationContext) {
|
||||||
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
|
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
|
||||||
servlet.setApplicationContext(applicationContext);
|
servlet.setApplicationContext(applicationContext);
|
||||||
servlet.setTransformWsdlLocations(true);
|
servlet.setTransformWsdlLocations(true);
|
||||||
return new ServletRegistrationBean(servlet, "/ws/*");
|
return new ServletRegistrationBean<>(servlet, "/ws/*");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean(name = "countries")
|
@Bean(name = "countries")
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue