diff --git a/algorithms-modules/algorithms-miscellaneous-3/README.md b/algorithms-modules/algorithms-miscellaneous-3/README.md index 8a606caa22..e86e4990a2 100644 --- a/algorithms-modules/algorithms-miscellaneous-3/README.md +++ b/algorithms-modules/algorithms-miscellaneous-3/README.md @@ -8,7 +8,6 @@ This module contains articles about algorithms. Some classes of algorithms, e.g. - [Java Two Pointer Technique](https://www.baeldung.com/java-two-pointer-technique) - [Implementing Simple State Machines with Java Enums](https://www.baeldung.com/java-enum-simple-state-machine) - [Converting Between Roman and Arabic Numerals in Java](https://www.baeldung.com/java-convert-roman-arabic) -- [Practical Java Examples of the Big O Notation](https://www.baeldung.com/java-algorithm-complexity) - [Checking If a List Is Sorted in Java](https://www.baeldung.com/java-check-if-list-sorted) - [Checking if a Java Graph Has a Cycle](https://www.baeldung.com/java-graph-has-a-cycle) - [A Guide to the Folding Technique in Java](https://www.baeldung.com/folding-hashing-technique) diff --git a/apache-httpclient/src/test/java/com/baeldung/httpclient/GetRequestMockServer.java b/apache-httpclient/src/test/java/com/baeldung/httpclient/GetRequestMockServer.java index 988a89e7af..92cb452dc8 100644 --- a/apache-httpclient/src/test/java/com/baeldung/httpclient/GetRequestMockServer.java +++ b/apache-httpclient/src/test/java/com/baeldung/httpclient/GetRequestMockServer.java @@ -7,7 +7,6 @@ import static org.mockserver.model.HttpResponse.response; import java.io.IOException; import java.net.ServerSocket; -import java.net.URISyntaxException; import org.apache.http.HttpStatus; import org.junit.jupiter.api.AfterAll; @@ -18,22 +17,19 @@ import org.mockserver.integration.ClientAndServer; public class GetRequestMockServer { public static ClientAndServer mockServer; - public static String serviceOneUrl; - public static String serviceTwoUrl; public static int serverPort; public static final String SERVER_ADDRESS = "127.0.0.1"; - public static final String PATH_ONE = "/test1"; - public static final String PATH_TWO = "/test2"; - public static final String METHOD = "GET"; + + public static final String SECURITY_PATH = "/spring-security-rest-basic-auth/api/foos/1"; + + public static final String UPLOAD_PATH = "/spring-mvc-java/stub/multipart"; @BeforeAll static void startServer() throws IOException { serverPort = getFreePort(); - System.out.println("Free port "+serverPort); - serviceOneUrl = "http://" + SERVER_ADDRESS + ":" + serverPort + PATH_ONE; - serviceTwoUrl = "http://" + SERVER_ADDRESS + ":" + serverPort + PATH_TWO; + System.out.println("Free port " + serverPort); mockServer = startClientAndServer(serverPort); mockGetRequest(); } @@ -44,33 +40,36 @@ public class GetRequestMockServer { } private static void mockGetRequest() { - new MockServerClient(SERVER_ADDRESS, serverPort) - .when( - request() - .withPath(PATH_ONE) - .withMethod(METHOD), - exactly(5) - ) - .respond( - response() - .withStatusCode(HttpStatus.SC_OK) - .withBody("{\"status\":\"ok\"}") - ); - new MockServerClient(SERVER_ADDRESS, serverPort) - .when( - request() - .withPath(PATH_TWO) - .withMethod(METHOD), - exactly(1) - ) - .respond( - response() - .withStatusCode(HttpStatus.SC_OK) - .withBody("{\"status\":\"ok\"}") - ); + + MockServerClient client = new MockServerClient(SERVER_ADDRESS, serverPort); + + client.when( + request() + .withPath(SECURITY_PATH) + .withMethod("GET"), + exactly(1) + ) + .respond( + response() + .withStatusCode(HttpStatus.SC_OK) + .withBody("{\"status\":\"ok\"}") + ); + + client.when( + request() + .withPath(UPLOAD_PATH) + .withMethod("POST"), + exactly(4) + ) + .respond( + response() + .withStatusCode(HttpStatus.SC_OK) + .withBody("{\"status\":\"ok\"}") + .withHeader("Content-Type", "multipart/form-data") + ); } - private static int getFreePort () throws IOException { + private static int getFreePort() throws IOException { try (ServerSocket serverSocket = new ServerSocket(0)) { return serverSocket.getLocalPort(); } diff --git a/apache-httpclient/src/test/java/com/baeldung/httpclient/HttpClientCancelRequestLiveTest.java b/apache-httpclient/src/test/java/com/baeldung/httpclient/HttpClientCancelRequestLiveTest.java index d19e0e1d86..d3e80c4429 100644 --- a/apache-httpclient/src/test/java/com/baeldung/httpclient/HttpClientCancelRequestLiveTest.java +++ b/apache-httpclient/src/test/java/com/baeldung/httpclient/HttpClientCancelRequestLiveTest.java @@ -19,7 +19,7 @@ class HttpClientCancelRequestLiveTest { void whenRequestIsCanceled_thenCorrect() throws IOException { HttpGet request = new HttpGet(SAMPLE_URL); try (CloseableHttpClient httpClient = HttpClients.createDefault()) { - httpClient.execute(request, response -> { + httpClient.execute(request, response -> { HttpEntity entity = response.getEntity(); System.out.println("----------------------------------------"); @@ -28,6 +28,12 @@ class HttpClientCancelRequestLiveTest { System.out.println("Response content length: " + entity.getContentLength()); } System.out.println("----------------------------------------"); + + if (entity != null) { + // Closes this stream and releases any system resources + entity.close(); + } + // Do not feel like reading the response body // Call abort on the request object request.abort(); diff --git a/apache-httpclient/src/test/java/com/baeldung/httpclient/HttpClientMultipartLiveTest.java b/apache-httpclient/src/test/java/com/baeldung/httpclient/HttpClientMultipartLiveTest.java index 720049378b..69eedc8e48 100644 --- a/apache-httpclient/src/test/java/com/baeldung/httpclient/HttpClientMultipartLiveTest.java +++ b/apache-httpclient/src/test/java/com/baeldung/httpclient/HttpClientMultipartLiveTest.java @@ -4,6 +4,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; import static org.junit.jupiter.api.Assertions.assertTrue; +import org.apache.hc.core5.http.ParseException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -13,7 +14,6 @@ import org.apache.hc.client5.http.entity.mime.HttpMultipartMode; import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder; import org.apache.hc.client5.http.entity.mime.StringBody; import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; -import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; import org.apache.hc.core5.http.ContentType; @@ -28,9 +28,7 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; -import com.baeldung.httpclient.handler.CustomHttpClientResponseHandler; - -class HttpClientMultipartLiveTest { +class HttpClientMultipartLiveTest extends GetRequestMockServer { // No longer available // private static final String SERVER = "http://echo.200please.com"; @@ -45,13 +43,15 @@ class HttpClientMultipartLiveTest { @BeforeEach public void before() { post = new HttpPost(SERVER); + String URL = "http://localhost:" + serverPort + "/spring-mvc-java/stub/multipart"; + post = new HttpPost(URL); } @Test void givenFileandMultipleTextParts_whenUploadwithAddPart_thenNoExceptions() throws IOException { final URL url = Thread.currentThread() - .getContextClassLoader() - .getResource("uploads/" + TEXTFILENAME); + .getContextClassLoader() + .getResource("uploads/" + TEXTFILENAME); final File file = new File(url.getPath()); final FileBody fileBody = new FileBody(file, ContentType.DEFAULT_BINARY); @@ -66,27 +66,28 @@ class HttpClientMultipartLiveTest { final HttpEntity entity = builder.build(); post.setEntity(entity); - try(CloseableHttpClient client = HttpClientBuilder.create() - .build(); + try (CloseableHttpClient client = HttpClientBuilder.create() + .build()) { - CloseableHttpResponse response = (CloseableHttpResponse) client - .execute(post, new CustomHttpClientResponseHandler())){ - final int statusCode = response.getCode(); - final String responseString = getContent(response.getEntity()); - final String contentTypeInHeader = getContentTypeHeader(); + client.execute(post, response -> { + final int statusCode = response.getCode(); + final String responseString = getContent(response.getEntity()); + final String contentTypeInHeader = getContentTypeHeader(); - assertThat(statusCode, equalTo(HttpStatus.SC_OK)); - assertTrue(contentTypeInHeader.contains("Content-Type: multipart/form-data;")); - System.out.println(responseString); - System.out.println("POST Content Type: " + contentTypeInHeader); + assertThat(statusCode, equalTo(HttpStatus.SC_OK)); + assertTrue(contentTypeInHeader.contains("multipart/form-data")); + System.out.println(responseString); + System.out.println("POST Content Type: " + contentTypeInHeader); + return response; + }); } } @Test void givenFileandTextPart_whenUploadwithAddBinaryBodyandAddTextBody_ThenNoExeption() throws IOException { final URL url = Thread.currentThread() - .getContextClassLoader() - .getResource("uploads/" + TEXTFILENAME); + .getContextClassLoader() + .getResource("uploads/" + TEXTFILENAME); final File file = new File(url.getPath()); final String message = "This is a multipart post"; final MultipartEntityBuilder builder = MultipartEntityBuilder.create(); @@ -96,30 +97,31 @@ class HttpClientMultipartLiveTest { final HttpEntity entity = builder.build(); post.setEntity(entity); - try(CloseableHttpClient client = HttpClientBuilder.create() - .build(); + try (CloseableHttpClient client = HttpClientBuilder.create() + .build()) { - CloseableHttpResponse response = (CloseableHttpResponse) client - .execute(post, new CustomHttpClientResponseHandler())){ + client.execute(post, response -> { - final int statusCode = response.getCode(); - final String responseString = getContent(response.getEntity()); - final String contentTypeInHeader = getContentTypeHeader(); - assertThat(statusCode, equalTo(HttpStatus.SC_OK)); - assertTrue(contentTypeInHeader.contains("Content-Type: multipart/form-data;")); - System.out.println(responseString); - System.out.println("POST Content Type: " + contentTypeInHeader); + final int statusCode = response.getCode(); + final String responseString = getContent(response.getEntity()); + final String contentTypeInHeader = getContentTypeHeader(); + assertThat(statusCode, equalTo(HttpStatus.SC_OK)); + assertTrue(contentTypeInHeader.contains("multipart/form-data")); + System.out.println(responseString); + System.out.println("POST Content Type: " + contentTypeInHeader); + return response; + }); } } @Test void givenFileAndInputStreamandText_whenUploadwithAddBinaryBodyandAddTextBody_ThenNoException() throws IOException { final URL url = Thread.currentThread() - .getContextClassLoader() - .getResource("uploads/" + ZIPFILENAME); + .getContextClassLoader() + .getResource("uploads/" + ZIPFILENAME); final URL url2 = Thread.currentThread() - .getContextClassLoader() - .getResource("uploads/" + IMAGEFILENAME); + .getContextClassLoader() + .getResource("uploads/" + IMAGEFILENAME); final InputStream inputStream = new FileInputStream(url.getPath()); final File file = new File(url2.getPath()); final String message = "This is a multipart post"; @@ -131,25 +133,25 @@ class HttpClientMultipartLiveTest { final HttpEntity entity = builder.build(); post.setEntity(entity); - try(CloseableHttpClient client = HttpClientBuilder.create() - .build(); + try (CloseableHttpClient client = HttpClientBuilder.create() + .build()) { - CloseableHttpResponse response = (CloseableHttpResponse) client - .execute(post, new CustomHttpClientResponseHandler())){ - - final int statusCode = response.getCode(); - final String responseString = getContent(response.getEntity()); - final String contentTypeInHeader = getContentTypeHeader(); - assertThat(statusCode, equalTo(HttpStatus.SC_OK)); - assertTrue(contentTypeInHeader.contains("Content-Type: multipart/form-data;")); - System.out.println(responseString); - System.out.println("POST Content Type: " + contentTypeInHeader); - inputStream.close(); + client.execute(post, response -> { + final int statusCode = response.getCode(); + final String responseString = getContent(response.getEntity()); + final String contentTypeInHeader = getContentTypeHeader(); + assertThat(statusCode, equalTo(HttpStatus.SC_OK)); + assertTrue(contentTypeInHeader.contains("multipart/form-data;")); + System.out.println(responseString); + System.out.println("POST Content Type: " + contentTypeInHeader); + inputStream.close(); + return response; + }); } } @Test - void givenCharArrayandText_whenUploadwithAddBinaryBodyandAddTextBody_ThenNoException() throws IOException { + void givenCharArrayandText_whenUploadwithAddBinaryBodyandAddTextBody_ThenNoException() throws IOException, ParseException { final String message = "This is a multipart post"; final byte[] bytes = "binary code".getBytes(); final MultipartEntityBuilder builder = MultipartEntityBuilder.create(); @@ -159,21 +161,20 @@ class HttpClientMultipartLiveTest { final HttpEntity entity = builder.build(); post.setEntity(entity); - try(CloseableHttpClient client = HttpClientBuilder.create() - .build(); + try (CloseableHttpClient httpClient = HttpClientBuilder.create() + .build()) { - CloseableHttpResponse response = (CloseableHttpResponse) client - .execute(post, new CustomHttpClientResponseHandler())){ - - final int statusCode = response.getCode(); - final String responseString = getContent(response.getEntity()); - final String contentTypeInHeader = getContentTypeHeader(); - assertThat(statusCode, equalTo(HttpStatus.SC_OK)); - assertTrue(contentTypeInHeader.contains("Content-Type: multipart/form-data;")); - System.out.println(responseString); - System.out.println("POST Content Type: " + contentTypeInHeader); + httpClient.execute(post, response -> { + final int statusCode = response.getCode(); + final String responseString = getContent(response.getEntity()); + final String contentTypeInHeader = getContentTypeHeader(); + assertThat(statusCode, equalTo(HttpStatus.SC_OK)); + assertTrue(contentTypeInHeader.contains("multipart/form-data;")); + System.out.println(responseString); + System.out.println("POST Content Type: " + contentTypeInHeader); + return response; + }); } - } // UTIL diff --git a/apache-httpclient/src/test/java/com/baeldung/httpclient/base/HttpClientLiveTest.java b/apache-httpclient/src/test/java/com/baeldung/httpclient/base/HttpClientLiveTest.java index 4173909f7d..b8bc536918 100644 --- a/apache-httpclient/src/test/java/com/baeldung/httpclient/base/HttpClientLiveTest.java +++ b/apache-httpclient/src/test/java/com/baeldung/httpclient/base/HttpClientLiveTest.java @@ -43,7 +43,7 @@ public class HttpClientLiveTest { @Test(expected = ConnectTimeoutException.class) public final void givenLowTimeout_whenExecutingRequestWithTimeout_thenException() throws IOException { - final RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(50).setConnectTimeout(50).setSocketTimeout(20).build(); + final RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(5).setConnectTimeout(5).setSocketTimeout(2).build(); final HttpGet request = new HttpGet(SAMPLE_URL); request.setConfig(requestConfig); response = instance.execute(request); diff --git a/apache-httpclient/src/test/java/com/baeldung/httpclient/base/HttpClientSandboxLiveTest.java b/apache-httpclient/src/test/java/com/baeldung/httpclient/base/HttpClientSandboxLiveTest.java index c667ae36f6..f72aa0c878 100644 --- a/apache-httpclient/src/test/java/com/baeldung/httpclient/base/HttpClientSandboxLiveTest.java +++ b/apache-httpclient/src/test/java/com/baeldung/httpclient/base/HttpClientSandboxLiveTest.java @@ -1,5 +1,6 @@ package com.baeldung.httpclient.base; +import com.baeldung.httpclient.GetRequestMockServer; import com.baeldung.httpclient.ResponseUtil; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; @@ -9,14 +10,14 @@ import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.io.IOException; /* * NOTE : Need module spring-security-rest-basic-auth to be running */ -public class HttpClientSandboxLiveTest { +public class HttpClientSandboxLiveTest extends GetRequestMockServer { @Test public final void givenGetRequestExecuted_whenAnalyzingTheResponse_thenCorrectStatusCode() throws IOException { @@ -26,7 +27,7 @@ public class HttpClientSandboxLiveTest { final CloseableHttpClient client = HttpClientBuilder.create().setDefaultCredentialsProvider(credentialsProvider).build(); - final HttpGet httpGet = new HttpGet("http://localhost:8080/spring-security-rest-basic-auth/api/foos/1"); + final HttpGet httpGet = new HttpGet("http://localhost:" + serverPort + "/spring-security-rest-basic-auth/api/foos/1"); final CloseableHttpResponse response = client.execute(httpGet); System.out.println(response.getStatusLine()); diff --git a/apache-httpclient/src/test/java/com/baeldung/httpclient/handler/CustomHttpClientResponseHandler.java b/apache-httpclient/src/test/java/com/baeldung/httpclient/handler/CustomHttpClientResponseHandler.java deleted file mode 100644 index 0559854b35..0000000000 --- a/apache-httpclient/src/test/java/com/baeldung/httpclient/handler/CustomHttpClientResponseHandler.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.baeldung.httpclient.handler; - -import org.apache.hc.core5.http.ClassicHttpResponse; -import org.apache.hc.core5.http.io.HttpClientResponseHandler; - -public class CustomHttpClientResponseHandler implements HttpClientResponseHandler { - @Override - public ClassicHttpResponse handleResponse(ClassicHttpResponse response) { - return response; - } -} \ No newline at end of file diff --git a/apache-httpclient4/pom.xml b/apache-httpclient4/pom.xml index e0bf9dd5f6..21c675db35 100644 --- a/apache-httpclient4/pom.xml +++ b/apache-httpclient4/pom.xml @@ -199,33 +199,7 @@ true - - - org.apache.maven.plugins - maven-war-plugin - ${maven-war-plugin.version} - - - org.codehaus.cargo - cargo-maven2-plugin - ${cargo-maven2-plugin.version} - - true - - jetty8x - embedded - - - - - - - 8082 - - - - - + @@ -233,26 +207,6 @@ live - - org.codehaus.cargo - cargo-maven2-plugin - - - start-server - pre-integration-test - - start - - - - stop-server - post-integration-test - - stop - - - - org.apache.maven.plugins maven-surefire-plugin @@ -269,9 +223,6 @@ **/*LiveTest.java - - cargo - @@ -291,7 +242,6 @@ 4.5.14 5.11.2 - 1.6.1 3.3.2 diff --git a/apache-httpclient4/src/test/java/com/baeldung/GetRequestMockServer.java b/apache-httpclient4/src/test/java/com/baeldung/GetRequestMockServer.java new file mode 100644 index 0000000000..52f1baa30d --- /dev/null +++ b/apache-httpclient4/src/test/java/com/baeldung/GetRequestMockServer.java @@ -0,0 +1,56 @@ +package com.baeldung; + +import static org.mockserver.integration.ClientAndServer.startClientAndServer; +import static org.mockserver.model.HttpRequest.request; +import static org.mockserver.model.HttpResponse.response; + +import java.io.IOException; +import java.net.ServerSocket; + +import org.apache.http.HttpStatus; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.mockserver.client.MockServerClient; +import org.mockserver.integration.ClientAndServer; + +public class GetRequestMockServer { + + public static ClientAndServer mockServer; + public static int serverPort; + public static String simplePathUrl; + public static final String SERVER_ADDRESS = "127.0.0.1"; + public static final String SIMPLE_PATH = "/httpclient-simple/api/bars/1"; + + @BeforeAll + static void startServer() throws IOException { + serverPort = getFreePort(); + System.out.println("Free port " + serverPort); + mockServer = startClientAndServer(serverPort); + + simplePathUrl = "http://" + SERVER_ADDRESS + ":" + serverPort + SIMPLE_PATH; + + mockGetRequest(); + } + + @AfterAll + static void stopServer() { + mockServer.stop(); + } + + private static void mockGetRequest() { + + MockServerClient client = new MockServerClient(SERVER_ADDRESS, serverPort); + + client.when(request().withPath(SIMPLE_PATH) + .withMethod("GET")) + .respond(response().withStatusCode(HttpStatus.SC_OK) + .withBody("{\"status\":\"ok\"}")); + } + + private static int getFreePort() throws IOException { + try (ServerSocket serverSocket = new ServerSocket(0)) { + return serverSocket.getLocalPort(); + } + } + +} \ No newline at end of file diff --git a/apache-httpclient4/src/test/java/com/baeldung/client/ClientLiveTest.java b/apache-httpclient4/src/test/java/com/baeldung/client/ClientLiveTest.java index 2785bc5d08..9d1052b7b3 100644 --- a/apache-httpclient4/src/test/java/com/baeldung/client/ClientLiveTest.java +++ b/apache-httpclient4/src/test/java/com/baeldung/client/ClientLiveTest.java @@ -10,7 +10,7 @@ import java.io.IOException; import java.security.GeneralSecurityException; import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLPeerUnverifiedException; +import javax.net.ssl.SSLHandshakeException; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpGet; @@ -31,10 +31,10 @@ import org.springframework.http.ResponseEntity; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.web.client.RestTemplate; +import com.baeldung.GetRequestMockServer; -class ClientLiveTest { +class ClientLiveTest extends GetRequestMockServer { - final String urlOverHttps = "http://localhost:8082/httpclient-simple/api/bars/1"; @Test void givenAcceptingAllCertificates_whenHttpsUrlIsConsumed_thenOk_2() throws GeneralSecurityException { @@ -54,13 +54,13 @@ class ClientLiveTest { .build(); final HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient); - final ResponseEntity response = new RestTemplate(requestFactory).exchange(urlOverHttps, HttpMethod.GET, null, String.class); + final ResponseEntity response = new RestTemplate(requestFactory).exchange(simplePathUrl, HttpMethod.GET, null, String.class); assertThat(response.getStatusCode().value(), equalTo(200)); } @Test void givenAcceptingAllCertificates_whenHttpsUrlIsConsumed_thenCorrect() throws IOException { - final HttpGet getMethod = new HttpGet(urlOverHttps); + final HttpGet getMethod = new HttpGet(simplePathUrl); try (final CloseableHttpClient httpClient = HttpClients.custom() .setSSLHostnameVerifier(new NoopHostnameVerifier()) @@ -80,20 +80,22 @@ class ClientLiveTest { final HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); requestFactory.setHttpClient(httpClient); - final ResponseEntity response = new RestTemplate(requestFactory).exchange(urlOverHttps, HttpMethod.GET, null, String.class); + final ResponseEntity response = new RestTemplate(requestFactory).exchange(simplePathUrl, HttpMethod.GET, null, String.class); assertThat(response.getStatusCode().value(), equalTo(200)); } @Test void whenHttpsUrlIsConsumed_thenException() { - String urlOverHttps = "https://localhost:8082/httpclient-simple"; + String urlOverHttps = "https://localhost:"+serverPort+"/httpclient-simple/api/bars/1"; HttpGet getMethod = new HttpGet(urlOverHttps); - assertThrows(SSLPeerUnverifiedException.class, () -> { + assertThrows(SSLHandshakeException.class, () -> { CloseableHttpClient httpClient = HttpClients.createDefault(); HttpResponse response = httpClient.execute(getMethod); assertThat(response.getStatusLine() .getStatusCode(), equalTo(200)); }); } + + } \ No newline at end of file diff --git a/apache-httpclient4/src/test/java/com/baeldung/client/RestClientV4LiveManualTest.java b/apache-httpclient4/src/test/java/com/baeldung/client/RestClientV4LiveManualTest.java index c336e6a068..3c0f5b7c63 100644 --- a/apache-httpclient4/src/test/java/com/baeldung/client/RestClientV4LiveManualTest.java +++ b/apache-httpclient4/src/test/java/com/baeldung/client/RestClientV4LiveManualTest.java @@ -1,6 +1,5 @@ package com.baeldung.client; -import static org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; @@ -89,4 +88,5 @@ public class RestClientV4LiveManualTest { HttpResponse response = httpClient.execute(getMethod); assertThat(response.getStatusLine().getStatusCode(), equalTo(200)); } + } diff --git a/apache-httpclient4/src/test/java/com/baeldung/httpclient/GetRequestMockServer.java b/apache-httpclient4/src/test/java/com/baeldung/httpclient/GetRequestMockServer.java deleted file mode 100644 index ae432e68f0..0000000000 --- a/apache-httpclient4/src/test/java/com/baeldung/httpclient/GetRequestMockServer.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.baeldung.httpclient; - -import static org.mockserver.integration.ClientAndServer.startClientAndServer; -import static org.mockserver.matchers.Times.exactly; -import static org.mockserver.model.HttpRequest.request; -import static org.mockserver.model.HttpResponse.response; - -import java.io.IOException; -import java.net.ServerSocket; -import java.net.URISyntaxException; - -import org.apache.http.HttpStatus; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.mockserver.client.MockServerClient; -import org.mockserver.integration.ClientAndServer; - -public class GetRequestMockServer { - - public static ClientAndServer mockServer; - public static String serviceOneUrl; - public static String serviceTwoUrl; - - public static int serverPort; - - public static final String SERVER_ADDRESS = "127.0.0.1"; - public static final String PATH_ONE = "/test1"; - public static final String PATH_TWO = "/test2"; - public static final String METHOD = "GET"; - - @BeforeAll - static void startServer() throws IOException, URISyntaxException { - serverPort = getFreePort(); - serviceOneUrl = "http://" + SERVER_ADDRESS + ":" + serverPort + PATH_ONE; - serviceTwoUrl = "http://" + SERVER_ADDRESS + ":" + serverPort + PATH_TWO; - mockServer = startClientAndServer(serverPort); - mockGetRequest(); - } - - @AfterAll - static void stopServer() { - mockServer.stop(); - } - - private static void mockGetRequest() { - new MockServerClient(SERVER_ADDRESS, serverPort) - .when( - request() - .withPath(PATH_ONE) - .withMethod(METHOD), - exactly(5) - ) - .respond( - response() - .withStatusCode(HttpStatus.SC_OK) - .withBody("{\"status\":\"ok\"}") - ); - new MockServerClient(SERVER_ADDRESS, serverPort) - .when( - request() - .withPath(PATH_TWO) - .withMethod(METHOD), - exactly(1) - ) - .respond( - response() - .withStatusCode(HttpStatus.SC_OK) - .withBody("{\"status\":\"ok\"}") - ); - } - - private static int getFreePort () throws IOException { - try (ServerSocket serverSocket = new ServerSocket(0)) { - return serverSocket.getLocalPort(); - } - } -} diff --git a/apache-httpclient4/src/test/java/com/baeldung/httpclient/HttpAsyncClientV4LiveTest.java b/apache-httpclient4/src/test/java/com/baeldung/httpclient/HttpAsyncClientV4LiveTest.java index e097f9f511..80b16d7f07 100644 --- a/apache-httpclient4/src/test/java/com/baeldung/httpclient/HttpAsyncClientV4LiveTest.java +++ b/apache-httpclient4/src/test/java/com/baeldung/httpclient/HttpAsyncClientV4LiveTest.java @@ -31,6 +31,7 @@ import org.apache.http.protocol.HttpContext; import org.apache.http.ssl.SSLContexts; import org.junit.jupiter.api.Test; +import com.baeldung.GetRequestMockServer; class HttpAsyncClientV4LiveTest extends GetRequestMockServer { diff --git a/apache-httpclient4/src/test/java/com/baeldung/httpclient/HttpClientCancelRequestV4LiveTest.java b/apache-httpclient4/src/test/java/com/baeldung/httpclient/HttpClientCancelRequestV4LiveTest.java index 226a7b8cf7..446c47c200 100644 --- a/apache-httpclient4/src/test/java/com/baeldung/httpclient/HttpClientCancelRequestV4LiveTest.java +++ b/apache-httpclient4/src/test/java/com/baeldung/httpclient/HttpClientCancelRequestV4LiveTest.java @@ -44,7 +44,9 @@ public class HttpClientCancelRequestV4LiveTest { System.out.println(response.getStatusLine()); if (entity != null) { System.out.println("Response content length: " + entity.getContentLength()); + entity.getContent().close(); } + System.out.println("----------------------------------------"); // Do not feel like reading the response body diff --git a/apache-httpclient4/src/test/java/com/baeldung/httpclient/HttpClientTimeoutV4LiveTest.java b/apache-httpclient4/src/test/java/com/baeldung/httpclient/HttpClientTimeoutV4LiveTest.java index 4d4dd7be15..ed22913ddd 100644 --- a/apache-httpclient4/src/test/java/com/baeldung/httpclient/HttpClientTimeoutV4LiveTest.java +++ b/apache-httpclient4/src/test/java/com/baeldung/httpclient/HttpClientTimeoutV4LiveTest.java @@ -21,7 +21,9 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; -class HttpClientTimeoutV4LiveTest { +import com.baeldung.GetRequestMockServer; + +class HttpClientTimeoutV4LiveTest extends GetRequestMockServer { private CloseableHttpResponse response; @@ -97,7 +99,7 @@ class HttpClientTimeoutV4LiveTest { int timeout = 20; // seconds RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(timeout * 1000) .setConnectTimeout(timeout * 1000).setSocketTimeout(timeout * 1000).build(); - HttpGet getMethod = new HttpGet("http://localhost:8082/httpclient-simple/api/bars/1"); + HttpGet getMethod = new HttpGet(simplePathUrl); getMethod.setConfig(requestConfig); int hardTimeout = 5; // seconds diff --git a/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/ApacheHttpClientUnitTest.java b/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/ApacheHttpClientUnitTest.java index 0d394b4ce7..9a7a734b65 100644 --- a/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/ApacheHttpClientUnitTest.java +++ b/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/ApacheHttpClientUnitTest.java @@ -13,13 +13,15 @@ import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.util.EntityUtils; import org.junit.jupiter.api.Test; +import com.baeldung.GetRequestMockServer; + class ApacheHttpClientUnitTest extends GetRequestMockServer { @Test void givenDeveloperUsedCloseableHttpResponse_whenExecutingGetRequest_thenStatusIsOk() throws IOException { try (CloseableHttpClient httpClient = HttpClientBuilder.create().build()) { - HttpGet httpGet = new HttpGet(serviceOneUrl); + HttpGet httpGet = new HttpGet(simplePathUrl); try (CloseableHttpResponse response = httpClient.execute(httpGet)) { HttpEntity entity = response.getEntity(); EntityUtils.consume(entity); diff --git a/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/GetRequestMockServer.java b/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/GetRequestMockServer.java deleted file mode 100644 index 3473117cef..0000000000 --- a/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/GetRequestMockServer.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.baeldung.httpclient.httpclient; - -import org.apache.http.HttpStatus; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.mockserver.client.MockServerClient; -import org.mockserver.integration.ClientAndServer; - -import java.io.IOException; -import java.net.ServerSocket; -import java.net.URISyntaxException; - -import static org.mockserver.integration.ClientAndServer.startClientAndServer; -import static org.mockserver.matchers.Times.exactly; -import static org.mockserver.model.HttpRequest.request; -import static org.mockserver.model.HttpResponse.response; - -public class GetRequestMockServer { - - public static ClientAndServer mockServer; - public static String serviceOneUrl; - public static String serviceTwoUrl; - - private static int serverPort; - - public static final String SERVER_ADDRESS = "127.0.0.1"; - public static final String PATH_ONE = "/test1"; - public static final String PATH_TWO = "/test2"; - public static final String METHOD = "GET"; - - @BeforeAll - static void startServer() throws IOException, URISyntaxException { - serverPort = getFreePort(); - serviceOneUrl = "http://" + SERVER_ADDRESS + ":" + serverPort + PATH_ONE; - serviceTwoUrl = "http://" + SERVER_ADDRESS + ":" + serverPort + PATH_TWO; - mockServer = startClientAndServer(serverPort); - mockGetRequest(); - } - - @AfterAll - static void stopServer() { - mockServer.stop(); - } - - private static void mockGetRequest() { - new MockServerClient(SERVER_ADDRESS, serverPort) - .when( - request() - .withPath(PATH_ONE) - .withMethod(METHOD), - exactly(5) - ) - .respond( - response() - .withStatusCode(HttpStatus.SC_OK) - .withBody("{\"status\":\"ok\"}") - ); - new MockServerClient(SERVER_ADDRESS, serverPort) - .when( - request() - .withPath(PATH_TWO) - .withMethod(METHOD), - exactly(1) - ) - .respond( - response() - .withStatusCode(HttpStatus.SC_OK) - .withBody("{\"status\":\"ok\"}") - ); - } - - private static int getFreePort () throws IOException { - try (ServerSocket serverSocket = new ServerSocket(0)) { - return serverSocket.getLocalPort(); - } - } - -} diff --git a/apache-poi-2/pom.xml b/apache-poi-2/pom.xml index 9a01a76d73..8741b12c8f 100644 --- a/apache-poi-2/pom.xml +++ b/apache-poi-2/pom.xml @@ -1,7 +1,7 @@ + xmlns="http://maven.apache.org/POM/4.0.0" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 apache-poi-2 0.0.1-SNAPSHOT diff --git a/aws-modules/aws-miscellaneous/pom.xml b/aws-modules/aws-miscellaneous/pom.xml index 036e692d24..2fb7e397a0 100644 --- a/aws-modules/aws-miscellaneous/pom.xml +++ b/aws-modules/aws-miscellaneous/pom.xml @@ -100,7 +100,6 @@ - 1.3.0 1.1.0 diff --git a/core-groovy-modules/core-groovy-2/gmavenplus-pom.xml b/core-groovy-modules/core-groovy-2/gmavenplus-pom.xml index 9d2711a9d0..975ad6f689 100644 --- a/core-groovy-modules/core-groovy-2/gmavenplus-pom.xml +++ b/core-groovy-modules/core-groovy-2/gmavenplus-pom.xml @@ -1,5 +1,6 @@ - 4.0.0 core-groovy-2 @@ -117,11 +118,11 @@ maven-surefire-plugin 2.20.1 - false - - **/*Test.java - **/*Spec.java - + false + + **/*Test.java + **/*Spec.java + diff --git a/core-java-modules/core-java-11-2/src/test/java/com/baeldung/httpclient/ssl/HttpClientSSLBypassUnitTest.java b/core-java-modules/core-java-11-2/src/test/java/com/baeldung/httpclient/ssl/HttpClientSSLBypassUnitTest.java index 68fcaae6d1..d0733d7149 100644 --- a/core-java-modules/core-java-11-2/src/test/java/com/baeldung/httpclient/ssl/HttpClientSSLBypassUnitTest.java +++ b/core-java-modules/core-java-11-2/src/test/java/com/baeldung/httpclient/ssl/HttpClientSSLBypassUnitTest.java @@ -4,29 +4,84 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import java.io.IOException; +import java.net.Socket; import java.net.URI; +import java.net.URISyntaxException; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.cert.X509Certificate; import java.util.Properties; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509ExtendedTrustManager; + public class HttpClientSSLBypassUnitTest { @Test - public void whenHttpsRequest_thenCorrect() throws IOException, InterruptedException { + public void givenDisableUsingJVMProperty_whenByPassCertificationVerification_thenSuccessHttpResponse() throws IOException, InterruptedException { final Properties props = System.getProperties(); props.setProperty("jdk.internal.httpclient.disableHostnameVerification", Boolean.TRUE.toString()); HttpClient httpClient = HttpClient.newBuilder() - .build(); + .build(); HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create("https://wrong.host.badssl.com/")) - .build(); + .uri(URI.create("https://wrong.host.badssl.com/")) + .build(); HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); props.setProperty("jdk.internal.httpclient.disableHostnameVerification", Boolean.FALSE.toString()); Assertions.assertEquals(200, response.statusCode()); } + + @Test + public void givenMockTrustManager_whenByPassCertificateVerification_thenSuccessHttpResponse() throws IOException, InterruptedException, NoSuchAlgorithmException, KeyManagementException, URISyntaxException { + SSLContext sslContext = SSLContext.getInstance("SSL"); // OR TLS + sslContext.init(null, new TrustManager[]{ MOCK_TRUST_MANAGER }, new SecureRandom()); + HttpClient httpClient = HttpClient.newBuilder().sslContext(sslContext).build(); + HttpRequest request = HttpRequest.newBuilder() + .uri(new URI("https://wrong.host.badssl.com/")) + .build(); + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + Assertions.assertEquals(200, response.statusCode()); + } + + + private static final TrustManager MOCK_TRUST_MANAGER = new X509ExtendedTrustManager() { + @Override + public java.security.cert.X509Certificate[] getAcceptedIssuers() { + return new java.security.cert.X509Certificate[0]; + } + + @Override + public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) { + } + + @Override + public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) { + } + + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType, SSLEngine engine) { + } + + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType, Socket socket) { + } + + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType, SSLEngine engine) { + } + + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType, Socket socket) { + } + }; } diff --git a/core-java-modules/core-java-11/pom.xml b/core-java-modules/core-java-11/pom.xml index d0c2c0acaa..5bbaec0057 100644 --- a/core-java-modules/core-java-11/pom.xml +++ b/core-java-modules/core-java-11/pom.xml @@ -72,7 +72,7 @@ org.openjdk.jmh.Main + implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/> diff --git a/core-java-modules/core-java-20/README.md b/core-java-modules/core-java-20/README.md index aba4e9e240..f859bf9e23 100644 --- a/core-java-modules/core-java-20/README.md +++ b/core-java-modules/core-java-20/README.md @@ -1,2 +1,3 @@ ## Relevant Articles - [Scoped Values in Java 20](https://www.baeldung.com/java-20-scoped-values) +- [How to Read Zip Files Entries With Java](https://www.baeldung.com/java-read-zip-files) diff --git a/core-java-modules/core-java-20/pom.xml b/core-java-modules/core-java-20/pom.xml index 9562a41b1c..ad0a956b80 100644 --- a/core-java-modules/core-java-20/pom.xml +++ b/core-java-modules/core-java-20/pom.xml @@ -1,7 +1,7 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 com.baeldung.core-java-modules diff --git a/core-java-modules/core-java-20/src/main/java/com/baeldung/convertpaths/RelativePathConverter.java b/core-java-modules/core-java-20/src/main/java/com/baeldung/convertpaths/RelativePathConverter.java new file mode 100644 index 0000000000..8e166aa441 --- /dev/null +++ b/core-java-modules/core-java-20/src/main/java/com/baeldung/convertpaths/RelativePathConverter.java @@ -0,0 +1,30 @@ +package com.baeldung.convertpaths; + +import java.io.File; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class RelativePathConverter { + + public static String convertToAbsoluteUsePathsClass(String relativePath) { + Path absolutePath = Paths.get(relativePath).toAbsolutePath(); + return absolutePath.toString(); + } + + public static String convertToAbsoluteUseFileClass(String relativePath) { + File file = new File(relativePath); + return file.getAbsolutePath(); + } + + public static String convertToAbsoluteUseFileSystemsClass(String relativePath) { + Path absolutePath = FileSystems.getDefault().getPath(relativePath).toAbsolutePath(); + return absolutePath.toString(); + } + + public static void main(String[] args) { + String relativePath = "myFolder/myFile.txt"; + String absolutePath = convertToAbsoluteUseFileSystemsClass(relativePath); + System.out.println("Absolute Path: " + absolutePath); + } +} diff --git a/core-java-modules/core-java-20/src/test/java/com/baeldung/convertpaths/RelativePathConverterUnitTest.java b/core-java-modules/core-java-20/src/test/java/com/baeldung/convertpaths/RelativePathConverterUnitTest.java new file mode 100644 index 0000000000..80f61d45c9 --- /dev/null +++ b/core-java-modules/core-java-20/src/test/java/com/baeldung/convertpaths/RelativePathConverterUnitTest.java @@ -0,0 +1,51 @@ +package com.baeldung.convertpaths; + +import org.junit.Test; + +public class RelativePathConverterUnitTest { + + @Test + public void givenRelativePath_whenConvertingToAbsolutePath_thenPrintOutput() { + String relativePath = "data/sample.txt"; + + System.out.println(RelativePathConverter.convertToAbsoluteUsePathsClass(relativePath)); + System.out.println(RelativePathConverter.convertToAbsoluteUseFileClass(relativePath)); + System.out.println(RelativePathConverter.convertToAbsoluteUseFileSystemsClass(relativePath)); + } + + @Test + public void givenAbsolutePath_whenConvertingToAbsolutePath_thenPrintOutput() { + String absolutePath = "/var/www/index.html"; + + System.out.println(RelativePathConverter.convertToAbsoluteUsePathsClass(absolutePath)); + System.out.println(RelativePathConverter.convertToAbsoluteUseFileClass(absolutePath)); + System.out.println(RelativePathConverter.convertToAbsoluteUseFileSystemsClass(absolutePath)); + } + + @Test + public void givenEmptyPath_whenConvertingToAbsolutePath_thenPrintOutput() { + String emptyPath = ""; + + System.out.println(RelativePathConverter.convertToAbsoluteUsePathsClass(emptyPath)); + System.out.println(RelativePathConverter.convertToAbsoluteUseFileClass(emptyPath)); + System.out.println(RelativePathConverter.convertToAbsoluteUseFileSystemsClass(emptyPath)); + } + + @Test + public void givenParentDirectoryPath_whenConvertingToAbsolutePath_thenPrintOutput() { + String relativePath = "../data/sample.txt"; + + System.out.println(RelativePathConverter.convertToAbsoluteUsePathsClass(relativePath)); + System.out.println(RelativePathConverter.convertToAbsoluteUseFileClass(relativePath)); + System.out.println(RelativePathConverter.convertToAbsoluteUseFileSystemsClass(relativePath)); + } + + @Test + public void givenRelativePathContainingDots_whenConvertingToAbsolutePath_thenPrintOutput() { + String relativePath = "././data/sample.txt"; + + System.out.println(RelativePathConverter.convertToAbsoluteUsePathsClass(relativePath)); + System.out.println(RelativePathConverter.convertToAbsoluteUseFileClass(relativePath)); + System.out.println(RelativePathConverter.convertToAbsoluteUseFileSystemsClass(relativePath)); + } +} diff --git a/core-java-modules/core-java-20/src/test/java/com/baeldung/zipentries/ZipEntryReaderTest.java b/core-java-modules/core-java-20/src/test/java/com/baeldung/zipentries/ZipEntryReaderUnitTest.java similarity index 92% rename from core-java-modules/core-java-20/src/test/java/com/baeldung/zipentries/ZipEntryReaderTest.java rename to core-java-modules/core-java-20/src/test/java/com/baeldung/zipentries/ZipEntryReaderUnitTest.java index 2eb47ff057..b21470baea 100644 --- a/core-java-modules/core-java-20/src/test/java/com/baeldung/zipentries/ZipEntryReaderTest.java +++ b/core-java-modules/core-java-20/src/test/java/com/baeldung/zipentries/ZipEntryReaderUnitTest.java @@ -7,7 +7,7 @@ import java.net.URISyntaxException; import java.nio.file.Path; import java.nio.file.Paths; -public class ZipEntryReaderTest { +public class ZipEntryReaderUnitTest { @Test public void givenZipFile_thenReadEntriesAndValidateContent() throws URISyntaxException, IOException { diff --git a/core-java-modules/core-java-9-jigsaw/library-core/pom.xml b/core-java-modules/core-java-9-jigsaw/library-core/pom.xml index b860d89932..80638367cf 100644 --- a/core-java-modules/core-java-9-jigsaw/library-core/pom.xml +++ b/core-java-modules/core-java-9-jigsaw/library-core/pom.xml @@ -1,55 +1,55 @@ - 4.0.0 - - com.baeldung - core-java-9-jigsaw - 0.2-SNAPSHOT - + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + + com.baeldung + core-java-9-jigsaw + 0.2-SNAPSHOT + - library-core + library-core - - 19 - 19 - UTF-8 - + + 19 + 19 + UTF-8 + - - - org.junit.jupiter - junit-jupiter-api - 5.9.2 - test - - - org.junit.jupiter - junit-jupiter-engine - 5.9.2 - test - - + + + org.junit.jupiter + junit-jupiter-api + 5.9.2 + test + + + org.junit.jupiter + junit-jupiter-engine + 5.9.2 + test + + - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.8.1 - - 9 - - - - org.apache.maven.plugins - maven-surefire-plugin - 3.0.0-M5 - - false - - - - + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 9 + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.0.0-M5 + + false + + + + \ No newline at end of file diff --git a/core-java-modules/core-java-collections-5/pom.xml b/core-java-modules/core-java-collections-5/pom.xml index 84f62c696d..da58ef1db5 100644 --- a/core-java-modules/core-java-collections-5/pom.xml +++ b/core-java-modules/core-java-collections-5/pom.xml @@ -1,7 +1,7 @@ + xmlns="http://maven.apache.org/POM/4.0.0" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 core-java-collections-5 core-java-collections-5 diff --git a/core-java-modules/core-java-collections-conversions-2/src/test/java/com/baeldung/convertlisttoarray/LongListToLongArrayConversionUnitTest.java b/core-java-modules/core-java-collections-conversions-2/src/test/java/com/baeldung/convertlisttoarray/LongListToLongArrayConversionUnitTest.java new file mode 100644 index 0000000000..915a4bfc02 --- /dev/null +++ b/core-java-modules/core-java-collections-conversions-2/src/test/java/com/baeldung/convertlisttoarray/LongListToLongArrayConversionUnitTest.java @@ -0,0 +1,74 @@ +package com.baeldung.convertlisttoarray; + +import static org.junit.Assert.assertTrue; + +import java.util.Arrays; +import java.util.List; + +import org.junit.Before; +import org.junit.Test; + +import com.google.common.primitives.Longs; + +public class LongListToLongArrayConversionUnitTest { + + private List list; + + @Before + public void setUp() { + list = Arrays.asList(1L, 2L, 3L, 4L, 5L); + } + + @Test + public void givenALongList_whenConvertWithListToArray_thenReturnLongArray() { + + // Init an array with the same size as the list to convert + Long[] arrayWithSettedSize = new Long[list.size()]; + arrayWithSettedSize = list.toArray(arrayWithSettedSize); + assertTrue(list.size() == arrayWithSettedSize.length); + + // Init an empty array + Long[] arrayWithNoSettedSize = new Long[0]; + arrayWithNoSettedSize = list.toArray(arrayWithNoSettedSize); + assertTrue(list.size() == arrayWithNoSettedSize.length); + } + + @Test + public void givenALongList_whenConvertWithLongsToArray_thenReturnLongArray() { + // Convertion using Guava library Longs.toArray() method + long[] array = Longs.toArray(list); + assertTrue(compareListWithArray(list, array)); + } + + @Test + public void givenALongList_whenConvertWithStreamMapToLong_thenReturnLongArray() { + // Using mapToLong() - lambda expression + long[] arrayUsingLambda = list.stream() + .mapToLong(l -> l) + .toArray(); + assertTrue(compareListWithArray(list, arrayUsingLambda)); + + // Using mapToLong() - method reference + long[] arrayUsingMethodReference = list.stream() + .mapToLong(Long::longValue) + .toArray(); + assertTrue(compareListWithArray(list, arrayUsingMethodReference)); + } + + public static boolean compareListWithArray(List list, long[] array) { + // Check if the sizes of the array and list are equal + if (array.length != list.size()) { + return false; + } + + // Compare each element of the array with the corresponding element in the list + for (int i = 0; i < array.length; i++) { + // Convert Long to long for comparison + if (array[i] != list.get(i)) { + return false; + } + } + + return true; + } +} diff --git a/core-java-modules/core-java-collections-list-5/README.md b/core-java-modules/core-java-collections-list-5/README.md index 99563c3103..18ff0c687d 100644 --- a/core-java-modules/core-java-collections-list-5/README.md +++ b/core-java-modules/core-java-collections-list-5/README.md @@ -9,5 +9,5 @@ This module contains articles about the Java List collection - [Check if a List Contains an Element From Another List in Java](https://www.baeldung.com/java-check-elements-between-lists) - [Array vs. List Performance in Java](https://www.baeldung.com/java-array-vs-list-performance) - [Set Default Value for Elements in List](https://www.baeldung.com/java-list-set-default-values) -- [Get Unique Values From an ArrayList In Java](https://www.baeldung.com/java-unique-values-arraylist) +- [Get Unique Values From an ArrayList in Java](https://www.baeldung.com/java-unique-values-arraylist) - [Converting a Java List to a Json Array](https://www.baeldung.com/java-converting-list-to-json-array) diff --git a/core-java-modules/core-java-collections-list-5/pom.xml b/core-java-modules/core-java-collections-list-5/pom.xml index 2269cce9fd..144fd12c45 100644 --- a/core-java-modules/core-java-collections-list-5/pom.xml +++ b/core-java-modules/core-java-collections-list-5/pom.xml @@ -14,7 +14,7 @@ - + org.openjdk.jmh jmh-core 1.36 @@ -45,7 +45,7 @@ - 1.21 + 1.21 2.2 3.12.0 diff --git a/core-java-modules/core-java-collections-maps-6/README.md b/core-java-modules/core-java-collections-maps-6/README.md index 0b5d69e8f6..7bd1d5ea11 100644 --- a/core-java-modules/core-java-collections-maps-6/README.md +++ b/core-java-modules/core-java-collections-maps-6/README.md @@ -3,3 +3,5 @@ - [Convert Hashmap to JSON Object in Java](https://www.baeldung.com/java-convert-hashmap-to-json-object) - [Converting Map to Map in Java](https://www.baeldung.com/java-converting-map-string-object-to-string-string) - [Converting Object To Map in Java](https://www.baeldung.com/java-convert-object-to-map) +- [Difference Between Map.clear() and Instantiating a New Map](https://www.baeldung.com/java-map-clear-vs-new-map) +- [Converting JsonNode Object to Map](https://www.baeldung.com/jackson-jsonnode-map) diff --git a/core-java-modules/core-java-collections-maps-6/src/test/java/com/baeldung/map/changekey/HashmapChangeKeyUnitTest.java b/core-java-modules/core-java-collections-maps-6/src/test/java/com/baeldung/map/changekey/HashmapChangeKeyUnitTest.java new file mode 100644 index 0000000000..f6ba9c290a --- /dev/null +++ b/core-java-modules/core-java-collections-maps-6/src/test/java/com/baeldung/map/changekey/HashmapChangeKeyUnitTest.java @@ -0,0 +1,98 @@ +package com.baeldung.map.changekey; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.jupiter.api.Test; + +class Player { + private String name; + + public Player(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof Player)) { + return false; + } + + Player player = (Player) o; + + return name.equals(player.name); + } + + @Override + public int hashCode() { + return name.hashCode(); + } +} + +public class HashmapChangeKeyUnitTest { + + @Test + void whenRemoveThenPutWithTheNewKey_thenGetExpectedResult() { + Map playerMap = new HashMap<>(); + + playerMap.put("Kai", 42); + playerMap.put("Amanda", 88); + playerMap.put("Tom", 200); + + // now replace Kai with Eric + playerMap.put("Eric", playerMap.remove("Kai")); + + assertFalse(playerMap.containsKey("Kai")); + assertTrue(playerMap.containsKey("Eric")); + assertEquals(42, playerMap.get("Eric")); + } + + @Test + void whenChangeTheKey_thenMayNotGetExpectedResult() { + Map myMap = new HashMap<>(); + Player kai = new Player("Kai"); + Player tom = new Player("Tom"); + Player amanda = new Player("Amanda"); + + myMap.put(kai, 42); + myMap.put(amanda, 88); + myMap.put(tom, 200); + + assertTrue(myMap.containsKey(kai)); + + //change Kai's name to Eric + kai.setName("Eric"); + assertEquals("Eric", kai.getName()); + + Player eric = new Player("Eric"); + assertEquals(eric, kai); + + // the map contains neither Kai nor Eric: + assertFalse(myMap.containsKey(kai)); + assertFalse(myMap.containsKey(eric)); + + // although the Player("Eric") exists: + long ericCount = myMap.keySet() + .stream() + .filter(player -> player.getName() + .equals("Eric")) + .count(); + + assertEquals(1, ericCount); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-concurrency-2/README.md b/core-java-modules/core-java-concurrency-2/README.md index c52f17a07b..3badd36d5e 100644 --- a/core-java-modules/core-java-concurrency-2/README.md +++ b/core-java-modules/core-java-concurrency-2/README.md @@ -6,3 +6,4 @@ - [Using a Mutex Object in Java](https://www.baeldung.com/java-mutex) - [Testing Multi-Threaded Code in Java](https://www.baeldung.com/java-testing-multithreaded) - [How to Check if All Runnables Are Done](https://www.baeldung.com/java-runnables-check-status) +- [Parallelize for Loop in Java](https://www.baeldung.com/java-for-loop-parallel) diff --git a/core-java-modules/core-java-concurrency-basic-3/README.md b/core-java-modules/core-java-concurrency-basic-3/README.md index 619a68cdef..b9c66b279c 100644 --- a/core-java-modules/core-java-concurrency-basic-3/README.md +++ b/core-java-modules/core-java-concurrency-basic-3/README.md @@ -8,4 +8,6 @@ This module contains articles about basic Java concurrency. - [Thread.sleep() vs Awaitility.await()](https://www.baeldung.com/java-thread-sleep-vs-awaitility-await) - [Is CompletableFuture Non-blocking?](https://www.baeldung.com/java-completablefuture-non-blocking) - [Returning a Value After Finishing Thread’s Job in Java](https://www.baeldung.com/java-return-value-after-thread-finish) +- [CompletableFuture and ThreadPool in Java](https://www.baeldung.com/java-completablefuture-threadpool) +- [CompletableFuture allOf().join() vs. CompletableFuture.join()](https://www.baeldung.com/java-completablefuture-allof-join) - [[<-- Prev]](../core-java-concurrency-basic-2) diff --git a/core-java-modules/core-java-concurrency-basic-3/src/main/java/com/baeldung/concurrent/completablefuture/threadpool/CustomCompletableFuture.java b/core-java-modules/core-java-concurrency-basic-3/src/main/java/com/baeldung/concurrent/completablefuture/threadpool/CustomCompletableFuture.java new file mode 100644 index 0000000000..1f3997768e --- /dev/null +++ b/core-java-modules/core-java-concurrency-basic-3/src/main/java/com/baeldung/concurrent/completablefuture/threadpool/CustomCompletableFuture.java @@ -0,0 +1,28 @@ +package com.baeldung.concurrent.completablefuture.threadpool; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.function.Supplier; + +public class CustomCompletableFuture extends CompletableFuture { + private static final Executor executor = Executors.newSingleThreadExecutor(runnable -> new Thread(runnable, "Custom-Single-Thread")); + + public static CustomCompletableFuture supplyAsync(Supplier supplier) { + CustomCompletableFuture future = new CustomCompletableFuture<>(); + executor.execute(() -> { + try { + future.complete(supplier.get()); + } catch (Exception ex) { + future.completeExceptionally(ex); + } + }); + return future; + } + + @Override + public Executor defaultExecutor() { + return executor; + } + +} \ No newline at end of file diff --git a/core-java-modules/core-java-concurrency-basic-3/src/test/java/com/baeldung/concurrent/completablefuture/allofvsjoin/CompletableFutureAllOffUnitTest.java b/core-java-modules/core-java-concurrency-basic-3/src/test/java/com/baeldung/concurrent/completablefuture/allofvsjoin/CompletableFutureAllOffUnitTest.java new file mode 100644 index 0000000000..8c7c8c95c7 --- /dev/null +++ b/core-java-modules/core-java-concurrency-basic-3/src/test/java/com/baeldung/concurrent/completablefuture/allofvsjoin/CompletableFutureAllOffUnitTest.java @@ -0,0 +1,112 @@ +package com.baeldung.concurrent.completablefuture.allofvsjoin; + +import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.time.LocalDateTime; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; + +public class CompletableFutureAllOffUnitTest { + + @Test + void whenCallingJoin_thenBlocksThreadAndGetValue() { + CompletableFuture future = waitAndReturn(1_000, "Harry"); + assertEquals("Harry", future.join()); + } + + @Test + void whenCallingJoin_thenBlocksThreadAndThrowException() { + CompletableFuture futureError = waitAndThrow(1_000); + assertThrows(RuntimeException.class, futureError::join); + } + + @Test + void whenCallingJoinTwoTimes_thenBlocksThreadAndGetValues() { + CompletableFuture f1 = waitAndReturn(1_000, "Harry"); + CompletableFuture f2 = waitAndReturn(2_000, "Ron"); + + assertEquals("Harry", f1.join()); + assertEquals("Ron", f2.join()); + } + + + @Test + void whenCallingAllOfJoin_thenBlocksThreadAndGetValues() { + CompletableFuture f1 = waitAndReturn(1_000, "Harry"); + CompletableFuture f2 = waitAndReturn(2_000, "Ron"); + + CompletableFuture combinedFutures = CompletableFuture.allOf(f1, f2); + combinedFutures.join(); + + assertEquals("Harry", f1.join()); + assertEquals("Ron", f2.join()); + } + + @Test + void whenCallingJoinInaLoop_thenProcessesDataPartially() { + CompletableFuture f1 = waitAndReturn(1_000, "Harry"); + CompletableFuture f2 = waitAndThrow(2_000); + CompletableFuture f3 = waitAndReturn(1_000, "Ron"); + + assertThrows(RuntimeException.class, () -> Stream.of(f1, f2, f3) + .map(CompletableFuture::join) + .forEach(this::sayHello)); + } + + @Test + void whenCallingAllOfJoin_thenFailsForAll() { + CompletableFuture f1 = waitAndReturn(1_000, "Harry"); + CompletableFuture f2 = waitAndThrow(2_000); + CompletableFuture f3 = waitAndReturn(1_000, "Ron"); + + assertThrows(RuntimeException.class, () -> CompletableFuture.allOf(f1, f2, f3) + .join()); + } + + @Test + void whenCallingExceptionally_thenRecoversWithDefaultValue() { + CompletableFuture f1 = waitAndReturn(1_000, "Harry"); + CompletableFuture f2 = waitAndThrow(2_000); + CompletableFuture f3 = waitAndReturn(1_000, "Ron"); + + CompletableFuture names = CompletableFuture.allOf(f1, f2, f3) + .thenApply(__ -> f1.join() + "," + f2.join() + "," + f3.join()) + .exceptionally(err -> { + System.out.println("oops, there was a problem! " + err.getMessage()); + return "names not found!"; + }); + + assertEquals("names not found!", names.join()); + } + + private void sayHello(String name) { + System.out.println(LocalDateTime.now() + " - " + name); + } + + private CompletableFuture waitAndReturn(long millis, String value) { + return CompletableFuture.supplyAsync(() -> { + try { + // Thread.sleep() is commented to avoid slowing down the pipeline + // Thread.sleep(millis); + return value; + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + } + + private CompletableFuture waitAndThrow(long millis) { + return CompletableFuture.supplyAsync(() -> { + try { + // Thread.sleep() is commented to avoid slowing down the pipeline + // Thread.sleep(millis); + } finally { + throw new RuntimeException(); + } + }); + } + +} diff --git a/core-java-modules/core-java-concurrency-basic-3/src/test/java/com/baeldung/concurrent/completablefuture/threadpool/CompletableFutureThreadPoolUnitTest.java b/core-java-modules/core-java-concurrency-basic-3/src/test/java/com/baeldung/concurrent/completablefuture/threadpool/CompletableFutureThreadPoolUnitTest.java new file mode 100644 index 0000000000..9deadfb906 --- /dev/null +++ b/core-java-modules/core-java-concurrency-basic-3/src/test/java/com/baeldung/concurrent/completablefuture/threadpool/CompletableFutureThreadPoolUnitTest.java @@ -0,0 +1,88 @@ +package com.baeldung.concurrent.completablefuture.threadpool; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; + +import org.junit.jupiter.api.Test; + +public class CompletableFutureThreadPoolUnitTest { + + @Test + void whenUsingNonAsync_thenUsesMainThread() throws ExecutionException, InterruptedException { + CompletableFuture name = CompletableFuture.supplyAsync(() -> "Baeldung"); + + CompletableFuture nameLength = name.thenApply(value -> { + printCurrentThread(); + return value.length(); + }); + + assertThat(nameLength.get()).isEqualTo(8); + } + + @Test + void whenUsingNonAsync_thenUsesCallersThread() throws InterruptedException { + Runnable test = () -> { + CompletableFuture name = CompletableFuture.supplyAsync(() -> "Baeldung"); + + CompletableFuture nameLength = name.thenApply(value -> { + printCurrentThread(); + return value.length(); + }); + + try { + assertThat(nameLength.get()).isEqualTo(8); + } catch (Exception e) { + fail(e.getMessage()); + } + }; + + new Thread(test, "test-thread").start(); + Thread.sleep(100l); + } + + @Test + void whenUsingAsync_thenUsesCommonPool() throws ExecutionException, InterruptedException { + CompletableFuture name = CompletableFuture.supplyAsync(() -> "Baeldung"); + + CompletableFuture nameLength = name.thenApplyAsync(value -> { + printCurrentThread(); + return value.length(); + }); + + assertThat(nameLength.get()).isEqualTo(8); + } + + @Test + void whenUsingAsync_thenUsesCustomExecutor() throws ExecutionException, InterruptedException { + Executor testExecutor = Executors.newFixedThreadPool(5); + CompletableFuture name = CompletableFuture.supplyAsync(() -> "Baeldung"); + + CompletableFuture nameLength = name.thenApplyAsync(value -> { + printCurrentThread(); + return value.length(); + }, testExecutor); + + assertThat(nameLength.get()).isEqualTo(8); + } + + @Test + void whenOverridingDefaultThreadPool_thenUsesCustomExecutor() throws ExecutionException, InterruptedException { + CompletableFuture name = CustomCompletableFuture.supplyAsync(() -> "Baeldung"); + + CompletableFuture nameLength = name.thenApplyAsync(value -> { + printCurrentThread(); + return value.length(); + }); + + assertThat(nameLength.get()).isEqualTo(8); + } + + private static void printCurrentThread() { + System.out.println(Thread.currentThread().getName()); + } +} diff --git a/core-java-modules/core-java-concurrency-basic/README.md b/core-java-modules/core-java-concurrency-basic/README.md index 137251b46a..e5c061710c 100644 --- a/core-java-modules/core-java-concurrency-basic/README.md +++ b/core-java-modules/core-java-concurrency-basic/README.md @@ -10,4 +10,5 @@ This module contains articles about basic Java concurrency - [ExecutorService – Waiting for Threads to Finish](https://www.baeldung.com/java-executor-wait-for-threads) - [Runnable vs. Callable in Java](https://www.baeldung.com/java-runnable-callable) - [What Is Thread-Safety and How to Achieve It?](https://www.baeldung.com/java-thread-safety) +- [How to Get Notified When a Task Completes in Java Executors](https://www.baeldung.com/java-executors-task-completed-notification) - [[Next -->]](/core-java-modules/core-java-concurrency-basic-2) diff --git a/core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/notificationforcompletetask/AlertingFutureTask.java b/core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/notificationforcompletetask/AlertingFutureTask.java new file mode 100644 index 0000000000..bd0bacaa3c --- /dev/null +++ b/core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/notificationforcompletetask/AlertingFutureTask.java @@ -0,0 +1,18 @@ +package com.baeldung.concurrent.notificationforcompletetask; + +import java.util.concurrent.FutureTask; + +public class AlertingFutureTask extends FutureTask { + + private final CallbackInterface callback; + + public AlertingFutureTask(Runnable runnable, Callback callback) { + super(runnable, null); + this.callback = callback; + } + + @Override + protected void done() { + callback.taskDone("task details here"); + } +} diff --git a/core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/notificationforcompletetask/AlertingThreadPoolExecutor.java b/core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/notificationforcompletetask/AlertingThreadPoolExecutor.java new file mode 100644 index 0000000000..029170256f --- /dev/null +++ b/core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/notificationforcompletetask/AlertingThreadPoolExecutor.java @@ -0,0 +1,21 @@ +package com.baeldung.concurrent.notificationforcompletetask; + +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +public class AlertingThreadPoolExecutor extends ThreadPoolExecutor { + + private final CallbackInterface callback; + + public AlertingThreadPoolExecutor(CallbackInterface callback) { + super(1, 1, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10)); + this.callback = callback; + } + + @Override + protected void afterExecute(Runnable r, Throwable t) { + super.afterExecute(r, t); + callback.taskDone("runnable details here"); + } +} diff --git a/core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/notificationforcompletetask/Callback.java b/core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/notificationforcompletetask/Callback.java new file mode 100644 index 0000000000..fd00a6e116 --- /dev/null +++ b/core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/notificationforcompletetask/Callback.java @@ -0,0 +1,10 @@ +package com.baeldung.concurrent.notificationforcompletetask; + +public class Callback implements CallbackInterface { + + public void taskDone(String details){ + System.out.println("task complete: " + details); + // Alerts/notifications go here + } + +} diff --git a/core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/notificationforcompletetask/CallbackInterface.java b/core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/notificationforcompletetask/CallbackInterface.java new file mode 100644 index 0000000000..6df5bc7208 --- /dev/null +++ b/core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/notificationforcompletetask/CallbackInterface.java @@ -0,0 +1,5 @@ +package com.baeldung.concurrent.notificationforcompletetask; + +public interface CallbackInterface { + void taskDone(String details); +} diff --git a/core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/notificationforcompletetask/RunnableImpl.java b/core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/notificationforcompletetask/RunnableImpl.java new file mode 100644 index 0000000000..a07254a87f --- /dev/null +++ b/core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/notificationforcompletetask/RunnableImpl.java @@ -0,0 +1,22 @@ +package com.baeldung.concurrent.notificationforcompletetask; + +public class RunnableImpl implements Runnable { + + private final Runnable task; + + private final CallbackInterface callback; + + private final String taskDoneMessage; + + public RunnableImpl(Runnable task, CallbackInterface callback, String taskDoneMessage) { + this.task = task; + this.callback = callback; + this.taskDoneMessage = taskDoneMessage; + } + + public void run() { + task.run(); + callback.taskDone(taskDoneMessage); + } + +} diff --git a/core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/notificationforcompletetask/Task.java b/core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/notificationforcompletetask/Task.java new file mode 100644 index 0000000000..601dfd79b8 --- /dev/null +++ b/core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/notificationforcompletetask/Task.java @@ -0,0 +1,9 @@ +package com.baeldung.concurrent.notificationforcompletetask; + +public class Task implements Runnable{ + @Override + public void run() { + System.out.println("Task in progress"); + // Business logic goes here + } +} diff --git a/core-java-modules/core-java-concurrency-basic/src/test/java/com/baeldung/concurrent/notificationforcompletetask/NotificationsForCompleteTasksUnitTest.java b/core-java-modules/core-java-concurrency-basic/src/test/java/com/baeldung/concurrent/notificationforcompletetask/NotificationsForCompleteTasksUnitTest.java new file mode 100644 index 0000000000..f15015da55 --- /dev/null +++ b/core-java-modules/core-java-concurrency-basic/src/test/java/com/baeldung/concurrent/notificationforcompletetask/NotificationsForCompleteTasksUnitTest.java @@ -0,0 +1,45 @@ +package com.baeldung.concurrent.notificationforcompletetask; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.FutureTask; + +import org.junit.Test; + +public class NotificationsForCompleteTasksUnitTest { + + @Test + public void whenImplementingRunnable_thenReceiveNotificationOfCompletedTask() { + Task task = new Task(); + Callback callback = new Callback(); + RunnableImpl runnableImpl = new RunnableImpl(task, callback, "ready for next task"); + runnableImpl.run(); + } + + @Test + public void whenUsingCompletableFuture_thenReceiveNotificationOfCompletedTask() { + Task task = new Task(); + Callback callback = new Callback(); + CompletableFuture.runAsync(task) + .thenAccept(result -> callback.taskDone("completion details: " + result)); + } + + @Test + public void whenUsingThreadPoolExecutor_thenReceiveNotificationOfCompletedTask(){ + Task task = new Task(); + Callback callback = new Callback(); + AlertingThreadPoolExecutor executor = new AlertingThreadPoolExecutor(callback); + executor.submit(task); + } + + @Test + public void whenUsingFutureTask_thenReceiveNotificationOfCompletedTask(){ + Task task = new Task(); + Callback callback = new Callback(); + FutureTask future = new AlertingFutureTask(task, callback); + ExecutorService executor = Executors.newSingleThreadExecutor(); + executor.submit(future); + } + +} diff --git a/core-java-modules/core-java-console/pom.xml b/core-java-modules/core-java-console/pom.xml index 4debf9388b..1b56f1f27c 100644 --- a/core-java-modules/core-java-console/pom.xml +++ b/core-java-modules/core-java-console/pom.xml @@ -19,6 +19,16 @@ jansi 2.4.0 + + org.junit.vintage + junit-vintage-engine + + + junit + junit + + + @@ -56,7 +66,7 @@ -Xmx300m -XX:+UseParallelGC -classpath - + com.baeldung.outofmemoryerror.OutOfMemoryGCLimitExceed @@ -70,6 +80,16 @@ ${target.version} + + org.apache.maven.plugins + maven-surefire-plugin + 3.1.2 + + + junit-vintage-engine + + + @@ -120,7 +140,7 @@ java -classpath - + org.openjdk.jmh.Main .* diff --git a/core-java-modules/core-java-console/src/test/java/com/baeldung/asciiart/AsciiArtIntegrationTest.java b/core-java-modules/core-java-console/src/test/java/com/baeldung/asciiart/AsciiArtIntegrationTest.java index 364435e890..4274551cf8 100644 --- a/core-java-modules/core-java-console/src/test/java/com/baeldung/asciiart/AsciiArtIntegrationTest.java +++ b/core-java-modules/core-java-console/src/test/java/com/baeldung/asciiart/AsciiArtIntegrationTest.java @@ -1,11 +1,11 @@ package com.baeldung.asciiart; -import com.baeldung.asciiart.AsciiArt.Settings; - -import java.awt.*; +import java.awt.Font; import org.junit.jupiter.api.Test; +import com.baeldung.asciiart.AsciiArt.Settings; + public class AsciiArtIntegrationTest { @Test diff --git a/core-java-modules/core-java-date-operations-3/README.md b/core-java-modules/core-java-date-operations-3/README.md index c87714f38a..97855814e5 100644 --- a/core-java-modules/core-java-date-operations-3/README.md +++ b/core-java-modules/core-java-date-operations-3/README.md @@ -8,4 +8,5 @@ This module contains articles about date operations in Java. - [How to Determine Date of the First Day of the Week Using LocalDate in Java](https://www.baeldung.com/java-first-day-of-the-week) - [Adding One Month to Current Date in Java](https://www.baeldung.com/java-adding-one-month-to-current-date) - [How to Get Last Day of a Month in Java](https://www.baeldung.com/java-last-day-month) +- [Getting Yesterday’s Date in Java](https://www.baeldung.com/java-find-yesterdays-date) - [[<-- Prev]](/core-java-modules/core-java-date-operations-2) diff --git a/core-java-modules/core-java-date-operations-3/src/test/java/com/baeldung/date/GetYesterdayDateUnitTest.java b/core-java-modules/core-java-date-operations-3/src/test/java/com/baeldung/date/GetYesterdayDateUnitTest.java new file mode 100644 index 0000000000..2b941cffdb --- /dev/null +++ b/core-java-modules/core-java-date-operations-3/src/test/java/com/baeldung/date/GetYesterdayDateUnitTest.java @@ -0,0 +1,71 @@ +package com.baeldung.date; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.time.LocalDate; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; + +import org.apache.commons.lang3.time.DateUtils; +import org.joda.time.Instant; +import org.junit.jupiter.api.Test; + +class GetYesterdayDateUnitTest { + + @SuppressWarnings("deprecation") + @Test + void givenDate_whenUsingDateClass_thenReturnYesterday() { + Date currentDate = new Date(2023, Calendar.DECEMBER, 20); + Date yesterdayDate = new Date(currentDate.getTime() - 24 * 60 * 60 * 1000); + Date expectedYesterdayDate = new Date(2023, Calendar.DECEMBER, 19); + + assertEquals(expectedYesterdayDate, yesterdayDate); + } + + @Test + void givenDate_whenUsingCalendarClass_thenReturnYesterday() { + Calendar date = new GregorianCalendar(2023, Calendar.APRIL, 20, 4, 0); + date.add(Calendar.DATE, -1); + Calendar expectedYesterdayDate = new GregorianCalendar(2023, Calendar.APRIL, 19, 4, 0); + + assertEquals(expectedYesterdayDate, date); + } + + @Test + void givenDate_whenUsingLocalDateClass_thenReturnYesterday() { + LocalDate localDate = LocalDate.of(2023, 12, 20); + LocalDate yesterdayDate = localDate.minusDays(1); + LocalDate expectedYesterdayDate = LocalDate.of(2023, 12, 19); + + assertEquals(expectedYesterdayDate, yesterdayDate); + } + + @Test + void givenDate_whenUsingInstantClass_thenReturnYesterday() { + Instant date = Instant.parse("2023-10-25"); + Instant yesterdayDate = date.minus(24 * 60 * 60 * 1000); + Instant expectedYesterdayDate = Instant.parse("2023-10-24"); + + assertEquals(expectedYesterdayDate, yesterdayDate); + } + + @Test + void givenDate_whenUsingJodaTimeLocalDateClass_thenReturnYesterday() { + org.joda.time.LocalDate localDate = new org.joda.time.LocalDate(2023, 12, 20); + org.joda.time.LocalDate yesterdayDate = localDate.minusDays(1); + org.joda.time.LocalDate expectedYesterdayDate = new org.joda.time.LocalDate(2023, 12, 19); + + assertEquals(expectedYesterdayDate, yesterdayDate); + } + + @Test + void givenDate_whenUsingApacheCommonsLangDateUtils_thenReturnYesterday() { + Date date = new GregorianCalendar(2023, Calendar.MAY, 16, 4, 0).getTime(); + Date yesterdayDate = DateUtils.addDays(date, -1); + Date expectedYesterdayDate = new GregorianCalendar(2023, Calendar.MAY, 15, 4, 0).getTime(); + + assertEquals(expectedYesterdayDate, yesterdayDate); + } + +} diff --git a/core-java-modules/core-java-date-operations-3/src/test/java/com/baeldung/firstandlastdayofyear/FirstAndLastDayOfYearUnitTest.java b/core-java-modules/core-java-date-operations-3/src/test/java/com/baeldung/firstandlastdayofyear/FirstAndLastDayOfYearUnitTest.java new file mode 100644 index 0000000000..5434c84af5 --- /dev/null +++ b/core-java-modules/core-java-date-operations-3/src/test/java/com/baeldung/firstandlastdayofyear/FirstAndLastDayOfYearUnitTest.java @@ -0,0 +1,55 @@ +package com.baeldung.firstandlastdayofyear; + +import static org.junit.Assert.assertEquals; + +import java.text.SimpleDateFormat; +import java.time.DayOfWeek; +import java.time.LocalDate; +import java.time.Month; +import java.util.Calendar; +import java.util.Date; +import org.junit.jupiter.api.Test; + +import static java.time.temporal.TemporalAdjusters.firstDayOfYear; +import static java.time.temporal.TemporalAdjusters.lastDayOfYear; + +public class FirstAndLastDayOfYearUnitTest { + + @Test + public void givenCurrentDate_whenGettingFirstAndLastDayOfYear_thenCorrectDatesReturned() { + LocalDate today = LocalDate.now(); + LocalDate firstDay = today.with(firstDayOfYear()); + LocalDate lastDay = today.with(lastDayOfYear()); + + assertEquals("2023-01-01", firstDay.toString()); + assertEquals("2023-12-31", lastDay.toString()); + } + + @Test + public void givenCalendarSetToFirstDayOfYear_whenFormattingDateToISO8601_thenFormattedDateMatchesFirstDay() { + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.YEAR, 2023); + cal.set(Calendar.DAY_OF_YEAR, 1); + Date firstDay = cal.getTime(); + + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + String formattedDate = sdf.format(firstDay); + + assertEquals("2023-01-01", formattedDate); + } + + @Test + public void givenCalendarSetToFirstDayOfYear_whenFormattingDateToISO8601_thenFormattedDateMatchesLastDay() { + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.YEAR, 2023); + cal.set(Calendar.MONTH, 11); + cal.set(Calendar.DAY_OF_MONTH, 31); + Date lastDay = cal.getTime(); + + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + String formattedDate = sdf.format(lastDay); + + assertEquals("2023-12-31", formattedDate); + } + +} diff --git a/core-java-modules/core-java-io-apis-2/README.md b/core-java-modules/core-java-io-apis-2/README.md index d62fd3dbd1..e86539c750 100644 --- a/core-java-modules/core-java-io-apis-2/README.md +++ b/core-java-modules/core-java-io-apis-2/README.md @@ -4,13 +4,5 @@ This module contains articles about core Java input/output(IO) APIs. ### Relevant Articles: - [Constructing a Relative Path From Two Absolute Paths in Java](https://www.baeldung.com/java-relative-path-absolute) -- [Java Scanner Taking a Character Input](https://www.baeldung.com/java-scanner-character-input) - [Get the Desktop Path in Java](https://www.baeldung.com/java-desktop-path) -- [Integer.parseInt(scanner.nextLine()) and scanner.nextInt() in Java](https://www.baeldung.com/java-scanner-integer) -- [Difference Between FileReader and BufferedReader in Java](https://www.baeldung.com/java-filereader-vs-bufferedreader) -- [Java: Read Multiple Inputs on Same Line](https://www.baeldung.com/java-read-multiple-inputs-same-line) -- [Storing Java Scanner Input in an Array](https://www.baeldung.com/java-store-scanner-input-in-array) -- [How to Take Input as String With Spaces in Java Using Scanner?](https://www.baeldung.com/java-scanner-input-with-spaces) -- [Write Console Output to Text File in Java](https://www.baeldung.com/java-write-console-output-file) -- [What’s the difference between Scanner next() and nextLine() methods?](https://www.baeldung.com/java-scanner-next-vs-nextline) -- [Handle NoSuchElementException When Reading a File Through Scanner](https://www.baeldung.com/java-scanner-nosuchelementexception-reading-file) +- [Check if a File Is Empty in Java](https://www.baeldung.com/java-check-file-empty) \ No newline at end of file diff --git a/core-java-modules/core-java-io-apis-2/pom.xml b/core-java-modules/core-java-io-apis-2/pom.xml index e828b730d2..bf7af998e3 100644 --- a/core-java-modules/core-java-io-apis-2/pom.xml +++ b/core-java-modules/core-java-io-apis-2/pom.xml @@ -92,12 +92,6 @@ 7.1.0 test - - org.testng - testng - 7.5 - compile - core-java-io-apis-2 diff --git a/core-java-modules/core-java-io-apis-2/src/test/java/com/baeldung/emptyfile/CheckFileIsEmptyUnitTest.java b/core-java-modules/core-java-io-apis-2/src/test/java/com/baeldung/emptyfile/CheckFileIsEmptyUnitTest.java new file mode 100644 index 0000000000..02b4d758b3 --- /dev/null +++ b/core-java-modules/core-java-io-apis-2/src/test/java/com/baeldung/emptyfile/CheckFileIsEmptyUnitTest.java @@ -0,0 +1,71 @@ +package com.baeldung.emptyfile; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +class CheckFileIsEmptyUnitTest { + @Test + void whenTheFileIsEmpty_thenFileLengthIsZero(@TempDir Path tempDir) throws IOException { + File emptyFile = tempDir.resolve("an-empty-file.txt") + .toFile(); + emptyFile.createNewFile(); + assertTrue(emptyFile.exists()); + assertEquals(0, emptyFile.length()); + } + + @Test + void whenFileDoesNotExist_thenFileLengthIsZero(@TempDir Path tempDir) { + File aNewFile = tempDir.resolve("a-new-file.txt") + .toFile(); + assertFalse(aNewFile.exists()); + assertEquals(0, aNewFile.length()); + } + + boolean isFileEmpty(File file) { + if (!file.exists()) { + throw new IllegalArgumentException("Cannot check the file length. The file is not found: " + file.getAbsolutePath()); + } + return file.length() == 0; + } + + @Test + void whenTheFileDoesNotExist_thenIsFilesEmptyThrowsException(@TempDir Path tempDir) { + File aNewFile = tempDir.resolve("a-new-file.txt") + .toFile(); + IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> isFileEmpty(aNewFile)); + assertEquals(ex.getMessage(), "Cannot check the file length. The file is not found: " + aNewFile.getAbsolutePath()); + } + + @Test + void whenTheFileIsEmpty_thenIsFilesEmptyReturnsTrue(@TempDir Path tempDir) throws IOException { + File emptyFile = tempDir.resolve("an-empty-file.txt") + .toFile(); + emptyFile.createNewFile(); + assertTrue(isFileEmpty(emptyFile)); + + } + + @Test + void whenTheFileIsEmpty_thenFilesSizeReturnsTrue(@TempDir Path tempDir) throws IOException { + Path emptyFilePath = tempDir.resolve("an-empty-file.txt"); + Files.createFile(emptyFilePath); + assertEquals(0, Files.size(emptyFilePath)); + } + + @Test + void whenTheFileDoesNotExist_thenFilesSizeThrowsException(@TempDir Path tempDir) { + Path aNewFilePath = tempDir.resolve("a-new-file.txt"); + assertThrows(NoSuchFileException.class, () -> Files.size(aNewFilePath)); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-io-apis-3/README.md b/core-java-modules/core-java-io-apis-3/README.md deleted file mode 100644 index 23f2b41ac7..0000000000 --- a/core-java-modules/core-java-io-apis-3/README.md +++ /dev/null @@ -1,6 +0,0 @@ -## Core Java IO APIs - -This module contains articles about core Java input/output(IO) APIs. - -### Relevant Articles: -- [Read Date in Java Using Scanner](https://www.baeldung.com/java-scanner-read-date) diff --git a/core-java-modules/core-java-io-apis-3/pom.xml b/core-java-modules/core-java-io-apis-3/pom.xml deleted file mode 100644 index 8b2431397b..0000000000 --- a/core-java-modules/core-java-io-apis-3/pom.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - 4.0.0 - core-java-io-apis-3 - core-java-io-apis-3 - jar - - - com.baeldung.core-java-modules - core-java-modules - 0.0.1-SNAPSHOT - - \ No newline at end of file diff --git a/core-java-modules/core-java-io-apis/README.md b/core-java-modules/core-java-io-apis/README.md index 9399443ebd..b00b0a6022 100644 --- a/core-java-modules/core-java-io-apis/README.md +++ b/core-java-modules/core-java-io-apis/README.md @@ -10,6 +10,6 @@ This module contains articles about core Java input/output(IO) APIs. - [Comparing getPath(), getAbsolutePath(), and getCanonicalPath() in Java](https://www.baeldung.com/java-path) - [Quick Use of FilenameFilter](https://www.baeldung.com/java-filename-filter) - [Guide to BufferedReader](https://www.baeldung.com/java-buffered-reader) -- [Java Scanner](https://www.baeldung.com/java-scanner) -- [Scanner nextLine() Method](https://www.baeldung.com/java-scanner-nextline) -- [Java Scanner hasNext() vs. hasNextLine()](https://www.baeldung.com/java-scanner-hasnext-vs-hasnextline) \ No newline at end of file +- [Difference Between FileReader and BufferedReader in Java](https://www.baeldung.com/java-filereader-vs-bufferedreader) +- [Java: Read Multiple Inputs on Same Line](https://www.baeldung.com/java-read-multiple-inputs-same-line) +- [Write Console Output to Text File in Java](https://www.baeldung.com/java-write-console-output-file) \ No newline at end of file diff --git a/core-java-modules/core-java-io-apis/pom.xml b/core-java-modules/core-java-io-apis/pom.xml index f9d404cd5b..8889fd5f50 100644 --- a/core-java-modules/core-java-io-apis/pom.xml +++ b/core-java-modules/core-java-io-apis/pom.xml @@ -31,6 +31,12 @@ ${lombok.version} provided + + org.testng + testng + 7.5 + compile + diff --git a/core-java-modules/core-java-io-apis-2/src/main/java/com/baeldung/multinput/MultiInputs.java b/core-java-modules/core-java-io-apis/src/main/java/com/baeldung/multinput/MultiInputs.java similarity index 97% rename from core-java-modules/core-java-io-apis-2/src/main/java/com/baeldung/multinput/MultiInputs.java rename to core-java-modules/core-java-io-apis/src/main/java/com/baeldung/multinput/MultiInputs.java index df799b2511..bc14c4275b 100644 --- a/core-java-modules/core-java-io-apis-2/src/main/java/com/baeldung/multinput/MultiInputs.java +++ b/core-java-modules/core-java-io-apis/src/main/java/com/baeldung/multinput/MultiInputs.java @@ -1,36 +1,36 @@ -package com.baeldung.multinput; - -import java.util.InputMismatchException; -import java.util.Scanner; - -public class MultiInputs { - public void UsingSpaceDelimiter(){ - Scanner scanner = new Scanner(System.in); - System.out.print("Enter two numbers: "); - int num1 = scanner.nextInt(); - int num2 = scanner.nextInt(); - System.out.println("You entered " + num1 + " and " + num2); - - } - public void UsingREDelimiter(){ - Scanner scanner = new Scanner(System.in); - scanner.useDelimiter("[\\s,]+"); - System.out.print("Enter two numbers separated by a space or a comma: "); - int num1 = scanner.nextInt(); - int num2 = scanner.nextInt(); - System.out.println("You entered " + num1 + " and " + num2); - - } - public void UsingCustomDelimiter(){ - Scanner scanner = new Scanner(System.in); - scanner.useDelimiter(";"); - System.out.print("Enter two numbers separated by a semicolon: "); - try { int num1 = scanner.nextInt(); - int num2 = scanner.nextInt(); - System.out.println("You entered " + num1 + " and " + num2); } - catch (InputMismatchException e) - { System.out.println("Invalid input. Please enter two integers separated by a semicolon."); } - - } -} - +package com.baeldung.multinput; + +import java.util.InputMismatchException; +import java.util.Scanner; + +public class MultiInputs { + public void UsingSpaceDelimiter(){ + Scanner scanner = new Scanner(System.in); + System.out.print("Enter two numbers: "); + int num1 = scanner.nextInt(); + int num2 = scanner.nextInt(); + System.out.println("You entered " + num1 + " and " + num2); + + } + public void UsingREDelimiter(){ + Scanner scanner = new Scanner(System.in); + scanner.useDelimiter("[\\s,]+"); + System.out.print("Enter two numbers separated by a space or a comma: "); + int num1 = scanner.nextInt(); + int num2 = scanner.nextInt(); + System.out.println("You entered " + num1 + " and " + num2); + + } + public void UsingCustomDelimiter(){ + Scanner scanner = new Scanner(System.in); + scanner.useDelimiter(";"); + System.out.print("Enter two numbers separated by a semicolon: "); + try { int num1 = scanner.nextInt(); + int num2 = scanner.nextInt(); + System.out.println("You entered " + num1 + " and " + num2); } + catch (InputMismatchException e) + { System.out.println("Invalid input. Please enter two integers separated by a semicolon."); } + + } +} + diff --git a/core-java-modules/core-java-io-apis-2/src/test/java/com/baeldung/bufferedreadervsfilereader/BufferedReaderUnitTest.java b/core-java-modules/core-java-io-apis/src/test/java/com/baeldung/bufferedreadervsfilereader/BufferedReaderUnitTest.java similarity index 96% rename from core-java-modules/core-java-io-apis-2/src/test/java/com/baeldung/bufferedreadervsfilereader/BufferedReaderUnitTest.java rename to core-java-modules/core-java-io-apis/src/test/java/com/baeldung/bufferedreadervsfilereader/BufferedReaderUnitTest.java index 62f0d9da22..6892ef33a9 100644 --- a/core-java-modules/core-java-io-apis-2/src/test/java/com/baeldung/bufferedreadervsfilereader/BufferedReaderUnitTest.java +++ b/core-java-modules/core-java-io-apis/src/test/java/com/baeldung/bufferedreadervsfilereader/BufferedReaderUnitTest.java @@ -1,36 +1,36 @@ -package com.baeldung.bufferedreadervsfilereader; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; - -import org.junit.jupiter.api.Test; - -class BufferedReaderUnitTest { - - @Test - void whenReadingAFile_thenReadsLineByLine() { - StringBuilder result = new StringBuilder(); - - final Path filePath = new File("src/test/resources/sampleText1.txt").toPath(); - try (BufferedReader br = new BufferedReader(new InputStreamReader(Files.newInputStream(filePath), StandardCharsets.UTF_8))) { - String line; - - while((line = br.readLine()) != null) { - result.append(line); - result.append('\n'); - } - } catch (IOException e) { - e.printStackTrace(); - } - - assertEquals("first line\nsecond line\nthird line\n", result.toString()); - } - -} +package com.baeldung.bufferedreadervsfilereader; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; + +import org.junit.jupiter.api.Test; + +class BufferedReaderUnitTest { + + @Test + void whenReadingAFile_thenReadsLineByLine() { + StringBuilder result = new StringBuilder(); + + final Path filePath = new File("src/test/resources/sampleText1.txt").toPath(); + try (BufferedReader br = new BufferedReader(new InputStreamReader(Files.newInputStream(filePath), StandardCharsets.UTF_8))) { + String line; + + while((line = br.readLine()) != null) { + result.append(line); + result.append('\n'); + } + } catch (IOException e) { + e.printStackTrace(); + } + + assertEquals("first line\nsecond line\nthird line\n", result.toString()); + } + +} diff --git a/core-java-modules/core-java-io-apis-2/src/test/java/com/baeldung/bufferedreadervsfilereader/FileReaderUnitTest.java b/core-java-modules/core-java-io-apis/src/test/java/com/baeldung/bufferedreadervsfilereader/FileReaderUnitTest.java similarity index 95% rename from core-java-modules/core-java-io-apis-2/src/test/java/com/baeldung/bufferedreadervsfilereader/FileReaderUnitTest.java rename to core-java-modules/core-java-io-apis/src/test/java/com/baeldung/bufferedreadervsfilereader/FileReaderUnitTest.java index da724d32e8..2c09d2a084 100644 --- a/core-java-modules/core-java-io-apis-2/src/test/java/com/baeldung/bufferedreadervsfilereader/FileReaderUnitTest.java +++ b/core-java-modules/core-java-io-apis/src/test/java/com/baeldung/bufferedreadervsfilereader/FileReaderUnitTest.java @@ -1,30 +1,30 @@ -package com.baeldung.bufferedreadervsfilereader; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.io.FileReader; -import java.io.IOException; - -import org.junit.jupiter.api.Test; - -class FileReaderUnitTest { - - @Test - void whenReadingAFile_thenReadsCharByChar() { - StringBuilder result = new StringBuilder(); - - try (FileReader fr = new FileReader("src/test/resources/sampleText2.txt")) { - int i = fr.read(); - - while(i != -1) { - result.append((char)i); - - i = fr.read(); - } - } catch (IOException e) { - e.printStackTrace(); - } - - assertEquals("qwerty", result.toString()); - } -} +package com.baeldung.bufferedreadervsfilereader; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.FileReader; +import java.io.IOException; + +import org.junit.jupiter.api.Test; + +class FileReaderUnitTest { + + @Test + void whenReadingAFile_thenReadsCharByChar() { + StringBuilder result = new StringBuilder(); + + try (FileReader fr = new FileReader("src/test/resources/sampleText2.txt")) { + int i = fr.read(); + + while(i != -1) { + result.append((char)i); + + i = fr.read(); + } + } catch (IOException e) { + e.printStackTrace(); + } + + assertEquals("qwerty", result.toString()); + } +} diff --git a/core-java-modules/core-java-io-apis-2/src/test/java/com/baeldung/multinput/TestMultipleInputsUnitTest.java b/core-java-modules/core-java-io-apis/src/test/java/com/baeldung/multinput/TestMultipleInputsUnitTest.java similarity index 84% rename from core-java-modules/core-java-io-apis-2/src/test/java/com/baeldung/multinput/TestMultipleInputsUnitTest.java rename to core-java-modules/core-java-io-apis/src/test/java/com/baeldung/multinput/TestMultipleInputsUnitTest.java index 317d9e817e..0fbcd9bbb2 100644 --- a/core-java-modules/core-java-io-apis-2/src/test/java/com/baeldung/multinput/TestMultipleInputsUnitTest.java +++ b/core-java-modules/core-java-io-apis/src/test/java/com/baeldung/multinput/TestMultipleInputsUnitTest.java @@ -1,47 +1,49 @@ -package com.baeldung.multinput; - import java.io.ByteArrayInputStream; - import java.io.InputStream; - import java.util.InputMismatchException; - import org.junit.jupiter.api.Assertions; - import org.testng.annotations.Test; -import com.baeldung.multinput.MultiInputs; -public class TestMultipleInputsUnitTest { - @Test - public void givenMultipleInputs_whenUsingSpaceDelimiter_thenExpectPrintingOutputs() { - String input = "10 20\n"; - InputStream in = new ByteArrayInputStream(input.getBytes()); - System.setIn(in); - MultiInputs mi = new MultiInputs(); - mi.UsingSpaceDelimiter(); - // You can add assertions here to verify the behavior of the method - } - - @Test - public void givenMultipleInputs_whenUsingREDelimiter_thenExpectPrintingOutputs() { - String input = "30, 40\n"; - InputStream in = new ByteArrayInputStream(input.getBytes()); - System.setIn(in); - MultiInputs mi = new MultiInputs(); - mi.UsingREDelimiter(); - // You can add assertions here to verify the behavior of the method - } - - @Test - public void givenMultipleInputs_whenUsingCustomDelimiter_thenExpectPrintingOutputs() { - String input = "50; 60\n"; - InputStream in = new ByteArrayInputStream(input.getBytes()); - System.setIn(in); - MultiInputs mi = new MultiInputs(); - mi.UsingCustomDelimiter(); - // You can add assertions here to verify the behavior of the method - } - - @Test - public void givenInvalidInput_whenUsingSpaceDelimiter_thenExpectInputMismatchException() { - String input = "abc\n"; - InputStream in = new ByteArrayInputStream(input.getBytes()); - System.setIn(in); - MultiInputs mi = new MultiInputs(); - Assertions.assertThrows(InputMismatchException.class, mi::UsingSpaceDelimiter); - } -} +package com.baeldung.multinput; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.util.InputMismatchException; + +import org.junit.jupiter.api.Assertions; +import org.testng.annotations.Test; + +public class TestMultipleInputsUnitTest { + @Test + public void givenMultipleInputs_whenUsingSpaceDelimiter_thenExpectPrintingOutputs() { + String input = "10 20\n"; + InputStream in = new ByteArrayInputStream(input.getBytes()); + System.setIn(in); + MultiInputs mi = new MultiInputs(); + mi.UsingSpaceDelimiter(); + // You can add assertions here to verify the behavior of the method + } + + @Test + public void givenMultipleInputs_whenUsingREDelimiter_thenExpectPrintingOutputs() { + String input = "30, 40\n"; + InputStream in = new ByteArrayInputStream(input.getBytes()); + System.setIn(in); + MultiInputs mi = new MultiInputs(); + mi.UsingREDelimiter(); + // You can add assertions here to verify the behavior of the method + } + + @Test + public void givenMultipleInputs_whenUsingCustomDelimiter_thenExpectPrintingOutputs() { + String input = "50; 60\n"; + InputStream in = new ByteArrayInputStream(input.getBytes()); + System.setIn(in); + MultiInputs mi = new MultiInputs(); + mi.UsingCustomDelimiter(); + // You can add assertions here to verify the behavior of the method + } + + @Test + public void givenInvalidInput_whenUsingSpaceDelimiter_thenExpectInputMismatchException() { + String input = "abc\n"; + InputStream in = new ByteArrayInputStream(input.getBytes()); + System.setIn(in); + MultiInputs mi = new MultiInputs(); + Assertions.assertThrows(InputMismatchException.class, mi::UsingSpaceDelimiter); + } +} diff --git a/core-java-modules/core-java-io-apis-2/src/test/java/com/baeldung/outputtofile/ConsoleOutputToFileUnitTest.java b/core-java-modules/core-java-io-apis/src/test/java/com/baeldung/outputtofile/ConsoleOutputToFileUnitTest.java similarity index 100% rename from core-java-modules/core-java-io-apis-2/src/test/java/com/baeldung/outputtofile/ConsoleOutputToFileUnitTest.java rename to core-java-modules/core-java-io-apis/src/test/java/com/baeldung/outputtofile/ConsoleOutputToFileUnitTest.java diff --git a/core-java-modules/core-java-io/pom.xml b/core-java-modules/core-java-io/pom.xml index ce072e6875..a59ac619bd 100644 --- a/core-java-modules/core-java-io/pom.xml +++ b/core-java-modules/core-java-io/pom.xml @@ -64,7 +64,7 @@ -Xmx300m -XX:+UseParallelGC -classpath - + com.baeldung.outofmemoryerror.OutOfMemoryGCLimitExceed @@ -116,7 +116,7 @@ java -classpath - + org.openjdk.jmh.Main .* diff --git a/core-java-modules/core-java-jar/README.md b/core-java-modules/core-java-jar/README.md index c99ea63b22..cf4c0f461e 100644 --- a/core-java-modules/core-java-jar/README.md +++ b/core-java-modules/core-java-jar/README.md @@ -4,7 +4,7 @@ This module contains articles about JAR files ### Relevant Articles: -- [How to Create an Executable JAR with Maven](http://www.baeldung.com/executable-jar-with-maven) +- [How to Create an Executable JAR with Maven](https://www.baeldung.com/executable-jar-with-maven) - [Importance of Main Manifest Attribute in a Self-Executing JAR](http://www.baeldung.com/java-jar-executable-manifest-main-class) - [Guide to Creating and Running a Jar File in Java](https://www.baeldung.com/java-create-jar) - [Get Names of Classes Inside a JAR File](https://www.baeldung.com/jar-file-get-class-names) diff --git a/core-java-modules/core-java-jar/pom.xml b/core-java-modules/core-java-jar/pom.xml index e4a43bdf1f..ec88abe444 100644 --- a/core-java-modules/core-java-jar/pom.xml +++ b/core-java-modules/core-java-jar/pom.xml @@ -189,7 +189,7 @@ -Xmx300m -XX:+UseParallelGC -classpath - + com.baeldung.outofmemoryerror.OutOfMemoryGCLimitExceed @@ -253,7 +253,7 @@ java -classpath - + org.openjdk.jmh.Main .* diff --git a/core-java-modules/core-java-jvm/pom.xml b/core-java-modules/core-java-jvm/pom.xml index 52bdf8bc5d..9bf75fe4e2 100644 --- a/core-java-modules/core-java-jvm/pom.xml +++ b/core-java-modules/core-java-jvm/pom.xml @@ -168,6 +168,7 @@ 3.27.0-GA + 2.5.2.0 0.10 9.4 6.5.0 diff --git a/core-java-modules/core-java-lang-6/README.md b/core-java-modules/core-java-lang-6/README.md new file mode 100644 index 0000000000..515e29bedd --- /dev/null +++ b/core-java-modules/core-java-lang-6/README.md @@ -0,0 +1,8 @@ +## Core Java Lang (Part 6) + +This module contains articles about core features in the Java language + +### Relevant Articles: + +- [Convert One Enum to Another Enum in Java](https://www.baeldung.com/java-convert-enums) +- [What Is the Maximum Depth of the Java Call Stack?](https://www.baeldung.com/java-call-stack-max-depth) diff --git a/core-java-modules/core-java-lang-6/pom.xml b/core-java-modules/core-java-lang-6/pom.xml new file mode 100644 index 0000000000..86121e0a7f --- /dev/null +++ b/core-java-modules/core-java-lang-6/pom.xml @@ -0,0 +1,52 @@ + + + 4.0.0 + + com.baeldung.core-java-modules + core-java-modules + 0.0.1-SNAPSHOT + + + core-java-lang-6 + + + + + org.mapstruct + mapstruct + ${mapstruct.version} + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.5.1 + + 17 + 17 + + + + org.mapstruct + mapstruct-processor + ${mapstruct.version} + + + + + + + + + 17 + 17 + UTF-8 + 1.5.5.Final + + + \ No newline at end of file diff --git a/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/callstack/RecursiveCallStackOverflow.java b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/callstack/RecursiveCallStackOverflow.java new file mode 100644 index 0000000000..aef8fb8879 --- /dev/null +++ b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/callstack/RecursiveCallStackOverflow.java @@ -0,0 +1,19 @@ +package com.baeldung.callstack; + +public class RecursiveCallStackOverflow { + static int depth = 0; + + private static void recursiveStackOverflow() { + depth++; + recursiveStackOverflow(); + } + + public static void main(String[] args) { + try { + recursiveStackOverflow(); + } catch (StackOverflowError e) { + System.out.println("Maximum depth of the call stack is " + depth); + } + } + +} diff --git a/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/enums/mapping/EnumMapper.java b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/enums/mapping/EnumMapper.java new file mode 100644 index 0000000000..5b6a82d860 --- /dev/null +++ b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/enums/mapping/EnumMapper.java @@ -0,0 +1,26 @@ +package com.baeldung.enums.mapping; + +import org.mapstruct.Mapper; +import org.mapstruct.MappingConstants; +import org.mapstruct.ValueMapping; + +import com.baeldung.enums.mapping.order.CmsOrderStatus; +import com.baeldung.enums.mapping.order.OrderStatus; +import com.baeldung.enums.mapping.user.ExternalUserStatus; +import com.baeldung.enums.mapping.user.UserStatus; + +@Mapper +public interface EnumMapper { + + CmsOrderStatus map(OrderStatus orderStatus); + + @ValueMapping(source = "PENDING", target = "INACTIVE") + @ValueMapping(source = "BLOCKED", target = "INACTIVE") + @ValueMapping(source = "INACTIVATED_BY_SYSTEM", target = "INACTIVE") + @ValueMapping(source = "DELETED", target = "INACTIVE") + ExternalUserStatus map(UserStatus userStatus); + + @ValueMapping(source = MappingConstants.ANY_REMAINING, target = "INACTIVE") + ExternalUserStatus mapDefault(UserStatus userStatus); + +} diff --git a/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/enums/mapping/order/CmsOrderStatus.java b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/enums/mapping/order/CmsOrderStatus.java new file mode 100644 index 0000000000..8c35f62180 --- /dev/null +++ b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/enums/mapping/order/CmsOrderStatus.java @@ -0,0 +1,5 @@ +package com.baeldung.enums.mapping.order; + +public enum CmsOrderStatus { + PENDING, APPROVED, PACKED, DELIVERED +} diff --git a/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/enums/mapping/order/OrderStatus.java b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/enums/mapping/order/OrderStatus.java new file mode 100644 index 0000000000..b46018cc4f --- /dev/null +++ b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/enums/mapping/order/OrderStatus.java @@ -0,0 +1,13 @@ +package com.baeldung.enums.mapping.order; + +public enum OrderStatus { + PENDING, APPROVED, PACKED, DELIVERED; + + public CmsOrderStatus toCmsOrderStatus() { + return CmsOrderStatus.valueOf(this.name()); + } + + public CmsOrderStatus toCmsOrderStatusOrdinal() { + return CmsOrderStatus.values()[this.ordinal()]; + } +} diff --git a/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/enums/mapping/user/ExternalUserStatus.java b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/enums/mapping/user/ExternalUserStatus.java new file mode 100644 index 0000000000..7361e8fe75 --- /dev/null +++ b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/enums/mapping/user/ExternalUserStatus.java @@ -0,0 +1,5 @@ +package com.baeldung.enums.mapping.user; + +public enum ExternalUserStatus { + ACTIVE, INACTIVE +} diff --git a/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/enums/mapping/user/UserStatus.java b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/enums/mapping/user/UserStatus.java new file mode 100644 index 0000000000..6e6d5d2a9a --- /dev/null +++ b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/enums/mapping/user/UserStatus.java @@ -0,0 +1,26 @@ +package com.baeldung.enums.mapping.user; + +public enum UserStatus { + PENDING, ACTIVE, BLOCKED, INACTIVATED_BY_SYSTEM, DELETED; + + public ExternalUserStatus toExternalUserStatusViaSwitchStatement() { + return switch (this) { + case PENDING, BLOCKED, INACTIVATED_BY_SYSTEM, DELETED -> ExternalUserStatus.INACTIVE; + case ACTIVE -> ExternalUserStatus.ACTIVE; + }; + } + + public ExternalUserStatus toExternalUserStatusViaRegularSwitch() { + switch (this) { + case PENDING: + case BLOCKED: + case INACTIVATED_BY_SYSTEM: + case DELETED: + return ExternalUserStatus.INACTIVE; + case ACTIVE: + return ExternalUserStatus.ACTIVE; + } + return null; + } + +} diff --git a/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/enums/mapping/user/UserStatusMapper.java b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/enums/mapping/user/UserStatusMapper.java new file mode 100644 index 0000000000..a9ec017d6d --- /dev/null +++ b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/enums/mapping/user/UserStatusMapper.java @@ -0,0 +1,20 @@ +package com.baeldung.enums.mapping.user; + +import java.util.EnumMap; + +public class UserStatusMapper { + public static EnumMap statusesMap; + + static { + statusesMap = new EnumMap<>(UserStatus.class); + statusesMap.put(UserStatus.PENDING, ExternalUserStatus.INACTIVE); + statusesMap.put(UserStatus.BLOCKED, ExternalUserStatus.INACTIVE); + statusesMap.put(UserStatus.DELETED, ExternalUserStatus.INACTIVE); + statusesMap.put(UserStatus.INACTIVATED_BY_SYSTEM, ExternalUserStatus.INACTIVE); + statusesMap.put(UserStatus.ACTIVE, ExternalUserStatus.ACTIVE); + } + + public static ExternalUserStatus toExternalUserStatus(UserStatus userStatus) { + return statusesMap.get(userStatus); + } +} diff --git a/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/enums/mapping/user/UserStatusWithFieldVariable.java b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/enums/mapping/user/UserStatusWithFieldVariable.java new file mode 100644 index 0000000000..49ec9200ae --- /dev/null +++ b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/enums/mapping/user/UserStatusWithFieldVariable.java @@ -0,0 +1,19 @@ +package com.baeldung.enums.mapping.user; + +public enum UserStatusWithFieldVariable { + PENDING(ExternalUserStatus.INACTIVE), + ACTIVE(ExternalUserStatus.ACTIVE), + BLOCKED(ExternalUserStatus.INACTIVE), + INACTIVATED_BY_SYSTEM(ExternalUserStatus.INACTIVE), + DELETED(ExternalUserStatus.INACTIVE); + + private final ExternalUserStatus externalUserStatus; + + UserStatusWithFieldVariable(ExternalUserStatus externalUserStatus) { + this.externalUserStatus = externalUserStatus; + } + + public ExternalUserStatus toExternalUserStatus() { + return externalUserStatus; + } +} diff --git a/core-java-modules/core-java-lang-6/src/test/java/com/baeldung/enums/mapping/EnumConversionUnitTest.java b/core-java-modules/core-java-lang-6/src/test/java/com/baeldung/enums/mapping/EnumConversionUnitTest.java new file mode 100644 index 0000000000..9272f9b63a --- /dev/null +++ b/core-java-modules/core-java-lang-6/src/test/java/com/baeldung/enums/mapping/EnumConversionUnitTest.java @@ -0,0 +1,120 @@ +package com.baeldung.enums.mapping; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +import com.baeldung.enums.mapping.order.CmsOrderStatus; +import com.baeldung.enums.mapping.order.OrderStatus; +import com.baeldung.enums.mapping.user.ExternalUserStatus; +import com.baeldung.enums.mapping.user.UserStatus; +import com.baeldung.enums.mapping.user.UserStatusMapper; +import com.baeldung.enums.mapping.user.UserStatusWithFieldVariable; + +public class EnumConversionUnitTest { + + @Test + void whenUsingSwitchStatement_thenEnumConverted() { + UserStatus userStatusDeleted = UserStatus.DELETED; + UserStatus userStatusPending = UserStatus.PENDING; + UserStatus userStatusActive = UserStatus.ACTIVE; + + assertEquals(ExternalUserStatus.INACTIVE, userStatusDeleted.toExternalUserStatusViaSwitchStatement()); + assertEquals(ExternalUserStatus.INACTIVE, userStatusPending.toExternalUserStatusViaSwitchStatement()); + assertEquals(ExternalUserStatus.ACTIVE, userStatusActive.toExternalUserStatusViaSwitchStatement()); + } + + @Test + void whenUsingSwitch_thenEnumConverted() { + UserStatus userStatusDeleted = UserStatus.DELETED; + UserStatus userStatusPending = UserStatus.PENDING; + UserStatus userStatusActive = UserStatus.ACTIVE; + + assertEquals(ExternalUserStatus.INACTIVE, userStatusDeleted.toExternalUserStatusViaRegularSwitch()); + assertEquals(ExternalUserStatus.INACTIVE, userStatusPending.toExternalUserStatusViaRegularSwitch()); + assertEquals(ExternalUserStatus.ACTIVE, userStatusActive.toExternalUserStatusViaRegularSwitch()); + } + + @Test + void whenUsingFieldVariable_thenEnumConverted() { + UserStatusWithFieldVariable userStatusDeleted = UserStatusWithFieldVariable.DELETED; + UserStatusWithFieldVariable userStatusPending = UserStatusWithFieldVariable.PENDING; + UserStatusWithFieldVariable userStatusActive = UserStatusWithFieldVariable.ACTIVE; + + assertEquals(ExternalUserStatus.INACTIVE, userStatusDeleted.toExternalUserStatus()); + assertEquals(ExternalUserStatus.INACTIVE, userStatusPending.toExternalUserStatus()); + assertEquals(ExternalUserStatus.ACTIVE, userStatusActive.toExternalUserStatus()); + } + + @Test + void whenUsingEnumMap_thenEnumConverted() { + UserStatus userStatusDeleted = UserStatus.DELETED; + UserStatus userStatusPending = UserStatus.PENDING; + UserStatus userStatusActive = UserStatus.ACTIVE; + + assertEquals(ExternalUserStatus.INACTIVE, UserStatusMapper.toExternalUserStatus(userStatusDeleted)); + assertEquals(ExternalUserStatus.INACTIVE, UserStatusMapper.toExternalUserStatus(userStatusPending)); + assertEquals(ExternalUserStatus.ACTIVE, UserStatusMapper.toExternalUserStatus(userStatusActive)); + } + + @Test + void whenUsingOrdinalApproach_thenEnumConverted() { + OrderStatus orderStatusApproved = OrderStatus.APPROVED; + OrderStatus orderStatusDelivered = OrderStatus.DELIVERED; + OrderStatus orderStatusPending = OrderStatus.PENDING; + + assertEquals(CmsOrderStatus.APPROVED, orderStatusApproved.toCmsOrderStatusOrdinal()); + assertEquals(CmsOrderStatus.DELIVERED, orderStatusDelivered.toCmsOrderStatusOrdinal()); + assertEquals(CmsOrderStatus.PENDING, orderStatusPending.toCmsOrderStatusOrdinal()); + } + + @Test + void whenUsingEnumName_thenEnumConverted() { + OrderStatus orderStatusApproved = OrderStatus.APPROVED; + OrderStatus orderStatusDelivered = OrderStatus.DELIVERED; + OrderStatus orderStatusPending = OrderStatus.PENDING; + + assertEquals(CmsOrderStatus.APPROVED, orderStatusApproved.toCmsOrderStatus()); + assertEquals(CmsOrderStatus.DELIVERED, orderStatusDelivered.toCmsOrderStatus()); + assertEquals(CmsOrderStatus.PENDING, orderStatusPending.toCmsOrderStatus()); + } + + @Test + void whenUsingDefaultMapstruct_thenEnumConverted() { + UserStatus userStatusDeleted = UserStatus.DELETED; + UserStatus userStatusPending = UserStatus.PENDING; + UserStatus userStatusActive = UserStatus.ACTIVE; + + EnumMapper enumMapper = new EnumMapperImpl(); + + assertEquals(ExternalUserStatus.INACTIVE, enumMapper.map(userStatusDeleted)); + assertEquals(ExternalUserStatus.INACTIVE, enumMapper.map(userStatusPending)); + assertEquals(ExternalUserStatus.ACTIVE, enumMapper.map(userStatusActive)); + } + + @Test + void whenUsingConfiguredMapstruct_thenEnumConverted() { + OrderStatus orderStatusApproved = OrderStatus.APPROVED; + OrderStatus orderStatusDelivered = OrderStatus.DELIVERED; + OrderStatus orderStatusPending = OrderStatus.PENDING; + + EnumMapper enumMapper = new EnumMapperImpl(); + + assertEquals(CmsOrderStatus.APPROVED, enumMapper.map(orderStatusApproved)); + assertEquals(CmsOrderStatus.DELIVERED, enumMapper.map(orderStatusDelivered)); + assertEquals(CmsOrderStatus.PENDING, enumMapper.map(orderStatusPending)); + } + + @Test + void whenUsingConfiguredWithRemainingMapstruct_thenEnumConverted() { + UserStatus userStatusDeleted = UserStatus.DELETED; + UserStatus userStatusPending = UserStatus.PENDING; + UserStatus userStatusActive = UserStatus.ACTIVE; + + EnumMapper enumMapper = new EnumMapperImpl(); + + assertEquals(ExternalUserStatus.INACTIVE, enumMapper.mapDefault(userStatusDeleted)); + assertEquals(ExternalUserStatus.INACTIVE, enumMapper.mapDefault(userStatusPending)); + assertEquals(ExternalUserStatus.ACTIVE, enumMapper.mapDefault(userStatusActive)); + } +} diff --git a/core-java-modules/core-java-lang-math-2/README.md b/core-java-modules/core-java-lang-math-2/README.md index 9567ea6fb6..b2162fde99 100644 --- a/core-java-modules/core-java-lang-math-2/README.md +++ b/core-java-modules/core-java-lang-math-2/README.md @@ -5,7 +5,6 @@ ### Relevant articles: - [Calculate Factorial in Java](https://www.baeldung.com/java-calculate-factorial) -- [Generate Combinations in Java](https://www.baeldung.com/java-combinations-algorithm) - [Check if Two Rectangles Overlap in Java](https://www.baeldung.com/java-check-if-two-rectangles-overlap) - [Calculate the Distance Between Two Points in Java](https://www.baeldung.com/java-distance-between-two-points) - [Find the Intersection of Two Lines in Java](https://www.baeldung.com/java-intersection-of-two-lines) diff --git a/core-java-modules/core-java-lang-oop-generics/pom.xml b/core-java-modules/core-java-lang-oop-generics/pom.xml index b13683d1cd..fe6b5a9f36 100644 --- a/core-java-modules/core-java-lang-oop-generics/pom.xml +++ b/core-java-modules/core-java-lang-oop-generics/pom.xml @@ -29,7 +29,7 @@ ${maven.compiler.source} ${maven.compiler.target} - + diff --git a/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/demeter/DemeterApplication.java b/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/demeter/DemeterApplication.java new file mode 100644 index 0000000000..64ba2e2642 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/demeter/DemeterApplication.java @@ -0,0 +1,16 @@ +package com.baeldung.demeter; + +public class DemeterApplication { + public static void main(String[] args) { + + Expenses expenses = new Expenses(100, 10); + Employee employee = new Employee(); + employee.getDepartment() + .getManager() + .approveExpense(expenses); + + Manager mgr = new Manager(); + Employee emp = new Employee(mgr); + emp.submitExpense(expenses); + } +} diff --git a/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/demeter/Department.java b/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/demeter/Department.java new file mode 100644 index 0000000000..6591193f1f --- /dev/null +++ b/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/demeter/Department.java @@ -0,0 +1,11 @@ +package com.baeldung.demeter; + +public class Department { + + private Manager manager = new Manager(); + + public Manager getManager() { + return manager; + } + +} diff --git a/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/demeter/Employee.java b/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/demeter/Employee.java new file mode 100644 index 0000000000..7995ee9743 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/demeter/Employee.java @@ -0,0 +1,23 @@ +package com.baeldung.demeter; + +public class Employee { + private Department department = new Department(); + private Manager manager; + + public Employee() { + + } + + Employee(Manager manager) { + this.manager = manager; + } + + public Department getDepartment() { + return department; + } + + public void submitExpense(Expenses expenses) { + manager.approveExpense(expenses); + } + +} \ No newline at end of file diff --git a/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/demeter/Expenses.java b/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/demeter/Expenses.java new file mode 100644 index 0000000000..d0b2a3ec4d --- /dev/null +++ b/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/demeter/Expenses.java @@ -0,0 +1,16 @@ +package com.baeldung.demeter; + +public class Expenses { + + private double total; + private double tax; + + public Expenses(double total, double tax) { + this.total = total; + this.tax = tax; + } + + public double total() { + return total + tax; + } +} diff --git a/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/demeter/Greetings.java b/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/demeter/Greetings.java new file mode 100644 index 0000000000..1267b17c4c --- /dev/null +++ b/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/demeter/Greetings.java @@ -0,0 +1,33 @@ +package com.baeldung.demeter; + +public class Greetings { + + HelloCountries helloCountries = new HelloCountries(); + + private static HelloCountries helloCountriesStatic = new HelloCountries(); + + public String generalGreeting() { + return "Welcome" + world(); + } + + public String world() { + return "Hello World"; + } + + public String getHelloBrazil() { + HelloCountries helloCountries = new HelloCountries(); + return helloCountries.helloBrazil(); + } + + public String getHelloIndia(HelloCountries helloCountries) { + return helloCountries.helloIndia(); + } + + public String getHelloJapan() { + return helloCountries.helloJapan(); + } + + public String getHellStaticWorld() { + return helloCountriesStatic.helloStaticWorld(); + } +} diff --git a/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/demeter/HelloCountries.java b/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/demeter/HelloCountries.java new file mode 100644 index 0000000000..7fca0a6ec5 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/demeter/HelloCountries.java @@ -0,0 +1,20 @@ +package com.baeldung.demeter; + +public class HelloCountries { + + public String helloBrazil() { + return "Hello Brazil"; + } + + public String helloIndia() { + return "Hello India"; + } + + public String helloJapan() { + return "Hello Japan"; + } + + public String helloStaticWorld() { + return "Hello Static World"; + } +} diff --git a/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/demeter/Manager.java b/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/demeter/Manager.java new file mode 100644 index 0000000000..c26b23daf6 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-others/src/main/java/com/baeldung/demeter/Manager.java @@ -0,0 +1,9 @@ +package com.baeldung.demeter; + +public class Manager { + + public void approveExpense(Expenses expenses) { + System.out.println("Expense approved" + expenses.total()); + } + +} \ No newline at end of file diff --git a/core-java-modules/core-java-lang-oop-patterns/README.md b/core-java-modules/core-java-lang-oop-patterns/README.md index ea3309dc0a..ba18c57ab0 100644 --- a/core-java-modules/core-java-lang-oop-patterns/README.md +++ b/core-java-modules/core-java-lang-oop-patterns/README.md @@ -9,3 +9,4 @@ This module contains articles about Object-oriented programming (OOP) patterns i - [How to Make a Deep Copy of an Object in Java](https://www.baeldung.com/java-deep-copy) - [Using an Interface vs. Abstract Class in Java](https://www.baeldung.com/java-interface-vs-abstract-class) - [Should We Create an Interface for Only One Implementation?](https://www.baeldung.com/java-interface-single-implementation) +- [How to Deep Copy an ArrayList in Java](https://www.baeldung.com/java-arraylist-deep-copy) diff --git a/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/deepcopyarraylist/Course.java b/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/deepcopyarraylist/Course.java index 5724be7218..f8367cfd50 100644 --- a/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/deepcopyarraylist/Course.java +++ b/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/deepcopyarraylist/Course.java @@ -36,7 +36,7 @@ public class Course implements Serializable, Cloneable { try { return (Course) super.clone(); } catch (CloneNotSupportedException e) { - throw new AssertionError(); + throw new IllegalStateException(e); } } } diff --git a/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/deepcopyarraylist/Student.java b/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/deepcopyarraylist/Student.java index fedc9010ab..0b3f1ba4a9 100644 --- a/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/deepcopyarraylist/Student.java +++ b/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/deepcopyarraylist/Student.java @@ -95,7 +95,7 @@ public class Student implements Serializable, Cloneable { try { student = (Student) super.clone(); } catch (CloneNotSupportedException e) { - throw new AssertionError(); + throw new IllegalStateException(e); } student.course = this.course.clone(); return student; diff --git a/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/stateless/BubbleSort.java b/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/stateless/BubbleSort.java new file mode 100644 index 0000000000..1dffa23331 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/stateless/BubbleSort.java @@ -0,0 +1,20 @@ +package com.baeldung.stateless; + +public enum BubbleSort implements SortingStrategy { + + INSTANCE; + + @Override + public void sort(int[] array) { + int n = array.length; + for (int i = 0; i < n - 1; i++) { + for (int j = 0; j < n - i - 1; j++) { + if (array[j] > array[j + 1]) { + int swap = array[j]; + array[j] = array[j + 1]; + array[j + 1] = swap; + } + } + } + } +} diff --git a/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/stateless/QuickSort.java b/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/stateless/QuickSort.java new file mode 100644 index 0000000000..eab564e7ee --- /dev/null +++ b/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/stateless/QuickSort.java @@ -0,0 +1,36 @@ +package com.baeldung.stateless; + +public enum QuickSort implements SortingStrategy { + + INSTANCE; + + @Override + public void sort(int[] array) { + quickSort(array, 0, array.length - 1); + } + + private void quickSort(int[] array, int begin, int end) { + if (begin < end) { + int pi = partition(array, begin, end); + quickSort(array, begin, pi - 1); + quickSort(array, pi + 1, end); + } + } + + private int partition(int[] array, int low, int high) { + int pivot = array[high]; + int i = low - 1; + for (int j = low; j < high; j++) { + if (array[j] < pivot) { + i++; + int swap = array[i]; + array[i] = array[j]; + array[j] = swap; + } + } + int swap = array[i + 1]; + array[i + 1] = array[high]; + array[high] = swap; + return i + 1; + } +} diff --git a/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/stateless/SortingStrategy.java b/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/stateless/SortingStrategy.java new file mode 100644 index 0000000000..bc151482fd --- /dev/null +++ b/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/stateless/SortingStrategy.java @@ -0,0 +1,7 @@ +package com.baeldung.stateless; + +public interface SortingStrategy { + + public void sort(int[] array); + +} diff --git a/core-java-modules/core-java-lang-oop-patterns/src/test/java/com/baeldung/stateless/ArraySortingUnitTest.java b/core-java-modules/core-java-lang-oop-patterns/src/test/java/com/baeldung/stateless/ArraySortingUnitTest.java new file mode 100644 index 0000000000..c909e09325 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-patterns/src/test/java/com/baeldung/stateless/ArraySortingUnitTest.java @@ -0,0 +1,28 @@ +package com.baeldung.stateless; + +import static org.junit.Assert.assertArrayEquals; + +import org.junit.jupiter.api.Test; + +public class ArraySortingUnitTest { + + @Test + void givenArray_whenBubbleSorting_thenSorted() { + int[] arrayToSort = {17, 6, 11, 41, 5, 3, 4, -9}; + int[] sortedArray = {-9, 3, 4, 5, 6, 11, 17, 41}; + + SortingStrategy sortingStrategy = BubbleSort.INSTANCE; + sortingStrategy.sort(arrayToSort); + assertArrayEquals(sortedArray, arrayToSort); + } + + @Test + void givenArray_whenQuickSortSorting_thenSorted() { + int[] arrayToSort = {17, 6, 11, 41, 5, 3, 4, -9}; + int[] sortedArray = {-9, 3, 4, 5, 6, 11, 17, 41}; + + SortingStrategy sortingStrategy = QuickSort.INSTANCE; + sortingStrategy.sort(arrayToSort); + assertArrayEquals(sortedArray, arrayToSort); + } +} diff --git a/core-java-modules/core-java-locale/pom.xml b/core-java-modules/core-java-locale/pom.xml index f493d572a1..f4fd823444 100644 --- a/core-java-modules/core-java-locale/pom.xml +++ b/core-java-modules/core-java-locale/pom.xml @@ -13,7 +13,7 @@ core-java-modules 0.0.1-SNAPSHOT - + diff --git a/core-java-modules/core-java-networking/pom.xml b/core-java-modules/core-java-networking/pom.xml index 59aadbd1ed..5c959c62be 100644 --- a/core-java-modules/core-java-networking/pom.xml +++ b/core-java-modules/core-java-networking/pom.xml @@ -1,7 +1,7 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 core-java-networking core-java-networking diff --git a/core-java-modules/core-java-nio-2/src/test/java/com/baeldung/niovsnio2/NioVsNio2UnitTest.java b/core-java-modules/core-java-nio-2/src/test/java/com/baeldung/niovsnio2/NioVsNio2UnitTest.java index 7413ebda13..6d6ed0ebbf 100644 --- a/core-java-modules/core-java-nio-2/src/test/java/com/baeldung/niovsnio2/NioVsNio2UnitTest.java +++ b/core-java-modules/core-java-nio-2/src/test/java/com/baeldung/niovsnio2/NioVsNio2UnitTest.java @@ -65,6 +65,7 @@ public class NioVsNio2UnitTest { public void listFilesUsingWalk() throws Exception { Path path = Paths.get("src/test"); Stream walk = Files.walk(path); - walk.forEach(System.out::println); + + assertThat(walk.findAny()).isPresent(); } } diff --git a/core-java-modules/core-java-numbers-3/src/main/java/com/baeldung/randomnumbers/RandomNumbersGeneratorWithExclusion.java b/core-java-modules/core-java-numbers-3/src/main/java/com/baeldung/randomnumbers/RandomNumbersGeneratorWithExclusion.java new file mode 100644 index 0000000000..4aa228559a --- /dev/null +++ b/core-java-modules/core-java-numbers-3/src/main/java/com/baeldung/randomnumbers/RandomNumbersGeneratorWithExclusion.java @@ -0,0 +1,42 @@ +package com.baeldung.randomnumbers; + +import java.util.Arrays; +import java.util.OptionalInt; +import java.util.Random; + +public class RandomNumbersGeneratorWithExclusion { + + public static int getRandomWithExclusionUsingMathRandom(int min, int max, int[] exclude) { + Arrays.sort(exclude); + int random = min + (int) ((max - min + 1 - exclude.length) * Math.random()); + for (int ex : exclude) { + if (random < ex) { + break; + } + random++; + } + return random; + } + + public static int getRandomNumberWithExclusionUsingNextInt(int min, int max, int[] exclude) { + Random rnd = new Random(); + Arrays.sort(exclude); + int random = min + rnd.nextInt(max - min + 1 - exclude.length); + for (int ex : exclude) { + if (random < ex) { + break; + } + random++; + } + return random; + } + + public int getRandomWithExclusion(int min, int max, int[] exclude) { + Random rnd = new Random(); + OptionalInt random = rnd.ints(min, max + 1) + .filter(num -> Arrays.stream(exclude).noneMatch(ex -> num == ex)) + .findFirst(); + return random.orElse(min); + } + +} diff --git a/core-java-modules/core-java-numbers-6/README.md b/core-java-modules/core-java-numbers-6/README.md index 959d434935..560a84f851 100644 --- a/core-java-modules/core-java-numbers-6/README.md +++ b/core-java-modules/core-java-numbers-6/README.md @@ -1,4 +1,6 @@ ### Relevant Articles: - [Java Program to Estimate Pi](https://www.baeldung.com/java-monte-carlo-compute-pi) - [Convert Integer to Hexadecimal in Java](https://www.baeldung.com/java-convert-int-to-hex) +- [Integer.class Vs. Integer.TYPE Vs. int.class](https://www.baeldung.com/java-integer-class-vs-type-vs-int) +- [Does Java Read Integers in Little Endian or Big Endian?](https://www.baeldung.com/java-integers-little-big-endian) - More articles: [[<-- prev]](../core-java-numbers-5) diff --git a/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/endianness/Endianness.java b/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/endianness/Endianness.java new file mode 100644 index 0000000000..b84f301ee8 --- /dev/null +++ b/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/endianness/Endianness.java @@ -0,0 +1,17 @@ +package com.baeldung.endianness; + +import java.nio.ByteBuffer; + +public class Endianness { + + public static void main(String[] args) { + int value = 123456789; + byte[] bytes = ByteBuffer.allocate(4) + .putInt(value) + .array(); + + for (byte b : bytes) { + System.out.format("0x%x ", b); + } + } +} diff --git a/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/integerclassintegertypeintclass/IntegerClassIntegerTYPEIntClassUnitTest.java b/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/integerclassintegertypeintclass/IntegerClassIntegerTYPEIntClassUnitTest.java new file mode 100644 index 0000000000..53d6c7f71e --- /dev/null +++ b/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/integerclassintegertypeintclass/IntegerClassIntegerTYPEIntClassUnitTest.java @@ -0,0 +1,45 @@ +package com.baeldung.integerclassintegertypeintclass; + +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +public class IntegerClassIntegerTYPEIntClassUnitTest { + + @Test + public void givenIntegerClass_whenGetName_thenVerifyClassName() { + Class integerClass = Integer.class; + Assertions.assertEquals("java.lang.Integer", integerClass.getName()); + Assertions.assertEquals(Number.class, integerClass.getSuperclass()); + Assertions.assertFalse(integerClass.isPrimitive()); + } + + public int sum(int a, int b) { + return a + b; + } + + public int sum(Integer a, Integer b) { + return a + b; + } + + public int sum(int a, Integer b) { + return a + b; + } + + @Test + public void givenIntAndInteger_whenAddingValues_thenVerifySum() { + int primitiveValue = 10; + Integer wrapperValue = Integer.valueOf(primitiveValue); + Assertions.assertEquals(20, sum(primitiveValue, primitiveValue)); + Assertions.assertEquals(20, sum(primitiveValue, wrapperValue)); + Assertions.assertEquals(20, sum(wrapperValue, wrapperValue)); + Assertions.assertEquals(Integer.TYPE.getName(), int.class.getName()); + } + + @Test + public void givenIntValue_whenUsingIntClass_thenVerifyIntClassProperties() { + Class intClass = int.class; + Assertions.assertEquals("int", intClass.getName()); + Assertions.assertTrue(intClass.isPrimitive()); + Assertions.assertEquals(int.class, intClass); + } +} diff --git a/core-java-modules/core-java-numbers-conversions/README.md b/core-java-modules/core-java-numbers-conversions/README.md index 21810834bd..b4c593c494 100644 --- a/core-java-modules/core-java-numbers-conversions/README.md +++ b/core-java-modules/core-java-numbers-conversions/README.md @@ -1,2 +1,3 @@ ### Relevant Articles: - [Convert a Number to a Letter in Java](https://www.baeldung.com/java-convert-number-to-letter) +- [Convert Long to BigDecimal in Java](https://www.baeldung.com/java-convert-long-bigdecimal) diff --git a/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/longtobigdecimal/LongToBigDecimalUnitTest.java b/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/longtobigdecimal/LongToBigDecimalUnitTest.java new file mode 100644 index 0000000000..f59d0a6f09 --- /dev/null +++ b/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/longtobigdecimal/LongToBigDecimalUnitTest.java @@ -0,0 +1,70 @@ +package com.baeldung.longtobigdecimal; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotSame; +import static org.junit.jupiter.api.Assertions.assertSame; + +import java.math.BigDecimal; + +import org.junit.jupiter.api.Test; + +public class LongToBigDecimalUnitTest { + @Test + void whenUsingTheConstructor_thenGetTheExpectedBigDecimal() { + Long num4 = 4L; + BigDecimal result4 = new BigDecimal(num4); + assertEquals(new BigDecimal("4"), result4); + + Long num42 = -42L; + BigDecimal result42 = new BigDecimal(num42); + assertEquals(new BigDecimal("-42"), result42); + } + + @Test + void whenUsingTheValueOf_thenGetTheExpectedBigDecimal() { + Long num4 = 4L; + BigDecimal result4 = BigDecimal.valueOf(num4); + assertEquals(new BigDecimal("4"), result4); + + Long num42 = -42L; + BigDecimal result42 = BigDecimal.valueOf(num42); + assertEquals(new BigDecimal("-42"), result42); + } + + @Test + void when0To10AndUsingTheValueOfMethod_thenGetTheSameBigDecimalObject() { + Long num4 = 4L; + BigDecimal bd4_1 = BigDecimal.valueOf(num4); + BigDecimal bd4_2 = BigDecimal.valueOf(num4); + BigDecimal bd4_3 = BigDecimal.valueOf(num4); + assertSame(bd4_1, bd4_2); + assertSame(bd4_2, bd4_3); + + Long num42 = -42L; + BigDecimal bd42_1 = BigDecimal.valueOf(num42); + BigDecimal bd42_2 = BigDecimal.valueOf(num42); + BigDecimal bd42_3 = BigDecimal.valueOf(num42); + assertNotSame(bd42_1, bd42_2); + assertNotSame(bd42_1, bd42_3); + assertNotSame(bd42_2, bd42_3); + } + + @Test + void when0To10AndUsingTheConstructor_thenGetTheDifferentBigDecimalObjects() { + Long num4 = 4L; + BigDecimal result1 = new BigDecimal(num4); + BigDecimal result2 = new BigDecimal(num4); + BigDecimal result3 = new BigDecimal(num4); + assertNotSame(result1, result2); + assertNotSame(result2, result3); + assertNotSame(result1, result3); + + Long num42 = -42L; + BigDecimal bd42_1 = new BigDecimal(num42); + BigDecimal bd42_2 = new BigDecimal(num42); + BigDecimal bd42_3 = new BigDecimal(num42); + assertNotSame(bd42_1, bd42_2); + assertNotSame(bd42_1, bd42_3); + assertNotSame(bd42_2, bd42_3); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-records/pom.xml b/core-java-modules/core-java-records/pom.xml index ed9a36fc14..0caa1765fd 100644 --- a/core-java-modules/core-java-records/pom.xml +++ b/core-java-modules/core-java-records/pom.xml @@ -1,7 +1,7 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> core-java-modules com.baeldung.core-java-modules diff --git a/core-java-modules/core-java-scanner/README.md b/core-java-modules/core-java-scanner/README.md new file mode 100644 index 0000000000..87bd9c41bc --- /dev/null +++ b/core-java-modules/core-java-scanner/README.md @@ -0,0 +1,15 @@ +## Core Java Scanner + +This module contains articles about the Scanner. + +### Relevant Articles: +- [Java Scanner](https://www.baeldung.com/java-scanner) +- [Scanner nextLine() Method](https://www.baeldung.com/java-scanner-nextline) +- [Java Scanner hasNext() vs. hasNextLine()](https://www.baeldung.com/java-scanner-hasnext-vs-hasnextline) +- [Read Date in Java Using Scanner](https://www.baeldung.com/java-scanner-read-date) +- [Java Scanner Taking a Character Input](https://www.baeldung.com/java-scanner-character-input) +- [Integer.parseInt(scanner.nextLine()) and scanner.nextInt() in Java](https://www.baeldung.com/java-scanner-integer) +- [Storing Java Scanner Input in an Array](https://www.baeldung.com/java-store-scanner-input-in-array) +- [How to Take Input as String With Spaces in Java Using Scanner?](https://www.baeldung.com/java-scanner-input-with-spaces) +- [What’s the difference between Scanner next() and nextLine() methods?](https://www.baeldung.com/java-scanner-next-vs-nextline) +- [Handle NoSuchElementException When Reading a File Through Scanner](https://www.baeldung.com/java-scanner-nosuchelementexception-reading-file) diff --git a/core-java-modules/core-java-scanner/pom.xml b/core-java-modules/core-java-scanner/pom.xml new file mode 100644 index 0000000000..f149f51955 --- /dev/null +++ b/core-java-modules/core-java-scanner/pom.xml @@ -0,0 +1,34 @@ + + + 4.0.0 + core-java-scanner + core-java-scanner + jar + + + com.baeldung.core-java-modules + core-java-modules + 0.0.1-SNAPSHOT + + + + + log4j + log4j + ${log4j.version} + + + org.slf4j + log4j-over-slf4j + ${org.slf4j.version} + + + org.projectlombok + lombok + ${lombok.version} + provided + + + \ No newline at end of file diff --git a/core-java-modules/core-java-io-apis-3/src/main/java/com/baeldung/scanner/DateScanner.java b/core-java-modules/core-java-scanner/src/main/java/com/baeldung/scanner/DateScanner.java similarity index 96% rename from core-java-modules/core-java-io-apis-3/src/main/java/com/baeldung/scanner/DateScanner.java rename to core-java-modules/core-java-scanner/src/main/java/com/baeldung/scanner/DateScanner.java index a9f3ba820a..79fda8dc35 100644 --- a/core-java-modules/core-java-io-apis-3/src/main/java/com/baeldung/scanner/DateScanner.java +++ b/core-java-modules/core-java-scanner/src/main/java/com/baeldung/scanner/DateScanner.java @@ -1,29 +1,29 @@ -package com.baeldung.scanner; - -import java.text.DateFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.time.LocalDate; -import java.time.format.DateTimeFormatter; -import java.util.Date; -import java.util.Scanner; - -public class DateScanner { - - LocalDate scanToLocalDate(String input) { - try (Scanner scanner = new Scanner(input)) { - String dateString = scanner.next(); - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); - return LocalDate.parse(dateString, formatter); - } - } - - Date scanToDate(String input) throws ParseException { - try (Scanner scanner = new Scanner(input)) { - String dateString = scanner.next(); - DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); - return formatter.parse(dateString); - } - } - -} +package com.baeldung.scanner; + +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.Date; +import java.util.Scanner; + +public class DateScanner { + + LocalDate scanToLocalDate(String input) { + try (Scanner scanner = new Scanner(input)) { + String dateString = scanner.next(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + return LocalDate.parse(dateString, formatter); + } + } + + Date scanToDate(String input) throws ParseException { + try (Scanner scanner = new Scanner(input)) { + String dateString = scanner.next(); + DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); + return formatter.parse(dateString); + } + } + +} diff --git a/core-java-modules/core-java-io-apis/src/main/java/com/baeldung/scanner/HasNextVsHasNextLineDemo.java b/core-java-modules/core-java-scanner/src/main/java/com/baeldung/scanner/HasNextVsHasNextLineDemo.java similarity index 100% rename from core-java-modules/core-java-io-apis/src/main/java/com/baeldung/scanner/HasNextVsHasNextLineDemo.java rename to core-java-modules/core-java-scanner/src/main/java/com/baeldung/scanner/HasNextVsHasNextLineDemo.java diff --git a/core-java-modules/core-java-io-apis/src/main/java/com/baeldung/scanner/NextLineAfterNextMethods.java b/core-java-modules/core-java-scanner/src/main/java/com/baeldung/scanner/NextLineAfterNextMethods.java similarity index 100% rename from core-java-modules/core-java-io-apis/src/main/java/com/baeldung/scanner/NextLineAfterNextMethods.java rename to core-java-modules/core-java-scanner/src/main/java/com/baeldung/scanner/NextLineAfterNextMethods.java diff --git a/core-java-modules/core-java-io-apis-2/src/main/java/com/baeldung/scanner/ScannerNoSuchElementException.java b/core-java-modules/core-java-scanner/src/main/java/com/baeldung/scanner/ScannerNoSuchElementException.java similarity index 100% rename from core-java-modules/core-java-io-apis-2/src/main/java/com/baeldung/scanner/ScannerNoSuchElementException.java rename to core-java-modules/core-java-scanner/src/main/java/com/baeldung/scanner/ScannerNoSuchElementException.java diff --git a/core-java-modules/core-java-io-apis-3/src/test/java/com/baeldung/emptyfile/CheckFileIsEmptyUnitTest.java b/core-java-modules/core-java-scanner/src/test/java/com/baeldung/emptyfile/CheckFileIsEmptyUnitTest.java similarity index 100% rename from core-java-modules/core-java-io-apis-3/src/test/java/com/baeldung/emptyfile/CheckFileIsEmptyUnitTest.java rename to core-java-modules/core-java-scanner/src/test/java/com/baeldung/emptyfile/CheckFileIsEmptyUnitTest.java diff --git a/core-java-modules/core-java-io-apis-3/src/test/java/com/baeldung/scanner/DateScannerUnitTest.java b/core-java-modules/core-java-scanner/src/test/java/com/baeldung/scanner/DateScannerUnitTest.java similarity index 96% rename from core-java-modules/core-java-io-apis-3/src/test/java/com/baeldung/scanner/DateScannerUnitTest.java rename to core-java-modules/core-java-scanner/src/test/java/com/baeldung/scanner/DateScannerUnitTest.java index 1ecd440d95..0a02db12f3 100644 --- a/core-java-modules/core-java-io-apis-3/src/test/java/com/baeldung/scanner/DateScannerUnitTest.java +++ b/core-java-modules/core-java-scanner/src/test/java/com/baeldung/scanner/DateScannerUnitTest.java @@ -1,26 +1,26 @@ -package com.baeldung.scanner; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.time.LocalDate; -import java.time.format.DateTimeFormatter; - -import org.junit.jupiter.api.Test; - -class DateScannerUnitTest { - - @Test - void whenScanToLocalDate_ThenCorrectLocalDate() { - String dateString = "2018-09-09"; - assertEquals(LocalDate.parse(dateString, DateTimeFormatter.ofPattern("yyyy-MM-dd")), new DateScanner().scanToLocalDate(dateString)); - } - - @Test - void whenScanToDate_ThenCorrectDate() throws ParseException { - String dateString = "2018-09-09"; - assertEquals(new SimpleDateFormat("yyyy-MM-dd").parse(dateString), new DateScanner().scanToDate(dateString)); - } - -} +package com.baeldung.scanner; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; + +import org.junit.jupiter.api.Test; + +class DateScannerUnitTest { + + @Test + void whenScanToLocalDate_ThenCorrectLocalDate() { + String dateString = "2018-09-09"; + assertEquals(LocalDate.parse(dateString, DateTimeFormatter.ofPattern("yyyy-MM-dd")), new DateScanner().scanToLocalDate(dateString)); + } + + @Test + void whenScanToDate_ThenCorrectDate() throws ParseException { + String dateString = "2018-09-09"; + assertEquals(new SimpleDateFormat("yyyy-MM-dd").parse(dateString), new DateScanner().scanToDate(dateString)); + } + +} diff --git a/core-java-modules/core-java-io-apis-2/src/test/java/com/baeldung/scanner/InputWithSpacesUnitTest.java b/core-java-modules/core-java-scanner/src/test/java/com/baeldung/scanner/InputWithSpacesUnitTest.java similarity index 100% rename from core-java-modules/core-java-io-apis-2/src/test/java/com/baeldung/scanner/InputWithSpacesUnitTest.java rename to core-java-modules/core-java-scanner/src/test/java/com/baeldung/scanner/InputWithSpacesUnitTest.java diff --git a/core-java-modules/core-java-io-apis/src/test/java/com/baeldung/scanner/JavaScannerUnitTest.java b/core-java-modules/core-java-scanner/src/test/java/com/baeldung/scanner/JavaScannerUnitTest.java similarity index 100% rename from core-java-modules/core-java-io-apis/src/test/java/com/baeldung/scanner/JavaScannerUnitTest.java rename to core-java-modules/core-java-scanner/src/test/java/com/baeldung/scanner/JavaScannerUnitTest.java diff --git a/core-java-modules/core-java-io-apis-2/src/test/java/com/baeldung/scanner/NextLineVsNextIntUnitTest.java b/core-java-modules/core-java-scanner/src/test/java/com/baeldung/scanner/NextLineVsNextIntUnitTest.java similarity index 96% rename from core-java-modules/core-java-io-apis-2/src/test/java/com/baeldung/scanner/NextLineVsNextIntUnitTest.java rename to core-java-modules/core-java-scanner/src/test/java/com/baeldung/scanner/NextLineVsNextIntUnitTest.java index 3aae0469d0..8fab7c62e9 100644 --- a/core-java-modules/core-java-io-apis-2/src/test/java/com/baeldung/scanner/NextLineVsNextIntUnitTest.java +++ b/core-java-modules/core-java-scanner/src/test/java/com/baeldung/scanner/NextLineVsNextIntUnitTest.java @@ -1,85 +1,85 @@ -package com.baeldung.scanner; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; - -import java.util.InputMismatchException; -import java.util.Scanner; - -import org.junit.jupiter.api.Test; - -public class NextLineVsNextIntUnitTest { - - @Test - void whenInputLineIsNumber_thenNextLineAndNextIntBothWork() { - String input = "42\n"; - - //nextLine() - Scanner sc1 = new Scanner(input); - int num1 = Integer.parseInt(sc1.nextLine()); - assertEquals(42, num1); - - //nextInt() - Scanner sc2 = new Scanner(input); - int num2 = sc2.nextInt(); - assertEquals(42, num2); - - } - - @Test - void whenInputIsNotValidNumber_thenNextLineAndNextIntThrowDifferentException() { - String input = "Nan\n"; - - //nextLine() -> NumberFormatException - Scanner sc1 = new Scanner(input); - assertThrows(NumberFormatException.class, () -> Integer.parseInt(sc1.nextLine())); - - //nextInt() -> InputMismatchException - Scanner sc2 = new Scanner(input); - assertThrows(InputMismatchException.class, sc2::nextInt); - } - - @Test - void whenUsingNextInt_thenTheNextTokenAfterItFailsToParseIsNotConsumed() { - String input = "42 is a magic number\n"; - - //nextInt() to read '42' - Scanner sc2 = new Scanner(input); - int num2 = sc2.nextInt(); - assertEquals(42, num2); - - // call nextInt() again on "is" - assertThrows(InputMismatchException.class, sc2::nextInt); - - String theNextToken = sc2.next(); - assertEquals("is", theNextToken); - - theNextToken = sc2.next(); - assertEquals("a", theNextToken); - } - - @Test - void whenReadingTwoInputLines_thenNextLineAndNextIntBehaveDifferently() { - - String input = new StringBuilder().append("42\n") - .append("It is a magic number.\n") - .toString(); - - //nextLine() - Scanner sc1 = new Scanner(input); - int num1 = Integer.parseInt(sc1.nextLine()); - String nextLineText1 = sc1.nextLine(); - assertEquals(42, num1); - assertEquals("It is a magic number.", nextLineText1); - - //nextInt() - Scanner sc2 = new Scanner(input); - int num2 = sc2.nextInt(); - assertEquals(42, num2); - - // nextInt() leaves the newline character (\n) behind - String nextLineText2 = sc2.nextLine(); - assertEquals("", nextLineText2); - } - +package com.baeldung.scanner; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.InputMismatchException; +import java.util.Scanner; + +import org.junit.jupiter.api.Test; + +public class NextLineVsNextIntUnitTest { + + @Test + void whenInputLineIsNumber_thenNextLineAndNextIntBothWork() { + String input = "42\n"; + + //nextLine() + Scanner sc1 = new Scanner(input); + int num1 = Integer.parseInt(sc1.nextLine()); + assertEquals(42, num1); + + //nextInt() + Scanner sc2 = new Scanner(input); + int num2 = sc2.nextInt(); + assertEquals(42, num2); + + } + + @Test + void whenInputIsNotValidNumber_thenNextLineAndNextIntThrowDifferentException() { + String input = "Nan\n"; + + //nextLine() -> NumberFormatException + Scanner sc1 = new Scanner(input); + assertThrows(NumberFormatException.class, () -> Integer.parseInt(sc1.nextLine())); + + //nextInt() -> InputMismatchException + Scanner sc2 = new Scanner(input); + assertThrows(InputMismatchException.class, sc2::nextInt); + } + + @Test + void whenUsingNextInt_thenTheNextTokenAfterItFailsToParseIsNotConsumed() { + String input = "42 is a magic number\n"; + + //nextInt() to read '42' + Scanner sc2 = new Scanner(input); + int num2 = sc2.nextInt(); + assertEquals(42, num2); + + // call nextInt() again on "is" + assertThrows(InputMismatchException.class, sc2::nextInt); + + String theNextToken = sc2.next(); + assertEquals("is", theNextToken); + + theNextToken = sc2.next(); + assertEquals("a", theNextToken); + } + + @Test + void whenReadingTwoInputLines_thenNextLineAndNextIntBehaveDifferently() { + + String input = new StringBuilder().append("42\n") + .append("It is a magic number.\n") + .toString(); + + //nextLine() + Scanner sc1 = new Scanner(input); + int num1 = Integer.parseInt(sc1.nextLine()); + String nextLineText1 = sc1.nextLine(); + assertEquals(42, num1); + assertEquals("It is a magic number.", nextLineText1); + + //nextInt() + Scanner sc2 = new Scanner(input); + int num2 = sc2.nextInt(); + assertEquals(42, num2); + + // nextInt() leaves the newline character (\n) behind + String nextLineText2 = sc2.nextLine(); + assertEquals("", nextLineText2); + } + } \ No newline at end of file diff --git a/core-java-modules/core-java-io-apis-2/src/test/java/com/baeldung/scanner/NextVsNextLineUnitTest.java b/core-java-modules/core-java-scanner/src/test/java/com/baeldung/scanner/NextVsNextLineUnitTest.java similarity index 100% rename from core-java-modules/core-java-io-apis-2/src/test/java/com/baeldung/scanner/NextVsNextLineUnitTest.java rename to core-java-modules/core-java-scanner/src/test/java/com/baeldung/scanner/NextVsNextLineUnitTest.java diff --git a/core-java-modules/core-java-io-apis-2/src/test/java/com/baeldung/scanner/ScanACharacterUnitTest.java b/core-java-modules/core-java-scanner/src/test/java/com/baeldung/scanner/ScanACharacterUnitTest.java similarity index 96% rename from core-java-modules/core-java-io-apis-2/src/test/java/com/baeldung/scanner/ScanACharacterUnitTest.java rename to core-java-modules/core-java-scanner/src/test/java/com/baeldung/scanner/ScanACharacterUnitTest.java index 340b58bbf6..1a70c6e3af 100644 --- a/core-java-modules/core-java-io-apis-2/src/test/java/com/baeldung/scanner/ScanACharacterUnitTest.java +++ b/core-java-modules/core-java-scanner/src/test/java/com/baeldung/scanner/ScanACharacterUnitTest.java @@ -1,38 +1,38 @@ -package com.baeldung.scanner; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.util.Scanner; - -import org.junit.jupiter.api.Test; - -public class ScanACharacterUnitTest { - - // given - input scanner source, no need to scan from console - String input = new StringBuilder().append("abc\n") - .append("mno\n") - .append("xyz\n") - .toString(); - - @Test - public void givenInputSource_whenScanCharUsingNext_thenOneCharIsRead() { - Scanner sc = new Scanner(input); - char c = sc.next().charAt(0); - assertEquals('a', c); - } - - @Test - public void givenInputSource_whenScanCharUsingFindInLine_thenOneCharIsRead() { - Scanner sc = new Scanner(input); - char c = sc.findInLine(".").charAt(0); - assertEquals('a', c); - } - - @Test - public void givenInputSource_whenScanCharUsingUseDelimiter_thenOneCharIsRead() { - Scanner sc = new Scanner(input); - char c = sc.useDelimiter("").next().charAt(0); - assertEquals('a', c); - } - -} +package com.baeldung.scanner; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.Scanner; + +import org.junit.jupiter.api.Test; + +public class ScanACharacterUnitTest { + + // given - input scanner source, no need to scan from console + String input = new StringBuilder().append("abc\n") + .append("mno\n") + .append("xyz\n") + .toString(); + + @Test + public void givenInputSource_whenScanCharUsingNext_thenOneCharIsRead() { + Scanner sc = new Scanner(input); + char c = sc.next().charAt(0); + assertEquals('a', c); + } + + @Test + public void givenInputSource_whenScanCharUsingFindInLine_thenOneCharIsRead() { + Scanner sc = new Scanner(input); + char c = sc.findInLine(".").charAt(0); + assertEquals('a', c); + } + + @Test + public void givenInputSource_whenScanCharUsingUseDelimiter_thenOneCharIsRead() { + Scanner sc = new Scanner(input); + char c = sc.useDelimiter("").next().charAt(0); + assertEquals('a', c); + } + +} diff --git a/core-java-modules/core-java-io-apis-2/src/test/java/com/baeldung/scanner/ScannerNoSuchElementExceptionUnitTest.java b/core-java-modules/core-java-scanner/src/test/java/com/baeldung/scanner/ScannerNoSuchElementExceptionUnitTest.java similarity index 100% rename from core-java-modules/core-java-io-apis-2/src/test/java/com/baeldung/scanner/ScannerNoSuchElementExceptionUnitTest.java rename to core-java-modules/core-java-scanner/src/test/java/com/baeldung/scanner/ScannerNoSuchElementExceptionUnitTest.java diff --git a/core-java-modules/core-java-io-apis-2/src/test/java/com/baeldung/scanner/ScannerToArrayUnitTest.java b/core-java-modules/core-java-scanner/src/test/java/com/baeldung/scanner/ScannerToArrayUnitTest.java similarity index 100% rename from core-java-modules/core-java-io-apis-2/src/test/java/com/baeldung/scanner/ScannerToArrayUnitTest.java rename to core-java-modules/core-java-scanner/src/test/java/com/baeldung/scanner/ScannerToArrayUnitTest.java diff --git a/core-java-modules/core-java-io-apis/src/test/java/com/baeldung/scannernextline/ScannerNextLineUnitTest.java b/core-java-modules/core-java-scanner/src/test/java/com/baeldung/scannernextline/ScannerNextLineUnitTest.java similarity index 100% rename from core-java-modules/core-java-io-apis/src/test/java/com/baeldung/scannernextline/ScannerNextLineUnitTest.java rename to core-java-modules/core-java-scanner/src/test/java/com/baeldung/scannernextline/ScannerNextLineUnitTest.java index f3e76229da..5ea29e63e0 100644 --- a/core-java-modules/core-java-io-apis/src/test/java/com/baeldung/scannernextline/ScannerNextLineUnitTest.java +++ b/core-java-modules/core-java-scanner/src/test/java/com/baeldung/scannernextline/ScannerNextLineUnitTest.java @@ -1,11 +1,11 @@ package com.baeldung.scannernextline; -import org.junit.Test; +import static org.junit.Assert.assertEquals; import java.util.NoSuchElementException; import java.util.Scanner; -import static org.junit.Assert.assertEquals; +import org.junit.Test; public class ScannerNextLineUnitTest { diff --git a/core-java-modules/core-java-io-apis-2/src/test/resources/emptyFile.txt b/core-java-modules/core-java-scanner/src/test/resources/emptyFile.txt similarity index 100% rename from core-java-modules/core-java-io-apis-2/src/test/resources/emptyFile.txt rename to core-java-modules/core-java-scanner/src/test/resources/emptyFile.txt diff --git a/core-java-modules/core-java-io-apis/src/test/resources/test_read.in b/core-java-modules/core-java-scanner/src/test/resources/test_read.in similarity index 100% rename from core-java-modules/core-java-io-apis/src/test/resources/test_read.in rename to core-java-modules/core-java-scanner/src/test/resources/test_read.in diff --git a/core-java-modules/core-java-io-apis/src/test/resources/test_read_d.in b/core-java-modules/core-java-scanner/src/test/resources/test_read_d.in similarity index 100% rename from core-java-modules/core-java-io-apis/src/test/resources/test_read_d.in rename to core-java-modules/core-java-scanner/src/test/resources/test_read_d.in diff --git a/core-java-modules/core-java-io-apis/src/test/resources/test_read_multiple.in b/core-java-modules/core-java-scanner/src/test/resources/test_read_multiple.in similarity index 100% rename from core-java-modules/core-java-io-apis/src/test/resources/test_read_multiple.in rename to core-java-modules/core-java-scanner/src/test/resources/test_read_multiple.in diff --git a/core-java-modules/core-java-serialization/pom.xml b/core-java-modules/core-java-serialization/pom.xml index 04144fb27f..5a6f256687 100644 --- a/core-java-modules/core-java-serialization/pom.xml +++ b/core-java-modules/core-java-serialization/pom.xml @@ -90,7 +90,7 @@ -Xmx300m -XX:+UseParallelGC -classpath - + com.baeldung.outofmemoryerror.OutOfMemoryGCLimitExceed @@ -154,7 +154,7 @@ java -classpath - + org.openjdk.jmh.Main .* diff --git a/core-java-modules/core-java-streams-2/src/test/java/com/baeldung/streams/StreamToImmutableUnitTest.java b/core-java-modules/core-java-streams-2/src/test/java/com/baeldung/streams/StreamToImmutableUnitTest.java index e5339d8327..ba99a6eaf7 100644 --- a/core-java-modules/core-java-streams-2/src/test/java/com/baeldung/streams/StreamToImmutableUnitTest.java +++ b/core-java-modules/core-java-streams-2/src/test/java/com/baeldung/streams/StreamToImmutableUnitTest.java @@ -1,57 +1,59 @@ package com.baeldung.streams; import com.google.common.collect.ImmutableList; -import org.junit.Test; import java.util.*; import java.util.stream.IntStream; import static java.util.stream.Collectors.*; +import static org.junit.jupiter.api.Assertions.assertEquals; -public class StreamToImmutableUnitTest { +import org.junit.jupiter.api.Test; + +class StreamToImmutableUnitTest { @Test - public void whenUsingCollectingToImmutableSet_thenSuccess() { + void whenUsingCollectingToImmutableSet_thenSuccess() { List givenList = Arrays.asList("a", "b", "c"); List result = givenList.stream() .collect(collectingAndThen(toSet(), ImmutableList::copyOf)); - System.out.println(result.getClass()); + assertEquals("com.google.common.collect.RegularImmutableList", result.getClass().getName()); } @Test - public void whenUsingCollectingToUnmodifiableList_thenSuccess() { + void whenUsingCollectingToUnmodifiableList_thenSuccess() { List givenList = new ArrayList<>(Arrays.asList("a", "b", "c")); List result = givenList.stream() .collect(collectingAndThen(toList(), Collections::unmodifiableList)); - System.out.println(result.getClass()); + assertEquals("java.util.Collections$UnmodifiableRandomAccessList", result.getClass().getName()); } @Test - public void whenCollectToImmutableList_thenSuccess() { + void whenCollectToImmutableList_thenSuccess() { List list = IntStream.range(0, 9) .boxed() .collect(ImmutableList.toImmutableList()); - System.out.println(list.getClass()); + assertEquals("com.google.common.collect.RegularImmutableList", list.getClass().getName()); } @Test - public void whenCollectToMyImmutableListCollector_thenSuccess() { + void whenCollectToMyImmutableListCollector_thenSuccess() { List givenList = Arrays.asList("a", "b", "c", "d"); List result = givenList.stream() .collect(MyImmutableListCollector.toImmutableList()); - System.out.println(result.getClass()); + assertEquals("java.util.Collections$UnmodifiableRandomAccessList", result.getClass().getName()); } @Test - public void whenPassingSupplier_thenSuccess() { + void whenPassingSupplier_thenSuccess() { List givenList = Arrays.asList("a", "b", "c", "d"); List result = givenList.stream() .collect(MyImmutableListCollector.toImmutableList(LinkedList::new)); - System.out.println(result.getClass()); + assertEquals("java.util.Collections$UnmodifiableList", result.getClass().getName()); } } diff --git a/core-java-modules/core-java-string-conversions-3/pom.xml b/core-java-modules/core-java-string-conversions-3/pom.xml index 1fdf79283f..ddd5f7a497 100644 --- a/core-java-modules/core-java-string-conversions-3/pom.xml +++ b/core-java-modules/core-java-string-conversions-3/pom.xml @@ -23,5 +23,4 @@ - \ No newline at end of file diff --git a/core-java-modules/core-java-string-operations-3/src/main/java/com/baeldung/stringfilenamevalidaiton/StringFilenameValidationUtils.java b/core-java-modules/core-java-string-operations-3/src/main/java/com/baeldung/stringfilenamevalidaiton/StringFilenameValidationUtils.java index 6721d52d35..6cb4d3c141 100644 --- a/core-java-modules/core-java-string-operations-3/src/main/java/com/baeldung/stringfilenamevalidaiton/StringFilenameValidationUtils.java +++ b/core-java-modules/core-java-string-operations-3/src/main/java/com/baeldung/stringfilenamevalidaiton/StringFilenameValidationUtils.java @@ -10,7 +10,7 @@ public class StringFilenameValidationUtils { public static final Character[] INVALID_WINDOWS_SPECIFIC_CHARS = {'"', '*', '<', '>', '?', '|'}; public static final Character[] INVALID_UNIX_SPECIFIC_CHARS = {'\000'}; - public static final String REGEX_PATTERN = "^[A-za-z0-9.]{1,255}$"; + public static final String REGEX_PATTERN = "^[A-Za-z0-9.]{1,255}$"; private StringFilenameValidationUtils() { } diff --git a/core-java-modules/core-java-string-operations-6/README.md b/core-java-modules/core-java-string-operations-6/README.md index e866f50860..10f59a56e3 100644 --- a/core-java-modules/core-java-string-operations-6/README.md +++ b/core-java-modules/core-java-string-operations-6/README.md @@ -5,4 +5,7 @@ - [Check if a String Is All Uppercase or Lowercase in Java](https://www.baeldung.com/java-check-string-uppercase-lowercase) - [Java – Generate Random String](https://www.baeldung.com/java-random-string) - [Fixing “constant string too long” Build Error](https://www.baeldung.com/java-constant-string-too-long-error) -- [Compact Strings in Java 9](https://www.baeldung.com/java-9-compact-string) \ No newline at end of file +- [Compact Strings in Java 9](https://www.baeldung.com/java-9-compact-string) +- [Split a String Into Digit and Non-Digit Substrings](https://www.baeldung.com/java-split-string-digits-letters) +- [Check if a String Contains Non-Alphanumeric Characters](https://www.baeldung.com/java-string-test-special-characters) +- [Check if a String Has All Unique Characters in Java](https://www.baeldung.com/java-check-string-all-unique-chars) diff --git a/core-java-modules/core-java-string-operations-6/pom.xml b/core-java-modules/core-java-string-operations-6/pom.xml index ddbb5d0e40..0ec32d91b1 100644 --- a/core-java-modules/core-java-string-operations-6/pom.xml +++ b/core-java-modules/core-java-string-operations-6/pom.xml @@ -18,7 +18,16 @@ commons-lang3 ${apache.commons-lang.version} - + + org.openjdk.jmh + jmh-core + ${jmh.version} + + + org.openjdk.jmh + jmh-generator-annprocess + ${jmh.version} + @@ -38,6 +47,7 @@ 11 11 3.12.0 + 1.36 \ No newline at end of file diff --git a/core-java-modules/core-java-string-operations-6/src/main/java/com/baeldung/performance/BatchConcatBenchmark.java b/core-java-modules/core-java-string-operations-6/src/main/java/com/baeldung/performance/BatchConcatBenchmark.java new file mode 100644 index 0000000000..e834777761 --- /dev/null +++ b/core-java-modules/core-java-string-operations-6/src/main/java/com/baeldung/performance/BatchConcatBenchmark.java @@ -0,0 +1,138 @@ +package com.baeldung.performance; + +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.Blackhole; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +@State(Scope.Benchmark) +@BenchmarkMode(Mode.AverageTime) +@Warmup(iterations = 1, time = 2, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS) +@OutputTimeUnit(TimeUnit.MICROSECONDS) +@Fork(value = 1) +public class BatchConcatBenchmark { + + private static final String TOKEN = "string"; + private static final String[] DATA_100 = prepareData(100); + private static final String[] DATA_1000 = prepareData(1000); + private static final String[] DATA_10000 = prepareData(10000); + + private static final String FORMAT_STR_100 = getFormatStr(100); + private static final String FORMAT_STR_1000 = getFormatStr(1000); + private static final String FORMAT_STR_10000 = getFormatStr(10000); + + private static String[] prepareData(int size) { + String[] data = new String[size]; + for (int n=0;n strList = List.of(data); + concatString = strList.stream().collect(Collectors.joining("")); + blackhole.consume(concatString); + } + + public static void main(String[] args) throws Exception { + Options options = new OptionsBuilder() + .include(BatchConcatBenchmark.class.getSimpleName()).threads(1) + .shouldFailOnError(true) + .shouldDoGC(true) + .jvmArgs("-server").build(); + new Runner(options).run(); + } + +} \ No newline at end of file diff --git a/core-java-modules/core-java-string-operations-6/src/main/java/com/baeldung/performance/LoopConcatBenchmark.java b/core-java-modules/core-java-string-operations-6/src/main/java/com/baeldung/performance/LoopConcatBenchmark.java new file mode 100644 index 0000000000..198754e57d --- /dev/null +++ b/core-java-modules/core-java-string-operations-6/src/main/java/com/baeldung/performance/LoopConcatBenchmark.java @@ -0,0 +1,211 @@ +package com.baeldung.performance; + +import java.util.ArrayList; +import java.util.List; +import java.util.StringJoiner; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.Blackhole; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +@State(Scope.Benchmark) +@BenchmarkMode(Mode.AverageTime) +@Warmup(iterations = 1, time = 2, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS) +@OutputTimeUnit(TimeUnit.MICROSECONDS) +@Fork(value = 1) +public class LoopConcatBenchmark { + + private static final String TOKEN = "string"; + private static final int ITERATION_100 = 100; + private static final int ITERATION_1000 = 1000; + private static final int ITERATION_10000 = 10000; + + @Benchmark + public static void concatByPlusBy100(Blackhole blackhole) { + concatByPlus(ITERATION_100, blackhole); + } + + @Benchmark + public static void concatByPlusBy1000(Blackhole blackhole) { + concatByPlus(ITERATION_1000, blackhole); + } + + @Benchmark + public static void concatByPlusBy10000(Blackhole blackhole) { + concatByPlus(ITERATION_10000, blackhole); + } + + public static void concatByPlus(int iterations, Blackhole blackhole) { + String concatString = ""; + for (int n=0;n strList = new ArrayList<>(); + strList.add(concatString); + strList.add(TOKEN); + for (int n=0; n set = new HashSet <>(); + for (char c: chars) { + set.add(c); + } + return set.size() == str.length(); + } + + public static boolean useStreamCheck(String str) { + boolean isUnique = str.toUpperCase().chars() + .mapToObj(c -> (char)c) + .collect(Collectors.toSet()) + .size() == str.length(); + return isUnique; + } + + public static boolean useStringUtilscheck(String str) { + for (int i = 0; i < str.length(); i++) { + String curChar = String.valueOf(str.charAt(i)); + String remainingStr = str.substring(i+1); + if(StringUtils.containsIgnoreCase(remainingStr, curChar)) { + return false; + } + } + return true; + } +} diff --git a/core-java-modules/core-java-string-operations-6/src/test/java/com/baeldung/digitsandnondigits/BenchmarkLiveTest.java b/core-java-modules/core-java-string-operations-6/src/test/java/com/baeldung/digitsandnondigits/BenchmarkLiveTest.java new file mode 100644 index 0000000000..7c5c8101f8 --- /dev/null +++ b/core-java-modules/core-java-string-operations-6/src/test/java/com/baeldung/digitsandnondigits/BenchmarkLiveTest.java @@ -0,0 +1,47 @@ +package com.baeldung.digitsandnondigits; + +import static com.baeldung.digitsandnondigits.SplitDigitsAndNondigitsUnitTest.parseString; + +import java.util.concurrent.TimeUnit; + +import org.junit.jupiter.api.Test; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Threads; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +@State(Scope.Benchmark) +@Threads(1) +@BenchmarkMode(Mode.Throughput) +@Fork(warmups = 1, value = 1) +@Warmup(iterations = 2, time = 10, timeUnit = TimeUnit.MILLISECONDS) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +public class BenchmarkLiveTest { + private static final String INPUT = "01Michael Jackson23Michael Jordan42Michael Bolton999Michael Johnson000"; + + @Param({ "10000" }) + public int iterations; + + @Benchmark + public void regexBased(Blackhole blackhole) { + blackhole.consume(INPUT.split("(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)")); + } + + @Benchmark + public void nonRegexBased(Blackhole blackhole) { + blackhole.consume(parseString(INPUT)); + } + + @Test + public void benchmark() throws Exception { + String[] argv = {}; + org.openjdk.jmh.Main.main(argv); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-string-operations-6/src/test/java/com/baeldung/digitsandnondigits/SplitDigitsAndNondigitsUnitTest.java b/core-java-modules/core-java-string-operations-6/src/test/java/com/baeldung/digitsandnondigits/SplitDigitsAndNondigitsUnitTest.java new file mode 100644 index 0000000000..55e0e48070 --- /dev/null +++ b/core-java-modules/core-java-string-operations-6/src/test/java/com/baeldung/digitsandnondigits/SplitDigitsAndNondigitsUnitTest.java @@ -0,0 +1,69 @@ +package com.baeldung.digitsandnondigits; + +import static com.baeldung.digitsandnondigits.SplitDigitsAndNondigitsUnitTest.State.INIT; +import static com.baeldung.digitsandnondigits.SplitDigitsAndNondigitsUnitTest.State.PARSING_DIGIT; +import static com.baeldung.digitsandnondigits.SplitDigitsAndNondigitsUnitTest.State.PARSING_NON_DIGIT; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.junit.jupiter.api.Test; + +public class SplitDigitsAndNondigitsUnitTest { + private static final String INPUT1 = "01Michael Jackson23Michael Jordan42Michael Bolton999Michael Johnson000"; + private static final String[] EXPECTED1 = new String[] { "01", "Michael Jackson", "23", "Michael Jordan", "42", "Michael Bolton", "999", "Michael Johnson", "000" }; + private static final List EXPECTED_LIST1 = Arrays.asList(EXPECTED1); + + private static final String INPUT2 = "Michael Jackson01Michael Jordan23Michael Bolton42Michael Johnson999Great Michaels"; + private static final String[] EXPECTED2 = new String[] { "Michael Jackson", "01", "Michael Jordan", "23", "Michael Bolton", "42", "Michael Johnson", "999", "Great Michaels" }; + private static final List EXPECTED_LIST2 = Arrays.asList(EXPECTED2); + + @Test + void whenUsingLookaroundRegex_thenGetExpectedResult() { + String splitRE = "(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)"; + String[] result1 = INPUT1.split(splitRE); + assertArrayEquals(EXPECTED1, result1); + + String[] result2 = INPUT2.split(splitRE); + assertArrayEquals(EXPECTED2, result2); + } + + enum State { + INIT, PARSING_DIGIT, PARSING_NON_DIGIT + } + + static List parseString(String input) { + List result = new ArrayList<>(); + int start = 0; + State state = INIT; + for (int i = 0; i < input.length(); i++) { + if (input.charAt(i) >= '0' && input.charAt(i) <= '9') { + if (state == PARSING_NON_DIGIT) { + result.add(input.substring(start, i)); + start = i; + } + state = PARSING_DIGIT; + } else { + if (state == PARSING_DIGIT) { + result.add(input.substring(start, i)); + start = i; + } + state = PARSING_NON_DIGIT; + } + } + result.add(input.substring(start)); + return result; + } + + @Test + void whenCheckEachChar_thenGetExpectedResult() { + List result1 = parseString(INPUT1); + assertEquals(EXPECTED_LIST1, result1); + + List result2 = parseString(INPUT2); + assertEquals(EXPECTED_LIST2, result2); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-string-operations-6/src/test/java/com/baeldung/uniquecharcheck/UniqueCharCheckerUnitTest.java b/core-java-modules/core-java-string-operations-6/src/test/java/com/baeldung/uniquecharcheck/UniqueCharCheckerUnitTest.java new file mode 100644 index 0000000000..98473c6630 --- /dev/null +++ b/core-java-modules/core-java-string-operations-6/src/test/java/com/baeldung/uniquecharcheck/UniqueCharCheckerUnitTest.java @@ -0,0 +1,92 @@ +package com.baeldung.uniquecharcheck; + +import org.junit.Test; + +import java.util.Arrays; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + + +public class UniqueCharCheckerUnitTest { + + @Test + public void givenUnique_whenBruteForceCheck_thenReturnTrue() { + String[] sampleStrings = new String[]{"Justfewdi123", "$%&Hibusc", "Hibusc%$#", "მშვნიერ"}; + final String MSG = "Duplicate found"; + Arrays.stream(sampleStrings) + .forEach(sampleStr -> assertTrue(MSG + " in " + sampleStr, UniqueCharChecker.bruteForceCheck(sampleStr))); + } + @Test + public void givenUnique_whenSortAndThenCheck_thenReturnTrue() { + String[] sampleStrings = new String[]{"Justfewdi123", "$%&Hibusc", "Hibusc%$#", "მშვნიერ"}; + final String MSG = "Duplicate found"; + Arrays.stream(sampleStrings) + .forEach(sampleStr -> assertTrue(MSG + " in " + sampleStr, UniqueCharChecker.sortAndThenCheck(sampleStr))); + } + + @Test + public void givenUnique_whenUseSetCheck_thenReturnTrue() { + String[] sampleStrings = new String[]{"Justfewdi123", "$%&Hibusc", "Hibusc%$#", "მშვნიერ"}; + final String MSG = "Duplicate found"; + Arrays.stream(sampleStrings) + .forEach(sampleStr -> assertTrue(MSG + " in " + sampleStr, UniqueCharChecker.useSetCheck(sampleStr))); + } + + @Test + public void givenUnique_whenUseStreamCheck_thenReturnTrue() { + String[] sampleStrings = new String[]{"Justfewdi123", "$%&Hibusc", "Hibusc%$#", "მშვნიერ"}; + final String MSG = "Duplicate found"; + Arrays.stream(sampleStrings) + .forEach(sampleStr -> assertTrue(MSG + " in " + sampleStr, UniqueCharChecker.useStreamCheck(sampleStr))); + } + @Test + public void givenUnique_whenUseStringUtilscheck_thenReturnTrue() { + String[] sampleStrings = new String[]{"Justfewdi123", "$%&Hibusc", "Hibusc%$#", "მშვნიერ"}; + final String MSG = "Duplicate found"; + Arrays.stream(sampleStrings) + .forEach(sampleStr -> assertTrue(MSG + " in " + sampleStr, UniqueCharChecker.useStringUtilscheck(sampleStr))); + } + + @Test + public void givenNotUnique_whenBruteForceCheck_thenReturnFalse() { + String[] sampleStrings = new String[]{"Justfewdif123", "$%&Hibushc", "Hibusuc%$#", "Hi%busc%$#", "მშვენიერი"}; + final String MSG = "Duplicate not found"; + Arrays.stream(sampleStrings) + .forEach(sampleStr -> assertFalse(MSG + " in " + sampleStr, UniqueCharChecker.bruteForceCheck(sampleStr))); + } + + @Test + public void givenNotUnique_whenSortAndThenCheck_thenReturnFalse() { + String[] sampleStrings = new String[]{"Justfewdif123", "$%&Hibushc", "Hibusuc%$#", "Hi%busc%$#", "მშვენიერი"}; + final String MSG = "Duplicate not found"; + Arrays.stream(sampleStrings) + .forEach(sampleStr -> assertFalse(MSG + " in " + sampleStr, UniqueCharChecker.sortAndThenCheck(sampleStr))); + + } + + @Test + public void givenNotUnique_whenUseSetCheck_thenReturnFalse() { + String[] sampleStrings = new String[]{"Justfewdif123", "$%&Hibushc", "Hibusuc%$#", "Hi%busc%$#", "მშვენიერი"}; + final String MSG = "Duplicate not found"; + Arrays.stream(sampleStrings) + .forEach(sampleStr -> assertFalse(MSG + " in " + sampleStr, UniqueCharChecker.useSetCheck(sampleStr))); + } + + @Test + public void givenNotUnique_whenUseStreamCheck_thenReturnFalse() { + String[] sampleStrings = new String[]{"Justfewdif123", "$%&Hibushc", "Hibusuc%$#", "Hi%busc%$#", "მშვენიერი"}; + final String MSG = "Duplicate not found"; + Arrays.stream(sampleStrings) + .forEach(sampleStr -> assertFalse(MSG + " in " + sampleStr, UniqueCharChecker.useStreamCheck(sampleStr))); + } + + @Test + public void givenNotUnique_whenUseStringUtilscheck_thenReturnFalse() { + String[] sampleStrings = new String[]{"Justfewdif123", "$%&Hibushc", "Hibusuc%$#", "Hi%busc%$#", "მშვენიერი"}; + final String MSG = "Duplicate not found"; + Arrays.stream(sampleStrings) + .forEach(sampleStr -> assertFalse(MSG + " in " + sampleStr, UniqueCharChecker.useStringUtilscheck(sampleStr))); + } + +} diff --git a/core-java-modules/core-java-string-operations/src/test/java/com/baeldung/split/SplitIntoHalvesUnitTest.java b/core-java-modules/core-java-string-operations/src/test/java/com/baeldung/split/SplitIntoHalvesUnitTest.java new file mode 100644 index 0000000000..b47868ce70 --- /dev/null +++ b/core-java-modules/core-java-string-operations/src/test/java/com/baeldung/split/SplitIntoHalvesUnitTest.java @@ -0,0 +1,19 @@ +package com.baeldung.split; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class SplitIntoHalvesUnitTest { + + @Test + public void givenAString_whenSplitInHalf_thenCorrectParts() { + String hello = "Baeldung"; + int mid = hello.length() / 2; + String[] parts = { hello.substring(0, mid), hello.substring(mid) }; + + assertEquals("Bael", parts[0]); + assertEquals("dung", parts[1]); + } +} diff --git a/core-java-modules/core-java-sun/pom.xml b/core-java-modules/core-java-sun/pom.xml index c9427f66a3..7f1517e246 100644 --- a/core-java-modules/core-java-sun/pom.xml +++ b/core-java-modules/core-java-sun/pom.xml @@ -42,7 +42,7 @@ -Xmx300m -XX:+UseParallelGC -classpath - + com.baeldung.outofmemoryerror.OutOfMemoryGCLimitExceed @@ -71,7 +71,7 @@ java -classpath - + org.openjdk.jmh.Main .* diff --git a/core-java-modules/core-java-uuid/pom.xml b/core-java-modules/core-java-uuid/pom.xml index c0e93c1d32..d46fcd8a65 100644 --- a/core-java-modules/core-java-uuid/pom.xml +++ b/core-java-modules/core-java-uuid/pom.xml @@ -76,7 +76,7 @@ -Xmx300m -XX:+UseParallelGC -classpath - + com.baeldung.outofmemoryerror.OutOfMemoryGCLimitExceed @@ -140,7 +140,7 @@ java -classpath - + org.openjdk.jmh.Main .* diff --git a/core-java-modules/pom.xml b/core-java-modules/pom.xml index 9144e16359..ada8b68d1a 100644 --- a/core-java-modules/pom.xml +++ b/core-java-modules/pom.xml @@ -75,13 +75,12 @@ core-java-function core-java-functional core-java-hex - core-java-io + core-java-io-2 core-java-io-3 core-java-io-4 core-java-io-apis core-java-io-apis-2 - core-java-io-apis-3 core-java-io-conversions core-java-jar core-java-jndi @@ -93,6 +92,7 @@ core-java-lang-3 core-java-lang-4 core-java-lang-5 + core-java-lang-6 core-java-lang-math core-java-lang-math-2 core-java-lang-oop-constructors @@ -124,6 +124,7 @@ core-java-properties core-java-reflection core-java-reflection-2 + core-java-scanner core-java-security-2 core-java-security-3 core-java-security-algorithms diff --git a/feign/README.md b/feign/README.md index 074ce1cbd2..7c5e648bef 100644 --- a/feign/README.md +++ b/feign/README.md @@ -6,4 +6,5 @@ This module contains articles about Feign - [Intro to Feign](https://www.baeldung.com/intro-to-feign) - [Retrying Feign Calls](https://www.baeldung.com/feign-retry) -- [Setting Request Headers Using Feign](https://www.baeldung.com/java-feign-request-headers) \ No newline at end of file +- [Setting Request Headers Using Feign](https://www.baeldung.com/java-feign-request-headers) +- [RequestLine with Feign Client](https://www.baeldung.com/feign-requestline) \ No newline at end of file diff --git a/gradle-modules/gradle-7/README.md b/gradle-modules/gradle-7/README.md index 98fb968e82..e59b59f9fd 100644 --- a/gradle-modules/gradle-7/README.md +++ b/gradle-modules/gradle-7/README.md @@ -6,3 +6,4 @@ - [Different Dependency Version Declarations in Gradle](https://www.baeldung.com/gradle-different-dependency-version-declarations) - [Generating Javadoc With Gradle](https://www.baeldung.com/java-gradle-javadoc) - [Generating WSDL Stubs With Gradle](https://www.baeldung.com/java-gradle-create-wsdl-stubs) +- [Gradle Toolchains Support for JVM Projects](https://www.baeldung.com/java-gradle-toolchains-jvm-projects) diff --git a/gradle-modules/gradle-7/toolchains-feature/.gitattributes b/gradle-modules/gradle-7/toolchains-feature/.gitattributes new file mode 100644 index 0000000000..097f9f98d9 --- /dev/null +++ b/gradle-modules/gradle-7/toolchains-feature/.gitattributes @@ -0,0 +1,9 @@ +# +# https://help.github.com/articles/dealing-with-line-endings/ +# +# Linux start script should use lf +/gradlew text eol=lf + +# These are Windows script files and should use crlf +*.bat text eol=crlf + diff --git a/gradle-modules/gradle-7/toolchains-feature/.gitignore b/gradle-modules/gradle-7/toolchains-feature/.gitignore new file mode 100644 index 0000000000..1b6985c009 --- /dev/null +++ b/gradle-modules/gradle-7/toolchains-feature/.gitignore @@ -0,0 +1,5 @@ +# Ignore Gradle project-specific cache directory +.gradle + +# Ignore Gradle build output directory +build diff --git a/gradle-modules/gradle-7/toolchains-feature/build.gradle b/gradle-modules/gradle-7/toolchains-feature/build.gradle new file mode 100644 index 0000000000..de1f6ad6e3 --- /dev/null +++ b/gradle-modules/gradle-7/toolchains-feature/build.gradle @@ -0,0 +1,49 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * This is a general purpose Gradle build. + * Learn more about Gradle by exploring our samples at https://docs.gradle.org/8.1.1/samples + */ +plugins { + id 'java' +} +java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} + +tasks { + compileTestJava { + sourceCompatibility = JavaVersion.VERSION_1_7 + targetCompatibility = JavaVersion.VERSION_1_7 + } +} + +//compileTestJava.getOptions().setFork(true) +//compileTestJava.getOptions().getForkOptions().setExecutable('/home/mpolivaha/.jdks/corretto-17.0.4.1/bin/javac') + +//compileJava.getOptions().setFork(true) +//compileJava.getOptions().getForkOptions().setExecutable('/home/mpolivaha/.jdks/corretto-17.0.4.1/bin/javac') + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(17) + vendor = JvmVendorSpec.AMAZON + implementation = JvmImplementation.VENDOR_SPECIFIC + } +} + +tasks.named('compileJava').get().configure { + javaCompiler = javaToolchains.compilerFor { + languageVersion = JavaLanguageVersion.of(17) + vendor = JvmVendorSpec.AMAZON + implementation = JvmImplementation.VENDOR_SPECIFIC + } +} +tasks.register("testOnAmazonJdk", Test.class, { + javaLauncher = javaToolchains.launcherFor { + languageVersion = JavaLanguageVersion.of(17) + vendor = JvmVendorSpec.AMAZON + } +}) +tasks.named("testClasses").get().finalizedBy("testOnAmazonJdk") \ No newline at end of file diff --git a/gradle-modules/gradle-7/toolchains-feature/gradle/wrapper/gradle-wrapper.properties b/gradle-modules/gradle-7/toolchains-feature/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000..37aef8d3f0 --- /dev/null +++ b/gradle-modules/gradle-7/toolchains-feature/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip +networkTimeout=10000 +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradle-modules/gradle-7/toolchains-feature/gradlew b/gradle-modules/gradle-7/toolchains-feature/gradlew new file mode 100755 index 0000000000..aeb74cbb43 --- /dev/null +++ b/gradle-modules/gradle-7/toolchains-feature/gradlew @@ -0,0 +1,245 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gradle-modules/gradle-7/toolchains-feature/gradlew.bat b/gradle-modules/gradle-7/toolchains-feature/gradlew.bat new file mode 100644 index 0000000000..93e3f59f13 --- /dev/null +++ b/gradle-modules/gradle-7/toolchains-feature/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/gradle-modules/gradle-7/toolchains-feature/settings.gradle b/gradle-modules/gradle-7/toolchains-feature/settings.gradle new file mode 100644 index 0000000000..1de93d5f8c --- /dev/null +++ b/gradle-modules/gradle-7/toolchains-feature/settings.gradle @@ -0,0 +1,10 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * The settings file is used to specify which projects to include in your build. + * + * Detailed information about configuring a multi-project build in Gradle can be found + * in the user manual at https://docs.gradle.org/8.1.1/userguide/multi_project_builds.html + */ + +rootProject.name = 'toolchains-feature' diff --git a/jackson-jr/src/main/java/com/baeldung/jacksonjr/JacksonJrFeatures.java b/jackson-jr/src/main/java/com/baeldung/jacksonjr/JacksonJrFeatures.java deleted file mode 100644 index 26adbf12d2..0000000000 --- a/jackson-jr/src/main/java/com/baeldung/jacksonjr/JacksonJrFeatures.java +++ /dev/null @@ -1,96 +0,0 @@ -package com.baeldung.jacksonjr; - -import com.fasterxml.jackson.jr.annotationsupport.JacksonAnnotationExtension; -import com.fasterxml.jackson.jr.ob.JSON; -import com.fasterxml.jackson.jr.ob.JacksonJrExtension; -import com.fasterxml.jackson.jr.ob.api.ExtensionContext; - -import java.io.IOException; -import java.util.LinkedHashMap; - -public class JacksonJrFeatures { - - public static String jsonObject() throws IOException { - return JSON.std - .with(JSON.Feature.PRETTY_PRINT_OUTPUT) - .asString(new LinkedHashMap() {{ - put("name", "John Doe"); - put("age", 30); - }}); - } - - public static String jsonComposer() throws IOException { - return JSON.std - .with(JSON.Feature.PRETTY_PRINT_OUTPUT) - .composeString() - .startObject() - .startArrayField("objectArray") - .startObject() - .put("name", "name1") - .put("age", 11) - .end() - .startObject() - .put("name", "name2") - .put("age", 12) - .end() - .end() - .startArrayField("array") - .add(1) - .add(2) - .add(3) - .end() - .startObjectField("object") - .put("name", "name3") - .put("age", 13) - .end() - .put("last", true) - .end() - .finish(); - } - - public static String objectSerialization(Person person) throws IOException { - return JSON.std - .with(JSON.Feature.PRETTY_PRINT_OUTPUT) - .asString(person); - } - - public static String objectAnnotationSerialization(Person person) throws IOException { - return JSON.builder() - .register(JacksonAnnotationExtension.std) - .build() - .with(JSON.Feature.PRETTY_PRINT_OUTPUT) - .asString(person); - } - - public static String customObjectSerialization(Person person) throws IOException { - return JSON.builder() - .register(new JacksonJrExtension() { - @Override - protected void register (ExtensionContext extensionContext) { - extensionContext.insertProvider(new MyHandlerProvider()); - } - }) - .build() - .with(JSON.Feature.PRETTY_PRINT_OUTPUT) - .asString(person); - } - - public static Person objectDeserialization(String json) throws IOException { - return JSON.std - .with(JSON.Feature.PRETTY_PRINT_OUTPUT) - .beanFrom(Person.class, json); - } - - public static Person customObjectDeserialization(String json) throws IOException { - return JSON.builder() - .register(new JacksonJrExtension() { - @Override - protected void register (ExtensionContext extensionContext) { - extensionContext.insertProvider(new MyHandlerProvider()); - } - }) - .build() - .with(JSON.Feature.PRETTY_PRINT_OUTPUT) - .beanFrom(Person.class, json); - } -} diff --git a/jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/defaultvalues/JsonSetterDefaultValue.java b/jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/defaultvalues/SetterDefaultValue.java similarity index 82% rename from jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/defaultvalues/JsonSetterDefaultValue.java rename to jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/defaultvalues/SetterDefaultValue.java index 5d8c758e86..e1e0c9332c 100644 --- a/jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/defaultvalues/JsonSetterDefaultValue.java +++ b/jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/defaultvalues/SetterDefaultValue.java @@ -1,13 +1,10 @@ package com.baeldung.jackson.defaultvalues; -import com.fasterxml.jackson.annotation.JsonSetter; - -public class JsonSetterDefaultValue { +public class SetterDefaultValue { private String required; private String optional = "valueIfMissingEntirely"; - @JsonSetter("optional") public void setOptional(String optional){ if(optional == null){ this.optional = "valueIfNull"; diff --git a/jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/defaultvalues/DefaultValuesUnitTest.java b/jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/defaultvalues/DefaultValuesUnitTest.java index 813cfaae16..a7d41be764 100644 --- a/jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/defaultvalues/DefaultValuesUnitTest.java +++ b/jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/defaultvalues/DefaultValuesUnitTest.java @@ -17,10 +17,10 @@ public class DefaultValuesUnitTest { } @Test - public void givenAClassWithAJsonSetter_whenReadingJsonWithNullOptionalValue_thenExpectDefaultValueInResult() throws JsonProcessingException { + public void givenAClassWithASetter_whenReadingJsonWithNullOptionalValue_thenExpectDefaultValueInResult() throws JsonProcessingException { String nullOptionalField = "{\"required\": \"value\", \"optional\": null}"; ObjectMapper objectMapper = new ObjectMapper(); - JsonSetterDefaultValue createdObject = objectMapper.readValue(nullOptionalField, JsonSetterDefaultValue.class); + SetterDefaultValue createdObject = objectMapper.readValue(nullOptionalField, SetterDefaultValue.class); assert(createdObject.getRequired()).equals("value"); assert(createdObject.getOptional()).equals("valueIfNull"); } diff --git a/jackson-jr/pom.xml b/jackson-modules/jackson-jr/pom.xml similarity index 78% rename from jackson-jr/pom.xml rename to jackson-modules/jackson-jr/pom.xml index 0dcb62fdae..7f806f0d89 100644 --- a/jackson-jr/pom.xml +++ b/jackson-modules/jackson-jr/pom.xml @@ -9,9 +9,8 @@ com.baeldung - parent-java + jackson-modules 0.0.1-SNAPSHOT - ../parent-java @@ -35,4 +34,14 @@ + + jackson-jr + + + src/main/resources + true + + + + \ No newline at end of file diff --git a/jackson-jr/src/main/java/com/baeldung/jacksonjr/CustomDateDeserializer.java b/jackson-modules/jackson-jr/src/main/java/com/baeldung/jacksonjr/CustomDateDeserializer.java similarity index 81% rename from jackson-jr/src/main/java/com/baeldung/jacksonjr/CustomDateDeserializer.java rename to jackson-modules/jackson-jr/src/main/java/com/baeldung/jacksonjr/CustomDateDeserializer.java index df977de966..3edaee8be0 100644 --- a/jackson-jr/src/main/java/com/baeldung/jacksonjr/CustomDateDeserializer.java +++ b/jackson-modules/jackson-jr/src/main/java/com/baeldung/jacksonjr/CustomDateDeserializer.java @@ -1,22 +1,22 @@ package com.baeldung.jacksonjr; -import com.fasterxml.jackson.jr.ob.api.ValueReader; -import com.fasterxml.jackson.jr.ob.impl.JSONReader; -import com.fasterxml.jackson.jr.private_.JsonParser; - import java.io.IOException; import java.time.LocalDate; import java.time.format.DateTimeFormatter; +import com.fasterxml.jackson.jr.ob.api.ValueReader; +import com.fasterxml.jackson.jr.ob.impl.JSONReader; +import com.fasterxml.jackson.jr.private_.JsonParser; + public class CustomDateDeserializer extends ValueReader { private final static DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd"); - public CustomDateDeserializer () { + public CustomDateDeserializer() { super(LocalDate.class); } @Override - public Object read (JSONReader jsonReader, JsonParser jsonParser) throws IOException { + public Object read(JSONReader jsonReader, JsonParser jsonParser) throws IOException { return LocalDate.parse(jsonParser.getText(), dtf); } } diff --git a/jackson-jr/src/main/java/com/baeldung/jacksonjr/CustomDateSerializer.java b/jackson-modules/jackson-jr/src/main/java/com/baeldung/jacksonjr/CustomDateSerializer.java similarity index 74% rename from jackson-jr/src/main/java/com/baeldung/jacksonjr/CustomDateSerializer.java rename to jackson-modules/jackson-jr/src/main/java/com/baeldung/jacksonjr/CustomDateSerializer.java index 9b2596cd2c..cfd08548c6 100644 --- a/jackson-jr/src/main/java/com/baeldung/jacksonjr/CustomDateSerializer.java +++ b/jackson-modules/jackson-jr/src/main/java/com/baeldung/jacksonjr/CustomDateSerializer.java @@ -1,20 +1,20 @@ package com.baeldung.jacksonjr; +import java.io.IOException; +import java.time.LocalDate; + import com.fasterxml.jackson.jr.ob.api.ValueWriter; import com.fasterxml.jackson.jr.ob.impl.JSONWriter; import com.fasterxml.jackson.jr.private_.JsonGenerator; -import java.io.IOException; -import java.time.LocalDate; - public class CustomDateSerializer implements ValueWriter { @Override - public void writeValue (JSONWriter jsonWriter, JsonGenerator jsonGenerator, Object o) throws IOException { + public void writeValue(JSONWriter jsonWriter, JsonGenerator jsonGenerator, Object o) throws IOException { jsonGenerator.writeString(o.toString()); } @Override - public Class valueType () { + public Class valueType() { return LocalDate.class; } } diff --git a/jackson-modules/jackson-jr/src/main/java/com/baeldung/jacksonjr/JacksonJrFeatures.java b/jackson-modules/jackson-jr/src/main/java/com/baeldung/jacksonjr/JacksonJrFeatures.java new file mode 100644 index 0000000000..6e99638ca6 --- /dev/null +++ b/jackson-modules/jackson-jr/src/main/java/com/baeldung/jacksonjr/JacksonJrFeatures.java @@ -0,0 +1,92 @@ +package com.baeldung.jacksonjr; + +import java.io.IOException; +import java.util.LinkedHashMap; + +import com.fasterxml.jackson.jr.annotationsupport.JacksonAnnotationExtension; +import com.fasterxml.jackson.jr.ob.JSON; +import com.fasterxml.jackson.jr.ob.JacksonJrExtension; +import com.fasterxml.jackson.jr.ob.api.ExtensionContext; + +public class JacksonJrFeatures { + + public static String jsonObject() throws IOException { + return JSON.std.with(JSON.Feature.PRETTY_PRINT_OUTPUT) + .asString(new LinkedHashMap() {{ + put("name", "John Doe"); + put("age", 30); + }}); + } + + public static String jsonComposer() throws IOException { + return JSON.std.with(JSON.Feature.PRETTY_PRINT_OUTPUT) + .composeString() + .startObject() + .startArrayField("objectArray") + .startObject() + .put("name", "name1") + .put("age", 11) + .end() + .startObject() + .put("name", "name2") + .put("age", 12) + .end() + .end() + .startArrayField("array") + .add(1) + .add(2) + .add(3) + .end() + .startObjectField("object") + .put("name", "name3") + .put("age", 13) + .end() + .put("last", true) + .end() + .finish(); + } + + public static String objectSerialization(Person person) throws IOException { + return JSON.std.with(JSON.Feature.PRETTY_PRINT_OUTPUT) + .asString(person); + } + + public static String objectAnnotationSerialization(Person person) throws IOException { + return JSON.builder() + .register(JacksonAnnotationExtension.std) + .build() + .with(JSON.Feature.PRETTY_PRINT_OUTPUT) + .asString(person); + } + + public static String customObjectSerialization(Person person) throws IOException { + return JSON.builder() + .register(new JacksonJrExtension() { + @Override + protected void register(ExtensionContext extensionContext) { + extensionContext.insertProvider(new MyHandlerProvider()); + } + }) + .build() + .with(JSON.Feature.PRETTY_PRINT_OUTPUT) + .asString(person); + } + + public static Person objectDeserialization(String json) throws IOException { + return JSON.std.with(JSON.Feature.PRETTY_PRINT_OUTPUT) + .beanFrom(Person.class, json); + } + + public static Person customObjectDeserialization(String json) throws IOException { + return JSON.builder() + .register(new JacksonJrExtension() { + @Override + protected void register(ExtensionContext extensionContext) { + extensionContext.insertProvider(new MyHandlerProvider()); + } + }) + .build() + .with(JSON.Feature.PRETTY_PRINT_OUTPUT) + .beanFrom(Person.class, json); + } +} diff --git a/jackson-jr/src/main/java/com/baeldung/jacksonjr/MyHandlerProvider.java b/jackson-modules/jackson-jr/src/main/java/com/baeldung/jacksonjr/MyHandlerProvider.java similarity index 82% rename from jackson-jr/src/main/java/com/baeldung/jacksonjr/MyHandlerProvider.java rename to jackson-modules/jackson-jr/src/main/java/com/baeldung/jacksonjr/MyHandlerProvider.java index 266a09eecc..8fc67c6591 100644 --- a/jackson-jr/src/main/java/com/baeldung/jacksonjr/MyHandlerProvider.java +++ b/jackson-modules/jackson-jr/src/main/java/com/baeldung/jacksonjr/MyHandlerProvider.java @@ -1,17 +1,17 @@ package com.baeldung.jacksonjr; +import java.time.LocalDate; + import com.fasterxml.jackson.jr.ob.api.ReaderWriterProvider; import com.fasterxml.jackson.jr.ob.api.ValueReader; import com.fasterxml.jackson.jr.ob.api.ValueWriter; import com.fasterxml.jackson.jr.ob.impl.JSONReader; import com.fasterxml.jackson.jr.ob.impl.JSONWriter; -import java.time.LocalDate; - public class MyHandlerProvider extends ReaderWriterProvider { @Override - public ValueWriter findValueWriter (JSONWriter writeContext, Class type) { + public ValueWriter findValueWriter(JSONWriter writeContext, Class type) { if (type == LocalDate.class) { return new CustomDateSerializer(); } @@ -19,7 +19,7 @@ public class MyHandlerProvider extends ReaderWriterProvider { } @Override - public ValueReader findValueReader (JSONReader readContext, Class type) { + public ValueReader findValueReader(JSONReader readContext, Class type) { if (type.equals(LocalDate.class)) { return new CustomDateDeserializer(); } diff --git a/jackson-jr/src/main/java/com/baeldung/jacksonjr/Person.java b/jackson-modules/jackson-jr/src/main/java/com/baeldung/jacksonjr/Person.java similarity index 88% rename from jackson-jr/src/main/java/com/baeldung/jacksonjr/Person.java rename to jackson-modules/jackson-jr/src/main/java/com/baeldung/jacksonjr/Person.java index 8effc64cd9..12c48c3270 100644 --- a/jackson-jr/src/main/java/com/baeldung/jacksonjr/Person.java +++ b/jackson-modules/jackson-jr/src/main/java/com/baeldung/jacksonjr/Person.java @@ -1,13 +1,13 @@ package com.baeldung.jacksonjr; -import com.fasterxml.jackson.annotation.JsonFormat; +import java.time.LocalDate; + import com.fasterxml.jackson.annotation.JsonProperty; + import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; -import java.time.LocalDate; - @Data @NoArgsConstructor @AllArgsConstructor diff --git a/jackson-jr/src/test/java/com/baeldung/jacksonjr/JacksonJrFeaturesUnitTest.java b/jackson-modules/jackson-jr/src/test/java/com/baeldung/jacksonjr/JacksonJrFeaturesUnitTest.java similarity index 92% rename from jackson-jr/src/test/java/com/baeldung/jacksonjr/JacksonJrFeaturesUnitTest.java rename to jackson-modules/jackson-jr/src/test/java/com/baeldung/jacksonjr/JacksonJrFeaturesUnitTest.java index db17d2e175..04719c9303 100644 --- a/jackson-jr/src/test/java/com/baeldung/jacksonjr/JacksonJrFeaturesUnitTest.java +++ b/jackson-modules/jackson-jr/src/test/java/com/baeldung/jacksonjr/JacksonJrFeaturesUnitTest.java @@ -1,11 +1,13 @@ package com.baeldung.jacksonjr; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; import java.time.LocalDate; -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class JacksonJrFeaturesUnitTest { diff --git a/jackson-modules/pom.xml b/jackson-modules/pom.xml index 531d5628f7..1f4a22e379 100644 --- a/jackson-modules/pom.xml +++ b/jackson-modules/pom.xml @@ -21,6 +21,7 @@ jackson-core jackson-custom-conversions jackson-exceptions + jackson-jr diff --git a/jackson-simple/pom.xml b/jackson-simple/pom.xml index d1fcc867cf..d01c43dc90 100644 --- a/jackson-simple/pom.xml +++ b/jackson-simple/pom.xml @@ -34,6 +34,7 @@ 2.14.2 + 17 \ No newline at end of file diff --git a/jackson-simple/src/main/java/com/baeldung/jackson/objectmapper/ObjectMapperBuilder.java b/jackson-simple/src/main/java/com/baeldung/jackson/objectmapper/ObjectMapperBuilder.java index 0810d68da5..8faa26a3de 100644 --- a/jackson-simple/src/main/java/com/baeldung/jackson/objectmapper/ObjectMapperBuilder.java +++ b/jackson-simple/src/main/java/com/baeldung/jackson/objectmapper/ObjectMapperBuilder.java @@ -3,6 +3,7 @@ package com.baeldung.jackson.objectmapper; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.time.ZoneId; +import java.util.Locale; import java.util.TimeZone; import com.fasterxml.jackson.databind.ObjectMapper; @@ -19,7 +20,7 @@ public class ObjectMapperBuilder { } public ObjectMapperBuilder dateFormat() { - SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm a z"); + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm a z", Locale.ENGLISH); simpleDateFormat.setTimeZone(TimeZone.getTimeZone(ZoneId.of("Asia/Kolkata"))); this.dateFormat = simpleDateFormat; return this; diff --git a/javax-validation-advanced/.gitignore b/javax-validation-advanced/.gitignore deleted file mode 100644 index 8027134ae9..0000000000 --- a/javax-validation-advanced/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -.classpath -.project -.settings/ -target/ -bin/ - diff --git a/javax-validation-advanced/README.md b/javax-validation-advanced/README.md deleted file mode 100644 index b3ed669c39..0000000000 --- a/javax-validation-advanced/README.md +++ /dev/null @@ -1,6 +0,0 @@ -## Java Bean Validation Examples - -This module contains articles about Bean Validation. - -### Relevant Articles: -- [Object Validation After Deserialization](https://www.baeldung.com/java-object-validation-deserialization) diff --git a/javax-validation-advanced/pom.xml b/javax-validation-advanced/pom.xml deleted file mode 100644 index 7709f37883..0000000000 --- a/javax-validation-advanced/pom.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - 4.0.0 - javax-validation-advanced - javax-validation-advanced - - - com.baeldung - parent-modules - 1.0.0-SNAPSHOT - - - - - org.springframework.boot - spring-boot-starter-validation - ${spring.boot.version} - - - com.fasterxml.jackson.core - jackson-databind - ${jackson.databind.version} - - - - - 2.7.5 - 2.14.0 - - - \ No newline at end of file diff --git a/javaxval-2/README.md b/javaxval-2/README.md index 0fd5ce163b..b7603d9e84 100644 --- a/javaxval-2/README.md +++ b/javaxval-2/README.md @@ -3,7 +3,8 @@ This module contains articles about Bean Validation. ### Relevant Articles: -- [Method Constraints with Bean Validation 2.0](https://www.baeldung.com/javax-validation-method-constraints) +- [Method Constraints with Bean Validation 3.0](https://www.baeldung.com/javax-validation-method-constraints) - [Guide to ParameterMessageInterpolator](https://www.baeldung.com/hibernate-parametermessageinterpolator) - [Hibernate Validator Annotation Processor in Depth](https://www.baeldung.com/hibernate-validator-annotation-processor) -- More articles: [[<-- prev]](../javaxval) \ No newline at end of file +- [Object Validation After Deserialization](https://www.baeldung.com/java-object-validation-deserialization) +- More articles: [[<-- prev]](../javaxval) diff --git a/javaxval-2/pom.xml b/javaxval-2/pom.xml index 7d84b4ce9b..f73f23bcb2 100644 --- a/javaxval-2/pom.xml +++ b/javaxval-2/pom.xml @@ -25,6 +25,11 @@ ${spring.boot.version} test + + com.fasterxml.jackson.core + jackson-databind + ${jackson.databind.version} + @@ -39,6 +44,7 @@ 3.0.4 + 2.14.0 \ No newline at end of file diff --git a/javax-validation-advanced/src/main/java/com/baeldung/javaxval/afterdeserialization/BeanDeserializerModifierWithValidation.java b/javaxval-2/src/main/java/com/baeldung/javaxval/afterdeserialization/BeanDeserializerModifierWithValidation.java similarity index 97% rename from javax-validation-advanced/src/main/java/com/baeldung/javaxval/afterdeserialization/BeanDeserializerModifierWithValidation.java rename to javaxval-2/src/main/java/com/baeldung/javaxval/afterdeserialization/BeanDeserializerModifierWithValidation.java index 3e20ebad6b..f2425b542f 100644 --- a/javax-validation-advanced/src/main/java/com/baeldung/javaxval/afterdeserialization/BeanDeserializerModifierWithValidation.java +++ b/javaxval-2/src/main/java/com/baeldung/javaxval/afterdeserialization/BeanDeserializerModifierWithValidation.java @@ -1,20 +1,20 @@ -package com.baeldung.javaxval.afterdeserialization; - -import com.fasterxml.jackson.databind.BeanDescription; -import com.fasterxml.jackson.databind.DeserializationConfig; -import com.fasterxml.jackson.databind.JsonDeserializer; -import com.fasterxml.jackson.databind.deser.BeanDeserializer; -import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier; - -public class BeanDeserializerModifierWithValidation extends BeanDeserializerModifier { - - @Override - public JsonDeserializer modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer deserializer) { - if (deserializer instanceof BeanDeserializer) { - return new BeanDeserializerWithValidation((BeanDeserializer) deserializer); - } - - return deserializer; - } - -} +package com.baeldung.javaxval.afterdeserialization; + +import com.fasterxml.jackson.databind.BeanDescription; +import com.fasterxml.jackson.databind.DeserializationConfig; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.deser.BeanDeserializer; +import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier; + +public class BeanDeserializerModifierWithValidation extends BeanDeserializerModifier { + + @Override + public JsonDeserializer modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer deserializer) { + if (deserializer instanceof BeanDeserializer) { + return new BeanDeserializerWithValidation((BeanDeserializer) deserializer); + } + + return deserializer; + } + +} diff --git a/javax-validation-advanced/src/main/java/com/baeldung/javaxval/afterdeserialization/BeanDeserializerWithValidation.java b/javaxval-2/src/main/java/com/baeldung/javaxval/afterdeserialization/BeanDeserializerWithValidation.java similarity index 81% rename from javax-validation-advanced/src/main/java/com/baeldung/javaxval/afterdeserialization/BeanDeserializerWithValidation.java rename to javaxval-2/src/main/java/com/baeldung/javaxval/afterdeserialization/BeanDeserializerWithValidation.java index 332c83010d..178baaac95 100644 --- a/javax-validation-advanced/src/main/java/com/baeldung/javaxval/afterdeserialization/BeanDeserializerWithValidation.java +++ b/javaxval-2/src/main/java/com/baeldung/javaxval/afterdeserialization/BeanDeserializerWithValidation.java @@ -1,40 +1,40 @@ -package com.baeldung.javaxval.afterdeserialization; - -import java.io.IOException; -import java.util.Set; - -import javax.validation.ConstraintViolation; -import javax.validation.ConstraintViolationException; -import javax.validation.Validation; -import javax.validation.Validator; -import javax.validation.ValidatorFactory; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.deser.BeanDeserializer; -import com.fasterxml.jackson.databind.deser.BeanDeserializerBase; - -public class BeanDeserializerWithValidation extends BeanDeserializer { - - private static final ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); - private static final Validator validator = factory.getValidator(); - - protected BeanDeserializerWithValidation(BeanDeserializerBase src) { - super(src); - } - - @Override - public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { - Object instance = super.deserialize(p, ctxt); - validate(instance); - return instance; - } - - public void validate(T t) { - Set> violations = validator.validate(t); - if (!violations.isEmpty()) { - throw new ConstraintViolationException(violations); - } - } - -} +package com.baeldung.javaxval.afterdeserialization; + +import java.io.IOException; +import java.util.Set; + +import jakarta.validation.ConstraintViolation; +import jakarta.validation.ConstraintViolationException; +import jakarta.validation.Validation; +import jakarta.validation.Validator; +import jakarta.validation.ValidatorFactory; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.deser.BeanDeserializer; +import com.fasterxml.jackson.databind.deser.BeanDeserializerBase; + +public class BeanDeserializerWithValidation extends BeanDeserializer { + + private static final ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); + private static final Validator validator = factory.getValidator(); + + protected BeanDeserializerWithValidation(BeanDeserializerBase src) { + super(src); + } + + @Override + public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + Object instance = super.deserialize(p, ctxt); + validate(instance); + return instance; + } + + public void validate(T t) { + Set> violations = validator.validate(t); + if (!violations.isEmpty()) { + throw new ConstraintViolationException(violations); + } + } + +} diff --git a/javax-validation-advanced/src/main/java/com/baeldung/javaxval/afterdeserialization/Student.java b/javaxval-2/src/main/java/com/baeldung/javaxval/afterdeserialization/Student.java similarity index 82% rename from javax-validation-advanced/src/main/java/com/baeldung/javaxval/afterdeserialization/Student.java rename to javaxval-2/src/main/java/com/baeldung/javaxval/afterdeserialization/Student.java index c1923de265..b359f67078 100644 --- a/javax-validation-advanced/src/main/java/com/baeldung/javaxval/afterdeserialization/Student.java +++ b/javaxval-2/src/main/java/com/baeldung/javaxval/afterdeserialization/Student.java @@ -1,14 +1,14 @@ -package com.baeldung.javaxval.afterdeserialization; - -import javax.validation.constraints.Size; - -public class Student { - - @Size(min = 5, max = 10, message = "Student's name must be between 5 and 10 characters") - private String name; - - public String getName() { - return name; - } - -} +package com.baeldung.javaxval.afterdeserialization; + +import jakarta.validation.constraints.Size; + +public class Student { + + @Size(min = 5, max = 10, message = "Student's name must be between 5 and 10 characters") + private String name; + + public String getName() { + return name; + } + +} diff --git a/javax-validation-advanced/src/main/java/com/baeldung/javaxval/afterdeserialization/StudentDeserializerWithValidation.java b/javaxval-2/src/main/java/com/baeldung/javaxval/afterdeserialization/StudentDeserializerWithValidation.java similarity index 97% rename from javax-validation-advanced/src/main/java/com/baeldung/javaxval/afterdeserialization/StudentDeserializerWithValidation.java rename to javaxval-2/src/main/java/com/baeldung/javaxval/afterdeserialization/StudentDeserializerWithValidation.java index e652a43ccb..588493782e 100644 --- a/javax-validation-advanced/src/main/java/com/baeldung/javaxval/afterdeserialization/StudentDeserializerWithValidation.java +++ b/javaxval-2/src/main/java/com/baeldung/javaxval/afterdeserialization/StudentDeserializerWithValidation.java @@ -1,24 +1,24 @@ -package com.baeldung.javaxval.afterdeserialization; - -import java.io.IOException; -import java.io.InputStream; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.module.SimpleModule; - -public class StudentDeserializerWithValidation { - - public static Student readStudent(InputStream inputStream) throws IOException { - ObjectMapper mapper = getObjectMapperWithValidation(); - return mapper.readValue(inputStream, Student.class); - } - - private static ObjectMapper getObjectMapperWithValidation() { - SimpleModule validationModule = new SimpleModule(); - validationModule.setDeserializerModifier(new BeanDeserializerModifierWithValidation()); - ObjectMapper mapper = new ObjectMapper(); - mapper.registerModule(validationModule); - return mapper; - } - -} +package com.baeldung.javaxval.afterdeserialization; + +import java.io.IOException; +import java.io.InputStream; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.module.SimpleModule; + +public class StudentDeserializerWithValidation { + + public static Student readStudent(InputStream inputStream) throws IOException { + ObjectMapper mapper = getObjectMapperWithValidation(); + return mapper.readValue(inputStream, Student.class); + } + + private static ObjectMapper getObjectMapperWithValidation() { + SimpleModule validationModule = new SimpleModule(); + validationModule.setDeserializerModifier(new BeanDeserializerModifierWithValidation()); + ObjectMapper mapper = new ObjectMapper(); + mapper.registerModule(validationModule); + return mapper; + } + +} diff --git a/javax-validation-advanced/src/test/java/com/baeldung/javaxval/StudentDeserializerWithValidationUnitTest.java b/javaxval-2/src/test/java/com/baeldung/javaxval/afterdeserialization/StudentDeserializerWithValidationUnitTest.java similarity index 95% rename from javax-validation-advanced/src/test/java/com/baeldung/javaxval/StudentDeserializerWithValidationUnitTest.java rename to javaxval-2/src/test/java/com/baeldung/javaxval/afterdeserialization/StudentDeserializerWithValidationUnitTest.java index edbe85ecfe..094236e963 100644 --- a/javax-validation-advanced/src/test/java/com/baeldung/javaxval/StudentDeserializerWithValidationUnitTest.java +++ b/javaxval-2/src/test/java/com/baeldung/javaxval/afterdeserialization/StudentDeserializerWithValidationUnitTest.java @@ -1,51 +1,51 @@ -package com.baeldung.javaxval; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; - -import java.io.IOException; -import java.io.InputStream; - -import javax.validation.ConstraintViolationException; - -import org.junit.jupiter.api.Test; - -import com.baeldung.javaxval.afterdeserialization.Student; -import com.baeldung.javaxval.afterdeserialization.StudentDeserializerWithValidation; - -public class StudentDeserializerWithValidationUnitTest { - - private final String EXPECTED_ERROR_MESSAGE = "name: Student's name must be between 5 and 10 characters"; - private final String EXPECTED_STUDENT_NAME = "Daniel"; - private final String NAME_TOO_LONG_STUDENT_FILE = "nameTooLongStudent.json"; - private final String NAME_TOO_SHORT_STUDENT_FILE = "nameTooShortStudent.json"; - private final String SUBDIRECTORY = "afterdeserialization/"; - private final String VALID_STUDENT_FILE = "validStudent.json"; - - @Test - void givenValidStudent_WhenReadStudent_ThenReturnStudent() throws IOException { - InputStream inputStream = getInputStream(VALID_STUDENT_FILE); - Student result = StudentDeserializerWithValidation.readStudent(inputStream); - assertEquals(EXPECTED_STUDENT_NAME, result.getName()); - } - - @Test - void givenStudentWithTooShortName_WhenReadStudent_ThenThrows() { - InputStream inputStream = getInputStream(NAME_TOO_SHORT_STUDENT_FILE); - ConstraintViolationException constraintViolationException = assertThrows(ConstraintViolationException.class, () -> StudentDeserializerWithValidation.readStudent(inputStream)); - assertEquals(EXPECTED_ERROR_MESSAGE, constraintViolationException.getMessage()); - } - - @Test - void givenStudentWithTooLongName_WhenReadStudent_ThenThrows() { - InputStream inputStream = getInputStream(NAME_TOO_LONG_STUDENT_FILE); - ConstraintViolationException constraintViolationException = assertThrows(ConstraintViolationException.class, () -> StudentDeserializerWithValidation.readStudent(inputStream)); - assertEquals(EXPECTED_ERROR_MESSAGE, constraintViolationException.getMessage()); - } - - private InputStream getInputStream(String fileName) { - return getClass().getClassLoader() - .getResourceAsStream(SUBDIRECTORY + fileName); - } - -} +package com.baeldung.javaxval; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.io.IOException; +import java.io.InputStream; + +import jakarta.validation.ConstraintViolationException; + +import org.junit.jupiter.api.Test; + +import com.baeldung.javaxval.afterdeserialization.Student; +import com.baeldung.javaxval.afterdeserialization.StudentDeserializerWithValidation; + +public class StudentDeserializerWithValidationUnitTest { + + private final String EXPECTED_ERROR_MESSAGE = "name: Student's name must be between 5 and 10 characters"; + private final String EXPECTED_STUDENT_NAME = "Daniel"; + private final String NAME_TOO_LONG_STUDENT_FILE = "nameTooLongStudent.json"; + private final String NAME_TOO_SHORT_STUDENT_FILE = "nameTooShortStudent.json"; + private final String SUBDIRECTORY = "afterdeserialization/"; + private final String VALID_STUDENT_FILE = "validStudent.json"; + + @Test + void givenValidStudent_WhenReadStudent_ThenReturnStudent() throws IOException { + InputStream inputStream = getInputStream(VALID_STUDENT_FILE); + Student result = StudentDeserializerWithValidation.readStudent(inputStream); + assertEquals(EXPECTED_STUDENT_NAME, result.getName()); + } + + @Test + void givenStudentWithTooShortName_WhenReadStudent_ThenThrows() { + InputStream inputStream = getInputStream(NAME_TOO_SHORT_STUDENT_FILE); + ConstraintViolationException constraintViolationException = assertThrows(ConstraintViolationException.class, () -> StudentDeserializerWithValidation.readStudent(inputStream)); + assertEquals(EXPECTED_ERROR_MESSAGE, constraintViolationException.getMessage()); + } + + @Test + void givenStudentWithTooLongName_WhenReadStudent_ThenThrows() { + InputStream inputStream = getInputStream(NAME_TOO_LONG_STUDENT_FILE); + ConstraintViolationException constraintViolationException = assertThrows(ConstraintViolationException.class, () -> StudentDeserializerWithValidation.readStudent(inputStream)); + assertEquals(EXPECTED_ERROR_MESSAGE, constraintViolationException.getMessage()); + } + + private InputStream getInputStream(String fileName) { + return getClass().getClassLoader() + .getResourceAsStream(SUBDIRECTORY + fileName); + } + +} diff --git a/javax-validation-advanced/src/test/resources/afterdeserialization/nameTooLongStudent.json b/javaxval-2/src/test/resources/afterdeserialization/nameTooLongStudent.json similarity index 89% rename from javax-validation-advanced/src/test/resources/afterdeserialization/nameTooLongStudent.json rename to javaxval-2/src/test/resources/afterdeserialization/nameTooLongStudent.json index e537ecb25d..486709db60 100644 --- a/javax-validation-advanced/src/test/resources/afterdeserialization/nameTooLongStudent.json +++ b/javaxval-2/src/test/resources/afterdeserialization/nameTooLongStudent.json @@ -1,3 +1,3 @@ -{ - "name": "Constantine" +{ + "name": "Constantine" } \ No newline at end of file diff --git a/javax-validation-advanced/src/test/resources/afterdeserialization/nameTooShortStudent.json b/javaxval-2/src/test/resources/afterdeserialization/nameTooShortStudent.json similarity index 85% rename from javax-validation-advanced/src/test/resources/afterdeserialization/nameTooShortStudent.json rename to javaxval-2/src/test/resources/afterdeserialization/nameTooShortStudent.json index 79ab10cb80..23410153e3 100644 --- a/javax-validation-advanced/src/test/resources/afterdeserialization/nameTooShortStudent.json +++ b/javaxval-2/src/test/resources/afterdeserialization/nameTooShortStudent.json @@ -1,3 +1,3 @@ -{ - "name": "Max" +{ + "name": "Max" } \ No newline at end of file diff --git a/javax-validation-advanced/src/test/resources/afterdeserialization/validStudent.json b/javaxval-2/src/test/resources/afterdeserialization/validStudent.json similarity index 87% rename from javax-validation-advanced/src/test/resources/afterdeserialization/validStudent.json rename to javaxval-2/src/test/resources/afterdeserialization/validStudent.json index 938002ea51..d106f7d7ce 100644 --- a/javax-validation-advanced/src/test/resources/afterdeserialization/validStudent.json +++ b/javaxval-2/src/test/resources/afterdeserialization/validStudent.json @@ -1,3 +1,3 @@ -{ - "name": "Daniel" +{ + "name": "Daniel" } \ No newline at end of file diff --git a/jeromq/README.md b/jeromq/README.md new file mode 100644 index 0000000000..473d5181df --- /dev/null +++ b/jeromq/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [Introduction to JeroMQ](https://www.baeldung.com/java-jeromq-zeromq) diff --git a/jeromq/pom.xml b/jeromq/pom.xml new file mode 100644 index 0000000000..dfb5086683 --- /dev/null +++ b/jeromq/pom.xml @@ -0,0 +1,57 @@ + + + 4.0.0 + jeromq + 0.0.1-SNAPSHOT + jeromq + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + + + + + org.zeromq + jeromq + 0.5.3 + + + org.junit.platform + junit-platform-engine + ${junit-platform.version} + test + + + org.junit.platform + junit-platform-console-standalone + ${junit-platform.version} + test + + + org.junit.jupiter + junit-jupiter-migrationsupport + ${junit-jupiter.version} + test + + + + + + + src/main/resources + true + + + src/test/resources + true + + + + + + + diff --git a/jeromq/src/test/java/com/baeldung/jeromq/DealerRouterLiveTest.java b/jeromq/src/test/java/com/baeldung/jeromq/DealerRouterLiveTest.java new file mode 100644 index 0000000000..1f2eff1325 --- /dev/null +++ b/jeromq/src/test/java/com/baeldung/jeromq/DealerRouterLiveTest.java @@ -0,0 +1,256 @@ +package com.baeldung.jeromq; + +import org.junit.jupiter.api.Test; +import org.zeromq.SocketType; +import org.zeromq.ZContext; +import org.zeromq.ZMQ; + +import java.util.Random; +import java.util.Set; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +public class DealerRouterLiveTest { + @Test + public void single() throws Exception { + Thread brokerThread = new Thread(() -> { + try (ZContext context = new ZContext()) { + + ZMQ.Socket broker = context.createSocket(SocketType.ROUTER); + broker.bind("tcp://*:5555"); + + String identity = broker.recvStr(); + System.out.println(Thread.currentThread().getName() + " - Received identity " + identity); + + broker.recv(0); // Envelope delimiter + System.out.println(Thread.currentThread().getName() + " - Received envelope"); + String message = broker.recvStr(0); // Response from worker + System.out.println(Thread.currentThread().getName() + " - Received message " + message); + + broker.sendMore(identity); + broker.sendMore("xxx"); + broker.send("Hello back"); + } + }); + brokerThread.setName("broker"); + + Thread workerThread = new Thread(() -> { + try (ZContext context = new ZContext()) { + ZMQ.Socket worker = context.createSocket(SocketType.DEALER); + worker.setIdentity(Thread.currentThread().getName().getBytes(ZMQ.CHARSET)); + + worker.connect("tcp://localhost:5555"); + System.out.println(Thread.currentThread().getName() + " - Connected"); + + worker.sendMore(""); + worker.send("Hello " + Thread.currentThread().getName()); + System.out.println(Thread.currentThread().getName() + " - Sent Hello"); + + worker.recvStr(); // Envelope delimiter + System.out.println(Thread.currentThread().getName() + " - Received Envelope"); + String workload = worker.recvStr(); + System.out.println(Thread.currentThread().getName() + " - Received " + workload); + } + }); + workerThread.setName("worker"); + + brokerThread.start(); + workerThread.start(); + + workerThread.join(); + brokerThread.join(); + } + + @Test + public void asynchronous() throws Exception { + Thread brokerThread = new Thread(() -> { + try (ZContext context = new ZContext()) { + + ZMQ.Socket broker = context.createSocket(SocketType.ROUTER); + broker.bind("tcp://*:5555"); + + while (true) { + String identity = broker.recvStr(ZMQ.DONTWAIT); + System.out.println(Thread.currentThread().getName() + " - Received identity " + identity); + + if (identity == null) { + try { + Thread.sleep(100); + } catch (InterruptedException e) {} + } else { + + broker.recv(0); // Envelope delimiter + System.out.println(Thread.currentThread().getName() + " - Received envelope"); + String message = broker.recvStr(0); // Response from worker + System.out.println(Thread.currentThread().getName() + " - Received message " + message); + + broker.sendMore(identity); + broker.sendMore("xxx"); + broker.send("Hello back"); + + break; + } + } + } + }); + brokerThread.setName("broker"); + + Thread workerThread = new Thread(() -> { + try (ZContext context = new ZContext()) { + ZMQ.Socket worker = context.createSocket(SocketType.DEALER); + worker.setIdentity(Thread.currentThread().getName().getBytes(ZMQ.CHARSET)); + + worker.connect("tcp://localhost:5555"); + System.out.println(Thread.currentThread().getName() + " - Connected"); + + worker.sendMore(""); + worker.send("Hello " + Thread.currentThread().getName()); + System.out.println(Thread.currentThread().getName() + " - Sent Hello"); + + worker.recvStr(); // Envelope delimiter + System.out.println(Thread.currentThread().getName() + " - Received Envelope"); + String workload = worker.recvStr(); + System.out.println(Thread.currentThread().getName() + " - Received " + workload); + } + }); + workerThread.setName("worker"); + + brokerThread.start(); + workerThread.start(); + + workerThread.join(); + brokerThread.join(); + } + + + @Test + public void many() throws Exception { + Thread brokerThread = new Thread(() -> { + try (ZContext context = new ZContext()) { + + ZMQ.Socket broker = context.createSocket(SocketType.ROUTER); + broker.bind("tcp://*:5555"); + + while (!Thread.currentThread().isInterrupted()) { + String identity = broker.recvStr(); + System.out.println(Thread.currentThread().getName() + " - Received identity " + identity); + + broker.recv(0); // Envelope delimiter + String message = broker.recvStr(0); // Response from worker + System.out.println(Thread.currentThread().getName() + " - Received message " + message); + + broker.sendMore(identity); + broker.sendMore(""); + broker.send("Hello back to " + identity); + } + } + }); + brokerThread.setName("broker"); + + Set workers = IntStream.range(0, 10) + .mapToObj(index -> { + Thread workerThread = new Thread(() -> { + try (ZContext context = new ZContext()) { + ZMQ.Socket worker = context.createSocket(SocketType.DEALER); + worker.setIdentity(Thread.currentThread().getName().getBytes(ZMQ.CHARSET)); + + worker.connect("tcp://localhost:5555"); + System.out.println(Thread.currentThread().getName() + " - Connected"); + + worker.sendMore(""); + worker.send("Hello " + Thread.currentThread().getName()); + System.out.println(Thread.currentThread().getName() + " - Sent Hello"); + + worker.recvStr(); // Envelope delimiter + String workload = worker.recvStr(); + System.out.println(Thread.currentThread().getName() + " - Received " + workload); + } + }); + workerThread.setName("worker-" + index); + + return workerThread; + }) + .collect(Collectors.toSet()); + + brokerThread.start(); + workers.forEach(Thread::start); + + for (Thread worker : workers) { + worker.join(); + } + brokerThread.interrupt(); + } + + @Test + public void threaded() throws Exception { + Thread brokerThread = new Thread(() -> { + try (ZContext context = new ZContext()) { + + ZMQ.Socket broker = context.createSocket(SocketType.ROUTER); + broker.bind("tcp://*:5555"); + + ExecutorService threadPool = Executors.newFixedThreadPool(5); + Random rng = new Random(); + + while (!Thread.currentThread().isInterrupted()) { + String identity = broker.recvStr(); + System.out.println(Thread.currentThread().getName() + " - Received identity " + identity); + + broker.recv(0); // Envelope delimiter + String message = broker.recvStr(0); // Response from worker + System.out.println(Thread.currentThread().getName() + " - Received message " + message); + + threadPool.submit(() -> { + try { + Thread.sleep(rng.nextInt(1000) + 1000 ); + } catch (Exception e) {} + + synchronized(broker) { + broker.sendMore(identity); + broker.sendMore(""); + broker.send("Hello back to " + identity + " from " + Thread.currentThread().getName()); + } + }); + } + + threadPool.shutdown(); + } + }); + brokerThread.setName("broker"); + + Set workers = IntStream.range(0, 10) + .mapToObj(index -> { + Thread workerThread = new Thread(() -> { + try (ZContext context = new ZContext()) { + ZMQ.Socket worker = context.createSocket(SocketType.DEALER); + worker.setIdentity(Thread.currentThread().getName().getBytes(ZMQ.CHARSET)); + + worker.connect("tcp://localhost:5555"); + System.out.println(Thread.currentThread().getName() + " - Connected"); + + worker.sendMore(""); + worker.send("Hello " + Thread.currentThread().getName()); + System.out.println(Thread.currentThread().getName() + " - Sent Hello"); + + worker.recvStr(); // Envelope delimiter + String workload = worker.recvStr(); + System.out.println(Thread.currentThread().getName() + " - Received " + workload); + } + }); + workerThread.setName("worker-" + index); + + return workerThread; + }) + .collect(Collectors.toSet()); + + brokerThread.start(); + workers.forEach(Thread::start); + + for (Thread worker : workers) { + worker.join(); + } + brokerThread.interrupt(); + } +} diff --git a/jeromq/src/test/java/com/baeldung/jeromq/PubSubLiveTest.java b/jeromq/src/test/java/com/baeldung/jeromq/PubSubLiveTest.java new file mode 100644 index 0000000000..44699646b5 --- /dev/null +++ b/jeromq/src/test/java/com/baeldung/jeromq/PubSubLiveTest.java @@ -0,0 +1,101 @@ +package com.baeldung.jeromq; + +import org.junit.jupiter.api.Test; +import org.zeromq.SocketType; +import org.zeromq.ZContext; +import org.zeromq.ZMQ; + +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +public class PubSubLiveTest { + @Test + public void singleSub() throws Exception { + Thread server = new Thread(() -> { + try (ZContext context = new ZContext()) { + ZMQ.Socket pub = context.createSocket(SocketType.PUB); + pub.bind("tcp://*:5555"); + + try { + Thread.sleep(3000); + } catch (InterruptedException e) {} + + System.out.println(Thread.currentThread().getName() + " - Sending"); + pub.send("Hello"); + } + }); + server.setName("server"); + + Thread client = new Thread(() -> { + try (ZContext context = new ZContext()) { + ZMQ.Socket sub = context.createSocket(SocketType.SUB); + sub.connect("tcp://localhost:5555"); + System.out.println(Thread.currentThread().getName() + " - Connected"); + + sub.subscribe("".getBytes()); + System.out.println(Thread.currentThread().getName() + " - Subscribed"); + + String message = sub.recvStr(); + System.out.println(Thread.currentThread().getName() + " - " + message); + } + }); + client.setName("client"); + + server.start(); + client.start(); + + client.join(); + server.join(); + } + + + @Test + public void manySub() throws Exception { + Thread server = new Thread(() -> { + try (ZContext context = new ZContext()) { + ZMQ.Socket pub = context.createSocket(SocketType.PUB); + pub.bind("tcp://*:5555"); + + try { + Thread.sleep(3000); + } catch (InterruptedException e) {} + + System.out.println(Thread.currentThread().getName() + " - Sending"); + pub.send("Hello"); + } + }); + server.setName("server"); + + Set clients = IntStream.range(0, 10) + .mapToObj(index -> { + Thread client = new Thread(() -> { + try (ZContext context = new ZContext()) { + ZMQ.Socket sub = context.createSocket(SocketType.SUB); + sub.connect("tcp://localhost:5555"); + System.out.println(Thread.currentThread().getName() + " - Connected"); + + sub.subscribe("".getBytes()); + System.out.println(Thread.currentThread().getName() + " - Subscribed"); + + String message = sub.recvStr(); + System.out.println(Thread.currentThread().getName() + " - " + message); + } + }); + client.setName("client-" + index); + + return client; + }) + .collect(Collectors.toSet()); + + + server.start(); + clients.forEach(Thread::start); + + for (Thread client : clients) { + client.join(); + } + + server.join(); + } +} diff --git a/jeromq/src/test/java/com/baeldung/jeromq/RequestResponseLiveTest.java b/jeromq/src/test/java/com/baeldung/jeromq/RequestResponseLiveTest.java new file mode 100644 index 0000000000..8c0728e446 --- /dev/null +++ b/jeromq/src/test/java/com/baeldung/jeromq/RequestResponseLiveTest.java @@ -0,0 +1,96 @@ +package com.baeldung.jeromq; + +import org.junit.jupiter.api.Test; +import org.zeromq.SocketType; +import org.zeromq.ZContext; +import org.zeromq.ZMQ; + +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +public class RequestResponseLiveTest { + @Test + public void requestResponse() throws Exception { + try (ZContext context = new ZContext()) { + Thread server = new Thread(() -> { + ZMQ.Socket socket = context.createSocket(SocketType.REP); + socket.bind("inproc://test"); + + while (!Thread.currentThread().isInterrupted()) { + byte[] reply = socket.recv(0); + System.out.println("Server Received " + ": [" + new String(reply, ZMQ.CHARSET) + "]"); + + String response = new String(reply, ZMQ.CHARSET) + ", world"; + socket.send(response.getBytes(ZMQ.CHARSET), 0); + } + }); + + Thread client = new Thread(() -> { + ZMQ.Socket socket = context.createSocket(SocketType.REQ); + socket.connect("inproc://test"); + + for (int requestNbr = 0; requestNbr != 10; requestNbr++) { + String request = "Hello " + requestNbr; + System.out.println("Sending " + request); + socket.send(request.getBytes(ZMQ.CHARSET), 0); + + byte[] reply = socket.recv(0); + System.out.println("Client Received " + new String(reply, ZMQ.CHARSET)); + } + + }); + + server.start(); + client.start(); + + client.join(); + server.interrupt(); + } + } + + @Test + public void manyRequestResponse() throws Exception { + try (ZContext context = new ZContext()) { + Thread server = new Thread(() -> { + ZMQ.Socket socket = context.createSocket(SocketType.REP); + socket.bind("tcp://*:5555"); + + while (!Thread.currentThread().isInterrupted()) { + byte[] reply = socket.recv(0); + System.out.println("Server Received " + ": [" + new String(reply, ZMQ.CHARSET) + "]"); + + String response = new String(reply, ZMQ.CHARSET) + ", world"; + socket.send(response.getBytes(ZMQ.CHARSET), 0); + } + }); + + Set clients = IntStream.range(0, 10).mapToObj(index -> + new Thread(() -> { + ZMQ.Socket socket = context.createSocket(SocketType.REQ); + socket.connect("tcp://localhost:5555"); + + for (int requestNbr = 0; requestNbr != 10; requestNbr++) { + String request = "Hello " + index + " - " + requestNbr; + System.out.println("Sending " + request); + socket.send(request.getBytes(ZMQ.CHARSET), 0); + + byte[] reply = socket.recv(0); + System.out.println("Client " + index + " Received " + new String(reply, ZMQ.CHARSET)); + } + + }) + ).collect(Collectors.toSet()); + + server.start(); + clients.forEach(Thread::start); + + for (Thread client : clients) { + client.join(); + } + + server.interrupt(); + } + + } +} diff --git a/jmh/pom.xml b/jmh/pom.xml index 5b98d59002..e5e0f46044 100644 --- a/jmh/pom.xml +++ b/jmh/pom.xml @@ -18,12 +18,12 @@ org.openjdk.jmh jmh-core - 1.36 + ${jmh-core.version} org.openjdk.jmh jmh-generator-annprocess - 1.36 + ${jmh-generator.version} org.openjdk.jol diff --git a/json-modules/gson-2/README.md b/json-modules/gson-2/README.md index 5580479753..3deb61f25d 100644 --- a/json-modules/gson-2/README.md +++ b/json-modules/gson-2/README.md @@ -4,4 +4,5 @@ This module contains articles about Gson ### Relevant Articles: - [Solving Gson Parsing Errors](https://www.baeldung.com/gson-parsing-errors) +- [Difference between Gson @Expose and @SerializedName](https://www.baeldung.com/gson-expose-vs-serializedname) diff --git a/json-modules/gson-2/src/main/java/com/baeldung/gson/entities/BankAccount.java b/json-modules/gson-2/src/main/java/com/baeldung/gson/entities/BankAccount.java new file mode 100644 index 0000000000..0ac01f0477 --- /dev/null +++ b/json-modules/gson-2/src/main/java/com/baeldung/gson/entities/BankAccount.java @@ -0,0 +1,31 @@ +package com.baeldung.gson.entities; + +import com.google.gson.annotations.Expose; + +public class BankAccount { + @Expose(serialize = false, deserialize = false) + private String accountNumber; + @Expose(serialize = true, deserialize = true) + private String bankName; + + public BankAccount(String accountNumber, String bankName) { + this.accountNumber = accountNumber; + this.bankName = bankName; + } + + public String getAccountNumber() { + return accountNumber; + } + + public void setAccountNumber(String accountNumber) { + this.accountNumber = accountNumber; + } + + public String getBankName() { + return bankName; + } + + public void setBankName(String bankName) { + this.bankName = bankName; + } +} diff --git a/json-modules/gson-2/src/main/java/com/baeldung/gson/entities/Country.java b/json-modules/gson-2/src/main/java/com/baeldung/gson/entities/Country.java new file mode 100644 index 0000000000..070c91849f --- /dev/null +++ b/json-modules/gson-2/src/main/java/com/baeldung/gson/entities/Country.java @@ -0,0 +1,50 @@ +package com.baeldung.gson.entities; + +import com.google.gson.annotations.SerializedName; + +public class Country { + @SerializedName(value = "name") + private String countryName; + @SerializedName(value = "capital") + private String countryCapital; + @SerializedName(value = "continent") + private String continentName; + + public Country(String countryName, String countryCapital, String continentName) { + this.countryName = countryName; + this.countryCapital = countryCapital; + this.continentName = continentName; + } + @Override + public String toString() { + return "Country{" + + "countryName='" + countryName + '\'' + + ", countryCapital='" + countryCapital + '\'' + + ", continentName='" + continentName + '\'' + + '}'; + } + + public String getCountryName() { + return countryName; + } + + public void setCountryName(String countryName) { + this.countryName = countryName; + } + + public String getCountryCapital() { + return countryCapital; + } + + public void setCountryCapital(String countryCapital) { + this.countryCapital = countryCapital; + } + + public String getContinentName() { + return continentName; + } + + public void setContinentName(String continentName) { + this.continentName = continentName; + } +} diff --git a/json-modules/gson-2/src/main/java/com/baeldung/gson/entities/Person.java b/json-modules/gson-2/src/main/java/com/baeldung/gson/entities/Person.java new file mode 100644 index 0000000000..6178668ff9 --- /dev/null +++ b/json-modules/gson-2/src/main/java/com/baeldung/gson/entities/Person.java @@ -0,0 +1,69 @@ +package com.baeldung.gson.entities; + +import com.google.gson.annotations.Expose; + + +import java.util.List; + +public class Person { + + public Person(String firstName, String lastName, String emailAddress, String password, List bankAccounts) { + this.firstName = firstName; + this.lastName = lastName; + this.emailAddress = emailAddress; + this.password = password; + this.bankAccounts = bankAccounts; + } + + @Expose(serialize = true) + private String firstName; + @Expose(serialize = true) + private String lastName; + @Expose() + private String emailAddress; + @Expose(serialize = false) + private String password; + + @Expose(serialize = true) + private List bankAccounts; + + public List getBankAccounts() { + return bankAccounts; + } + + public void setBankAccounts(List bankAccounts) { + this.bankAccounts = bankAccounts; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getEmailAddress() { + return emailAddress; + } + + public void setEmailAddress(String emailAddress) { + this.emailAddress = emailAddress; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } +} diff --git a/json-modules/gson-2/src/main/java/com/baeldung/gson/exposevsserializedname/PersonSerializer.java b/json-modules/gson-2/src/main/java/com/baeldung/gson/exposevsserializedname/PersonSerializer.java new file mode 100644 index 0000000000..23fc282caa --- /dev/null +++ b/json-modules/gson-2/src/main/java/com/baeldung/gson/exposevsserializedname/PersonSerializer.java @@ -0,0 +1,27 @@ +package com.baeldung.gson.exposevsserializedname; + +import com.baeldung.gson.entities.Country; +import com.baeldung.gson.entities.Person; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +public class PersonSerializer { + private static final Gson configuredGson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create(); + private static final Gson defaultGson = new Gson(); + + public static String serializeWithConfiguredGson(Person person) { + return configuredGson.toJson(person); + } + + public static String serializeWithDefaultGson(Person person) { + return defaultGson.toJson(person); + } + + public static String toJsonString(Object obj) { + return defaultGson.toJson(obj); + } + + public static Country fromJsonString(String json) { + return defaultGson.fromJson(json, Country.class); + } +} diff --git a/json-modules/gson-2/src/test/java/com/baeldung/gson/exposevsserializedname/PersonSerializerUnitTest.java b/json-modules/gson-2/src/test/java/com/baeldung/gson/exposevsserializedname/PersonSerializerUnitTest.java new file mode 100644 index 0000000000..11cf33937d --- /dev/null +++ b/json-modules/gson-2/src/test/java/com/baeldung/gson/exposevsserializedname/PersonSerializerUnitTest.java @@ -0,0 +1,75 @@ +package com.baeldung.gson.exposevsserializedname; + +import com.baeldung.gson.entities.BankAccount; +import com.baeldung.gson.entities.Country; +import com.baeldung.gson.entities.Person; + +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.*; + +public class PersonSerializerUnitTest { + private static final Logger logger = LoggerFactory.getLogger(PersonSerializerUnitTest.class); + private Person person = null; + private Country country = null; + @Before + public void preparePersonObj() { + List accounts = new ArrayList<>(); + BankAccount acc1 = new BankAccount("4565432312", "Bank of America"); + BankAccount acc2 = new BankAccount("4565432616", "Bank of America"); + accounts.add(acc1); + accounts.add(acc2); + person = new Person( + "James", "Cameron", "james.cameron@gmail.com", + "secret", accounts); + + country = new Country("India", "New Delhi", "Asia"); + } + + @Test + public void whenUseCustomGson_thenDonotSerializeAccountNumAndPassword () { + + String personJson = PersonSerializer.serializeWithConfiguredGson(person); + logger.info(personJson); + assertFalse("Test failed: password found", personJson.contains("password")); + assertFalse("Test failed: account number found", personJson.contains("accountNumber:")); + } + + @Test + public void whenUseDefaultGson_thenSerializeAccountNumAndPassword () { + + String personJson = PersonSerializer.serializeWithDefaultGson(person); + logger.info(personJson); + assertTrue("Test failed: password not found", personJson.contains("password")); + assertTrue("Test failed: account number not found", personJson.contains("accountNumber")); + } + + @Test + public void whenUseSerializedAnnotation_thenUseSerializedNameinJsonString() { + String countryJson = PersonSerializer.toJsonString(country); + logger.info(countryJson); + assertFalse("Test failed: No change in the keys", countryJson.contains("countryName")); + assertFalse("Test failed: No change in the keys", countryJson.contains("contentName")); + assertFalse("Test failed: No change in the keys", countryJson.contains("countryCapital")); + + assertTrue("Test failed: No change in the keys", countryJson.contains("name")); + assertTrue("Test failed: No change in the keys", countryJson.contains("continent")); + assertTrue("Test failed: No change in the keys", countryJson.contains("capital")); + } + + @Test + public void whenJsonStrCreatedWithCustomKeys_thenCreateObjUsingGson() { + String countryJson = PersonSerializer.toJsonString(country); + Country country = PersonSerializer.fromJsonString(countryJson); + logger.info(country.toString()); + assertEquals("Fail: Object creation failed", country.getCountryName(), "India"); + assertEquals("Fail: Object creation failed", country.getCountryCapital(), "New Delhi"); + assertEquals("Fail: Object creation failed", country.getContinentName(), "Asia"); + } +} diff --git a/json-modules/json-2/README.md b/json-modules/json-2/README.md index bf2cb06aba..adf55c3618 100644 --- a/json-modules/json-2/README.md +++ b/json-modules/json-2/README.md @@ -11,5 +11,6 @@ This module contains articles about JSON. - [A Guide to FastJson](https://www.baeldung.com/fastjson) - [Check Whether a String Is Valid JSON in Java](https://www.baeldung.com/java-validate-json-string) - [Getting a Value in JSONObject](https://www.baeldung.com/java-jsonobject-get-value) +- [Pretty-Print a JSON in Java](https://www.baeldung.com/java-json-pretty-print) - More Articles: [[<-- prev]](/json-modules/json) diff --git a/json-modules/json-2/src/main/java/com/baeldung/jsonminifier/JsonMinifier.java b/json-modules/json-2/src/main/java/com/baeldung/jsonminifier/JsonMinifier.java new file mode 100644 index 0000000000..d402e8b1a1 --- /dev/null +++ b/json-modules/json-2/src/main/java/com/baeldung/jsonminifier/JsonMinifier.java @@ -0,0 +1,58 @@ +package com.baeldung.jsonminifier; + +import java.lang.reflect.Type; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; + +public class JsonMinifier { + public String removeExtraWhitespace(String json) { + StringBuilder result = new StringBuilder(json.length()); + boolean inQuotes = false; + boolean escapeMode = false; + + for (char character : json.toCharArray()) { + if (escapeMode) { + result.append(character); + escapeMode = false; + } else if (character == '"') { + inQuotes = !inQuotes; + result.append(character); + } else if (character == '\\') { + escapeMode = true; + result.append(character); + } else if (!inQuotes && character == ' ') { + continue; + } else { + result.append(character); + } + } + + return result.toString(); + } + + public String removeExtraWhitespaceUsingJackson(String json) throws Exception { + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode jsonNode = objectMapper.readTree(json); + return objectMapper.writeValueAsString(jsonNode); + } + + public String removeWhitespacesUsingGson(String json) { + Gson gson = new GsonBuilder().registerTypeAdapter(String.class, new StringSerializer()).create(); + JsonElement jsonElement = gson.fromJson(json, JsonElement.class); + return gson.toJson(jsonElement); + } + + class StringSerializer implements JsonSerializer { + @Override + public JsonElement serialize(String src, Type typeOfSrc, JsonSerializationContext context) { + return new JsonPrimitive(src.trim()); + } + } +} diff --git a/json-modules/json-2/src/main/java/com/baeldung/jsonprettyprinter/JsonPrettyPrinter.java b/json-modules/json-2/src/main/java/com/baeldung/jsonprettyprinter/JsonPrettyPrinter.java new file mode 100644 index 0000000000..85bd3197d6 --- /dev/null +++ b/json-modules/json-2/src/main/java/com/baeldung/jsonprettyprinter/JsonPrettyPrinter.java @@ -0,0 +1,34 @@ +package com.baeldung.jsonprettyprinter; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + + +/* + * Class to print string JSON to well-formatted JSON using Jackson and Gson. + */ +public class JsonPrettyPrinter { + private ObjectMapper mapper = new ObjectMapper(); + + public String prettyPrintJsonUsingDefaultPrettyPrinter(String uglyJsonString) throws JsonProcessingException { + ObjectMapper objectMapper = new ObjectMapper(); + Object jsonObject = objectMapper.readValue(uglyJsonString, Object.class); + return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonObject); + } + + public String prettyPrintUsingGlobalSetting(String uglyJsonString) throws JsonProcessingException { + ObjectMapper mapper = new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT); + Object jsonObject = mapper.readValue(uglyJsonString, Object.class); + return mapper.writeValueAsString(jsonObject); + } + + public String prettyPrintUsingGson(String uglyJsonString) { + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + Object jsonObject = gson.fromJson(uglyJsonString, Object.class); + return gson.toJson(jsonObject); + } +} diff --git a/json-modules/json-2/src/test/java/com/baeldung/jsonminifier/JsonMinifierUnitTest.java b/json-modules/json-2/src/test/java/com/baeldung/jsonminifier/JsonMinifierUnitTest.java new file mode 100644 index 0000000000..056e3429bd --- /dev/null +++ b/json-modules/json-2/src/test/java/com/baeldung/jsonminifier/JsonMinifierUnitTest.java @@ -0,0 +1,34 @@ +package com.baeldung.jsonminifier; + +import static org.junit.Assert.assertEquals; +import org.junit.jupiter.api.Test; + +public class JsonMinifierUnitTest { + private JsonMinifier jsonMinifier = new JsonMinifier(); + private String inputJson = "{ \"name\" : \"John\" , \"address\" : \"New York\", \"age\" : 30 , \"phoneNumber\" : 9999999999 }"; + + + @Test + public void givenWhiteSpaceRemoval_whenJsonContainsWhitespaces_thenWhitespaceRemoved() { + String expectedJson = "{\"name\":\"John\",\"address\":\"New York\",\"age\":30,\"phoneNumber\":9999999999}"; + String result = jsonMinifier.removeExtraWhitespace(inputJson); + System.out.println(result); + assertEquals(expectedJson, result); + } + + @Test + public void givenWhiteSpaceRemovalUsingJackson_whenJsonContainsWhitespaces_thenWhitespaceRemoved() throws Exception { + String expectedJson = "{\"name\":\"John\",\"address\":\"New York\",\"age\":30,\"phoneNumber\":9999999999}"; + String result = jsonMinifier.removeExtraWhitespaceUsingJackson(inputJson); + System.out.println(result); + assertEquals(expectedJson, result); + } + + @Test + public void givenWhiteSpaceRemovalUsingGson_whenJsonContainsWhitespaces_thenWhitespaceRemoved() { + String expectedJson = "{\"name\":\"John\",\"address\":\"New York\",\"age\":30,\"phoneNumber\":9999999999}"; + String result = jsonMinifier.removeWhitespacesUsingGson(inputJson); + System.out.println(result); + assertEquals(expectedJson, result); + } +} diff --git a/json-modules/json-2/src/test/java/com/baeldung/jsonprettyprinter/JsonPrettyPrinterUnitTest.java b/json-modules/json-2/src/test/java/com/baeldung/jsonprettyprinter/JsonPrettyPrinterUnitTest.java new file mode 100644 index 0000000000..245c2436a4 --- /dev/null +++ b/json-modules/json-2/src/test/java/com/baeldung/jsonprettyprinter/JsonPrettyPrinterUnitTest.java @@ -0,0 +1,63 @@ +package com.baeldung.jsonprettyprinter; + +import com.fasterxml.jackson.core.JsonProcessingException; + +import org.junit.Test; +import static org.junit.Assert.assertEquals; + +public class JsonPrettyPrinterUnitTest { + + private String uglyJsonString = "{\"one\":\"AAA\",\"two\":[\"BBB\",\"CCC\"],\"three\":{\"four\":\"DDD\",\"five\":[\"EEE\",\"FFF\"]}}"; + private JsonPrettyPrinter jsonPrettyPrinter = new JsonPrettyPrinter(); + + @Test + public void shouldPrettyPrintJsonStringUsingDefaultPrettyPrinter() throws JsonProcessingException { + String formattedJsonString = jsonPrettyPrinter.prettyPrintJsonUsingDefaultPrettyPrinter(uglyJsonString); + String expectedJson = "{\n" + + " \"one\" : \"AAA\",\n" + + " \"two\" : [ \"BBB\", \"CCC\" ],\n" + + " \"three\" : {\n" + + " \"four\" : \"DDD\",\n" + + " \"five\" : [ \"EEE\", \"FFF\" ]\n" + + " }\n" + + "}"; + System.out.println("Formatted String: " + formattedJsonString); + assertEquals(expectedJson, formattedJsonString); + } + + @Test + public void shouldPrettyPrintJsonStringUsingGlobalSetting() throws JsonProcessingException { + String formattedJsonString = jsonPrettyPrinter.prettyPrintUsingGlobalSetting(uglyJsonString); + String expectedJson = "{\n" + + " \"one\" : \"AAA\",\n" + + " \"two\" : [ \"BBB\", \"CCC\" ],\n" + + " \"three\" : {\n" + + " \"four\" : \"DDD\",\n" + + " \"five\" : [ \"EEE\", \"FFF\" ]\n" + + " }\n" + + "}"; + System.out.println("Formatted String: " + formattedJsonString); + assertEquals(expectedJson, formattedJsonString); + } + + @Test + public void shouldPrettyPrintJsonStringUsingGson() { + String formattedJsonString = jsonPrettyPrinter.prettyPrintUsingGson(uglyJsonString); + String expectedPrettyJson = "{\n" + + " \"one\": \"AAA\",\n" + + " \"two\": [\n" + + " \"BBB\",\n" + + " \"CCC\"\n" + + " ],\n" + + " \"three\": {\n" + + " \"four\": \"DDD\",\n" + + " \"five\": [\n" + + " \"EEE\",\n" + + " \"FFF\"\n" + + " ]\n" + + " }\n" + + "}"; + System.out.println("Formatted String: " + formattedJsonString); + assertEquals(expectedPrettyJson, formattedJsonString); + } +} diff --git a/logging-modules/logback/README.md b/logging-modules/logback/README.md index 9a9ffc6e70..1bebcd20d3 100644 --- a/logging-modules/logback/README.md +++ b/logging-modules/logback/README.md @@ -6,3 +6,4 @@ - [Mask Sensitive Data in Logs With Logback](https://www.baeldung.com/logback-mask-sensitive-data) - [Creating a Custom Logback Appender](https://www.baeldung.com/custom-logback-appender) - [A Guide To Logback](https://www.baeldung.com/logback) +- [Parameterized Logging with SLF4J](TODO) \ No newline at end of file diff --git a/logging-modules/logback/pom.xml b/logging-modules/logback/pom.xml index e7313d902a..cddc2e72ea 100644 --- a/logging-modules/logback/pom.xml +++ b/logging-modules/logback/pom.xml @@ -24,11 +24,6 @@ logback-classic ${logback.version} - - ch.qos.logback - logback-core - ${logback.version} - ch.qos.logback.contrib logback-json-classic @@ -75,6 +70,12 @@ ${angus.activation.version} runtime + + org.projectlombok + lombok + provided + ${lombok.version} + @@ -118,8 +119,9 @@ 3.3.5 2.0.1 2.0.0 - 1.3.5 + 1.4.8 2.0.4 + 1.18.22 \ No newline at end of file diff --git a/logging-modules/logback/src/main/java/com/baeldung/parameterized/logging/FluentLoggingPlayground.java b/logging-modules/logback/src/main/java/com/baeldung/parameterized/logging/FluentLoggingPlayground.java new file mode 100644 index 0000000000..cc27d70c33 --- /dev/null +++ b/logging-modules/logback/src/main/java/com/baeldung/parameterized/logging/FluentLoggingPlayground.java @@ -0,0 +1,36 @@ +package com.baeldung.parameterized.logging; + +import java.time.LocalDateTime; +import java.time.ZonedDateTime; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class FluentLoggingPlayground { + + public static void main(String[] args) { + + Exception exceptionCause = new Exception(new IllegalArgumentException("Something unprocessable")); + + log.atInfo() + .setMessage("App is running at {}, zone = {}") + .addArgument(LocalDateTime.now()) + .addArgument(ZonedDateTime.now().getZone()) + .log(); + + log.atInfo() + .setMessage("App is running at {}, zone = {}") + .addArgument(LocalDateTime.now()) + .addArgument(ZonedDateTime.now().getZone()) + .setCause(exceptionCause) + .log(); + + log.atInfo() + .setMessage("App is running at") + .addKeyValue("time", LocalDateTime.now()) + .addKeyValue("zone", ZonedDateTime.now().getZone()) + .setCause(exceptionCause) + .log(); + + } +} diff --git a/logging-modules/logback/src/main/java/com/baeldung/parameterized/logging/LoggingPlayground.java b/logging-modules/logback/src/main/java/com/baeldung/parameterized/logging/LoggingPlayground.java new file mode 100644 index 0000000000..32a937fcf7 --- /dev/null +++ b/logging-modules/logback/src/main/java/com/baeldung/parameterized/logging/LoggingPlayground.java @@ -0,0 +1,40 @@ +package com.baeldung.parameterized.logging; + +import java.time.LocalDateTime; +import java.time.ZonedDateTime; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class LoggingPlayground { + + public static final Logger log = LoggerFactory.getLogger(LoggingPlayground.class); + + public static void main(String[] args) { + log.info("App is running at {}", LocalDateTime.now()); + + log.info("App is running at {}, zone = {}", LocalDateTime.now(), ZonedDateTime.now() + .getZone()); + + log.info("App is running at {}, zone = {}, java version = {}", LocalDateTime.now(), ZonedDateTime.now() + .getZone(), System.getProperty("java.version")); + + log.info("App is running at {}, zone = {}, java version = {}, java vm = {}", LocalDateTime.now(), ZonedDateTime.now() + .getZone(), System.getProperty("java.version"), System.getProperty("java.vm.name")); + + //old approach to print multiple parameters + log.info("App is running at {}, zone = {}, java version = {}, java vm = {}", + new Object[] { ZonedDateTime.now(), ZonedDateTime.now().getZone(), System.getProperty("java.version"), System.getProperty("java.vm.name") }); + + Exception exceptionCause = new Exception(new IllegalArgumentException("Something unprocessable")); + + //exception as last parameters is considered as exception and printed with trace + log.info("App is running at {}, zone = {}, java version = {}, java vm = {}", LocalDateTime.now(), ZonedDateTime.now() + .getZone(), System.getProperty("java.version"), System.getProperty("java.vm.name"), exceptionCause); + + //exception in between parameters is considered as pure parameter and printed without trace + log.info("App is running at {}, zone = {}, java version = {}, java vm = {}", LocalDateTime.now(), ZonedDateTime.now() + .getZone(), System.getProperty("java.version"), exceptionCause, System.getProperty("java.vm.name")); + + } +} diff --git a/logging-modules/logback/src/main/resources/logback.xml b/logging-modules/logback/src/main/resources/logback.xml index 2d56c110e0..07d5a6bee7 100644 --- a/logging-modules/logback/src/main/resources/logback.xml +++ b/logging-modules/logback/src/main/resources/logback.xml @@ -6,7 +6,7 @@ - %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg %kvp%n @@ -66,4 +66,7 @@ + + + \ No newline at end of file diff --git a/maven-modules/maven-plugins/jaxws/pom.xml b/maven-modules/maven-plugins/jaxws/pom.xml index a7c4740acb..f17d70c182 100644 --- a/maven-modules/maven-plugins/jaxws/pom.xml +++ b/maven-modules/maven-plugins/jaxws/pom.xml @@ -13,9 +13,9 @@ - javax.xml.bind - jaxb-api - 2.3.0 + jakarta.xml.ws + jakarta.xml.ws-api + 4.0.0 org.glassfish.jaxb @@ -44,9 +44,9 @@ - org.codehaus.mojo + com.sun.xml.ws jaxws-maven-plugin - 2.6 + 4.0.1 diff --git a/messaging-modules/pom.xml b/messaging-modules/pom.xml index 27524637ab..6fd14f7c64 100644 --- a/messaging-modules/pom.xml +++ b/messaging-modules/pom.xml @@ -22,7 +22,7 @@ spring-amqp spring-apache-camel spring-jms - postgres-notify + postgres-notify \ No newline at end of file diff --git a/messaging-modules/postgres-notify/pom.xml b/messaging-modules/postgres-notify/pom.xml index 876519f40c..174d66b7f5 100644 --- a/messaging-modules/postgres-notify/pom.xml +++ b/messaging-modules/postgres-notify/pom.xml @@ -42,36 +42,37 @@ lombok true - + - - 1.8 - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - - instance1 - - - - org.springframework.boot - spring-boot-maven-plugin - - -Dserver.port=8081 - - - - - - - + + 1.8 + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + instance1 + + + + org.springframework.boot + spring-boot-maven-plugin + + -Dserver.port=8081 + + + + + + + \ No newline at end of file diff --git a/messaging-modules/spring-apache-camel/README.md b/messaging-modules/spring-apache-camel/README.md index 66079d4e83..d77befc328 100644 --- a/messaging-modules/spring-apache-camel/README.md +++ b/messaging-modules/spring-apache-camel/README.md @@ -14,7 +14,7 @@ This module contains articles about Spring with Apache Camel ### Framework Versions: - Spring 5.3.25 -- Apache Camel 3.14.7 +- Apache Camel 3.21.0 ### Build and Run Application diff --git a/messaging-modules/spring-apache-camel/pom.xml b/messaging-modules/spring-apache-camel/pom.xml index c64d84efdc..ba2054b182 100644 --- a/messaging-modules/spring-apache-camel/pom.xml +++ b/messaging-modules/spring-apache-camel/pom.xml @@ -19,12 +19,12 @@ org.apache.camel camel-core - ${env.camel.version} + ${camel.version} org.apache.camel camel-spring - ${env.camel.version} + ${camel.version} commons-logging @@ -35,17 +35,12 @@ org.apache.camel camel-stream - ${env.camel.version} + ${camel.version} org.springframework spring-context - ${env.spring.version} - - - org.apache.camel - camel-spring-javaconfig - ${env.camel.version} + ${spring.version} org.apache.camel.springboot @@ -77,12 +72,16 @@ ${camel.version} test + + org.apache.camel + camel-spring-xml + ${camel.version} + - 3.14.7 - 5.3.25 - 3.15.0 + 5.3.25 + 3.21.0 diff --git a/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/apache/file/cfg/ContentBasedFileRouterConfig.java b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/apache/file/cfg/ContentBasedFileRouterConfig.java index 2b24cf2a51..208a3dd5cd 100644 --- a/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/apache/file/cfg/ContentBasedFileRouterConfig.java +++ b/messaging-modules/spring-apache-camel/src/main/java/com/baeldung/camel/apache/file/cfg/ContentBasedFileRouterConfig.java @@ -1,26 +1,24 @@ package com.baeldung.camel.apache.file.cfg; -import java.util.Arrays; +import java.util.Collections; import java.util.List; import org.apache.camel.builder.RouteBuilder; -import org.apache.camel.spring.javaconfig.CamelConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.baeldung.camel.apache.file.ContentBasedFileRouter; @Configuration -public class ContentBasedFileRouterConfig extends CamelConfiguration { +public class ContentBasedFileRouterConfig { @Bean ContentBasedFileRouter getContentBasedFileRouter() { return new ContentBasedFileRouter(); } - @Override public List routes() { - return Arrays.asList(getContentBasedFileRouter()); + return Collections.singletonList(getContentBasedFileRouter()); } } diff --git a/microservices-modules/helidon/helidon-mp/pom.xml b/microservices-modules/helidon/helidon-mp/pom.xml index 3e61d05f61..a79ae5c76a 100644 --- a/microservices-modules/helidon/helidon-mp/pom.xml +++ b/microservices-modules/helidon/helidon-mp/pom.xml @@ -15,7 +15,7 @@ io.helidon.microprofile.bundles - helidon-microprofile-1.2 + helidon-microprofile ${helidon-microprofile.version} @@ -26,8 +26,8 @@ - 0.10.4 - 2.26 + 3.2.2 + 3.1.2 \ No newline at end of file diff --git a/microservices-modules/helidon/helidon-mp/src/main/java/com/baeldung/microprofile/LibraryApplication.java b/microservices-modules/helidon/helidon-mp/src/main/java/com/baeldung/microprofile/LibraryApplication.java index 58913c8b39..49197ea0eb 100644 --- a/microservices-modules/helidon/helidon-mp/src/main/java/com/baeldung/microprofile/LibraryApplication.java +++ b/microservices-modules/helidon/helidon-mp/src/main/java/com/baeldung/microprofile/LibraryApplication.java @@ -1,11 +1,10 @@ package com.baeldung.microprofile; import com.baeldung.microprofile.web.BookEndpoint; -import io.helidon.common.CollectionsHelper; import io.helidon.microprofile.server.Server; +import jakarta.ws.rs.ApplicationPath; +import jakarta.ws.rs.core.Application; -import javax.ws.rs.ApplicationPath; -import javax.ws.rs.core.Application; import java.util.Set; @ApplicationPath("/library") @@ -13,7 +12,7 @@ public class LibraryApplication extends Application { @Override public Set> getClasses() { - return CollectionsHelper.setOf(BookEndpoint.class); + return Set.of(BookEndpoint.class); } public static void main(String... args) { diff --git a/microservices-modules/helidon/helidon-mp/src/main/java/com/baeldung/microprofile/providers/BookListMessageBodyWriter.java b/microservices-modules/helidon/helidon-mp/src/main/java/com/baeldung/microprofile/providers/BookListMessageBodyWriter.java index f7d0bfc5f7..c1300c2a48 100644 --- a/microservices-modules/helidon/helidon-mp/src/main/java/com/baeldung/microprofile/providers/BookListMessageBodyWriter.java +++ b/microservices-modules/helidon/helidon-mp/src/main/java/com/baeldung/microprofile/providers/BookListMessageBodyWriter.java @@ -3,21 +3,21 @@ package com.baeldung.microprofile.providers; import com.baeldung.microprofile.model.Book; import com.baeldung.microprofile.util.BookMapper; -import javax.json.Json; -import javax.json.JsonArray; -import javax.json.JsonWriter; -import javax.ws.rs.Produces; -import javax.ws.rs.WebApplicationException; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.MultivaluedMap; -import javax.ws.rs.ext.MessageBodyWriter; -import javax.ws.rs.ext.Provider; -import java.io.IOException; import java.io.OutputStream; import java.lang.annotation.Annotation; import java.lang.reflect.Type; import java.util.List; +import jakarta.json.Json; +import jakarta.json.JsonArray; +import jakarta.json.JsonWriter; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.MultivaluedMap; +import jakarta.ws.rs.ext.MessageBodyWriter; +import jakarta.ws.rs.ext.Provider; + @Provider @Produces(MediaType.APPLICATION_JSON) public class BookListMessageBodyWriter implements MessageBodyWriter> { @@ -33,7 +33,9 @@ public class BookListMessageBodyWriter implements MessageBodyWriter> } @Override - public void writeTo(List books, Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException { + public void writeTo( + List books, Class type, Type genericType, Annotation[] annotations, MediaType mediaType, + MultivaluedMap httpHeaders, OutputStream entityStream) throws WebApplicationException { JsonWriter jsonWriter = Json.createWriter(entityStream); JsonArray jsonArray = BookMapper.map(books); jsonWriter.writeArray(jsonArray); diff --git a/microservices-modules/helidon/helidon-mp/src/main/java/com/baeldung/microprofile/providers/BookMessageBodyReader.java b/microservices-modules/helidon/helidon-mp/src/main/java/com/baeldung/microprofile/providers/BookMessageBodyReader.java index 26ce4c1b64..d1f893e4a9 100644 --- a/microservices-modules/helidon/helidon-mp/src/main/java/com/baeldung/microprofile/providers/BookMessageBodyReader.java +++ b/microservices-modules/helidon/helidon-mp/src/main/java/com/baeldung/microprofile/providers/BookMessageBodyReader.java @@ -3,17 +3,18 @@ package com.baeldung.microprofile.providers; import com.baeldung.microprofile.model.Book; import com.baeldung.microprofile.util.BookMapper; -import javax.ws.rs.Consumes; -import javax.ws.rs.WebApplicationException; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.MultivaluedMap; -import javax.ws.rs.ext.MessageBodyReader; -import javax.ws.rs.ext.Provider; import java.io.IOException; import java.io.InputStream; import java.lang.annotation.Annotation; import java.lang.reflect.Type; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.MultivaluedMap; +import jakarta.ws.rs.ext.MessageBodyReader; +import jakarta.ws.rs.ext.Provider; + @Provider @Consumes(MediaType.APPLICATION_JSON) public class BookMessageBodyReader implements MessageBodyReader { @@ -24,7 +25,10 @@ public class BookMessageBodyReader implements MessageBodyReader { } @Override - public Book readFrom(Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, InputStream entityStream) throws IOException, WebApplicationException { + public Book readFrom( + Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, + InputStream entityStream + ) throws IOException, WebApplicationException { return BookMapper.map(entityStream); } } \ No newline at end of file diff --git a/microservices-modules/helidon/helidon-mp/src/main/java/com/baeldung/microprofile/providers/BookMessageBodyWriter.java b/microservices-modules/helidon/helidon-mp/src/main/java/com/baeldung/microprofile/providers/BookMessageBodyWriter.java index 9bc6e89958..6e72bd37d6 100644 --- a/microservices-modules/helidon/helidon-mp/src/main/java/com/baeldung/microprofile/providers/BookMessageBodyWriter.java +++ b/microservices-modules/helidon/helidon-mp/src/main/java/com/baeldung/microprofile/providers/BookMessageBodyWriter.java @@ -3,20 +3,20 @@ package com.baeldung.microprofile.providers; import com.baeldung.microprofile.model.Book; import com.baeldung.microprofile.util.BookMapper; -import javax.json.Json; -import javax.json.JsonObject; -import javax.json.JsonWriter; -import javax.ws.rs.Produces; -import javax.ws.rs.WebApplicationException; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.MultivaluedMap; -import javax.ws.rs.ext.MessageBodyWriter; -import javax.ws.rs.ext.Provider; -import java.io.IOException; +import jakarta.json.Json; +import jakarta.json.JsonObject; +import jakarta.json.JsonWriter; import java.io.OutputStream; import java.lang.annotation.Annotation; import java.lang.reflect.Type; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.MultivaluedMap; +import jakarta.ws.rs.ext.MessageBodyWriter; +import jakarta.ws.rs.ext.Provider; + @Provider @Produces(MediaType.APPLICATION_JSON) public class BookMessageBodyWriter implements MessageBodyWriter { @@ -33,21 +33,11 @@ public class BookMessageBodyWriter implements MessageBodyWriter { return 0; } - /** - * Marsahl Book to OutputStream - * - * @param book - * @param type - * @param genericType - * @param annotations - * @param mediaType - * @param httpHeaders - * @param entityStream - * @throws IOException - * @throws WebApplicationException - */ @Override - public void writeTo(Book book, Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException { + public void writeTo( + Book book, Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, + OutputStream entityStream + ) throws WebApplicationException { JsonWriter jsonWriter = Json.createWriter(entityStream); JsonObject jsonObject = BookMapper.map(book); jsonWriter.writeObject(jsonObject); diff --git a/microservices-modules/helidon/helidon-mp/src/main/java/com/baeldung/microprofile/repo/BookManager.java b/microservices-modules/helidon/helidon-mp/src/main/java/com/baeldung/microprofile/repo/BookManager.java index 924cf0ce71..a583a53902 100644 --- a/microservices-modules/helidon/helidon-mp/src/main/java/com/baeldung/microprofile/repo/BookManager.java +++ b/microservices-modules/helidon/helidon-mp/src/main/java/com/baeldung/microprofile/repo/BookManager.java @@ -2,7 +2,7 @@ package com.baeldung.microprofile.repo; import com.baeldung.microprofile.model.Book; -import javax.enterprise.context.ApplicationScoped; +import jakarta.enterprise.context.ApplicationScoped; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.ArrayList; diff --git a/microservices-modules/helidon/helidon-mp/src/main/java/com/baeldung/microprofile/util/BookMapper.java b/microservices-modules/helidon/helidon-mp/src/main/java/com/baeldung/microprofile/util/BookMapper.java index 861b172299..17ece60f77 100644 --- a/microservices-modules/helidon/helidon-mp/src/main/java/com/baeldung/microprofile/util/BookMapper.java +++ b/microservices-modules/helidon/helidon-mp/src/main/java/com/baeldung/microprofile/util/BookMapper.java @@ -2,7 +2,7 @@ package com.baeldung.microprofile.util; import com.baeldung.microprofile.model.Book; -import javax.json.*; +import jakarta.json.*; import java.io.InputStream; import java.util.List; diff --git a/microservices-modules/helidon/helidon-mp/src/main/java/com/baeldung/microprofile/web/BookEndpoint.java b/microservices-modules/helidon/helidon-mp/src/main/java/com/baeldung/microprofile/web/BookEndpoint.java index 13143a5644..53abcd3e51 100644 --- a/microservices-modules/helidon/helidon-mp/src/main/java/com/baeldung/microprofile/web/BookEndpoint.java +++ b/microservices-modules/helidon/helidon-mp/src/main/java/com/baeldung/microprofile/web/BookEndpoint.java @@ -3,12 +3,18 @@ package com.baeldung.microprofile.web; import com.baeldung.microprofile.model.Book; import com.baeldung.microprofile.repo.BookManager; -import javax.enterprise.context.RequestScoped; -import javax.inject.Inject; -import javax.ws.rs.*; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.UriBuilder; +import jakarta.enterprise.context.RequestScoped; +import jakarta.inject.Inject; + +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.UriBuilder; @Path("books") @RequestScoped diff --git a/microservices-modules/helidon/helidon-se/pom.xml b/microservices-modules/helidon/helidon-se/pom.xml index e26390a99d..a400cbe85e 100644 --- a/microservices-modules/helidon/helidon-se/pom.xml +++ b/microservices-modules/helidon/helidon-se/pom.xml @@ -28,13 +28,13 @@ io.helidon.webserver helidon-webserver-netty - ${helidon.version} + ${helidon-webserver-netty.version} runtime io.helidon.webserver helidon-webserver-json - ${helidon.version} + ${helidon-webserver-json.version} @@ -43,19 +43,26 @@ ${helidon.version} - io.helidon.security - helidon-security-provider-http-auth + io.helidon.security.providers + helidon-security-providers-http-auth ${helidon.version} - io.helidon.security + io.helidon.security.integration helidon-security-integration-webserver ${helidon.version} + + io.helidon.webserver + helidon-webserver-http2 + ${helidon.version} + - 0.10.4 + 3.2.2 + 0.10.6 + 0.11.0 \ No newline at end of file diff --git a/microservices-modules/helidon/helidon-se/src/main/java/com/baeldung/helidon/se/config/ConfigApplication.java b/microservices-modules/helidon/helidon-se/src/main/java/com/baeldung/helidon/se/config/ConfigApplication.java index beac5511c1..4ef0d5a8d2 100644 --- a/microservices-modules/helidon/helidon-se/src/main/java/com/baeldung/helidon/se/config/ConfigApplication.java +++ b/microservices-modules/helidon/helidon-se/src/main/java/com/baeldung/helidon/se/config/ConfigApplication.java @@ -6,7 +6,7 @@ import io.helidon.config.spi.ConfigSource; public class ConfigApplication { - public static void main(String... args) throws Exception { + public static void main(String... args) { ConfigSource configSource = ConfigSources.classpath("application.yaml").build(); Config config = Config.builder() @@ -15,10 +15,10 @@ public class ConfigApplication { .sources(configSource) .build(); - int port = config.get("server.port").asInt(); - int pageSize = config.get("web.page-size").asInt(); - boolean debug = config.get("web.debug").asBoolean(); - String userHome = config.get("user.home").asString(); + int port = config.get("server.port").asInt().get(); + int pageSize = config.get("web.page-size").asInt().get(); + boolean debug = config.get("web.debug").asBoolean().get(); + String userHome = config.get("user.home").asString().get(); System.out.println("port: " + port); System.out.println("pageSize: " + pageSize); diff --git a/microservices-modules/helidon/helidon-se/src/main/java/com/baeldung/helidon/se/routing/BookResource.java b/microservices-modules/helidon/helidon-se/src/main/java/com/baeldung/helidon/se/routing/BookResource.java index b0db191851..278bbfefcf 100644 --- a/microservices-modules/helidon/helidon-se/src/main/java/com/baeldung/helidon/se/routing/BookResource.java +++ b/microservices-modules/helidon/helidon-se/src/main/java/com/baeldung/helidon/se/routing/BookResource.java @@ -50,9 +50,7 @@ public class BookResource implements Service { private JsonArray from(List books) { JsonArrayBuilder jsonArrayBuilder = Json.createArrayBuilder(); - books.forEach(book -> { - jsonArrayBuilder.add(from(book)); - }); + books.forEach(book -> jsonArrayBuilder.add(from(book))); return jsonArrayBuilder.build(); } } diff --git a/microservices-modules/helidon/helidon-se/src/main/java/com/baeldung/helidon/se/routing/WebApplicationRouting.java b/microservices-modules/helidon/helidon-se/src/main/java/com/baeldung/helidon/se/routing/WebApplicationRouting.java index 17bf2bcc8f..805afd5ecb 100644 --- a/microservices-modules/helidon/helidon-se/src/main/java/com/baeldung/helidon/se/routing/WebApplicationRouting.java +++ b/microservices-modules/helidon/helidon-se/src/main/java/com/baeldung/helidon/se/routing/WebApplicationRouting.java @@ -1,25 +1,21 @@ package com.baeldung.helidon.se.routing; import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerConfiguration; import io.helidon.webserver.WebServer; import io.helidon.webserver.json.JsonSupport; public class WebApplicationRouting { - public static void main(String... args) throws Exception { - - ServerConfiguration serverConfig = ServerConfiguration.builder() - .port(9080) - .build(); + public static void main(String... args) { Routing routing = Routing.builder() - .register(JsonSupport.get()) + .register(JsonSupport.create()) .register("/books", new BookResource()) .get("/greet", (request, response) -> response.send("Hello World !")) .build(); - WebServer.create(serverConfig, routing) + WebServer.builder().port(9080).addRouting(routing) + .build() .start() .thenAccept(ws -> System.out.println("Server started at: http://localhost:" + ws.port()) diff --git a/microservices-modules/helidon/helidon-se/src/main/java/com/baeldung/helidon/se/security/MyUser.java b/microservices-modules/helidon/helidon-se/src/main/java/com/baeldung/helidon/se/security/MyUser.java index d1a8446f6a..0f7b536121 100644 --- a/microservices-modules/helidon/helidon-se/src/main/java/com/baeldung/helidon/se/security/MyUser.java +++ b/microservices-modules/helidon/helidon-se/src/main/java/com/baeldung/helidon/se/security/MyUser.java @@ -1,10 +1,11 @@ package com.baeldung.helidon.se.security; -import io.helidon.security.provider.httpauth.UserStore; +import io.helidon.security.providers.httpauth.SecureUserStore; +import java.util.Arrays; import java.util.Collection; -public class MyUser implements UserStore.User { +public class MyUser implements SecureUserStore.User { private String login; private char[] password; @@ -17,17 +18,17 @@ public class MyUser implements UserStore.User { } @Override - public String getLogin() { + public String login() { return login; } @Override - public char[] getPassword() { - return password; + public boolean isPasswordValid(char[] chars) { + return Arrays.equals(chars, password); } @Override - public Collection getRoles() { + public Collection roles() { return roles; } } diff --git a/microservices-modules/helidon/helidon-se/src/main/java/com/baeldung/helidon/se/security/WebApplicationSecurity.java b/microservices-modules/helidon/helidon-se/src/main/java/com/baeldung/helidon/se/security/WebApplicationSecurity.java index 4eb7c6c01f..a3429b20fe 100644 --- a/microservices-modules/helidon/helidon-se/src/main/java/com/baeldung/helidon/se/security/WebApplicationSecurity.java +++ b/microservices-modules/helidon/helidon-se/src/main/java/com/baeldung/helidon/se/security/WebApplicationSecurity.java @@ -3,30 +3,28 @@ package com.baeldung.helidon.se.security; import io.helidon.config.Config; import io.helidon.security.Security; import io.helidon.security.SubjectType; -import io.helidon.security.provider.httpauth.HttpBasicAuthProvider; -import io.helidon.security.provider.httpauth.UserStore; -import io.helidon.security.webserver.WebSecurity; +import io.helidon.security.integration.webserver.WebSecurity; +import io.helidon.security.providers.httpauth.HttpBasicAuthProvider; +import io.helidon.security.providers.httpauth.SecureUserStore; import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerConfiguration; import io.helidon.webserver.WebServer; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Optional; public class WebApplicationSecurity { - public static void main(String... args) throws Exception { + public static void main(String... args) { Config config = Config.create(); - ServerConfiguration serverConfig = - ServerConfiguration.fromConfig(config.get("server")); Map users = new HashMap<>(); - users.put("user", new MyUser("user", "user".toCharArray(), Arrays.asList("ROLE_USER"))); + users.put("user", new MyUser("user", "user".toCharArray(), Collections.singletonList("ROLE_USER"))); users.put("admin", new MyUser("admin", "admin".toCharArray(), Arrays.asList("ROLE_USER", "ROLE_ADMIN"))); - UserStore store = user -> Optional.ofNullable(users.get(user)); + SecureUserStore store = user -> Optional.ofNullable(users.get(user)); HttpBasicAuthProvider httpBasicAuthProvider = HttpBasicAuthProvider.builder() .realm("myRealm") @@ -38,13 +36,12 @@ public class WebApplicationSecurity { Security security = Security.builder() .addAuthenticationProvider(httpBasicAuthProvider) .build(); - //Security security = Security.fromConfig(config); + //Security security = Security.create(config); //2. WebSecurity from Security or from Config - // WebSecurity webSecurity = WebSecurity.from(security) - // .securityDefaults(WebSecurity.authenticate()); + // WebSecurity webSecurity = WebSecurity.create(security).securityDefaults(WebSecurity.authenticate()); - WebSecurity webSecurity = WebSecurity.from(config); + WebSecurity webSecurity = WebSecurity.create(config); Routing routing = Routing.builder() .register(webSecurity) @@ -52,7 +49,7 @@ public class WebApplicationSecurity { .get("/admin", (request, response) -> response.send("Hello, I'm a Helidon SE user with ROLE_ADMIN")) .build(); - WebServer webServer = WebServer.create(serverConfig, routing); + WebServer webServer = WebServer.create(routing, config.get("server")); webServer.start().thenAccept(ws -> System.out.println("Server started at: http://localhost:" + ws.port()) diff --git a/microservices-modules/helidon/helidon-se/src/main/java/com/baeldung/helidon/se/webserver/SimpleWebApplication.java b/microservices-modules/helidon/helidon-se/src/main/java/com/baeldung/helidon/se/webserver/SimpleWebApplication.java index a9a92cf1b9..c528c57782 100644 --- a/microservices-modules/helidon/helidon-se/src/main/java/com/baeldung/helidon/se/webserver/SimpleWebApplication.java +++ b/microservices-modules/helidon/helidon-se/src/main/java/com/baeldung/helidon/se/webserver/SimpleWebApplication.java @@ -1,22 +1,18 @@ package com.baeldung.helidon.se.webserver; import io.helidon.webserver.Routing; -import io.helidon.webserver.ServerConfiguration; import io.helidon.webserver.WebServer; public class SimpleWebApplication { - public static void main(String... args) throws Exception { - - ServerConfiguration serverConfig = ServerConfiguration.builder() - .port(9001) - .build(); + public static void main(String... args) { Routing routing = Routing.builder() .get("/greet", (request, response) -> response.send("Hello World !")) .build(); - WebServer.create(serverConfig, routing) + WebServer.builder(routing) + .port(9001).addRouting(routing).build() .start() .thenAccept(ws -> System.out.println("Server started at: http://localhost:" + ws.port()) diff --git a/muleesb/src/test/resources/log4j2-test.xml b/muleesb/src/test/resources/log4j2-test.xml index 6351ae041c..771817a1bc 100644 --- a/muleesb/src/test/resources/log4j2-test.xml +++ b/muleesb/src/test/resources/log4j2-test.xml @@ -18,8 +18,8 @@ - - + + diff --git a/mybatis/pom.xml b/mybatis/pom.xml index 4cd705c917..1670dc5410 100644 --- a/mybatis/pom.xml +++ b/mybatis/pom.xml @@ -18,9 +18,16 @@ mybatis ${mybatis.version} + + com.h2database + h2 + ${h2database.version} + + + 2.2.220 3.2.2 diff --git a/mybatis/src/main/java/com/baeldung/mybatis_sqlscript/Main.java b/mybatis/src/main/java/com/baeldung/mybatis_sqlscript/Main.java new file mode 100644 index 0000000000..ae0d83a153 --- /dev/null +++ b/mybatis/src/main/java/com/baeldung/mybatis_sqlscript/Main.java @@ -0,0 +1,118 @@ +package org.baeldung.mybatis_sqlscript; + +import org.apache.ibatis.jdbc.ScriptRunner; + +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.sql.*; +import java.util.List; +import java.util.Scanner; + + +public class Main { + // JDBC driver name and database URL + static final String JDBC_DRIVER = "org.h2.Driver"; + static final String DB_URL = "jdbc:h2:mem:testDB"; + + // Database credentials + static final String USER = "sa"; + static final String PASS = ""; + private static Connection conn; + private static Statement stmt; + + public static void main(String[] args){ + try { + //Register JDBC driver + Class.forName(JDBC_DRIVER); + + //Open a connection + System.out.println("Connecting to database..."); + conn = DriverManager.getConnection(DB_URL, USER, PASS); + stmt = conn.createStatement(); + } + catch(Exception e) + { + //Handle errors for Class.forName + e.printStackTrace(); + } + + try { + Scanner sc = new Scanner(System.in); + System.out.println("Enter full path of the file: "); + String filePath= sc.next(); + Path path = Paths.get(filePath); + + System.out.println("Press 1: Execute SQL Script Using Plain Java: "); + System.out.println("Press 2: Execute SQL Script Using Apache iBatis: "); + List sqlLines=Files.readAllLines(path); + int choice = sc.nextInt(); + + switch (choice) + { + case 1: + // Running SQL Script using Plain Java + for (String sql : sqlLines) { + System.out.println("Query: " + sql); + + if (sql.contains("SELECT")) { + ResultSet rs = stmt.executeQuery(sql); + System.out.print("ID" + "\t" + "Name" + "\t" + "Surname" + "\t" + "Age"); + System.out.println(""); + // Extract data from result set + while (rs.next()) { + // Retrieve by column name + int id = rs.getRow(); + int age = rs.getInt("age"); + String name = rs.getString("name"); + String surname = rs.getString("surname"); + + // Display values + System.out.print(id + "\t" + name + "\t" + surname + "\t" + age); + System.out.println(""); + } + } + else + stmt.execute(sql); + } + + break; + + case 2: + ScriptRunner scriptExecutor = new ScriptRunner(conn); + BufferedReader reader = new BufferedReader(new FileReader(filePath)); + scriptExecutor.runScript(reader); + reader.close(); + break; + + + + + } + + + + } + catch(SQLException se) + { + //Handle errors for JDBC + se.printStackTrace(); + } catch(Exception e) + { + //Handle errors for Class.forName + e.printStackTrace(); + } + System.out.println("Reached End of Code!"); + } + +} + + + + + + diff --git a/mybatis/src/main/resources/script.sql b/mybatis/src/main/resources/script.sql new file mode 100644 index 0000000000..fb3bf296f3 --- /dev/null +++ b/mybatis/src/main/resources/script.sql @@ -0,0 +1,10 @@ +CREATE TABLE CUSTOMER (id number, name varchar(20), surname varchar(20), age number); +INSERT INTO CUSTOMER VALUES (1, 'John', 'Doe', 25); +INSERT INTO CUSTOMER VALUES (2, 'Jill', 'Johnson', 18); +INSERT INTO CUSTOMER VALUES (3, 'Jake', 'Peralta', 29); +INSERT INTO CUSTOMER VALUES (4, 'Jack', 'Ryan', 35); +UPDATE CUSTOMER SET AGE = 19 WHERE name = 'Jake'; +SELECT * FROM CUSTOMER; +DELETE FROM CUSTOMER WHERE name='John'; +SELECT * FROM CUSTOMER ORDER BY NAME; +SELECT * FROM CUSTOMER WHERE AGE > 18; \ No newline at end of file diff --git a/persistence-modules/deltaspike/src/test/resources/logback-test.xml b/persistence-modules/deltaspike/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..bdc292924b --- /dev/null +++ b/persistence-modules/deltaspike/src/test/resources/logback-test.xml @@ -0,0 +1,19 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + + + + + \ No newline at end of file diff --git a/persistence-modules/hibernate-annotations/README.md b/persistence-modules/hibernate-annotations/README.md index a03fb7e8e3..dad29edc32 100644 --- a/persistence-modules/hibernate-annotations/README.md +++ b/persistence-modules/hibernate-annotations/README.md @@ -11,3 +11,4 @@ This module contains articles about Annotations used in Hibernate. - [Usage of the Hibernate @LazyCollection Annotation](https://www.baeldung.com/hibernate-lazycollection) - [@Immutable in Hibernate](https://www.baeldung.com/hibernate-immutable) - [Hibernate @CreationTimestamp and @UpdateTimestamp](https://www.baeldung.com/hibernate-creationtimestamp-updatetimestamp) +- [Difference Between @JoinColumn and @PrimaryKeyJoinColumn in JPA](https://www.baeldung.com/java-jpa-join-vs-primarykeyjoin) diff --git a/persistence-modules/hibernate-annotations/pom.xml b/persistence-modules/hibernate-annotations/pom.xml index 6417421fed..3e33aca5ae 100644 --- a/persistence-modules/hibernate-annotations/pom.xml +++ b/persistence-modules/hibernate-annotations/pom.xml @@ -79,7 +79,7 @@ io.hypersistence hypersistence-utils-hibernate-60 - 3.3.1 + ${hypersistance-utils-hibernate-60.version} @@ -90,6 +90,7 @@ 6.1.7.Final true 9.0.0.M26 + 3.3.1 \ No newline at end of file diff --git a/persistence-modules/hibernate-annotations/src/main/java/com/baeldung/hibernate/primarykeyjoincolumn/Department.java b/persistence-modules/hibernate-annotations/src/main/java/com/baeldung/hibernate/primarykeyjoincolumn/Department.java new file mode 100644 index 0000000000..d27b0518bf --- /dev/null +++ b/persistence-modules/hibernate-annotations/src/main/java/com/baeldung/hibernate/primarykeyjoincolumn/Department.java @@ -0,0 +1,35 @@ +package com.baeldung.hibernate.primarykeyjoincolumn; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; + +@Entity +@Table(name = "department") +public class Department { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String name; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + +} diff --git a/persistence-modules/hibernate-annotations/src/main/java/com/baeldung/hibernate/primarykeyjoincolumn/Person.java b/persistence-modules/hibernate-annotations/src/main/java/com/baeldung/hibernate/primarykeyjoincolumn/Person.java new file mode 100644 index 0000000000..0dfa11541b --- /dev/null +++ b/persistence-modules/hibernate-annotations/src/main/java/com/baeldung/hibernate/primarykeyjoincolumn/Person.java @@ -0,0 +1,49 @@ +package com.baeldung.hibernate.primarykeyjoincolumn; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.OneToOne; +import jakarta.persistence.PrimaryKeyJoinColumn; +import jakarta.persistence.Table; + +@Entity +@Table(name = "person") +public class Person { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String name; + + @OneToOne + @PrimaryKeyJoinColumn + private Department department; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Department getDepartment() { + return department; + } + + public void setDepartment(Department department) { + this.department = department; + } + +} diff --git a/persistence-modules/hibernate-annotations/src/main/resources/META-INF/persistence.xml b/persistence-modules/hibernate-annotations/src/main/resources/META-INF/persistence.xml index 2915125295..81b4bf0669 100644 --- a/persistence-modules/hibernate-annotations/src/main/resources/META-INF/persistence.xml +++ b/persistence-modules/hibernate-annotations/src/main/resources/META-INF/persistence.xml @@ -3,14 +3,16 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" version="2.0"> - - Hibernate EntityManager Demo + + Hibernate EntityManager Demo + com.baeldung.hibernate.primarykeyjoincolumn.Person + com.baeldung.hibernate.primarykeyjoincolumn.Department true - + - - + + diff --git a/persistence-modules/hibernate-annotations/src/test/java/com/baeldung/hibernate/primarykeyjoincolumn/PrimaryKeyJoinColumnIntegrationTest.java b/persistence-modules/hibernate-annotations/src/test/java/com/baeldung/hibernate/primarykeyjoincolumn/PrimaryKeyJoinColumnIntegrationTest.java new file mode 100644 index 0000000000..98f1a274a3 --- /dev/null +++ b/persistence-modules/hibernate-annotations/src/test/java/com/baeldung/hibernate/primarykeyjoincolumn/PrimaryKeyJoinColumnIntegrationTest.java @@ -0,0 +1,51 @@ +package com.baeldung.hibernate.primarykeyjoincolumn; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.Persistence; + +class PrimaryKeyJoinColumnIntegrationTest { + + private static EntityManagerFactory emf; + + private static EntityManager em; + + @BeforeAll + public static void setup() { + emf = Persistence.createEntityManagerFactory("com.baeldung.department_person"); + em = emf.createEntityManager(); + em.getTransaction() + .begin(); + Department department = new Department(); + department.setName("IT"); + em.persist(department); + Person person = new Person(); + person.setName("John Doe"); + person.setDepartment(department); + em.persist(person); + em.getTransaction() + .commit(); + } + + @AfterAll + public static void teardown() { + em.close(); + emf.close(); + } + + @Test + void givenPersonEntity_getDepartment_shouldExist() { + Person person = em.find(Person.class, 1L); + assertNotNull(person); + assertEquals("John Doe", person.getName()); + assertNotNull(person.getDepartment()); + assertEquals("IT", person.getDepartment().getName()); + } +} diff --git a/persistence-modules/java-cassandra/src/test/resources/logback-test.xml b/persistence-modules/java-cassandra/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..d2c2764154 --- /dev/null +++ b/persistence-modules/java-cassandra/src/test/resources/logback-test.xml @@ -0,0 +1,17 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + + + \ No newline at end of file diff --git a/persistence-modules/pom.xml b/persistence-modules/pom.xml index 9eb7ca1f1d..24a55491d3 100644 --- a/persistence-modules/pom.xml +++ b/persistence-modules/pom.xml @@ -85,6 +85,7 @@ spring-data-jpa-query-3 spring-data-jpa-repo spring-data-jpa-repo-2 + spring-data-jpa-repo-4 spring-data-jdbc spring-data-keyvalue spring-data-mongodb @@ -96,6 +97,7 @@ spring-data-rest-2 spring-data-rest-querydsl spring-data-solr + spring-data-shardingsphere spring-jpa diff --git a/persistence-modules/spring-boot-persistence-2/README.md b/persistence-modules/spring-boot-persistence-2/README.md index d7c13fd363..66c91ca3ed 100644 --- a/persistence-modules/spring-boot-persistence-2/README.md +++ b/persistence-modules/spring-boot-persistence-2/README.md @@ -7,4 +7,5 @@ - [Oracle Connection Pooling With Spring](https://www.baeldung.com/spring-oracle-connection-pooling) - [Object States in Hibernate’s Session](https://www.baeldung.com/hibernate-session-object-states) - [Storing Files Indexed by a Database](https://www.baeldung.com/java-db-storing-files) -- More articles: [[<-- prev]](../spring-boot-persistence) +- More articles: [[<-- prev]](../spring-boot-persistence) [[next -->]](../spring-boot-persistence-3) + diff --git a/persistence-modules/spring-boot-persistence-3/README.md b/persistence-modules/spring-boot-persistence-3/README.md index ba97a02a9d..34bbe10dc3 100644 --- a/persistence-modules/spring-boot-persistence-3/README.md +++ b/persistence-modules/spring-boot-persistence-3/README.md @@ -1,3 +1,5 @@ ### Relevant Articles: - [Patterns for Iterating Over Large Result Sets With Spring Data JPA](https://www.baeldung.com/spring-data-jpa-iterate-large-result-sets) +- [Count the Number of Rows in Spring Data JPA](https://www.baeldung.com/spring-data-jpa-row-count) +- [A Guide to Spring AbstractRoutingDatasource](https://www.baeldung.com/spring-abstract-routing-data-source) - More articles: [[<-- prev]](../spring-boot-persistence-2) diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/dsrouting/ClientDao.java b/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/dsrouting/ClientDao.java similarity index 100% rename from persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/dsrouting/ClientDao.java rename to persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/dsrouting/ClientDao.java diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/dsrouting/ClientDataSourceRouter.java b/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/dsrouting/ClientDataSourceRouter.java similarity index 100% rename from persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/dsrouting/ClientDataSourceRouter.java rename to persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/dsrouting/ClientDataSourceRouter.java diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/dsrouting/ClientDatabase.java b/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/dsrouting/ClientDatabase.java similarity index 100% rename from persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/dsrouting/ClientDatabase.java rename to persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/dsrouting/ClientDatabase.java diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/dsrouting/ClientDatabaseContextHolder.java b/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/dsrouting/ClientDatabaseContextHolder.java similarity index 100% rename from persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/dsrouting/ClientDatabaseContextHolder.java rename to persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/dsrouting/ClientDatabaseContextHolder.java diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/dsrouting/ClientService.java b/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/dsrouting/ClientService.java similarity index 100% rename from persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/dsrouting/ClientService.java rename to persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/dsrouting/ClientService.java diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/dsrouting/model/ClientADetails.java b/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/dsrouting/model/ClientADetails.java similarity index 100% rename from persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/dsrouting/model/ClientADetails.java rename to persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/dsrouting/model/ClientADetails.java diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/dsrouting/model/ClientBDetails.java b/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/dsrouting/model/ClientBDetails.java similarity index 100% rename from persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/dsrouting/model/ClientBDetails.java rename to persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/dsrouting/model/ClientBDetails.java diff --git a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/dsrouting/DataSourceRoutingIntegrationTest.java b/persistence-modules/spring-boot-persistence-3/src/test/java/com/baeldung/boot/dsrouting/DataSourceRoutingIntegrationTest.java similarity index 90% rename from persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/dsrouting/DataSourceRoutingIntegrationTest.java rename to persistence-modules/spring-boot-persistence-3/src/test/java/com/baeldung/boot/dsrouting/DataSourceRoutingIntegrationTest.java index 0430d9e3af..6359761120 100644 --- a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/dsrouting/DataSourceRoutingIntegrationTest.java +++ b/persistence-modules/spring-boot-persistence-3/src/test/java/com/baeldung/boot/dsrouting/DataSourceRoutingIntegrationTest.java @@ -1,4 +1,4 @@ -package com.baeldung.dsrouting; +package com.baeldung.boot.dsrouting; import static org.junit.Assert.assertEquals; @@ -13,6 +13,10 @@ import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringRunner; +import com.baeldung.dsrouting.ClientDatabase; +import com.baeldung.dsrouting.ClientDatabaseContextHolder; +import com.baeldung.dsrouting.ClientService; + @RunWith(SpringRunner.class) @ContextConfiguration(classes = DataSourceRoutingTestConfiguration.class) @DirtiesContext diff --git a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/dsrouting/DataSourceRoutingTestConfiguration.java b/persistence-modules/spring-boot-persistence-3/src/test/java/com/baeldung/boot/dsrouting/DataSourceRoutingTestConfiguration.java similarity index 88% rename from persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/dsrouting/DataSourceRoutingTestConfiguration.java rename to persistence-modules/spring-boot-persistence-3/src/test/java/com/baeldung/boot/dsrouting/DataSourceRoutingTestConfiguration.java index 957114eba5..e7be8678de 100644 --- a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/dsrouting/DataSourceRoutingTestConfiguration.java +++ b/persistence-modules/spring-boot-persistence-3/src/test/java/com/baeldung/boot/dsrouting/DataSourceRoutingTestConfiguration.java @@ -1,4 +1,4 @@ -package com.baeldung.dsrouting; +package com.baeldung.boot.dsrouting; import java.util.HashMap; import java.util.Map; @@ -10,6 +10,11 @@ import org.springframework.context.annotation.Configuration; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; +import com.baeldung.dsrouting.ClientDao; +import com.baeldung.dsrouting.ClientDataSourceRouter; +import com.baeldung.dsrouting.ClientDatabase; +import com.baeldung.dsrouting.ClientService; + @Configuration public class DataSourceRoutingTestConfiguration { diff --git a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/dsrouting/SpringBootDataSourceRoutingIntegrationTest.java b/persistence-modules/spring-boot-persistence-3/src/test/java/com/baeldung/boot/dsrouting/SpringBootDataSourceRoutingIntegrationTest.java similarity index 92% rename from persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/dsrouting/SpringBootDataSourceRoutingIntegrationTest.java rename to persistence-modules/spring-boot-persistence-3/src/test/java/com/baeldung/boot/dsrouting/SpringBootDataSourceRoutingIntegrationTest.java index 75829c2153..4db411e283 100644 --- a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/dsrouting/SpringBootDataSourceRoutingIntegrationTest.java +++ b/persistence-modules/spring-boot-persistence-3/src/test/java/com/baeldung/boot/dsrouting/SpringBootDataSourceRoutingIntegrationTest.java @@ -1,9 +1,12 @@ -package com.baeldung.dsrouting; +package com.baeldung.boot.dsrouting; import static org.junit.Assert.assertEquals; import javax.sql.DataSource; +import com.baeldung.dsrouting.ClientDatabase; +import com.baeldung.dsrouting.ClientDatabaseContextHolder; +import com.baeldung.dsrouting.ClientService; import com.baeldung.dsrouting.model.ClientADetails; import com.baeldung.dsrouting.model.ClientBDetails; import org.junit.Before; diff --git a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/dsrouting/SpringBootDataSourceRoutingTestConfiguration.java b/persistence-modules/spring-boot-persistence-3/src/test/java/com/baeldung/boot/dsrouting/SpringBootDataSourceRoutingTestConfiguration.java similarity index 90% rename from persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/dsrouting/SpringBootDataSourceRoutingTestConfiguration.java rename to persistence-modules/spring-boot-persistence-3/src/test/java/com/baeldung/boot/dsrouting/SpringBootDataSourceRoutingTestConfiguration.java index 01f157998f..426dbbdb80 100644 --- a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/dsrouting/SpringBootDataSourceRoutingTestConfiguration.java +++ b/persistence-modules/spring-boot-persistence-3/src/test/java/com/baeldung/boot/dsrouting/SpringBootDataSourceRoutingTestConfiguration.java @@ -1,5 +1,9 @@ -package com.baeldung.dsrouting; +package com.baeldung.boot.dsrouting; +import com.baeldung.dsrouting.ClientDao; +import com.baeldung.dsrouting.ClientDataSourceRouter; +import com.baeldung.dsrouting.ClientDatabase; +import com.baeldung.dsrouting.ClientService; import com.baeldung.dsrouting.model.ClientADetails; import com.baeldung.dsrouting.model.ClientBDetails; import org.springframework.beans.factory.annotation.Autowired; diff --git a/persistence-modules/spring-boot-persistence-3/src/test/resources/application.properties b/persistence-modules/spring-boot-persistence-3/src/test/resources/application.properties new file mode 100644 index 0000000000..10bd344c28 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-3/src/test/resources/application.properties @@ -0,0 +1,13 @@ +# spring.datasource.x +spring.datasource.driver-class-name=org.h2.Driver +spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1 +spring.datasource.username=sa +spring.datasource.password=sa + +#database details for CLIENT_A +client-a.datasource.name=CLIENT_A +client-a.datasource.script=dsrouting-db.sql + +#database details for CLIENT_B +client-b.datasource.name=CLIENT_B +client-b.datasource.script=dsrouting-db.sql \ No newline at end of file diff --git a/persistence-modules/spring-boot-persistence/src/test/resources/dsrouting-db.sql b/persistence-modules/spring-boot-persistence-3/src/test/resources/dsrouting-db.sql similarity index 100% rename from persistence-modules/spring-boot-persistence/src/test/resources/dsrouting-db.sql rename to persistence-modules/spring-boot-persistence-3/src/test/resources/dsrouting-db.sql diff --git a/persistence-modules/spring-boot-persistence-4/pom.xml b/persistence-modules/spring-boot-persistence-4/pom.xml new file mode 100644 index 0000000000..99c39e205d --- /dev/null +++ b/persistence-modules/spring-boot-persistence-4/pom.xml @@ -0,0 +1,63 @@ + + + 4.0.0 + com.baeldung.boot.persistence + spring-boot-persistence-4 + 0.0.1-SNAPSHOT + spring-boot-persistence-4 + + + + + org.junit + junit-bom + ${junit-jupiter.version} + pom + import + + + org.springframework.boot + spring-boot-dependencies + ${spring.boot.dependencies} + pom + import + + + + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + com.h2database + h2 + runtime + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + 3.1.0 + 5.9.3 + 17 + 17 + + + \ No newline at end of file diff --git a/persistence-modules/spring-boot-persistence-4/src/main/java/com/baeldung/scrollapi/ScrollAPIApplication.java b/persistence-modules/spring-boot-persistence-4/src/main/java/com/baeldung/scrollapi/ScrollAPIApplication.java new file mode 100644 index 0000000000..27e6555e26 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-4/src/main/java/com/baeldung/scrollapi/ScrollAPIApplication.java @@ -0,0 +1,11 @@ +package com.baeldung.scrollapi; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class ScrollAPIApplication { + public static void main(String[] args) { + SpringApplication.run(ScrollAPIApplication.class, args); + } +} \ No newline at end of file diff --git a/persistence-modules/spring-boot-persistence-4/src/main/java/com/baeldung/scrollapi/entity/BookReview.java b/persistence-modules/spring-boot-persistence-4/src/main/java/com/baeldung/scrollapi/entity/BookReview.java new file mode 100644 index 0000000000..4baa2cda83 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-4/src/main/java/com/baeldung/scrollapi/entity/BookReview.java @@ -0,0 +1,53 @@ +package com.baeldung.scrollapi.entity; + +import jakarta.persistence.*; + +@Entity +@Table(name = "BOOK_REVIEWS") +public class BookReview { + + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "book_reviews_reviews_id_seq") + @SequenceGenerator(name = "book_reviews_reviews_id_seq", sequenceName = "book_reviews_reviews_id_seq", allocationSize = 1) + private Long reviewsId; + private String userId; + private String isbn; + private String bookRating; + + public Long getReviewsId() { + return reviewsId; + } + + public void setReviewsId(Long reviewsId) { + this.reviewsId = reviewsId; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getIsbn() { + return isbn; + } + + public void setIsbn(String isbn) { + this.isbn = isbn; + } + + public String getBookRating() { + return bookRating; + } + + public void setBookRating(String bookRating) { + this.bookRating = bookRating; + } + + @Override + public String toString() { + return "BookReview{" + "reviewsId=" + reviewsId + ", userId='" + userId + '\'' + ", isbn='" + isbn + '\'' + ", bookRating='" + bookRating + '\'' + '}'; + } +} diff --git a/persistence-modules/spring-boot-persistence-4/src/main/java/com/baeldung/scrollapi/repository/BookRepository.java b/persistence-modules/spring-boot-persistence-4/src/main/java/com/baeldung/scrollapi/repository/BookRepository.java new file mode 100644 index 0000000000..717cbc31c7 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-4/src/main/java/com/baeldung/scrollapi/repository/BookRepository.java @@ -0,0 +1,16 @@ +package com.baeldung.scrollapi.repository; + +import org.springframework.data.domain.KeysetScrollPosition; +import org.springframework.data.domain.OffsetScrollPosition; +import org.springframework.data.domain.Window; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.repository.Repository; + +import com.baeldung.scrollapi.entity.BookReview; + +public interface BookRepository extends JpaRepository { + + Window findFirst5ByBookRating(String bookRating, OffsetScrollPosition position); + + Window findFirst5ByBookRating(String bookRating, KeysetScrollPosition position); +} diff --git a/persistence-modules/spring-boot-persistence-4/src/main/java/com/baeldung/scrollapi/service/BookLogic.java b/persistence-modules/spring-boot-persistence-4/src/main/java/com/baeldung/scrollapi/service/BookLogic.java new file mode 100644 index 0000000000..aacf0e3a78 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-4/src/main/java/com/baeldung/scrollapi/service/BookLogic.java @@ -0,0 +1,53 @@ +package com.baeldung.scrollapi.service; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.KeysetScrollPosition; +import org.springframework.data.domain.OffsetScrollPosition; +import org.springframework.data.domain.ScrollPosition; +import org.springframework.data.domain.Window; +import org.springframework.data.support.WindowIterator; +import org.springframework.stereotype.Service; + +import com.baeldung.scrollapi.entity.BookReview; +import com.baeldung.scrollapi.repository.BookRepository; + +@Service +public class BookLogic { + + @Autowired + private BookRepository bookRepository; + + public List getBooksUsingOffset(String rating) { + OffsetScrollPosition offset = ScrollPosition.offset(); + + Window bookReviews = bookRepository.findFirst5ByBookRating(rating, offset); + List bookReviewsResult = new ArrayList<>(); + do { + bookReviews.forEach(bookReviewsResult::add); + bookReviews = bookRepository.findFirst5ByBookRating(rating, (OffsetScrollPosition) bookReviews.positionAt(bookReviews.size() - 1)); + } while (!bookReviews.isEmpty() && bookReviews.hasNext()); + + return bookReviewsResult; + } + + public List getBooksUsingOffSetFilteringAndWindowIterator(String rating) { + WindowIterator bookReviews = WindowIterator.of(position -> bookRepository.findFirst5ByBookRating("3.5", (OffsetScrollPosition) position)) + .startingAt(ScrollPosition.offset()); + List bookReviewsResult = new ArrayList<>(); + + bookReviews.forEachRemaining(bookReviewsResult::add); + return bookReviewsResult; + } + + public List getBooksUsingKeySetFiltering(String rating) { + WindowIterator bookReviews = WindowIterator.of(position -> bookRepository.findFirst5ByBookRating(rating, (KeysetScrollPosition) position)) + .startingAt(ScrollPosition.keyset()); + List bookReviewsResult = new ArrayList<>(); + + bookReviews.forEachRemaining(bookReviewsResult::add); + return bookReviewsResult; + } +} diff --git a/persistence-modules/spring-boot-persistence-4/src/main/resources/application.yml b/persistence-modules/spring-boot-persistence-4/src/main/resources/application.yml new file mode 100644 index 0000000000..bb9e377c34 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-4/src/main/resources/application.yml @@ -0,0 +1,4 @@ + +logging.level.org.hibernate: + SQL: DEBUG + type.descriptor.sql.BasicBinder: TRACE \ No newline at end of file diff --git a/persistence-modules/spring-boot-persistence-4/src/test/java/com/baeldung/boot/scrollapi/service/BookLogicUnitTest.java b/persistence-modules/spring-boot-persistence-4/src/test/java/com/baeldung/boot/scrollapi/service/BookLogicUnitTest.java new file mode 100644 index 0000000000..be816e62cf --- /dev/null +++ b/persistence-modules/spring-boot-persistence-4/src/test/java/com/baeldung/boot/scrollapi/service/BookLogicUnitTest.java @@ -0,0 +1,73 @@ +package com.baeldung.boot.scrollapi.service; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import java.util.List; +import java.util.UUID; +import java.util.stream.IntStream; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import com.baeldung.scrollapi.ScrollAPIApplication; +import com.baeldung.scrollapi.entity.BookReview; +import com.baeldung.scrollapi.repository.BookRepository; +import com.baeldung.scrollapi.service.BookLogic; + +@SpringBootTest(classes = ScrollAPIApplication.class) +class BookLogicUnitTest { + + @Autowired + private BookRepository bookRepository; + + @Autowired + private BookLogic bookLogic; + + @BeforeEach + public void beforeEach() { + IntStream.rangeClosed(1, 5) + .forEach(i -> insertBookReview()); + } + + @AfterEach + public void afterEach() { + bookRepository.deleteAll(); + } + + @Test + public void givenBookReviewInTable_whenGetBooksUsingOffset_returnsBookReviews() { + List bookReviews = bookLogic.getBooksUsingOffset("3.5"); + assertThat(bookReviews.size()).isEqualTo(5); + } + + @Test + public void givenBookReviewInTable_whenGetBooksUsingOffSetFilteringAndWindowIterator_returnsBookReviews() { + List bookReviews = bookLogic.getBooksUsingOffSetFilteringAndWindowIterator("3.5"); + assertThat(bookReviews.size()).isEqualTo(5); + } + + @Test + public void givenBookReviewInTable_whenGetBooksUsingKeySetFiltering_returnsBookReviews() { + List bookReviews = bookLogic.getBooksUsingKeySetFiltering("3.5"); + assertThat(bookReviews.size()).isEqualTo(5); + } + + private void insertBookReview() { + BookReview bookReview = getBookReview(); + bookRepository.save(bookReview); + } + + private static BookReview getBookReview() { + BookReview bookReview = new BookReview(); + String seed = UUID.randomUUID() + .toString(); + bookReview.setIsbn("isbn" + seed); + bookReview.setBookRating("3.5"); + bookReview.setUserId(seed); + + return bookReview; + } +} diff --git a/persistence-modules/spring-boot-persistence-4/src/test/resources/application.properties b/persistence-modules/spring-boot-persistence-4/src/test/resources/application.properties new file mode 100644 index 0000000000..a21dcc731e --- /dev/null +++ b/persistence-modules/spring-boot-persistence-4/src/test/resources/application.properties @@ -0,0 +1,5 @@ +# spring.datasource.x +spring.datasource.driver-class-name=org.h2.Driver +spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1 +spring.datasource.username=sa +spring.datasource.password=sa \ No newline at end of file diff --git a/persistence-modules/spring-boot-persistence/README.md b/persistence-modules/spring-boot-persistence/README.md index 6bbc2b37ae..88526cdb89 100644 --- a/persistence-modules/spring-boot-persistence/README.md +++ b/persistence-modules/spring-boot-persistence/README.md @@ -7,5 +7,4 @@ - [Resolving “Failed to Configure a DataSource” Error](https://www.baeldung.com/spring-boot-failed-to-configure-data-source) - [Hibernate Field Naming with Spring Boot](https://www.baeldung.com/hibernate-field-naming-spring-boot) - [Spring Boot with Hibernate](https://www.baeldung.com/spring-boot-hibernate) -- [A Guide to Spring AbstractRoutingDatasource](https://www.baeldung.com/spring-abstract-routing-data-source) - More articles: [[more -->]](../spring-boot-persistence-2) diff --git a/persistence-modules/spring-boot-persistence/src/test/resources/application.properties b/persistence-modules/spring-boot-persistence/src/test/resources/application.properties index 9f6f3f60d2..45af449122 100644 --- a/persistence-modules/spring-boot-persistence/src/test/resources/application.properties +++ b/persistence-modules/spring-boot-persistence/src/test/resources/application.properties @@ -4,14 +4,6 @@ spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1 spring.datasource.username=sa spring.datasource.password=sa -#database details for CLIENT_A -client-a.datasource.name=CLIENT_A -client-a.datasource.script=dsrouting-db.sql - -#database details for CLIENT_B -client-b.datasource.name=CLIENT_B -client-b.datasource.script=dsrouting-db.sql - # hibernate.X hibernate.dialect=org.hibernate.dialect.H2Dialect hibernate.show_sql=true diff --git a/persistence-modules/spring-data-cassandra-reactive/src/test/resources/logback-test.xml b/persistence-modules/spring-data-cassandra-reactive/src/test/resources/logback-test.xml index 8d4771e308..1daccde00e 100644 --- a/persistence-modules/spring-data-cassandra-reactive/src/test/resources/logback-test.xml +++ b/persistence-modules/spring-data-cassandra-reactive/src/test/resources/logback-test.xml @@ -6,6 +6,10 @@ + + + + diff --git a/persistence-modules/spring-data-dynamodb/pom.xml b/persistence-modules/spring-data-dynamodb/pom.xml index 06425cceb7..e6f5ea9cae 100644 --- a/persistence-modules/spring-data-dynamodb/pom.xml +++ b/persistence-modules/spring-data-dynamodb/pom.xml @@ -175,7 +175,7 @@ 4.3.4.RELEASE 4.5.2 5.1.0 - 1.11.64 + 1.12.331 3.3.7-1 1.0.392 1.21.1 diff --git a/persistence-modules/spring-data-jpa-repo-2/README.md b/persistence-modules/spring-data-jpa-repo-2/README.md index 12eeddae7f..23134ec02d 100644 --- a/persistence-modules/spring-data-jpa-repo-2/README.md +++ b/persistence-modules/spring-data-jpa-repo-2/README.md @@ -9,6 +9,4 @@ - [Difference Between JPA and Spring Data JPA](https://www.baeldung.com/spring-data-jpa-vs-jpa) - [Differences Between Spring Data JPA findFirst() and findTop()](https://www.baeldung.com/spring-data-jpa-findfirst-vs-findtop) - [Difference Between findBy and findAllBy in Spring Data JPA](https://www.baeldung.com/spring-data-jpa-find-by-vs-find-all-by) -- [Unidirectional One-to-Many and Cascading Delete in JPA](https://www.baeldung.com/spring-jpa-unidirectional-one-to-many-and-cascading-delete) -- [TRUNCATE TABLE in Spring Data JPA](https://www.baeldung.com/spring-data-jpa-truncate-table) - More articles: [[<-- prev]](../spring-data-jpa-repo) diff --git a/persistence-modules/spring-data-jpa-repo-4/README.md b/persistence-modules/spring-data-jpa-repo-4/README.md new file mode 100644 index 0000000000..a8afbbe733 --- /dev/null +++ b/persistence-modules/spring-data-jpa-repo-4/README.md @@ -0,0 +1,7 @@ +## Spring Data JPA - Repositories + +### Relevant Articles: + +- [Unidirectional One-to-Many and Cascading Delete in JPA](https://www.baeldung.com/spring-jpa-unidirectional-one-to-many-and-cascading-delete) +- [TRUNCATE TABLE in Spring Data JPA](https://www.baeldung.com/spring-data-jpa-truncate-table) +- More articles: [[<-- prev]](../spring-data-jpa-repo-3) diff --git a/persistence-modules/spring-data-jpa-repo-4/pom.xml b/persistence-modules/spring-data-jpa-repo-4/pom.xml new file mode 100644 index 0000000000..c823391d9f --- /dev/null +++ b/persistence-modules/spring-data-jpa-repo-4/pom.xml @@ -0,0 +1,101 @@ + + + 4.0.0 + spring-data-jpa-repo-4 + spring-data-jpa-repo-4 + + + com.baeldung + parent-boot-2 + 0.0.1-SNAPSHOT + ../../parent-boot-2 + + + + + org.springframework.boot + spring-boot-starter-web + + + javax.persistence + javax.persistence-api + + + org.springframework.data + spring-data-jpa + + + org.springframework.boot + spring-boot-starter-data-jpa + + + com.h2database + h2 + + + com.querydsl + querydsl-apt + + + com.querydsl + querydsl-jpa + + + com.google.guava + guava + ${guava.version} + + + + + + + com.mysema.maven + apt-maven-plugin + 1.1.3 + + + generate-sources + + process + + + ${project.build.directory}/generated-sources + com.querydsl.apt.jpa.JPAAnnotationProcessor + + + + + + org.bsc.maven + maven-processor-plugin + 3.3.3 + + + process + + process + + generate-sources + + ${project.build.directory}/generated-sources + + org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor + + + + + + + org.hibernate + hibernate-jpamodelgen + 5.6.11.Final + + + + + + + \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/truncate/EntityManagerRepository.java b/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/truncate/EntityManagerRepository.java similarity index 100% rename from persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/truncate/EntityManagerRepository.java rename to persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/truncate/EntityManagerRepository.java diff --git a/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/truncate/JdbcTemplateRepository.java b/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/truncate/JdbcTemplateRepository.java similarity index 100% rename from persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/truncate/JdbcTemplateRepository.java rename to persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/truncate/JdbcTemplateRepository.java diff --git a/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/truncate/MyEntity.java b/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/truncate/MyEntity.java similarity index 100% rename from persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/truncate/MyEntity.java rename to persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/truncate/MyEntity.java diff --git a/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/truncate/MyEntityRepository.java b/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/truncate/MyEntityRepository.java similarity index 100% rename from persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/truncate/MyEntityRepository.java rename to persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/truncate/MyEntityRepository.java diff --git a/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/truncate/TruncateSpringBootApplication.java b/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/truncate/TruncateSpringBootApplication.java similarity index 100% rename from persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/truncate/TruncateSpringBootApplication.java rename to persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/truncate/TruncateSpringBootApplication.java diff --git a/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/unidirectionalcascadingdelete/Article.java b/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/unidirectionalcascadingdelete/Article.java similarity index 100% rename from persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/unidirectionalcascadingdelete/Article.java rename to persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/unidirectionalcascadingdelete/Article.java diff --git a/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/unidirectionalcascadingdelete/ArticleRepository.java b/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/unidirectionalcascadingdelete/ArticleRepository.java similarity index 100% rename from persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/unidirectionalcascadingdelete/ArticleRepository.java rename to persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/unidirectionalcascadingdelete/ArticleRepository.java diff --git a/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/unidirectionalcascadingdelete/ArticleService.java b/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/unidirectionalcascadingdelete/ArticleService.java similarity index 100% rename from persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/unidirectionalcascadingdelete/ArticleService.java rename to persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/unidirectionalcascadingdelete/ArticleService.java diff --git a/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/unidirectionalcascadingdelete/CascadingDeleteApplication.java b/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/unidirectionalcascadingdelete/CascadingDeleteApplication.java similarity index 100% rename from persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/unidirectionalcascadingdelete/CascadingDeleteApplication.java rename to persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/unidirectionalcascadingdelete/CascadingDeleteApplication.java diff --git a/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/unidirectionalcascadingdelete/Comment.java b/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/unidirectionalcascadingdelete/Comment.java similarity index 100% rename from persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/unidirectionalcascadingdelete/Comment.java rename to persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/unidirectionalcascadingdelete/Comment.java diff --git a/persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/unidirectionalcascadingdelete/CommentRepository.java b/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/unidirectionalcascadingdelete/CommentRepository.java similarity index 100% rename from persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/unidirectionalcascadingdelete/CommentRepository.java rename to persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/unidirectionalcascadingdelete/CommentRepository.java diff --git a/persistence-modules/spring-data-jpa-repo-4/src/main/resources/application.properties b/persistence-modules/spring-data-jpa-repo-4/src/main/resources/application.properties new file mode 100644 index 0000000000..db4837d8d2 --- /dev/null +++ b/persistence-modules/spring-data-jpa-repo-4/src/main/resources/application.properties @@ -0,0 +1,11 @@ +spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1 +spring.datasource.username=sa +spring.datasource.password=sa + +spring.jpa.properties.hibernate.globally_quoted_identifiers=true +logging.level.com.baeldung.spring.data.persistence.search=debug + +spring.jpa.show-sql=true +logging.level.org.hibernate.SQL=DEBUG +logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE +spring.jpa.properties.hibernate.format_sql=true diff --git a/persistence-modules/spring-data-jpa-repo-2/src/test/java/com/baeldung/spring/data/persistence/deletionCascading/ArticleRepositoryIntegrationTest.java b/persistence-modules/spring-data-jpa-repo-4/src/test/java/com/baeldung/spring/data/persistence/deletionCascading/ArticleRepositoryIntegrationTest.java similarity index 100% rename from persistence-modules/spring-data-jpa-repo-2/src/test/java/com/baeldung/spring/data/persistence/deletionCascading/ArticleRepositoryIntegrationTest.java rename to persistence-modules/spring-data-jpa-repo-4/src/test/java/com/baeldung/spring/data/persistence/deletionCascading/ArticleRepositoryIntegrationTest.java diff --git a/persistence-modules/spring-data-jpa-repo-2/src/test/java/com/baeldung/spring/data/persistence/truncate/TruncateIntegrationTest.java b/persistence-modules/spring-data-jpa-repo-4/src/test/java/com/baeldung/spring/data/persistence/truncate/TruncateIntegrationTest.java similarity index 100% rename from persistence-modules/spring-data-jpa-repo-2/src/test/java/com/baeldung/spring/data/persistence/truncate/TruncateIntegrationTest.java rename to persistence-modules/spring-data-jpa-repo-4/src/test/java/com/baeldung/spring/data/persistence/truncate/TruncateIntegrationTest.java diff --git a/spring-web-modules/spring-thymeleaf-5/src/test/resources/logback-test.xml b/persistence-modules/spring-data-jpa-repo-4/src/test/resources/logback-test.xml similarity index 100% rename from spring-web-modules/spring-thymeleaf-5/src/test/resources/logback-test.xml rename to persistence-modules/spring-data-jpa-repo-4/src/test/resources/logback-test.xml diff --git a/persistence-modules/spring-data-rest-2/README.md b/persistence-modules/spring-data-rest-2/README.md index 1f0191cac9..be56a816d4 100644 --- a/persistence-modules/spring-data-rest-2/README.md +++ b/persistence-modules/spring-data-rest-2/README.md @@ -7,6 +7,7 @@ This module contains articles about Spring Data REST - [Spring Data Web Support](https://www.baeldung.com/spring-data-web-support) - [Spring REST and HAL Browser](https://www.baeldung.com/spring-rest-hal) - [Spring Data Rest – Serializing the Entity ID](https://www.baeldung.com/spring-data-rest-serialize-entity-id) +- [Consuming Page Entity Response From RestTemplate](https://www.baeldung.com/resttemplate-page-entity-response) ### The Course The "REST With Spring" Classes: http://bit.ly/restwithspring diff --git a/persistence-modules/spring-data-rest-2/src/main/java/com/baeldung/pageentityresponse/CustomPageImpl.java b/persistence-modules/spring-data-rest-2/src/main/java/com/baeldung/pageentityresponse/CustomPageImpl.java new file mode 100644 index 0000000000..946447db51 --- /dev/null +++ b/persistence-modules/spring-data-rest-2/src/main/java/com/baeldung/pageentityresponse/CustomPageImpl.java @@ -0,0 +1,37 @@ +package com.baeldung.pageentityresponse; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.JsonNode; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class CustomPageImpl extends PageImpl { + @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) + public CustomPageImpl(@JsonProperty("content") List content, @JsonProperty("number") int number, + @JsonProperty("size") int size, @JsonProperty("totalElements") Long totalElements, + @JsonProperty("pageable") JsonNode pageable, @JsonProperty("last") boolean last, + @JsonProperty("totalPages") int totalPages, @JsonProperty("sort") JsonNode sort, + @JsonProperty("numberOfElements") int numberOfElements) { + super(content, PageRequest.of(number, 1), 10); + } + + public CustomPageImpl(List content, Pageable pageable, long total) { + super(content, pageable, total); + } + + public CustomPageImpl(List content) { + super(content); + } + + public CustomPageImpl() { + super(new ArrayList<>()); + } +} diff --git a/persistence-modules/spring-data-rest-2/src/main/java/com/baeldung/pageentityresponse/EmployeeClient.java b/persistence-modules/spring-data-rest-2/src/main/java/com/baeldung/pageentityresponse/EmployeeClient.java new file mode 100644 index 0000000000..56757626e1 --- /dev/null +++ b/persistence-modules/spring-data-rest-2/src/main/java/com/baeldung/pageentityresponse/EmployeeClient.java @@ -0,0 +1,33 @@ +package com.baeldung.pageentityresponse; + +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponentsBuilder; + +@Component +public class EmployeeClient { + private final RestTemplate restTemplate; + + public EmployeeClient(RestTemplate restTemplate) { + this.restTemplate = restTemplate; + } + + public Page getEmployeeDataFromExternalAPI(Pageable pageable) { + String url = "http://localhost:8080/employee"; + + UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromUriString(url) + .queryParam("page", pageable.getPageNumber()) + .queryParam("size", pageable.getPageSize()); + + ResponseEntity> responseEntity = restTemplate.exchange(uriBuilder.toUriString(), + HttpMethod.GET, null, new ParameterizedTypeReference>() { + }); + + return responseEntity.getBody(); + } +} diff --git a/persistence-modules/spring-data-rest-2/src/main/java/com/baeldung/pageentityresponse/EmployeeController.java b/persistence-modules/spring-data-rest-2/src/main/java/com/baeldung/pageentityresponse/EmployeeController.java new file mode 100644 index 0000000000..f9f32efb53 --- /dev/null +++ b/persistence-modules/spring-data-rest-2/src/main/java/com/baeldung/pageentityresponse/EmployeeController.java @@ -0,0 +1,57 @@ +package com.baeldung.pageentityresponse; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/organisation") +public class EmployeeController { + + private final EmployeeService organisationService; + + public EmployeeController(EmployeeService organisationService) { + this.organisationService = organisationService; + } + + @GetMapping("/employee") + public ResponseEntity> getEmployeeData(Pageable pageable) { + Page employeeData = organisationService.getEmployeeData(pageable); + return ResponseEntity.ok(employeeData); + } + + @GetMapping("/data") + public ResponseEntity> getData(@RequestParam(defaultValue = "0") int page, + @RequestParam(defaultValue = "10") int size) { + List empList = listImplementation(); + + int totalSize = empList.size(); + int startIndex = page * size; + int endIndex = Math.min(startIndex + size, totalSize); + + List pageContent = empList.subList(startIndex, endIndex); + + Page employeeDtos = new PageImpl<>(pageContent, PageRequest.of(page, size), totalSize); + + return ResponseEntity.ok() + .body(employeeDtos); + } + + private static List listImplementation() { + List empList = new ArrayList<>(); + empList.add(new EmployeeDto("Jane", "Finance", 50000)); + empList.add(new EmployeeDto("Sarah", "IT", 70000)); + empList.add(new EmployeeDto("John", "IT", 90000)); + return empList; + } + +} diff --git a/persistence-modules/spring-data-rest-2/src/main/java/com/baeldung/pageentityresponse/EmployeeDto.java b/persistence-modules/spring-data-rest-2/src/main/java/com/baeldung/pageentityresponse/EmployeeDto.java new file mode 100644 index 0000000000..1ea22ed671 --- /dev/null +++ b/persistence-modules/spring-data-rest-2/src/main/java/com/baeldung/pageentityresponse/EmployeeDto.java @@ -0,0 +1,48 @@ +package com.baeldung.pageentityresponse; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class EmployeeDto { + @JsonProperty("name") + private String name; + + @JsonProperty("dept") + private String dept; + + @JsonProperty("salary") + private long salary; + + public EmployeeDto() { + } + + public EmployeeDto(String name, String dept, long salary) { + this.name = name; + this.dept = dept; + this.salary = salary; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDept() { + return dept; + } + + public void setDept(String dept) { + this.dept = dept; + } + + public long getSalary() { + return salary; + } + + public void setSalary(long salary) { + this.salary = salary; + } +} + diff --git a/persistence-modules/spring-data-rest-2/src/main/java/com/baeldung/pageentityresponse/EmployeeService.java b/persistence-modules/spring-data-rest-2/src/main/java/com/baeldung/pageentityresponse/EmployeeService.java new file mode 100644 index 0000000000..e6e13d986f --- /dev/null +++ b/persistence-modules/spring-data-rest-2/src/main/java/com/baeldung/pageentityresponse/EmployeeService.java @@ -0,0 +1,18 @@ +package com.baeldung.pageentityresponse; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; + +@Service +public class EmployeeService { + private final EmployeeClient employeeClient; + + public EmployeeService(EmployeeClient employeeClient) { + this.employeeClient = employeeClient; + } + + public Page getEmployeeData(Pageable pageable) { + return employeeClient.getEmployeeDataFromExternalAPI(pageable); + } +} \ No newline at end of file diff --git a/persistence-modules/spring-data-rest-2/src/main/java/com/baeldung/pageentityresponse/PageEntityResponseApp.java b/persistence-modules/spring-data-rest-2/src/main/java/com/baeldung/pageentityresponse/PageEntityResponseApp.java new file mode 100644 index 0000000000..fe5fc95268 --- /dev/null +++ b/persistence-modules/spring-data-rest-2/src/main/java/com/baeldung/pageentityresponse/PageEntityResponseApp.java @@ -0,0 +1,12 @@ +package com.baeldung.pageentityresponse; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class PageEntityResponseApp { + public static void main(String[] args) { + SpringApplication.run(PageEntityResponseApp.class, args); + } + +} diff --git a/persistence-modules/spring-data-rest-2/src/main/java/com/baeldung/pageentityresponse/RestTemplateConfig.java b/persistence-modules/spring-data-rest-2/src/main/java/com/baeldung/pageentityresponse/RestTemplateConfig.java new file mode 100644 index 0000000000..a0f9a5c4bb --- /dev/null +++ b/persistence-modules/spring-data-rest-2/src/main/java/com/baeldung/pageentityresponse/RestTemplateConfig.java @@ -0,0 +1,15 @@ +package com.baeldung.pageentityresponse; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.client.RestTemplate; + +@Configuration +public class RestTemplateConfig { + + @Bean + public RestTemplate restTemplate() { + return new RestTemplate(); + } +} + diff --git a/persistence-modules/spring-data-rest-2/src/test/java/com/baeldung/pageentityresponse/EmployeeClientUnitTest.java b/persistence-modules/spring-data-rest-2/src/test/java/com/baeldung/pageentityresponse/EmployeeClientUnitTest.java new file mode 100644 index 0000000000..73c51165d5 --- /dev/null +++ b/persistence-modules/spring-data-rest-2/src/test/java/com/baeldung/pageentityresponse/EmployeeClientUnitTest.java @@ -0,0 +1,68 @@ +package com.baeldung.pageentityresponse; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.isNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import java.util.Arrays; +import java.util.List; + +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.client.RestTemplate; + +public class EmployeeClientUnitTest { + + @Test + void givenRestTemplate_whenGetEmployeeDataFromExternalAPI_thenGetPageDataWithContents() { + CustomPageImpl mockedResponse = new CustomPageImpl<>(Arrays.asList( + new EmployeeDto("Jane", "Finance", 50000), + new EmployeeDto("Sarah", "IT", 70000), + new EmployeeDto("John", "IT", 90000) + )); + + RestTemplate restTemplate = mock(RestTemplate.class); + ResponseEntity> responseEntity = new ResponseEntity<>(mockedResponse, + HttpStatus.OK); + + String url = "http://localhost:8080/employee"; + int pageNumber = 0; + int pageSize = 10; + String expectedUrl = url + "?page=" + pageNumber + "&size=" + pageSize; + + HttpMethod expectedMethod = HttpMethod.GET; + ParameterizedTypeReference> responseType = new ParameterizedTypeReference>() { + }; + + Mockito.when(restTemplate.exchange( + expectedUrl, + expectedMethod, + null, + responseType + )).thenReturn(responseEntity); + + EmployeeClient employeeClient = new EmployeeClient(restTemplate); + + Page result = employeeClient.getEmployeeDataFromExternalAPI( + PageRequest.of(pageNumber, pageSize) + ); + + verify(restTemplate).exchange( + eq(expectedUrl), + eq(expectedMethod), + isNull(), + eq(responseType) + ); + assertEquals(3, result.getNumberOfElements()); + List content = result.getContent(); + assertEquals(mockedResponse.getContent(), content); + } +} diff --git a/persistence-modules/spring-data-rest-2/src/test/java/com/baeldung/pageentityresponse/EmployeeControllerIntegrationTest.java b/persistence-modules/spring-data-rest-2/src/test/java/com/baeldung/pageentityresponse/EmployeeControllerIntegrationTest.java new file mode 100644 index 0000000000..81e994cbee --- /dev/null +++ b/persistence-modules/spring-data-rest-2/src/test/java/com/baeldung/pageentityresponse/EmployeeControllerIntegrationTest.java @@ -0,0 +1,62 @@ +package com.baeldung.pageentityresponse; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import java.util.List; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.data.domain.PageImpl; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; + +@SpringBootTest(classes = PageEntityResponseApp.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@AutoConfigureMockMvc +public class EmployeeControllerIntegrationTest { + + @LocalServerPort + private int port; + + @Autowired + private TestRestTemplate restTemplate; + + @Test + void givenGetData_whenRestTemplateExchange_thenReturnsPageOfEmployee() { + ResponseEntity> responseEntity = restTemplate.exchange( + "http://localhost:" + port + "/organisation/data", HttpMethod.GET, null, + new ParameterizedTypeReference>() { + }); + + assertEquals(200, responseEntity.getStatusCodeValue()); + PageImpl restPage = responseEntity.getBody(); + assertNotNull(restPage); + + assertEquals(10, restPage.getTotalElements()); + + List content = restPage.getContent(); + assertNotNull(content); + assertEquals(3, content.size()); + + EmployeeDto employee1 = content.get(0); + assertEquals("Jane", employee1.getName()); + assertEquals("Finance", employee1.getDept()); + assertEquals(50000, employee1.getSalary()); + + EmployeeDto employee2 = content.get(1); + assertEquals("Sarah", employee2.getName()); + assertEquals("IT", employee2.getDept()); + assertEquals(70000, employee2.getSalary()); + + EmployeeDto employee3 = content.get(2); + assertEquals("John", employee3.getName()); + assertEquals("IT", employee3.getDept()); + assertEquals(90000, employee3.getSalary()); + } + +} diff --git a/persistence-modules/spring-data-shardingsphere/pom.xml b/persistence-modules/spring-data-shardingsphere/pom.xml new file mode 100644 index 0000000000..1f37bed4cc --- /dev/null +++ b/persistence-modules/spring-data-shardingsphere/pom.xml @@ -0,0 +1,80 @@ + + + 4.0.0 + spring-data-shardingsphere + 1.0 + spring-data-shardingsphere + jar + + + com.baeldung + parent-boot-3 + 0.0.1-SNAPSHOT + ../../parent-boot-3 + + + + 5.3.2 + 8.0.33 + + + + + + org.testcontainers + testcontainers-bom + 1.18.3 + pom + import + + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-test + test + + + mysql + mysql-connector-java + ${mysql.version} + + + org.apache.shardingsphere + shardingsphere-jdbc-core + ${shardingsphere.version} + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.testcontainers + junit-jupiter + test + + + org.testcontainers + mysql + test + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + + + diff --git a/persistence-modules/spring-data-shardingsphere/src/main/java/com/baeldung/shardingsphere/Main.java b/persistence-modules/spring-data-shardingsphere/src/main/java/com/baeldung/shardingsphere/Main.java new file mode 100644 index 0000000000..76786088ff --- /dev/null +++ b/persistence-modules/spring-data-shardingsphere/src/main/java/com/baeldung/shardingsphere/Main.java @@ -0,0 +1,12 @@ +package com.baeldung.shardingsphere; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Main { + + public static void main(String[] args) { + SpringApplication.run(Main.class, args); + } +} diff --git a/persistence-modules/spring-data-shardingsphere/src/main/java/com/baeldung/shardingsphere/Order.java b/persistence-modules/spring-data-shardingsphere/src/main/java/com/baeldung/shardingsphere/Order.java new file mode 100644 index 0000000000..bb1d69f08a --- /dev/null +++ b/persistence-modules/spring-data-shardingsphere/src/main/java/com/baeldung/shardingsphere/Order.java @@ -0,0 +1,110 @@ +package com.baeldung.shardingsphere; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.Id; +import jakarta.persistence.Table; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.Objects; + + +@Entity +@Table(name = "`order`") +public class Order { + + @Id + @Column(name = "order_id") + private Long orderId; + + @Column(name = "customer_id") + private Long customerId; + + @Column(name = "total_price") + private BigDecimal totalPrice; + + @Enumerated(EnumType.STRING) + @Column(name = "order_status") + private Status orderStatus; + + @Column(name = "order_date") + private LocalDate orderDate; + + @Column(name = "delivery_address") + private String deliveryAddress; + + public Long getOrderId() { + return orderId; + } + + public void setOrderId(Long orderId) { + this.orderId = orderId; + } + + public Long getCustomerId() { + return customerId; + } + + public void setCustomerId(Long customerId) { + this.customerId = customerId; + } + + public BigDecimal getTotalPrice() { + return totalPrice; + } + + public void setTotalPrice(BigDecimal totalPrice) { + this.totalPrice = totalPrice; + } + + public Status getOrderStatus() { + return orderStatus; + } + + public void setOrderStatus(Status orderStatus) { + this.orderStatus = orderStatus; + } + + public LocalDate getOrderDate() { + return orderDate; + } + + public void setOrderDate(LocalDate orderDate) { + this.orderDate = orderDate; + } + + public String getDeliveryAddress() { + return deliveryAddress; + } + + public void setDeliveryAddress(String deliveryAddress) { + this.deliveryAddress = deliveryAddress; + } + + protected Order() {} + + public Order(Long orderId, Long customerId, BigDecimal totalPrice, Status orderStatus, LocalDate orderDate, String deliveryAddress) { + this.orderId = orderId; + this.customerId = customerId; + this.totalPrice = totalPrice; + this.orderStatus = orderStatus; + this.orderDate = orderDate; + this.deliveryAddress = deliveryAddress; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Order order = (Order) o; + return Objects.equals(orderId, order.orderId); + } + + @Override + public int hashCode() { + return Objects.hash(orderId); + } +} diff --git a/persistence-modules/spring-data-shardingsphere/src/main/java/com/baeldung/shardingsphere/OrderController.java b/persistence-modules/spring-data-shardingsphere/src/main/java/com/baeldung/shardingsphere/OrderController.java new file mode 100644 index 0000000000..fe6294354e --- /dev/null +++ b/persistence-modules/spring-data-shardingsphere/src/main/java/com/baeldung/shardingsphere/OrderController.java @@ -0,0 +1,26 @@ +package com.baeldung.shardingsphere; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/orders") +public class OrderController { + + private final OrderService orderService; + + public OrderController(OrderService orderService) { + this.orderService = orderService; + } + + @PostMapping + public ResponseEntity createOrder(@RequestBody Order order) { + return ResponseEntity.ok(orderService.createOrder(order)); + } + + @GetMapping("/{id}") + public ResponseEntity getOrder(@PathVariable Long id) { + return ResponseEntity.ok(orderService.getOrder(id)); + } +} diff --git a/persistence-modules/spring-data-shardingsphere/src/main/java/com/baeldung/shardingsphere/OrderRepository.java b/persistence-modules/spring-data-shardingsphere/src/main/java/com/baeldung/shardingsphere/OrderRepository.java new file mode 100644 index 0000000000..54f9e4e140 --- /dev/null +++ b/persistence-modules/spring-data-shardingsphere/src/main/java/com/baeldung/shardingsphere/OrderRepository.java @@ -0,0 +1,5 @@ +package com.baeldung.shardingsphere; + +import org.springframework.data.jpa.repository.JpaRepository; + +public interface OrderRepository extends JpaRepository { } diff --git a/persistence-modules/spring-data-shardingsphere/src/main/java/com/baeldung/shardingsphere/OrderService.java b/persistence-modules/spring-data-shardingsphere/src/main/java/com/baeldung/shardingsphere/OrderService.java new file mode 100644 index 0000000000..dd796f1b9a --- /dev/null +++ b/persistence-modules/spring-data-shardingsphere/src/main/java/com/baeldung/shardingsphere/OrderService.java @@ -0,0 +1,22 @@ +package com.baeldung.shardingsphere; + +import org.springframework.stereotype.Service; + +@Service +public class OrderService { + + private final OrderRepository orderRepository; + + public OrderService(OrderRepository orderRepository) { + this.orderRepository = orderRepository; + } + + public Order createOrder(Order order) { + return orderRepository.save(order); + } + + public Order getOrder(Long id) { + return orderRepository.findById(id) + .orElseThrow(() -> new IllegalArgumentException("Order not found")); + } +} diff --git a/persistence-modules/spring-data-shardingsphere/src/main/java/com/baeldung/shardingsphere/Status.java b/persistence-modules/spring-data-shardingsphere/src/main/java/com/baeldung/shardingsphere/Status.java new file mode 100644 index 0000000000..9bd6ad4f93 --- /dev/null +++ b/persistence-modules/spring-data-shardingsphere/src/main/java/com/baeldung/shardingsphere/Status.java @@ -0,0 +1,6 @@ +package com.baeldung.shardingsphere; + + +public enum Status { + PROCESSING, SHIPPED, DELIVERED, CANCELLED +} diff --git a/persistence-modules/spring-data-shardingsphere/src/main/resources/application.yml b/persistence-modules/spring-data-shardingsphere/src/main/resources/application.yml new file mode 100644 index 0000000000..ec2d12b63f --- /dev/null +++ b/persistence-modules/spring-data-shardingsphere/src/main/resources/application.yml @@ -0,0 +1,10 @@ +spring: + datasource: + driver-class-name: org.apache.shardingsphere.driver.ShardingSphereDriver + url: jdbc:shardingsphere:classpath:sharding.yml + jpa: + properties: + hibernate: + dialect: org.hibernate.dialect.MySQL8Dialect + hibernate: + ddl-auto: create-drop \ No newline at end of file diff --git a/persistence-modules/spring-data-shardingsphere/src/main/resources/sharding.yml b/persistence-modules/spring-data-shardingsphere/src/main/resources/sharding.yml new file mode 100644 index 0000000000..3d5702f6e2 --- /dev/null +++ b/persistence-modules/spring-data-shardingsphere/src/main/resources/sharding.yml @@ -0,0 +1,31 @@ +dataSources: + ds0: + dataSourceClassName: com.zaxxer.hikari.HikariDataSource + driverClassName: com.mysql.jdbc.Driver + jdbcUrl: jdbc:mysql://localhost:13306/ds0?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8 + username: test + password: test + ds1: + dataSourceClassName: com.zaxxer.hikari.HikariDataSource + driverClassName: com.mysql.jdbc.Driver + jdbcUrl: jdbc:mysql://localhost:13307/ds1?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8 + username: test + password: test +rules: + - !SHARDING + tables: + order: + actualDataNodes: ds${0..1}.order + defaultDatabaseStrategy: + standard: + shardingColumn: order_id + shardingAlgorithmName: database_inline + defaultTableStrategy: + none: + shardingAlgorithms: + database_inline: + type: INLINE + props: + algorithm-expression: ds${order_id % 2} +props: + sql-show: false \ No newline at end of file diff --git a/persistence-modules/spring-data-shardingsphere/src/test/java/com/baeldung/shardingsphere/OrderServiceIntegrationTest.java b/persistence-modules/spring-data-shardingsphere/src/test/java/com/baeldung/shardingsphere/OrderServiceIntegrationTest.java new file mode 100644 index 0000000000..938d250058 --- /dev/null +++ b/persistence-modules/spring-data-shardingsphere/src/test/java/com/baeldung/shardingsphere/OrderServiceIntegrationTest.java @@ -0,0 +1,86 @@ +package com.baeldung.shardingsphere; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; +import org.testcontainers.containers.MySQLContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +import java.math.BigDecimal; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.time.LocalDate; +import java.util.List; + +@Testcontainers +@SpringBootTest +class OrderServiceIntegrationTest { + + @Container + static MySQLContainer mySQLContainer1 = new MySQLContainer<>("mysql:8.0.23") + .withDatabaseName("ds0") + .withUsername("test") + .withPassword("test"); + + @Container + static MySQLContainer mySQLContainer2 = new MySQLContainer<>("mysql:8.0.23") + .withDatabaseName("ds1") + .withUsername("test") + .withPassword("test"); + + static { + mySQLContainer2.setPortBindings(List.of("13307:3306")); + mySQLContainer1.setPortBindings(List.of("13306:3306")); + } + @Autowired + private OrderService orderService; + + @Autowired + private OrderRepository orderRepository; + + @DynamicPropertySource + static void setProperties(DynamicPropertyRegistry registry) { + registry.add("spring.jpa.hibernate.ddl-auto", () -> "create-drop"); + } + + @Test + void shouldFindOrderInCorrectShard() { + // given + Order order1 = new Order(1L, 1L, BigDecimal.TEN, Status.PROCESSING, LocalDate.now(), "123 Main St"); + Order order2 = new Order(2L, 2L, BigDecimal.valueOf(12.5), Status.SHIPPED, LocalDate.now(), "456 Main St"); + + // when + Order savedOrder1 = orderService.createOrder(order1); + Order savedOrder2 = orderService.createOrder(order2); + + // then + // Assuming the sharding strategy is based on the order id, data for order1 should be present only in ds0 + // and data for order2 should be present only in ds1 + Assertions.assertThat(orderService.getOrder(savedOrder1.getOrderId())).isEqualTo(savedOrder1); + Assertions.assertThat(orderService.getOrder(savedOrder2.getOrderId())).isEqualTo(savedOrder2); + + // Verify that the orders are not present in the wrong shards. + // You would need to implement these methods in your OrderService. + // They should use a JdbcTemplate or EntityManager to execute SQL directly against each shard. + Assertions.assertThat(assertOrderInShard(savedOrder1, mySQLContainer2)).isTrue(); + Assertions.assertThat(assertOrderInShard(savedOrder2, mySQLContainer1)).isTrue(); + } + + private boolean assertOrderInShard(Order order, MySQLContainer container) { + try (Connection conn = DriverManager.getConnection(container.getJdbcUrl(), container.getUsername(), container.getPassword())) { + PreparedStatement stmt = conn.prepareStatement("SELECT * FROM `order` WHERE order_id = ?"); + stmt.setLong(1, order.getOrderId()); + ResultSet rs = stmt.executeQuery(); + return rs.next(); + } catch (SQLException ex) { + throw new RuntimeException("Error querying order in shard", ex); + } + } +} diff --git a/persistence-modules/spring-data-yugabytedb/README.md b/persistence-modules/spring-data-yugabytedb/README.md new file mode 100644 index 0000000000..a6e7ec0fd5 --- /dev/null +++ b/persistence-modules/spring-data-yugabytedb/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [Quick Guide to YugabyteDB](https://www.baeldung.com/yugabytedb) diff --git a/persistence-modules/spring-data-yugabytedb/pom.xml b/persistence-modules/spring-data-yugabytedb/pom.xml index c1095a20ca..cf85988ac3 100644 --- a/persistence-modules/spring-data-yugabytedb/pom.xml +++ b/persistence-modules/spring-data-yugabytedb/pom.xml @@ -1,55 +1,51 @@ - 4.0.0 - spring-data-yugabytedb - 1.0 - spring-data-yugabytedb - jar + xmlns="http://maven.apache.org/POM/4.0.0" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + spring-data-yugabytedb + 1.0 + spring-data-yugabytedb + jar - - com.baeldung - parent-boot-2 - 0.0.1-SNAPSHOT - ../../parent-boot-2 - + + com.baeldung + parent-boot-2 + 0.0.1-SNAPSHOT + ../../parent-boot-2 + - - - org.springframework.boot - spring-boot-starter-web - - - org.projectlombok - lombok - - - org.springframework - spring-test - - - org.springframework.boot - spring-boot-starter-test - test - - - org.postgresql - postgresql - - - org.springframework.boot - spring-boot-starter-data-jpa - - + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework + spring-test + + + org.springframework.boot + spring-boot-starter-test + test + + + org.postgresql + postgresql + + + org.springframework.boot + spring-boot-starter-data-jpa + + - - - - org.apache.maven.plugins - maven-surefire-plugin - - - + + + + org.apache.maven.plugins + maven-surefire-plugin + + + diff --git a/persistence-modules/spring-data-yugabytedb/src/main/java/com/baeldung/Main.java b/persistence-modules/spring-data-yugabytedb/src/main/java/com/baeldung/Main.java index 27b087790a..8638528f6a 100644 --- a/persistence-modules/spring-data-yugabytedb/src/main/java/com/baeldung/Main.java +++ b/persistence-modules/spring-data-yugabytedb/src/main/java/com/baeldung/Main.java @@ -8,25 +8,25 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Main implements CommandLineRunner { - @Autowired - private UserRepository userRepository; + @Autowired + private UserRepository userRepository; - public static void main(String[] args) { - SpringApplication.run(Main.class, args); - } + public static void main(String[] args) { + SpringApplication.run(Main.class, args); + } - @Override - public void run(String... args) throws InterruptedException { + @Override + public void run(String... args) throws InterruptedException { - int iterationCount = 1_000; - int elementsPerIteration = 100; + int iterationCount = 1_000; + int elementsPerIteration = 100; - for (int i = 0; i < iterationCount; i++) { - for (long j = 0; j < elementsPerIteration; j++) { - User user = new User(); - userRepository.save(user); - } - Thread.sleep(1000); - } - } + for (int i = 0; i < iterationCount; i++) { + for (long j = 0; j < elementsPerIteration; j++) { + User user = new User(); + userRepository.save(user); + } + Thread.sleep(1000); + } + } } diff --git a/persistence-modules/spring-data-yugabytedb/src/main/java/com/baeldung/User.java b/persistence-modules/spring-data-yugabytedb/src/main/java/com/baeldung/User.java index 278bc6c9ae..54bbf2617c 100644 --- a/persistence-modules/spring-data-yugabytedb/src/main/java/com/baeldung/User.java +++ b/persistence-modules/spring-data-yugabytedb/src/main/java/com/baeldung/User.java @@ -11,34 +11,31 @@ import javax.persistence.Table; @Table(name = "users") public class User { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; - @Column - private String name; + @Column + private String name; - Long getId() { - return id; - } + public Long getId() { + return id; + } - void setId(Long id) { - this.id = id; - } + public void setId(Long id) { + this.id = id; + } - String getName() { - return name; - } + public String getName() { + return name; + } - void setName(String name) { - this.name = name; - } + public void setName(String name) { + this.name = name; + } - @Override - public String toString() { - return "User{" + - "id=" + id + - ", name='" + name + '\'' + - '}'; - } + @Override + public String toString() { + return "User{" + "id=" + id + ", name='" + name + '\'' + '}'; + } } diff --git a/persistence-modules/spring-data-yugabytedb/src/main/resources/docker-compose.yml b/persistence-modules/spring-data-yugabytedb/src/main/resources/docker-compose.yml new file mode 100644 index 0000000000..6d95320525 --- /dev/null +++ b/persistence-modules/spring-data-yugabytedb/src/main/resources/docker-compose.yml @@ -0,0 +1,13 @@ +version: '3' + +services: + yugabytedb: + image: yugabytedb/yugabyte:latest + container_name: yugabyte + user: root + ports: + - '5433:5433' + - '7000:7000' + - '9000:9000' + command: ["bin/yugabyted", "start", "--daemon=false"] + diff --git a/persistence-modules/spring-data-yugabytedb/src/test/java/com/baeldung/YugabyteDBLiveTest.java b/persistence-modules/spring-data-yugabytedb/src/test/java/com/baeldung/YugabyteDBLiveTest.java new file mode 100644 index 0000000000..8a9de9bab4 --- /dev/null +++ b/persistence-modules/spring-data-yugabytedb/src/test/java/com/baeldung/YugabyteDBLiveTest.java @@ -0,0 +1,37 @@ +package com.baeldung; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.List; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; + +/* + To run this test we need to run the databases first. + A dedicated docker-compose.yml file is located under the resources directory. + We can run it by simple executing `docker-compose up`. + */ +@SpringJUnitConfig +@SpringBootTest +@TestPropertySource("classpath:application.properties") +public class YugabyteDBLiveTest { + + @Autowired + private UserRepository userRepository; + + @Test + void givenTwoUsers_whenPersistUsingJPARepository_thenUserAreSaved() { + User user1 = new User(); + user1.setName("Alex"); + User user2 = new User(); + user2.setName("John"); + userRepository.save(user1); + userRepository.save(user2); + List allUsers = userRepository.findAll(); + assertEquals(2, allUsers.size()); + } +} diff --git a/pom.xml b/pom.xml index bea9a5a6fa..4672e24ed7 100644 --- a/pom.xml +++ b/pom.xml @@ -369,6 +369,8 @@ persistence-modules/spring-data-cassandra-reactive persistence-modules/spring-data-neo4j java-nashorn + jeromq + spring-ejb-modules/ejb-beans @@ -545,6 +547,7 @@ persistence-modules/spring-data-cassandra-reactive persistence-modules/spring-data-neo4j java-nashorn + spring-ejb-modules/ejb-beans @@ -703,6 +706,7 @@ osgi spring-katharsis logging-modules + spring-boot-documentation spring-boot-modules apache-httpclient apache-httpclient4 @@ -727,6 +731,7 @@ spring-batch-2 spring-boot-rest spring-drools + spring-cloud-modules/spring-cloud-azure spring-cloud-modules/spring-cloud-contract spring-cloud-modules/spring-cloud-data-flow spring-cloud-modules/spring-cloud-circuit-breaker @@ -778,7 +783,6 @@ custom-pmd data-structures ddd-contexts - jackson-jr jackson-modules jmh deeplearning4j @@ -850,7 +854,6 @@ javax-sound javaxval javaxval-2 - javax-validation-advanced jetbrains jgit jib @@ -975,6 +978,7 @@ osgi spring-katharsis logging-modules + spring-boot-documentation spring-boot-modules apache-httpclient apache-httpclient4 @@ -999,6 +1003,7 @@ spring-batch-2 spring-boot-rest spring-drools + spring-cloud-modules/spring-cloud-azure spring-cloud-modules/spring-cloud-circuit-breaker spring-exceptions spring-jenkins-pipeline @@ -1120,7 +1125,6 @@ javax-sound javaxval javaxval-2 - javax-validation-advanced jetbrains jgit jib @@ -1271,9 +1275,8 @@ 3.0.0 1.8 1.2.17 - 2.5.0.0 - 1.35 - 1.35 + 1.36 + 1.36 2.21.0 4.4 2.11.0 diff --git a/quarkus-modules/pom.xml b/quarkus-modules/pom.xml index ab9f7c3906..7036688711 100644 --- a/quarkus-modules/pom.xml +++ b/quarkus-modules/pom.xml @@ -18,6 +18,7 @@ quarkus-extension quarkus-jandex quarkus-vs-springboot + quarkus-funqy \ No newline at end of file diff --git a/security-modules/java-ee-8-security-api/app-auth-basic-store-db/src/main/java/com/baeldung/javaee/security/AdminServlet.java b/security-modules/java-ee-8-security-api/app-auth-basic-store-db/src/main/java/com/baeldung/javaee/security/AdminServlet.java index 32adbf1abb..5d64eedaf1 100644 --- a/security-modules/java-ee-8-security-api/app-auth-basic-store-db/src/main/java/com/baeldung/javaee/security/AdminServlet.java +++ b/security-modules/java-ee-8-security-api/app-auth-basic-store-db/src/main/java/com/baeldung/javaee/security/AdminServlet.java @@ -1,6 +1,5 @@ package com.baeldung.javaee.security; -import javax.servlet.ServletException; import javax.servlet.annotation.HttpConstraint; import javax.servlet.annotation.ServletSecurity; import javax.servlet.annotation.WebServlet; @@ -14,7 +13,7 @@ import java.io.IOException; public class AdminServlet extends HttpServlet { @Override - protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { response.getWriter().append("User :" + request.getUserPrincipal().getName() + "\n"); response.getWriter().append("User in Role user_role :" + request.isUserInRole("user_role") + "\n"); response.getWriter().append("User in Role admin_role :" + request.isUserInRole("admin_role")); diff --git a/security-modules/java-ee-8-security-api/app-auth-basic-store-db/src/main/java/com/baeldung/javaee/security/AppConfig.java b/security-modules/java-ee-8-security-api/app-auth-basic-store-db/src/main/java/com/baeldung/javaee/security/AppConfig.java index a16d944f5a..2d37b12851 100644 --- a/security-modules/java-ee-8-security-api/app-auth-basic-store-db/src/main/java/com/baeldung/javaee/security/AppConfig.java +++ b/security-modules/java-ee-8-security-api/app-auth-basic-store-db/src/main/java/com/baeldung/javaee/security/AppConfig.java @@ -2,7 +2,6 @@ package com.baeldung.javaee.security; import javax.enterprise.context.ApplicationScoped; import javax.security.enterprise.authentication.mechanism.http.BasicAuthenticationMechanismDefinition; -import javax.security.enterprise.authentication.mechanism.http.CustomFormAuthenticationMechanismDefinition; import javax.security.enterprise.identitystore.DatabaseIdentityStoreDefinition; @BasicAuthenticationMechanismDefinition(realmName = "defaultRealm") diff --git a/security-modules/java-ee-8-security-api/app-auth-basic-store-db/src/main/java/com/baeldung/javaee/security/UserServlet.java b/security-modules/java-ee-8-security-api/app-auth-basic-store-db/src/main/java/com/baeldung/javaee/security/UserServlet.java index 548b5f6d85..9f14cd8817 100644 --- a/security-modules/java-ee-8-security-api/app-auth-basic-store-db/src/main/java/com/baeldung/javaee/security/UserServlet.java +++ b/security-modules/java-ee-8-security-api/app-auth-basic-store-db/src/main/java/com/baeldung/javaee/security/UserServlet.java @@ -1,8 +1,5 @@ package com.baeldung.javaee.security; -import javax.annotation.security.DeclareRoles; -import javax.inject.Inject; -import javax.security.enterprise.SecurityContext; import javax.servlet.ServletException; import javax.servlet.annotation.HttpConstraint; import javax.servlet.annotation.ServletSecurity; diff --git a/security-modules/java-ee-8-security-api/app-auth-basic-store-db/src/main/liberty/config/server.xml b/security-modules/java-ee-8-security-api/app-auth-basic-store-db/src/main/liberty/config/server.xml index c49adff459..e1934ca608 100644 --- a/security-modules/java-ee-8-security-api/app-auth-basic-store-db/src/main/liberty/config/server.xml +++ b/security-modules/java-ee-8-security-api/app-auth-basic-store-db/src/main/liberty/config/server.xml @@ -4,6 +4,10 @@ webProfile-8.0 + + + + diff --git a/security-modules/java-ee-8-security-api/pom.xml b/security-modules/java-ee-8-security-api/pom.xml index 7d1a19cb88..08a7e9078a 100644 --- a/security-modules/java-ee-8-security-api/pom.xml +++ b/security-modules/java-ee-8-security-api/pom.xml @@ -31,32 +31,31 @@ + ${project.artifactId} + org.apache.maven.plugins maven-war-plugin + 3.3.2 + + + io.openliberty.tools + liberty-maven-plugin + 3.8.2 - false - pom.xml + guideServer - net.wasdev.wlp.maven.plugins - liberty-maven-plugin - ${liberty-maven-plugin.version} + org.apache.maven.plugins + maven-failsafe-plugin + 3.1.2 - - - https://public.dhe.ibm.com/ibmdl/export/pub/software/openliberty/runtime/release/2018-09-05_2337/openliberty-18.0.0.3.zip - - - true - project - src/main/liberty/config/server.xml - true - + ${defaultHttpPort} - ${defaultHttpsPort} - + ${defaultHttpPort} + ${liberty.var.app.context.root} + @@ -65,9 +64,10 @@ 9080 9443 - 8.0 + 8.0.1 2.3 18.0.0.1 + ${project.artifactId} \ No newline at end of file diff --git a/spring-aop-2/pom.xml b/spring-aop-2/pom.xml index e4748cdcbf..056e248a3c 100644 --- a/spring-aop-2/pom.xml +++ b/spring-aop-2/pom.xml @@ -51,8 +51,4 @@ - - 1.14.0 - - \ No newline at end of file diff --git a/spring-batch/pom.xml b/spring-batch/pom.xml index 810ddcdcdd..7d9becf089 100644 --- a/spring-batch/pom.xml +++ b/spring-batch/pom.xml @@ -25,7 +25,7 @@ jakarta.xml.bind jakarta.xml.bind-api - 4.0.0 + ${jakarta.xml.bind-api} org.glassfish.jaxb @@ -75,6 +75,7 @@ 6.0.6 5.7.1 + 4.0.0 4.0.2 2.14.2 4.5.14 diff --git a/spring-boot-documentation/README.md b/spring-boot-documentation/README.md new file mode 100644 index 0000000000..69e50f68dc --- /dev/null +++ b/spring-boot-documentation/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [Documenting Spring Event-Driven API Using AsyncAPI and Springwolf](https://www.baeldung.com/java-spring-doc-asyncapi-springwolf) diff --git a/spring-boot-documentation/pom.xml b/spring-boot-documentation/pom.xml new file mode 100644 index 0000000000..d718f33a99 --- /dev/null +++ b/spring-boot-documentation/pom.xml @@ -0,0 +1,46 @@ + + + 4.0.0 + com.baeldung.spring-boot-documentation + spring-boot-documentation + 1.0.0-SNAPSHOT + spring-boot-documentation + pom + + + com.baeldung + parent-boot-3 + 0.0.1-SNAPSHOT + ../parent-boot-3 + + + + springwolf + + + + + + org.junit + junit-bom + ${junit-jupiter.version} + pom + import + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} + pom + import + + + + + + 3.3.2 + + + diff --git a/spring-boot-documentation/springwolf/docker-compose.yml b/spring-boot-documentation/springwolf/docker-compose.yml new file mode 100644 index 0000000000..214e2d2ace --- /dev/null +++ b/spring-boot-documentation/springwolf/docker-compose.yml @@ -0,0 +1,37 @@ +version: '3' +services: + zookeeper: + image: confluentinc/cp-zookeeper:latest + environment: + ZOOKEEPER_CLIENT_PORT: 2181 + ZOOKEEPER_TICK_TIME: + + kafka: + image: confluentinc/cp-kafka:latest + depends_on: + - zookeeper + ports: + - "9092:9092" + environment: + KAFKA_BROKER_ID: 1 + KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 + KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 + KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092,PLAINTEXT_HOST://kafka:29092 + KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT + + + akhq: + image: tchiotludo/akhq + restart: unless-stopped + environment: + AKHQ_CONFIGURATION: | + akhq: + connections: + docker-kafka-server: + properties: + bootstrap.servers: "kafka:29092" + + ports: + - "9090:8080" + links: + - kafka diff --git a/spring-boot-documentation/springwolf/pom.xml b/spring-boot-documentation/springwolf/pom.xml new file mode 100644 index 0000000000..4bd9f24065 --- /dev/null +++ b/spring-boot-documentation/springwolf/pom.xml @@ -0,0 +1,82 @@ + + + 4.0.0 + springwolf + 0.0.1-SNAPSHOT + springwolf + Documentation Spring Event Driven API Using AsyncAPI and Springwolf + + + com.baeldung.spring-boot-documentation + spring-boot-documentation + 1.0.0-SNAPSHOT + + + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.kafka + spring-kafka + + + io.swagger.core.v3 + swagger-core-jakarta + ${swagger-core.version} + + + io.github.springwolf + springwolf-kafka + ${springwolf-kafka.version} + + + io.github.springwolf + springwolf-ui + ${springwolf-ui.version} + + + org.projectlombok + lombok + ${lombok.version} + + + org.springframework.kafka + spring-kafka-test + test + + + org.testcontainers + junit-jupiter + ${testcontainers-kafka.version} + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + com.baeldung.boot.documentation.springwolf.SpringwolfApplication + + + + + + + 2.2.11 + 0.12.1 + 0.8.0 + 1.18.3 + + + diff --git a/spring-boot-documentation/springwolf/src/main/java/com/baeldung/boot/documentation/springwolf/SpringwolfApplication.java b/spring-boot-documentation/springwolf/src/main/java/com/baeldung/boot/documentation/springwolf/SpringwolfApplication.java new file mode 100644 index 0000000000..1eed112a40 --- /dev/null +++ b/spring-boot-documentation/springwolf/src/main/java/com/baeldung/boot/documentation/springwolf/SpringwolfApplication.java @@ -0,0 +1,12 @@ +package com.baeldung.boot.documentation.springwolf; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SpringwolfApplication { + + public static void main(String[] args) { + SpringApplication.run(SpringwolfApplication.class, args); + } +} diff --git a/spring-boot-documentation/springwolf/src/main/java/com/baeldung/boot/documentation/springwolf/adapter/incoming/IncomingConsumer.java b/spring-boot-documentation/springwolf/src/main/java/com/baeldung/boot/documentation/springwolf/adapter/incoming/IncomingConsumer.java new file mode 100644 index 0000000000..ae201dbf30 --- /dev/null +++ b/spring-boot-documentation/springwolf/src/main/java/com/baeldung/boot/documentation/springwolf/adapter/incoming/IncomingConsumer.java @@ -0,0 +1,48 @@ +package com.baeldung.boot.documentation.springwolf.adapter.incoming; + +import com.baeldung.boot.documentation.springwolf.dto.IncomingPayloadDto; +import com.baeldung.boot.documentation.springwolf.service.ProcessorService; +import io.github.stavshamir.springwolf.asyncapi.scanners.channels.operationdata.annotation.AsyncListener; +import io.github.stavshamir.springwolf.asyncapi.scanners.channels.operationdata.annotation.AsyncOperation; +import io.github.stavshamir.springwolf.asyncapi.scanners.channels.operationdata.annotation.KafkaAsyncOperationBinding; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.stereotype.Component; + +import static org.springframework.kafka.support.mapping.AbstractJavaTypeMapper.DEFAULT_CLASSID_FIELD_NAME; + +@AllArgsConstructor +@Component +@Slf4j +public class IncomingConsumer { + + private static final String TOPIC_NAME = "incoming-topic"; + + private final ProcessorService processorService; + + @KafkaListener(topics = TOPIC_NAME) + @AsyncListener(operation = @AsyncOperation( + channelName = TOPIC_NAME, + description = "More details for the incoming topic", + headers = @AsyncOperation.Headers( + schemaName = "SpringKafkaDefaultHeadersIncomingPayloadDto", + values = { + // this header is generated by Spring by default + @AsyncOperation.Headers.Header( + name = DEFAULT_CLASSID_FIELD_NAME, + description = "Spring Type Id Header", + value = "com.baeldung.boot.documentation.springwolf.dto.IncomingPayloadDto" + ), + } + ) + ) + ) + @KafkaAsyncOperationBinding + public void consume(IncomingPayloadDto payload) { + log.info("Received new message: {}", payload.toString()); + + processorService.doHandle(payload); + } + +} diff --git a/spring-boot-documentation/springwolf/src/main/java/com/baeldung/boot/documentation/springwolf/adapter/outgoing/OutgoingProducer.java b/spring-boot-documentation/springwolf/src/main/java/com/baeldung/boot/documentation/springwolf/adapter/outgoing/OutgoingProducer.java new file mode 100644 index 0000000000..5630cd9a04 --- /dev/null +++ b/spring-boot-documentation/springwolf/src/main/java/com/baeldung/boot/documentation/springwolf/adapter/outgoing/OutgoingProducer.java @@ -0,0 +1,47 @@ +package com.baeldung.boot.documentation.springwolf.adapter.outgoing; + +import com.baeldung.boot.documentation.springwolf.dto.OutgoingPayloadDto; +import io.github.stavshamir.springwolf.asyncapi.scanners.channels.operationdata.annotation.AsyncOperation; +import io.github.stavshamir.springwolf.asyncapi.scanners.channels.operationdata.annotation.AsyncPublisher; +import io.github.stavshamir.springwolf.asyncapi.scanners.channels.operationdata.annotation.KafkaAsyncOperationBinding; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.stereotype.Component; + +import static org.springframework.kafka.support.mapping.AbstractJavaTypeMapper.DEFAULT_CLASSID_FIELD_NAME; + +@AllArgsConstructor +@Component +@Slf4j +public class OutgoingProducer { + + private static final String TOPIC_NAME = "outgoing-topic"; + + private final KafkaTemplate kafkaTemplate; + + @AsyncPublisher( + operation = @AsyncOperation( + channelName = TOPIC_NAME, + description = "More details for the outgoing topic", + headers = @AsyncOperation.Headers( + schemaName = "SpringKafkaDefaultHeadersOutgoingPayloadDto", + values = { + // this header is generated by Spring by default + @AsyncOperation.Headers.Header( + name = DEFAULT_CLASSID_FIELD_NAME, + description = "Spring Type Id Header", + value = "com.baeldung.boot.documentation.springwolf.dto.OutgoingPayloadDto" + ), + } + ) + ) + ) + @KafkaAsyncOperationBinding + public void publish(OutgoingPayloadDto payload) { + log.info("Publishing new message: {}", payload.toString()); + + kafkaTemplate.send(TOPIC_NAME, payload); + } + +} diff --git a/spring-boot-documentation/springwolf/src/main/java/com/baeldung/boot/documentation/springwolf/dto/IncomingPayloadDto.java b/spring-boot-documentation/springwolf/src/main/java/com/baeldung/boot/documentation/springwolf/dto/IncomingPayloadDto.java new file mode 100644 index 0000000000..a547d55db7 --- /dev/null +++ b/spring-boot-documentation/springwolf/src/main/java/com/baeldung/boot/documentation/springwolf/dto/IncomingPayloadDto.java @@ -0,0 +1,25 @@ +package com.baeldung.boot.documentation.springwolf.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.NOT_REQUIRED; +import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; + +@Data +@Schema(description = "Incoming payload model") +public class IncomingPayloadDto { + @Schema(description = "Some string field", example = "some string value", requiredMode = REQUIRED) + private String someString; + + @Schema(description = "Some long field", example = "5", requiredMode = NOT_REQUIRED) + private long someLong; + + @Schema(description = "Some enum field", example = "FOO2", requiredMode = REQUIRED) + private IncomingPayloadEnum someEnum; + + public enum IncomingPayloadEnum { + FOO1, FOO2, FOO3 + } + +} diff --git a/spring-boot-documentation/springwolf/src/main/java/com/baeldung/boot/documentation/springwolf/dto/OutgoingPayloadDto.java b/spring-boot-documentation/springwolf/src/main/java/com/baeldung/boot/documentation/springwolf/dto/OutgoingPayloadDto.java new file mode 100644 index 0000000000..2fb1ab1647 --- /dev/null +++ b/spring-boot-documentation/springwolf/src/main/java/com/baeldung/boot/documentation/springwolf/dto/OutgoingPayloadDto.java @@ -0,0 +1,20 @@ +package com.baeldung.boot.documentation.springwolf.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +import lombok.Data; + +import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.NOT_REQUIRED; +import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; + +@Data +@Builder +@Schema(description = "Outgoing payload model") +public class OutgoingPayloadDto { + + @Schema(description = "Foo field", example = "bar", requiredMode = NOT_REQUIRED) + private String foo; + + @Schema(description = "IncomingPayload field", requiredMode = REQUIRED) + private IncomingPayloadDto incomingWrapped; +} diff --git a/spring-boot-documentation/springwolf/src/main/java/com/baeldung/boot/documentation/springwolf/service/ProcessorService.java b/spring-boot-documentation/springwolf/src/main/java/com/baeldung/boot/documentation/springwolf/service/ProcessorService.java new file mode 100644 index 0000000000..980f978f4e --- /dev/null +++ b/spring-boot-documentation/springwolf/src/main/java/com/baeldung/boot/documentation/springwolf/service/ProcessorService.java @@ -0,0 +1,23 @@ +package com.baeldung.boot.documentation.springwolf.service; + +import com.baeldung.boot.documentation.springwolf.adapter.outgoing.OutgoingProducer; +import com.baeldung.boot.documentation.springwolf.dto.OutgoingPayloadDto; +import com.baeldung.boot.documentation.springwolf.dto.IncomingPayloadDto; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@AllArgsConstructor +public class ProcessorService { + + private final OutgoingProducer outgoingProducer; + + public void doHandle(IncomingPayloadDto payload) { + OutgoingPayloadDto message = OutgoingPayloadDto.builder() + .foo("Foo message") + .incomingWrapped(payload) + .build(); + + outgoingProducer.publish(message); + } +} diff --git a/spring-boot-documentation/springwolf/src/main/resources/application.properties b/spring-boot-documentation/springwolf/src/main/resources/application.properties new file mode 100644 index 0000000000..74cb93499e --- /dev/null +++ b/spring-boot-documentation/springwolf/src/main/resources/application.properties @@ -0,0 +1,30 @@ +######### +# Spring Configuration +spring.application.name=Baeldung Tutorial Springwolf Application + +######### +# Spring Kafka Configuration +spring.kafka.bootstrap-servers=localhost:9092 +spring.kafka.consumer.group-id=baeldung-kafka-group-id +spring.kafka.consumer.properties.spring.json.trusted.packages=com.baeldung.boot.documentation.springwolf.* +spring.kafka.consumer.key-deserializer=org.apache.kafka.common.serialization.StringDeserializer +spring.kafka.consumer.value-deserializer=org.springframework.kafka.support.serializer.JsonDeserializer +spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer +spring.kafka.producer.value-serializer=org.springframework.kafka.support.serializer.JsonSerializer + +######### +# Springwolf Configuration +springwolf.docket.base-package=com.baeldung.boot.documentation.springwolf.adapter +springwolf.docket.info.title=${spring.application.name} +springwolf.docket.info.version=1.0.0 +springwolf.docket.info.description=Baeldung Tutorial Application to Demonstrate AsyncAPI Documentation using Springwolf + +# Springwolf Kafka Configuration +springwolf.docket.servers.kafka.protocol=kafka +springwolf.docket.servers.kafka.url=localhost:9092 + +springwolf.plugin.kafka.publishing.enabled=true +springwolf.plugin.kafka.publishing.producer.bootstrap-servers=localhost:9092 +springwolf.plugin.kafka.publishing.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer +springwolf.plugin.kafka.publishing.producer.value-serializer=org.springframework.kafka.support.serializer.JsonSerializer +springwolf.plugin.kafka.publishing.producer.properties.spring.json.add.type.headers=false diff --git a/spring-boot-documentation/springwolf/src/test/java/com/baeldung/boot/documentation/springwolf/ApiIntegrationTest.java b/spring-boot-documentation/springwolf/src/test/java/com/baeldung/boot/documentation/springwolf/ApiIntegrationTest.java new file mode 100644 index 0000000000..ac237c0da9 --- /dev/null +++ b/spring-boot-documentation/springwolf/src/test/java/com/baeldung/boot/documentation/springwolf/ApiIntegrationTest.java @@ -0,0 +1,41 @@ +package com.baeldung.boot.documentation.springwolf; + +import org.json.JSONException; +import org.junit.jupiter.api.Test; +import org.skyscreamer.jsonassert.JSONAssert; +import org.skyscreamer.jsonassert.JSONCompareMode; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.kafka.test.context.EmbeddedKafka; +import org.springframework.test.annotation.DirtiesContext; +import org.testcontainers.shaded.org.apache.commons.io.IOUtils; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; + +@SpringBootTest(classes = {SpringwolfApplication.class}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@EmbeddedKafka( + partitions = 1, brokerProperties = { + "listeners=PLAINTEXT://localhost:9092", + "port=9092", +}) +@DirtiesContext +public class ApiIntegrationTest { + + @Autowired + private TestRestTemplate restTemplate; + + @Test + public void asyncApiResourceArtifactTest() throws JSONException, IOException { + // given + InputStream s = this.getClass().getResourceAsStream("/asyncapi.json"); + String expected = IOUtils.toString(s, StandardCharsets.UTF_8); + + String url = "/springwolf/docs"; + String actual = restTemplate.getForObject(url, String.class); + + JSONAssert.assertEquals(expected, actual, JSONCompareMode.STRICT); + } +} diff --git a/spring-boot-documentation/springwolf/src/test/resources/asyncapi.json b/spring-boot-documentation/springwolf/src/test/resources/asyncapi.json new file mode 100644 index 0000000000..0198733c1c --- /dev/null +++ b/spring-boot-documentation/springwolf/src/test/resources/asyncapi.json @@ -0,0 +1,168 @@ +{ + "asyncapi": "2.6.0", + "info": { + "title": "Baeldung Tutorial Springwolf Application", + "version": "1.0.0", + "description": "Baeldung Tutorial Application to Demonstrate AsyncAPI Documentation using Springwolf" + }, + "defaultContentType": "application/json", + "servers": { + "kafka": { + "url": "localhost:9092", + "protocol": "kafka" + } + }, + "channels": { + "incoming-topic": { + "publish": { + "operationId": "incoming-topic_publish", + "description": "More details for the incoming topic", + "bindings": { + "kafka": { } + }, + "message": { + "schemaFormat": "application/vnd.oai.openapi+json;version=3.0.0", + "name": "com.baeldung.boot.documentation.springwolf.dto.IncomingPayloadDto", + "title": "IncomingPayloadDto", + "description": "Incoming payload model", + "payload": { + "$ref": "#/components/schemas/IncomingPayloadDto" + }, + "headers": { + "$ref": "#/components/schemas/SpringKafkaDefaultHeadersIncomingPayloadDto" + }, + "bindings": { + "kafka": { } + } + } + } + }, + "outgoing-topic": { + "subscribe": { + "operationId": "outgoing-topic_subscribe", + "description": "More details for the outgoing topic", + "bindings": { + "kafka": { } + }, + "message": { + "schemaFormat": "application/vnd.oai.openapi+json;version=3.0.0", + "name": "com.baeldung.boot.documentation.springwolf.dto.OutgoingPayloadDto", + "title": "OutgoingPayloadDto", + "description": "Outgoing payload model", + "payload": { + "$ref": "#/components/schemas/OutgoingPayloadDto" + }, + "headers": { + "$ref": "#/components/schemas/SpringKafkaDefaultHeadersOutgoingPayloadDto" + }, + "bindings": { + "kafka": { } + } + } + } + } + }, + "components": { + "schemas": { + "HeadersNotDocumented": { + "type": "object", + "properties": { }, + "example": { } + }, + "IncomingPayloadDto": { + "required": [ + "someEnum", + "someString" + ], + "type": "object", + "properties": { + "someEnum": { + "type": "string", + "description": "Some enum field", + "example": "FOO2", + "enum": [ + "FOO1", + "FOO2", + "FOO3" + ] + }, + "someLong": { + "type": "integer", + "description": "Some long field", + "format": "int64", + "example": 5 + }, + "someString": { + "type": "string", + "description": "Some string field", + "example": "some string value" + } + }, + "description": "Incoming payload model", + "example": { + "someEnum": "FOO2", + "someLong": 5, + "someString": "some string value" + } + }, + "OutgoingPayloadDto": { + "required": [ + "incomingWrapped" + ], + "type": "object", + "properties": { + "foo": { + "type": "string", + "description": "Foo field", + "example": "bar" + }, + "incomingWrapped": { + "$ref": "#/components/schemas/IncomingPayloadDto" + } + }, + "description": "Outgoing payload model", + "example": { + "foo": "bar", + "incomingWrapped": { + "someEnum": "FOO2", + "someLong": 5, + "someString": "some string value" + } + } + }, + "SpringKafkaDefaultHeadersIncomingPayloadDto": { + "type": "object", + "properties": { + "__TypeId__": { + "type": "string", + "description": "Spring Type Id Header", + "example": "com.baeldung.boot.documentation.springwolf.dto.IncomingPayloadDto", + "enum": [ + "com.baeldung.boot.documentation.springwolf.dto.IncomingPayloadDto" + ] + } + }, + "example": { + "__TypeId__": "com.baeldung.boot.documentation.springwolf.dto.IncomingPayloadDto" + } + }, + "SpringKafkaDefaultHeadersOutgoingPayloadDto": { + "type": "object", + "properties": { + "__TypeId__": { + "type": "string", + "description": "Spring Type Id Header", + "example": "com.baeldung.boot.documentation.springwolf.dto.OutgoingPayloadDto", + "enum": [ + "com.baeldung.boot.documentation.springwolf.dto.OutgoingPayloadDto" + ] + } + }, + "example": { + "__TypeId__": "com.baeldung.boot.documentation.springwolf.dto.OutgoingPayloadDto" + } + } + } + }, + "tags": [ ] +} diff --git a/spring-boot-modules/pom.xml b/spring-boot-modules/pom.xml index 0417d83c61..0679f33ae7 100644 --- a/spring-boot-modules/pom.xml +++ b/spring-boot-modules/pom.xml @@ -73,6 +73,7 @@ spring-boot-swagger-2 spring-boot-swagger-jwt spring-boot-swagger-keycloak + spring-boot-swagger-springfox spring-boot-testing spring-boot-testing-2 spring-boot-testing-spock diff --git a/spring-boot-modules/spring-boot-3-observation/pom.xml b/spring-boot-modules/spring-boot-3-observation/pom.xml index f69ce699bc..b35e9e04d1 100644 --- a/spring-boot-modules/spring-boot-3-observation/pom.xml +++ b/spring-boot-modules/spring-boot-3-observation/pom.xml @@ -4,7 +4,6 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 spring-boot-3-observation - 0.0.1-SNAPSHOT spring-boot-3-observation Demo project for Spring Boot 3 Observation @@ -32,7 +31,7 @@ io.micrometer micrometer-tracing-bridge-brave - + io.micrometer @@ -62,11 +61,11 @@ org.springframework.boot spring-boot-starter-jdbc - + com.github.gavlyukovskiy p6spy-spring-boot-starter - 1.9.0 + ${p6spy-spring-boot-starter.version} com.h2database @@ -82,8 +81,34 @@ + + + + org.apache.maven.plugins + maven-surefire-plugin + + 3 + false + + + + org.junit.jupiter + junit-jupiter-engine + ${junit-jupiter.version} + + + org.junit.vintage + junit-vintage-engine + ${junit-jupiter.version} + + + + + + com.baeldung.samples.SimpleObservationApplication + 1.9.0 diff --git a/spring-boot-modules/spring-boot-3-test-pitfalls/pom.xml b/spring-boot-modules/spring-boot-3-test-pitfalls/pom.xml index f3ed67e87b..4aa4ab470b 100644 --- a/spring-boot-modules/spring-boot-3-test-pitfalls/pom.xml +++ b/spring-boot-modules/spring-boot-3-test-pitfalls/pom.xml @@ -69,7 +69,7 @@ org.projectlombok lombok-mapstruct-binding - 0.2.0 + ${lombok-mapstruct-binding.version} @@ -80,6 +80,7 @@ 1.5.3.Final + 0.2.0 3.0.0-M7 diff --git a/spring-boot-modules/spring-boot-3-url-matching/pom.xml b/spring-boot-modules/spring-boot-3-url-matching/pom.xml index 0ed6fdbd9b..aa83a676d7 100644 --- a/spring-boot-modules/spring-boot-3-url-matching/pom.xml +++ b/spring-boot-modules/spring-boot-3-url-matching/pom.xml @@ -46,13 +46,13 @@ org.springframework spring-test - 6.0.6 + ${spring-test.version} test javax.servlet javax.servlet-api - 3.1.0 + ${javax.servlet-api.version} provided @@ -62,12 +62,12 @@ io.projectreactor reactor-core - 3.5.4 + ${reactor-core.version} io.projectreactor reactor-test - 3.5.4 + ${reactor-test.version} test @@ -78,7 +78,6 @@ org.apache.maven.plugins maven-compiler-plugin - org.springframework.boot @@ -95,6 +94,10 @@ + 6.0.6 + 3.1.0 + 3.5.4 + 3.5.4> 3.0.0-M7 diff --git a/spring-boot-modules/spring-boot-3/pom.xml b/spring-boot-modules/spring-boot-3/pom.xml index 8fe995ca91..32c69801ca 100644 --- a/spring-boot-modules/spring-boot-3/pom.xml +++ b/spring-boot-modules/spring-boot-3/pom.xml @@ -1,7 +1,7 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 spring-boot-3 0.0.1-SNAPSHOT @@ -79,12 +79,64 @@ ${mapstruct.version} true + + org.springframework.boot + spring-boot-docker-compose + + + org.springframework.boot + spring-boot-starter-data-mongodb + + + org.springframework.boot + spring-boot-starter-actuator + org.springframework.boot spring-boot-starter-test + + + default + + true + + + + + org.springframework.boot + spring-boot-maven-plugin + + com.baeldung.virtualthreads.VirtualThreadsApp + + + org.projectlombok + lombok + + + + + + + + + docker-compose + + + + org.springframework.boot + spring-boot-maven-plugin + + com.baeldung.dockercompose.DockerComposeApplication + + + + + + + @@ -107,24 +159,11 @@ org.projectlombok lombok-mapstruct-binding - 0.2.0 + ${lombok-mapstruct-binding.version} - - org.springframework.boot - spring-boot-maven-plugin - - com.baeldung.virtualthreads.VirtualThreadsApp - - - org.projectlombok - lombok - - - - @@ -149,6 +188,8 @@ 3.0.0-M7 com.baeldung.sample.TodoApplication 5.14.0 + 3.1.0 + 0.2.0 \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/dockercompose/DockerComposeApplication.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/dockercompose/DockerComposeApplication.java new file mode 100644 index 0000000000..005226dedc --- /dev/null +++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/dockercompose/DockerComposeApplication.java @@ -0,0 +1,11 @@ +package com.baeldung.dockercompose; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class DockerComposeApplication { + public static void main(String[] args) { + SpringApplication.run(DockerComposeApplication.class, args); + } +} diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/dockercompose/config/MongoConfig.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/dockercompose/config/MongoConfig.java new file mode 100644 index 0000000000..9ebeb840b8 --- /dev/null +++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/dockercompose/config/MongoConfig.java @@ -0,0 +1,42 @@ +package com.baeldung.dockercompose.config; + +import java.util.Collection; +import java.util.Collections; + +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.data.mongodb.config.AbstractMongoClientConfiguration; + +import com.mongodb.ConnectionString; +import com.mongodb.MongoClientSettings; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; + +/** + * This profile is active for non docker-compose profile and will set up a MongoClient. + * When docker-compose profile is active, the application will boot with application-docker-compose.yml and the Docker Compose support will start a default configuration + */ +@Configuration +@Profile("!docker-compose") +public class MongoConfig extends AbstractMongoClientConfiguration { + + @Override + protected String getDatabaseName() { + return "test"; + } + + @Override + public MongoClient mongoClient() { + ConnectionString connectionString = new ConnectionString("mongodb://localhost:27017/test"); + MongoClientSettings mongoClientSettings = MongoClientSettings.builder() + .applyConnectionString(connectionString) + .build(); + + return MongoClients.create(mongoClientSettings); + } + + @Override + public Collection getMappingBasePackages() { + return Collections.singleton("com.baeldung.dockercompose"); + } +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/dockercompose/controller/ItemController.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/dockercompose/controller/ItemController.java new file mode 100644 index 0000000000..0b2b323131 --- /dev/null +++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/dockercompose/controller/ItemController.java @@ -0,0 +1,46 @@ +package com.baeldung.dockercompose.controller; + +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; + +import java.util.List; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.baeldung.dockercompose.model.Item; +import com.baeldung.dockercompose.repository.ItemRepository; + +import lombok.RequiredArgsConstructor; + +@RestController +@RequestMapping("/item") +@RequiredArgsConstructor +public class ItemController { + + private final ItemRepository itemRepository; + + @PostMapping(consumes = APPLICATION_JSON_VALUE) + public ResponseEntity save(final @RequestBody Item item) { + return ResponseEntity.ok(itemRepository.save(item)); + } + + @GetMapping(produces = APPLICATION_JSON_VALUE) + public Item findByName(@RequestParam final String name) { + return itemRepository.findItemByName(name); + } + + @GetMapping(value = "category", produces = APPLICATION_JSON_VALUE) + public List findByCategory(@RequestParam final String category) { + return itemRepository.findAllByCategory(category); + } + + @GetMapping(value = "count", produces = APPLICATION_JSON_VALUE) + public long count() { + return itemRepository.count(); + } +} diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/dockercompose/model/Item.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/dockercompose/model/Item.java new file mode 100644 index 0000000000..7c898bc2dc --- /dev/null +++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/dockercompose/model/Item.java @@ -0,0 +1,22 @@ +package com.baeldung.dockercompose.model; + +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Document("item") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class Item { + + @Id + private String id; + private String name; + private int quantity; + private String category; +} + diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/dockercompose/repository/ItemRepository.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/dockercompose/repository/ItemRepository.java new file mode 100644 index 0000000000..c608942e03 --- /dev/null +++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/dockercompose/repository/ItemRepository.java @@ -0,0 +1,20 @@ +package com.baeldung.dockercompose.repository; + +import java.util.List; + +import org.springframework.data.mongodb.repository.MongoRepository; +import org.springframework.data.mongodb.repository.Query; + +import com.baeldung.dockercompose.model.Item; + +public interface ItemRepository extends MongoRepository { + + @Query("{name:'?0'}") + Item findItemByName(String name); + + @Query(value = "{category:'?0'}") + List findAllByCategory(String category); + + long count(); +} + diff --git a/spring-boot-modules/spring-boot-3/src/main/resources/application-docker-compose.yml b/spring-boot-modules/spring-boot-3/src/main/resources/application-docker-compose.yml new file mode 100644 index 0000000000..bce67fa400 --- /dev/null +++ b/spring-boot-modules/spring-boot-3/src/main/resources/application-docker-compose.yml @@ -0,0 +1,7 @@ +spring: + docker: + compose: + enabled: true + file: docker-compose.yml + autoconfigure: + exclude: org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3/src/main/resources/application.yml b/spring-boot-modules/spring-boot-3/src/main/resources/application.yml index 5f9031bc9e..3885e59a61 100644 --- a/spring-boot-modules/spring-boot-3/src/main/resources/application.yml +++ b/spring-boot-modules/spring-boot-3/src/main/resources/application.yml @@ -15,8 +15,12 @@ spring: hibernate: dialect: org.hibernate.dialect.H2Dialect thread-executor: standard + docker: + compose: + enabled: false + autoconfigure: + exclude: org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration -# Custom Properties cors: allow: origins: ${CORS_ALLOWED_ORIGINS:*} diff --git a/spring-boot-modules/spring-boot-3/src/main/resources/docker-compose.yml b/spring-boot-modules/spring-boot-3/src/main/resources/docker-compose.yml new file mode 100644 index 0000000000..4bfc2349bd --- /dev/null +++ b/spring-boot-modules/spring-boot-3/src/main/resources/docker-compose.yml @@ -0,0 +1,14 @@ +version: '3.8' +services: + db: + image: mongo:latest + ports: + - '27017:27017' + volumes: + - db:/data/db + labels: + org.springframework.boot.service-connection: mongo +volumes: + db: + driver: + local \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-artifacts/pom.xml b/spring-boot-modules/spring-boot-artifacts/pom.xml index 996ed92014..dedeb0ab2a 100644 --- a/spring-boot-modules/spring-boot-artifacts/pom.xml +++ b/spring-boot-modules/spring-boot-artifacts/pom.xml @@ -99,7 +99,7 @@ org.apache.maven.plugins maven-failsafe-plugin - 2.18 + ${maven-failsafe-plugin.version} @@ -193,6 +193,7 @@ 2.2.4 3.1.7 4.5.8 + 2.18 \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-aws/pom.xml b/spring-boot-modules/spring-boot-aws/pom.xml index 2abce7df76..12a65908af 100644 --- a/spring-boot-modules/spring-boot-aws/pom.xml +++ b/spring-boot-modules/spring-boot-aws/pom.xml @@ -14,9 +14,6 @@ spring-boot-modules 1.0.0-SNAPSHOT - - 1.9.1 - @@ -43,7 +40,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.2.4 + ${maven-shade-plugin.version} false @@ -74,4 +71,9 @@ + + 1.9.1 + 3.2.4 + + \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-basic-customization/pom.xml b/spring-boot-modules/spring-boot-basic-customization/pom.xml index 20b2980f29..4b1009d38a 100644 --- a/spring-boot-modules/spring-boot-basic-customization/pom.xml +++ b/spring-boot-modules/spring-boot-basic-customization/pom.xml @@ -34,11 +34,6 @@ - - - com.baeldung.changeport.CustomApplication - - errorhandling @@ -77,7 +72,7 @@ org.springframework.boot spring-boot-maven-plugin - 1.5.2.RELEASE + ${spring-boot-maven-plugin.version} ${spring.boot.mainclass} @@ -85,4 +80,11 @@ + + 1.5.2.RELEASE + + com.baeldung.changeport.CustomApplication + + + \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-jsp/README.md b/spring-boot-modules/spring-boot-jsp/README.md index 535f86531d..f67587b949 100644 --- a/spring-boot-modules/spring-boot-jsp/README.md +++ b/spring-boot-modules/spring-boot-jsp/README.md @@ -1,3 +1,4 @@ ### Relevant Articles: - [Spring Boot With JavaServer Pages (JSP)](https://www.baeldung.com/spring-boot-jsp) +- [Reading a JSP Variable From JavaScript](https://www.baeldung.com/java-jsp-read-variable-js) diff --git a/spring-boot-modules/spring-boot-jsp/pom.xml b/spring-boot-modules/spring-boot-jsp/pom.xml index ab81d65cc6..9c6d0fcc0b 100644 --- a/spring-boot-modules/spring-boot-jsp/pom.xml +++ b/spring-boot-modules/spring-boot-jsp/pom.xml @@ -46,12 +46,22 @@ jstl ${jstl.version} + + org.apache.commons + commons-text + ${commons-text.version} + org.apache.tomcat.embed tomcat-embed-jasper + + + org.springframework.boot + spring-boot-devtools + org.projectlombok lombok @@ -100,6 +110,7 @@ 1.2 2.4.4 2.17.1 + 1.10.0 \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-jsp/src/main/java/com/baeldung/boot/jsp/controller/JSPVariableController.java b/spring-boot-modules/spring-boot-jsp/src/main/java/com/baeldung/boot/jsp/controller/JSPVariableController.java new file mode 100644 index 0000000000..c85d588c07 --- /dev/null +++ b/spring-boot-modules/spring-boot-jsp/src/main/java/com/baeldung/boot/jsp/controller/JSPVariableController.java @@ -0,0 +1,31 @@ +package com.baeldung.boot.jsp.controller; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +@RequestMapping("/jsp-var") +public class JSPVariableController { + + @GetMapping("/by-jsp") + public String byJsp() { + return "/jsp-var/by-jsp"; + } + + @GetMapping("/by-el") + public String byEl() { + return "/jsp-var/by-el"; + } + + @GetMapping("/by-jstl") + public String byJstl() { + return "/jsp-var/by-jstl"; + } + + @GetMapping("/to-dom") + public String byDom() { + return "/jsp-var/to-dom"; + } + +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-jsp/src/main/webapp/WEB-INF/jsp/jsp-var/by-el.jsp b/spring-boot-modules/spring-boot-jsp/src/main/webapp/WEB-INF/jsp/jsp-var/by-el.jsp new file mode 100644 index 0000000000..381df4f5eb --- /dev/null +++ b/spring-boot-modules/spring-boot-jsp/src/main/webapp/WEB-INF/jsp/jsp-var/by-el.jsp @@ -0,0 +1,18 @@ +<%@ page import="org.apache.commons.text.StringEscapeUtils" %> +<%@ page contentType="text/html;charset=UTF-8" language="java" %> +<% + String jspMsg = StringEscapeUtils.escapeEcmaScript("Hello! This is Sam's page."); + request.setAttribute("jspMsg", jspMsg); +%> + + + Conversion by JSP EL + + + +
Open the browser console to see the message.
+ + \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-jsp/src/main/webapp/WEB-INF/jsp/jsp-var/by-jsp.jsp b/spring-boot-modules/spring-boot-jsp/src/main/webapp/WEB-INF/jsp/jsp-var/by-jsp.jsp new file mode 100644 index 0000000000..84c1f0db29 --- /dev/null +++ b/spring-boot-modules/spring-boot-jsp/src/main/webapp/WEB-INF/jsp/jsp-var/by-jsp.jsp @@ -0,0 +1,16 @@ +<%@ page import="org.apache.commons.text.StringEscapeUtils" %> +<%@ page contentType="text/html;charset=UTF-8" language="java" %> +<% + String jspMsg = StringEscapeUtils.escapeEcmaScript("Hello! This is Sam's page."); +%> + + + Conversion by JSP expression tag + var jsMsg = '<%=jspMsg%>'; + console.info(jsMsg); + + + +
Open the browser console to see the message.
+ + \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-jsp/src/main/webapp/WEB-INF/jsp/jsp-var/by-jstl.jsp b/spring-boot-modules/spring-boot-jsp/src/main/webapp/WEB-INF/jsp/jsp-var/by-jstl.jsp new file mode 100644 index 0000000000..5ac4bc8daa --- /dev/null +++ b/spring-boot-modules/spring-boot-jsp/src/main/webapp/WEB-INF/jsp/jsp-var/by-jstl.jsp @@ -0,0 +1,19 @@ +<%@ page import="org.apache.commons.text.StringEscapeUtils" %> +<%@ page contentType="text/html;charset=UTF-8" language="java" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<% + String jspMsg = StringEscapeUtils.escapeEcmaScript("Hello! This is Sam's page."); + request.setAttribute("scopedMsg", jspMsg); +%> + + + Conversion by JSTL + + + +
Open the browser console to see the message.
+ + \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-jsp/src/main/webapp/WEB-INF/jsp/jsp-var/to-dom.jsp b/spring-boot-modules/spring-boot-jsp/src/main/webapp/WEB-INF/jsp/jsp-var/to-dom.jsp new file mode 100644 index 0000000000..2f44e5e664 --- /dev/null +++ b/spring-boot-modules/spring-boot-jsp/src/main/webapp/WEB-INF/jsp/jsp-var/to-dom.jsp @@ -0,0 +1,19 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> +<% + String jspTag = "

Hello

"; +%> + + + Convert to an HTML tag + + + +
<%=jspTag%>
+
Open the browser console to see the tags.
+ + \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-keycloak-adapters/pom.xml b/spring-boot-modules/spring-boot-keycloak-adapters/pom.xml index 0da8d920d1..035c226b6d 100644 --- a/spring-boot-modules/spring-boot-keycloak-adapters/pom.xml +++ b/spring-boot-modules/spring-boot-keycloak-adapters/pom.xml @@ -17,27 +17,12 @@ ../../parent-boot-2 - - - - org.keycloak.bom - keycloak-adapter-bom - ${keycloak-adapter-bom.version} - pom - import - - - - org.springframework.boot spring-boot-starter - - org.keycloak - keycloak-spring-boot-starter - + org.springframework.boot spring-boot-starter-data-jpa @@ -59,6 +44,10 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.boot + spring-boot-starter-oauth2-resource-server + org.hsqldb hsqldb @@ -84,8 +73,4 @@ - - 15.0.2 - - \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-keycloak-adapters/src/main/java/com/baeldung/keycloak/CustomUserAttrController.java b/spring-boot-modules/spring-boot-keycloak-adapters/src/main/java/com/baeldung/keycloak/CustomUserAttrController.java index 5b267ae19e..e6432ce19a 100644 --- a/spring-boot-modules/spring-boot-keycloak-adapters/src/main/java/com/baeldung/keycloak/CustomUserAttrController.java +++ b/spring-boot-modules/spring-boot-keycloak-adapters/src/main/java/com/baeldung/keycloak/CustomUserAttrController.java @@ -1,13 +1,10 @@ package com.baeldung.keycloak; -import java.security.Principal; import java.util.Map; -import org.keycloak.KeycloakPrincipal; -import org.keycloak.KeycloakSecurityContext; -import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken; -import org.keycloak.representations.IDToken; import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.oauth2.core.oidc.OidcIdToken; +import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; @@ -18,34 +15,27 @@ public class CustomUserAttrController { @GetMapping(path = "/users") public String getUserInfo(Model model) { - KeycloakAuthenticationToken authentication = (KeycloakAuthenticationToken) SecurityContextHolder.getContext() - .getAuthentication(); - - final Principal principal = (Principal) authentication.getPrincipal(); + final DefaultOidcUser user = (DefaultOidcUser) SecurityContextHolder.getContext() + .getAuthentication() + .getPrincipal(); String dob = ""; - String userIdByToken = ""; - String userIdByMapper = ""; + String userId = ""; - if (principal instanceof KeycloakPrincipal) { + OidcIdToken token = user.getIdToken(); - KeycloakPrincipal kPrincipal = (KeycloakPrincipal) principal; - IDToken token = kPrincipal.getKeycloakSecurityContext() - .getIdToken(); + Map customClaims = token.getClaims(); - userIdByToken = token.getSubject(); - userIdByMapper = token.getOtherClaims().get("user_id").toString(); - - Map customClaims = token.getOtherClaims(); - - if (customClaims.containsKey("DOB")) { - dob = String.valueOf(customClaims.get("DOB")); - } + if (customClaims.containsKey("user_id")) { + userId = String.valueOf(customClaims.get("user_id")); } - model.addAttribute("username", principal.getName()); - model.addAttribute("userIDByToken", userIdByToken); - model.addAttribute("userIDByMapper", userIdByMapper); + if (customClaims.containsKey("DOB")) { + dob = String.valueOf(customClaims.get("DOB")); + } + + model.addAttribute("username", user.getName()); + model.addAttribute("userID", userId); model.addAttribute("dob", dob); return "userInfo"; } diff --git a/spring-boot-modules/spring-boot-keycloak-adapters/src/main/java/com/baeldung/keycloak/KeycloakConfig.java b/spring-boot-modules/spring-boot-keycloak-adapters/src/main/java/com/baeldung/keycloak/KeycloakConfig.java deleted file mode 100644 index 6a3dc45717..0000000000 --- a/spring-boot-modules/spring-boot-keycloak-adapters/src/main/java/com/baeldung/keycloak/KeycloakConfig.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.baeldung.keycloak; - -import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -public class KeycloakConfig { - - @Bean - public KeycloakSpringBootConfigResolver keycloakConfigResolver() { - return new KeycloakSpringBootConfigResolver(); - } -} diff --git a/spring-boot-modules/spring-boot-keycloak-adapters/src/main/java/com/baeldung/keycloak/SecurityConfig.java b/spring-boot-modules/spring-boot-keycloak-adapters/src/main/java/com/baeldung/keycloak/SecurityConfig.java index c39e37cfaa..c85438952a 100644 --- a/spring-boot-modules/spring-boot-keycloak-adapters/src/main/java/com/baeldung/keycloak/SecurityConfig.java +++ b/spring-boot-modules/spring-boot-keycloak-adapters/src/main/java/com/baeldung/keycloak/SecurityConfig.java @@ -2,8 +2,11 @@ package com.baeldung.keycloak; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer; import org.springframework.security.core.session.SessionRegistryImpl; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy; @@ -36,6 +39,13 @@ class SecurityConfig { .logout() .addLogoutHandler(keycloakLogoutHandler) .logoutSuccessUrl("/"); + http.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt); return http.build(); } + + @Bean + public AuthenticationManager authenticationManager(HttpSecurity http) throws Exception { + return http.getSharedObject(AuthenticationManagerBuilder.class) + .build(); + } } diff --git a/spring-boot-modules/spring-boot-keycloak-adapters/src/main/resources/application-embedded.properties b/spring-boot-modules/spring-boot-keycloak-adapters/src/main/resources/application-embedded.properties deleted file mode 100644 index 7e1985f0ad..0000000000 --- a/spring-boot-modules/spring-boot-keycloak-adapters/src/main/resources/application-embedded.properties +++ /dev/null @@ -1,9 +0,0 @@ -### server port -server.port=8080 - -#Keycloak Configuration -keycloak.auth-server-url=http://localhost:8083/auth -keycloak.realm=baeldung -keycloak.resource=customerClient -keycloak.public-client=true -keycloak.principal-attribute=preferred_username \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-keycloak-adapters/src/main/resources/application.properties b/spring-boot-modules/spring-boot-keycloak-adapters/src/main/resources/application.properties index 323617e2ef..df2fadabae 100644 --- a/spring-boot-modules/spring-boot-keycloak-adapters/src/main/resources/application.properties +++ b/spring-boot-modules/spring-boot-keycloak-adapters/src/main/resources/application.properties @@ -1,15 +1,10 @@ ### server port server.port=8081 -#Keycloak Configuration -keycloak.auth-server-url=http://localhost:8180/auth -keycloak.realm=SpringBootKeycloak -keycloak.resource=login-app -keycloak.public-client=true -keycloak.principal-attribute=preferred_username - spring.security.oauth2.client.registration.keycloak.client-id=login-app spring.security.oauth2.client.registration.keycloak.authorization-grant-type=authorization_code spring.security.oauth2.client.registration.keycloak.scope=openid -spring.security.oauth2.client.provider.keycloak.issuer-uri=http://localhost:8180/auth/realms/SpringBootKeycloak -spring.security.oauth2.client.provider.keycloak.user-name-attribute=preferred_username \ No newline at end of file +spring.security.oauth2.client.provider.keycloak.issuer-uri=http://localhost:8080/realms/SpringBootKeycloak +spring.security.oauth2.client.provider.keycloak.user-name-attribute=preferred_username + +spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:8080/realms/SpringBootKeycloak \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-keycloak-adapters/src/main/resources/templates/userInfo.html b/spring-boot-modules/spring-boot-keycloak-adapters/src/main/resources/templates/userInfo.html index 7f772398c1..5b615fd914 100644 --- a/spring-boot-modules/spring-boot-keycloak-adapters/src/main/resources/templates/userInfo.html +++ b/spring-boot-modules/spring-boot-keycloak-adapters/src/main/resources/templates/userInfo.html @@ -8,10 +8,7 @@ Hello, --name--.

- User ID By Token: --userID--. -

-

- User ID By Mapper: --userID--. + User ID : --userID--.

Your Date of Birth as per our records is . diff --git a/spring-boot-modules/spring-boot-keycloak-adapters/src/test/java/com/baeldung/keycloak/KeycloakConfigurationIntegrationTest.java b/spring-boot-modules/spring-boot-keycloak-adapters/src/test/java/com/baeldung/keycloak/KeycloakConfigurationIntegrationTest.java new file mode 100644 index 0000000000..c14e006bd9 --- /dev/null +++ b/spring-boot-modules/spring-boot-keycloak-adapters/src/test/java/com/baeldung/keycloak/KeycloakConfigurationIntegrationTest.java @@ -0,0 +1,17 @@ +package com.baeldung.keycloak; + +import org.junit.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +@SpringBootTest(classes = { SpringBoot.class }) +public class KeycloakConfigurationIntegrationTest { + + @Test + public void whenLoadApplication_thenSuccess() { + + } + +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-keycloak-adapters/src/test/java/com/baeldung/keycloak/KeycloakConfigurationLiveTest.java b/spring-boot-modules/spring-boot-keycloak-adapters/src/test/java/com/baeldung/keycloak/KeycloakConfigurationLiveTest.java deleted file mode 100644 index 5fc8597252..0000000000 --- a/spring-boot-modules/spring-boot-keycloak-adapters/src/test/java/com/baeldung/keycloak/KeycloakConfigurationLiveTest.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.baeldung.keycloak; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.keycloak.KeycloakPrincipal; -import org.keycloak.KeycloakSecurityContext; -import org.keycloak.adapters.springboot.client.KeycloakSecurityContextClientRequestInterceptor; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.mockito.Spy; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.web.context.request.RequestContextHolder; -import org.springframework.web.context.request.ServletRequestAttributes; - -import static org.junit.Assert.assertNotNull; -import static org.mockito.Mockito.when; - -@RunWith(SpringJUnit4ClassRunner.class) -@SpringBootTest(classes = SpringBoot.class) -//requires running Keycloak server and realm setup as shown in https://www.baeldung.com/spring-boot-keycloak -public class KeycloakConfigurationLiveTest { - - @Spy - private KeycloakSecurityContextClientRequestInterceptor factory; - - private MockHttpServletRequest servletRequest; - - @Mock - public KeycloakSecurityContext keycloakSecurityContext; - - @Mock - private KeycloakPrincipal keycloakPrincipal; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - servletRequest = new MockHttpServletRequest(); - RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(servletRequest)); - servletRequest.setUserPrincipal(keycloakPrincipal); - when(keycloakPrincipal.getKeycloakSecurityContext()).thenReturn(keycloakSecurityContext); - } - - @Test - public void testGetKeycloakSecurityContext() throws Exception { - assertNotNull(keycloakPrincipal.getKeycloakSecurityContext()); - } - -} diff --git a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/postman/controller/PostmanUploadController.java b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/postman/controller/PostmanUploadController.java index ac19110318..6225a6b34b 100644 --- a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/postman/controller/PostmanUploadController.java +++ b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/postman/controller/PostmanUploadController.java @@ -5,6 +5,7 @@ import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RequestPart; import org.springframework.web.multipart.MultipartFile; import com.baeldung.postman.model.JsonRequest; @@ -23,4 +24,10 @@ public class PostmanUploadController { return ResponseEntity.ok() .body(json.getId() + json.getName()); } + + @PostMapping("/uploadJsonAndMultipartData") + public ResponseEntity handleJsonAndMultipartInput(@RequestPart("data") JsonRequest json, @RequestPart("file") MultipartFile file) { + return ResponseEntity.ok() + .body(json.getId() + json.getName()); + } } diff --git a/spring-boot-modules/spring-boot-properties-3/README.md b/spring-boot-modules/spring-boot-properties-3/README.md index f9bae5f12c..7c2cdcb572 100644 --- a/spring-boot-modules/spring-boot-properties-3/README.md +++ b/spring-boot-modules/spring-boot-properties-3/README.md @@ -10,6 +10,5 @@ - [Load Spring Boot Properties From a JSON File](https://www.baeldung.com/spring-boot-json-properties) - [IntelliJ – Cannot Resolve Spring Boot Configuration Properties Error](https://www.baeldung.com/intellij-resolve-spring-boot-configuration-properties) - [Log Properties in a Spring Boot Application](https://www.baeldung.com/spring-boot-log-properties) -- [Using Environment Variables in Spring Boot’s application.properties](https://www.baeldung.com/spring-boot-properties-env-variables) - [Loading Multiple YAML Configuration Files in Spring Boot](https://www.baeldung.com/spring-boot-load-multiple-yaml-configuration-files) - More articles: [[<-- Prev]](../spring-boot-properties-2) [[Next -->]](../spring-boot-properties-4) diff --git a/spring-boot-modules/spring-boot-resilience4j/pom.xml b/spring-boot-modules/spring-boot-resilience4j/pom.xml index 609bc7fc49..355ef8f92d 100644 --- a/spring-boot-modules/spring-boot-resilience4j/pom.xml +++ b/spring-boot-modules/spring-boot-resilience4j/pom.xml @@ -30,12 +30,12 @@ io.github.resilience4j resilience4j-spring-boot2 - 2.0.2 + ${resilience4j-spring-boot2.version} com.fasterxml.jackson.datatype jackson-datatype-jsr310 - 2.14.2 + ${jackson-datatype-jsr310.version} org.springframework.boot @@ -45,9 +45,15 @@ com.github.tomakehurst wiremock-jre8 - 2.35.0 + ${wiremock-jre8.version} test + + 2.35.0 + 2.0.2 + 2.15.2 + + \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-resilience4j/src/test/java/com/baeldung/resilience4j/eventendpoints/ResilientAppControllerIntegrationTest.java b/spring-boot-modules/spring-boot-resilience4j/src/test/java/com/baeldung/resilience4j/eventendpoints/ResilientAppControllerIntegrationTest.java index d1951218de..b4378a9248 100644 --- a/spring-boot-modules/spring-boot-resilience4j/src/test/java/com/baeldung/resilience4j/eventendpoints/ResilientAppControllerIntegrationTest.java +++ b/spring-boot-modules/spring-boot-resilience4j/src/test/java/com/baeldung/resilience4j/eventendpoints/ResilientAppControllerIntegrationTest.java @@ -8,12 +8,12 @@ import static org.springframework.http.HttpStatus.*; import com.baeldung.resilience4j.eventendpoints.model.*; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.datatype.jsr310.JSR310Module; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.github.tomakehurst.wiremock.client.WireMock; import com.github.tomakehurst.wiremock.core.WireMockConfiguration; import com.github.tomakehurst.wiremock.junit5.WireMockExtension; import java.net.URI; -import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Map; import java.util.concurrent.*; @@ -29,8 +29,10 @@ import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.test.annotation.DirtiesContext; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) class ResilientAppControllerIntegrationTest { private final Logger LOGGER = LoggerFactory.getLogger(getClass()); @@ -40,7 +42,7 @@ class ResilientAppControllerIntegrationTest { @LocalServerPort private Integer port; private static final ObjectMapper objectMapper = - new ObjectMapper().registerModule(new JSR310Module()); + new ObjectMapper().registerModule(new JavaTimeModule()); @RegisterExtension static WireMockExtension EXTERNAL_SERVICE = @@ -126,8 +128,7 @@ class ResilientAppControllerIntegrationTest { private List getCircuitBreakerEvents() throws Exception { String jsonEventsList = IOUtils.toString( - new URI("http://localhost:" + port + "/actuator/circuitbreakerevents"), - Charset.forName("UTF-8")); + new URI("http://localhost:" + port + "/actuator/circuitbreakerevents"), StandardCharsets.UTF_8); CircuitBreakerEvents circuitBreakerEvents = objectMapper.readValue(jsonEventsList, CircuitBreakerEvents.class); return circuitBreakerEvents.getCircuitBreakerEvents(); @@ -172,8 +173,7 @@ class ResilientAppControllerIntegrationTest { private List getRetryEvents() throws Exception { String jsonEventsList = IOUtils.toString( - new URI("http://localhost:" + port + "/actuator/retryevents"), - Charset.forName("UTF-8")); + new URI("http://localhost:" + port + "/actuator/retryevents"), StandardCharsets.UTF_8); RetryEvents retryEvents = objectMapper.readValue(jsonEventsList, RetryEvents.class); return retryEvents.getRetryEvents(); } @@ -197,8 +197,7 @@ class ResilientAppControllerIntegrationTest { private List getTimeLimiterEvents() throws Exception { String jsonEventsList = IOUtils.toString( - new URI("http://localhost:" + port + "/actuator/timelimiterevents"), - Charset.forName("UTF-8")); + new URI("http://localhost:" + port + "/actuator/timelimiterevents"), StandardCharsets.UTF_8); TimeLimiterEvents timeLimiterEvents = objectMapper.readValue(jsonEventsList, TimeLimiterEvents.class); return timeLimiterEvents.getTimeLimiterEvents(); @@ -256,8 +255,7 @@ class ResilientAppControllerIntegrationTest { private List getBulkheadEvents() throws Exception { String jsonEventsList = IOUtils.toString( - new URI("http://localhost:" + port + "/actuator/bulkheadevents"), - Charset.forName("UTF-8")); + new URI("http://localhost:" + port + "/actuator/bulkheadevents"), StandardCharsets.UTF_8); BulkheadEvents bulkheadEvents = objectMapper.readValue(jsonEventsList, BulkheadEvents.class); return bulkheadEvents.getBulkheadEvents(); } @@ -310,8 +308,7 @@ class ResilientAppControllerIntegrationTest { private List getRateLimiterEvents() throws Exception { String jsonEventsList = IOUtils.toString( - new URI("http://localhost:" + port + "/actuator/ratelimiterevents"), - Charset.forName("UTF-8")); + new URI("http://localhost:" + port + "/actuator/ratelimiterevents"), StandardCharsets.UTF_8); RateLimiterEvents rateLimiterEvents = objectMapper.readValue(jsonEventsList, RateLimiterEvents.class); return rateLimiterEvents.getRateLimiterEvents(); diff --git a/spring-boot-modules/spring-boot-runtime/src/main/java/com/baeldung/spring/boot/management/logging/LoggingController.java b/spring-boot-modules/spring-boot-runtime/src/main/java/com/baeldung/spring/boot/management/logging/LoggingController.java index 5bd15be10c..8b7077a4b5 100644 --- a/spring-boot-modules/spring-boot-runtime/src/main/java/com/baeldung/spring/boot/management/logging/LoggingController.java +++ b/spring-boot-modules/spring-boot-runtime/src/main/java/com/baeldung/spring/boot/management/logging/LoggingController.java @@ -2,6 +2,8 @@ package com.baeldung.spring.boot.management.logging; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.boot.logging.LogLevel; +import org.springframework.boot.logging.LoggingSystem; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -21,4 +23,12 @@ public class LoggingController { return "See the log for details"; } + + @GetMapping("/change-to-error") + public String changeLogLevelToError() { + LoggingSystem system = LoggingSystem.get(LoggingController.class.getClassLoader()); + system.setLogLevel(LoggingController.class.getName(), LogLevel.ERROR); + + return "changed log level to error"; + } } diff --git a/spring-boot-modules/spring-boot-swagger-2/README.md b/spring-boot-modules/spring-boot-swagger-2/README.md index 1b43b09e39..872a4386ea 100644 --- a/spring-boot-modules/spring-boot-swagger-2/README.md +++ b/spring-boot-modules/spring-boot-swagger-2/README.md @@ -2,6 +2,7 @@ - [Swagger: Specify Two Responses with the Same Response Code](https://www.baeldung.com/swagger-two-responses-one-response-code) - [Specify an Array of Strings as Body Parameters in Swagger](https://www.baeldung.com/swagger-body-array-of-strings) -- [Swagger @ApiParam vs @ApiModelProperty](https://www.baeldung.com/swagger-apiparam-vs-apimodelproperty) +- [Swagger @Parameter vs @Schema](https://www.baeldung.com/swagger-parameter-vs-schema) - [Map Date Types With OpenAPI Generator](https://www.baeldung.com/openapi-map-date-types) - [API First Development with Spring Boot and OpenAPI 3.0](https://www.baeldung.com/spring-boot-openapi-api-first-development) +- [Swagger @ApiParam vs @ApiModelProperty](https://www.baeldung.com/swagger-apiparam-vs-apimodelproperty) diff --git a/spring-boot-modules/spring-boot-swagger/README.md b/spring-boot-modules/spring-boot-swagger/README.md index ecf057bda1..75fb450120 100644 --- a/spring-boot-modules/spring-boot-swagger/README.md +++ b/spring-boot-modules/spring-boot-swagger/README.md @@ -3,4 +3,4 @@ - [Generate PDF from Swagger API Documentation](https://www.baeldung.com/swagger-generate-pdf) - [Setting Example and Description with Swagger](https://www.baeldung.com/swagger-set-example-description) - [Document Enum in Swagger](https://www.baeldung.com/swagger-enum) -- [@ApiOperation vs @ApiResponse in Swagger](https://www.baeldung.com/swagger-apioperation-vs-apiresponse) +- [@Operation vs @ApiResponse in Swagger](https://www.baeldung.com/swagger-operation-vs-apiresponse) diff --git a/spring-cloud-modules/pom.xml b/spring-cloud-modules/pom.xml index c4b89d6db0..9c926bbe61 100644 --- a/spring-cloud-modules/pom.xml +++ b/spring-cloud-modules/pom.xml @@ -55,7 +55,8 @@ spring-cloud-sleuth spring-cloud-open-telemetry - spring-cloud-azure + + spring-cloud-openfeign-2 @@ -98,4 +99,4 @@ 3.1.3 - \ No newline at end of file + diff --git a/spring-cloud-modules/spring-cloud-azure/pom.xml b/spring-cloud-modules/spring-cloud-azure/pom.xml index 5271ee7e7e..fd5589555f 100644 --- a/spring-cloud-modules/spring-cloud-azure/pom.xml +++ b/spring-cloud-modules/spring-cloud-azure/pom.xml @@ -52,7 +52,7 @@ 2021.0.3 - 4.0.0 + 5.0.0 \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-azure/src/test/java/com/baeldung/spring/cloud/azure/keyvault/KeyVaultAutoconfiguredClientIntegrationTest.java b/spring-cloud-modules/spring-cloud-azure/src/test/java/com/baeldung/spring/cloud/azure/keyvault/KeyVaultAutoconfiguredClientIntegrationTest.java index d480bc33d4..7236d371c5 100644 --- a/spring-cloud-modules/spring-cloud-azure/src/test/java/com/baeldung/spring/cloud/azure/keyvault/KeyVaultAutoconfiguredClientIntegrationTest.java +++ b/spring-cloud-modules/spring-cloud-azure/src/test/java/com/baeldung/spring/cloud/azure/keyvault/KeyVaultAutoconfiguredClientIntegrationTest.java @@ -11,7 +11,7 @@ import org.springframework.boot.test.context.SpringBootTest; import com.baeldung.spring.cloud.azure.keyvault.service.KeyVaultAutoconfiguredClient; @SpringBootTest(classes = Application.class) -public class KeyVaultAutoconfiguredClientIntegrationTest { +class KeyVaultAutoconfiguredClientIntegrationTest { @Autowired @Qualifier(value = "KeyVaultAutoconfiguredClient") @@ -22,5 +22,4 @@ public class KeyVaultAutoconfiguredClientIntegrationTest { String secretKey = "mySecret"; Assertions.assertThrows(NoSuchElementException.class, () -> keyVaultAutoconfiguredClient.getSecret(secretKey)); } - } diff --git a/spring-cloud-modules/spring-cloud-azure/src/test/resources/application.yaml b/spring-cloud-modules/spring-cloud-azure/src/test/resources/application.yaml index 88c54b32eb..3e9a0b5e87 100644 --- a/spring-cloud-modules/spring-cloud-azure/src/test/resources/application.yaml +++ b/spring-cloud-modules/spring-cloud-azure/src/test/resources/application.yaml @@ -12,10 +12,10 @@ spring: endpoint: https://spring-cloud-azure.vault.azure.net/ azure: keyvault: - vaultUrl: myVaultUrl - tenantId: myTenantId - clientId: myClientId - clientSecret: myClientSecret + vaultUrl: {$myVaultUrl} + tenantId: {$myTenantId} + clientId: {$myClientId} + clientSecret: {$myClientSecret} database: secret: value: my-database-secret \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-server/src/test/resources/logback-test.xml b/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-server/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..c270ba92f6 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-server/src/test/resources/logback-test.xml @@ -0,0 +1,17 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-netflix-feign/src/test/java/com/baeldung/cloud/netflix/feign/NetflixFeignUnitTest.java b/spring-cloud-modules/spring-cloud-netflix-feign/src/test/java/com/baeldung/cloud/netflix/feign/NetflixFeignIntegrationTest.java similarity index 98% rename from spring-cloud-modules/spring-cloud-netflix-feign/src/test/java/com/baeldung/cloud/netflix/feign/NetflixFeignUnitTest.java rename to spring-cloud-modules/spring-cloud-netflix-feign/src/test/java/com/baeldung/cloud/netflix/feign/NetflixFeignIntegrationTest.java index 9ee925201d..1cba547e0e 100644 --- a/spring-cloud-modules/spring-cloud-netflix-feign/src/test/java/com/baeldung/cloud/netflix/feign/NetflixFeignUnitTest.java +++ b/spring-cloud-modules/spring-cloud-netflix-feign/src/test/java/com/baeldung/cloud/netflix/feign/NetflixFeignIntegrationTest.java @@ -31,7 +31,7 @@ import static org.junit.Assert.assertTrue; @RunWith(SpringRunner.class) @SpringBootTest(properties = {"external.api.url=http://localhost:${wiremock.server.port}"}) @AutoConfigureWireMock(port = 0) -public class NetflixFeignUnitTest { +public class NetflixFeignIntegrationTest { @Autowired private JSONPlaceHolderService jsonPlaceHolderService; diff --git a/spring-cloud-modules/spring-cloud-netflix-feign/src/test/resources/logback-test.xml b/spring-cloud-modules/spring-cloud-netflix-feign/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..83bf131763 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-netflix-feign/src/test/resources/logback-test.xml @@ -0,0 +1,19 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-openfeign-2/README.md b/spring-cloud-modules/spring-cloud-openfeign-2/README.md new file mode 100644 index 0000000000..05ca78b6fd --- /dev/null +++ b/spring-cloud-modules/spring-cloud-openfeign-2/README.md @@ -0,0 +1,6 @@ +## Relevant Articles +- [Setup Http Patch Request With OpenFeign](https://www.baeldung.com/openfeign-http-patch-request) +- [Introduction to Spring Cloud OpenFeign](https://www.baeldung.com/spring-cloud-openfeign) +- [Feign Logging Configuration](https://www.baeldung.com/java-feign-logging) +- [Configuring Spring Cloud FeignClient URL](https://www.baeldung.com/spring-cloud-feignclient-url) +- More articles: [[<-- prev]](/spring-cloud-modules/spring-cloud-openfeign) diff --git a/spring-cloud-modules/spring-cloud-openfeign-2/pom.xml b/spring-cloud-modules/spring-cloud-openfeign-2/pom.xml new file mode 100644 index 0000000000..ebfbc02755 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-openfeign-2/pom.xml @@ -0,0 +1,61 @@ + + + 4.0.0 + com.baeldung.cloud + spring-cloud-openfeign-2 + spring-cloud-openfeign-2 + OpenFeign project for Spring Boot + + + com.baeldung.spring.cloud + spring-cloud-modules + 1.0.0-SNAPSHOT + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.cloud + spring-cloud-starter-openfeign + + + io.github.openfeign + feign-okhttp + + + com.github.tomakehurst + wiremock-jre8 + ${wire.mock.version} + test + + + org.junit.jupiter + junit-jupiter-engine + ${junit-jupiter.version} + test + + + + + 2021.0.7 + 2.35.0 + + + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/ExampleApplication.java b/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/ExampleApplication.java new file mode 100644 index 0000000000..c7f07f6667 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/ExampleApplication.java @@ -0,0 +1,16 @@ +package com.baeldung.cloud.openfeign; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.openfeign.EnableFeignClients; + +@SpringBootApplication +@EnableFeignClients +public class ExampleApplication { + + public static void main(String[] args) { + SpringApplication.run(ExampleApplication.class, args); + } + +} + diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/client/AlbumClient.java b/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/client/AlbumClient.java similarity index 99% rename from spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/client/AlbumClient.java rename to spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/client/AlbumClient.java index b1db2dbcab..f7c74b0944 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/client/AlbumClient.java +++ b/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/client/AlbumClient.java @@ -1,10 +1,11 @@ package com.baeldung.cloud.openfeign.client; -import com.baeldung.cloud.openfeign.model.Album; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; +import com.baeldung.cloud.openfeign.model.Album; + @FeignClient(name = "albumClient", url = "https://jsonplaceholder.typicode.com/albums/") public interface AlbumClient { @GetMapping(value = "/{id}") diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/client/JSONPlaceHolderClient.java b/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/client/JSONPlaceHolderClient.java similarity index 99% rename from spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/client/JSONPlaceHolderClient.java rename to spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/client/JSONPlaceHolderClient.java index bdbe6efeeb..06ce26fc06 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/client/JSONPlaceHolderClient.java +++ b/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/client/JSONPlaceHolderClient.java @@ -1,14 +1,15 @@ package com.baeldung.cloud.openfeign.client; -import com.baeldung.cloud.openfeign.config.ClientConfiguration; -import com.baeldung.cloud.openfeign.hystrix.JSONPlaceHolderFallback; -import com.baeldung.cloud.openfeign.model.Post; +import java.util.List; + import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; -import java.util.List; +import com.baeldung.cloud.openfeign.config.ClientConfiguration; +import com.baeldung.cloud.openfeign.hystrix.JSONPlaceHolderFallback; +import com.baeldung.cloud.openfeign.model.Post; @FeignClient(value = "jplaceholder", url = "https://jsonplaceholder.typicode.com/", diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/client/PostClient.java b/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/client/PostClient.java similarity index 99% rename from spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/client/PostClient.java rename to spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/client/PostClient.java index e8e773b6a1..ba90830bb2 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/client/PostClient.java +++ b/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/client/PostClient.java @@ -1,10 +1,11 @@ package com.baeldung.cloud.openfeign.client; -import com.baeldung.cloud.openfeign.model.Post; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; +import com.baeldung.cloud.openfeign.model.Post; + @FeignClient(name = "postClient", url = "${spring.cloud.openfeign.client.config.postClient.url}") public interface PostClient { @GetMapping(value = "/{id}") diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/client/TodoClient.java b/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/client/TodoClient.java similarity index 99% rename from spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/client/TodoClient.java rename to spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/client/TodoClient.java index c768ef6b5f..a3be43de3e 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/client/TodoClient.java +++ b/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/client/TodoClient.java @@ -1,10 +1,12 @@ package com.baeldung.cloud.openfeign.client; -import com.baeldung.cloud.openfeign.model.Todo; -import feign.RequestLine; +import java.net.URI; + import org.springframework.cloud.openfeign.FeignClient; -import java.net.URI; +import com.baeldung.cloud.openfeign.model.Todo; + +import feign.RequestLine; @FeignClient(name = "todoClient") public interface TodoClient { diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/config/ClientConfiguration.java b/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/config/ClientConfiguration.java similarity index 100% rename from spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/config/ClientConfiguration.java rename to spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/config/ClientConfiguration.java diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/config/CustomErrorDecoder.java b/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/config/CustomErrorDecoder.java similarity index 99% rename from spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/config/CustomErrorDecoder.java rename to spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/config/CustomErrorDecoder.java index 303a5db526..4b264e0eda 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/config/CustomErrorDecoder.java +++ b/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/config/CustomErrorDecoder.java @@ -2,6 +2,7 @@ package com.baeldung.cloud.openfeign.config; import com.baeldung.cloud.openfeign.exception.BadRequestException; import com.baeldung.cloud.openfeign.exception.NotFoundException; + import feign.Response; import feign.codec.ErrorDecoder; diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/config/DynamicUrlInterceptor.java b/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/config/DynamicUrlInterceptor.java similarity index 100% rename from spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/config/DynamicUrlInterceptor.java rename to spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/config/DynamicUrlInterceptor.java index 286426edb3..0fb12855b2 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/config/DynamicUrlInterceptor.java +++ b/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/config/DynamicUrlInterceptor.java @@ -1,10 +1,10 @@ package com.baeldung.cloud.openfeign.config; +import java.util.function.Supplier; + import feign.RequestInterceptor; import feign.RequestTemplate; -import java.util.function.Supplier; - public class DynamicUrlInterceptor implements RequestInterceptor { private final Supplier urlSupplier; diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/controller/ConfigureFeignUrlController.java b/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/controller/ConfigureFeignUrlController.java similarity index 99% rename from spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/controller/ConfigureFeignUrlController.java rename to spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/controller/ConfigureFeignUrlController.java index ca49bca605..5358ec1a60 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/controller/ConfigureFeignUrlController.java +++ b/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/controller/ConfigureFeignUrlController.java @@ -1,16 +1,7 @@ package com.baeldung.cloud.openfeign.controller; -import com.baeldung.cloud.openfeign.config.DynamicUrlInterceptor; -import com.baeldung.cloud.openfeign.client.AlbumClient; -import com.baeldung.cloud.openfeign.client.PostClient; -import com.baeldung.cloud.openfeign.client.TodoClient; -import com.baeldung.cloud.openfeign.model.Album; -import com.baeldung.cloud.openfeign.model.Post; -import com.baeldung.cloud.openfeign.model.Todo; -import feign.Feign; -import feign.Target; -import feign.codec.Decoder; -import feign.codec.Encoder; +import java.net.URI; + import org.springframework.beans.factory.ObjectFactory; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.http.HttpMessageConverters; @@ -24,7 +15,18 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; -import java.net.URI; +import com.baeldung.cloud.openfeign.client.AlbumClient; +import com.baeldung.cloud.openfeign.client.PostClient; +import com.baeldung.cloud.openfeign.client.TodoClient; +import com.baeldung.cloud.openfeign.config.DynamicUrlInterceptor; +import com.baeldung.cloud.openfeign.model.Album; +import com.baeldung.cloud.openfeign.model.Post; +import com.baeldung.cloud.openfeign.model.Todo; + +import feign.Feign; +import feign.Target; +import feign.codec.Decoder; +import feign.codec.Encoder; @RestController @Import(FeignClientsConfiguration.class) diff --git a/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/exception/BadRequestException.java b/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/exception/BadRequestException.java new file mode 100644 index 0000000000..50200957ad --- /dev/null +++ b/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/exception/BadRequestException.java @@ -0,0 +1,21 @@ +package com.baeldung.cloud.openfeign.exception; + +public class BadRequestException extends Exception { + + public BadRequestException() { + } + + public BadRequestException(String message) { + super(message); + } + + public BadRequestException(Throwable cause) { + super(cause); + } + + @Override + public String toString() { + return "BadRequestException: "+getMessage(); + } + +} diff --git a/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/exception/NotFoundException.java b/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/exception/NotFoundException.java new file mode 100644 index 0000000000..19f6204b86 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/exception/NotFoundException.java @@ -0,0 +1,18 @@ +package com.baeldung.cloud.openfeign.exception; + +public class NotFoundException extends Exception { + + public NotFoundException(String message) { + super(message); + } + + public NotFoundException(Throwable cause) { + super(cause); + } + + @Override + public String toString() { + return "NotFoundException: " + getMessage(); + } + +} diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/hystrix/JSONPlaceHolderFallback.java b/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/hystrix/JSONPlaceHolderFallback.java similarity index 99% rename from spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/hystrix/JSONPlaceHolderFallback.java rename to spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/hystrix/JSONPlaceHolderFallback.java index 1aa3112320..dc23844a00 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/hystrix/JSONPlaceHolderFallback.java +++ b/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/hystrix/JSONPlaceHolderFallback.java @@ -1,12 +1,13 @@ package com.baeldung.cloud.openfeign.hystrix; -import com.baeldung.cloud.openfeign.client.JSONPlaceHolderClient; -import com.baeldung.cloud.openfeign.model.Post; -import org.springframework.stereotype.Component; - import java.util.Collections; import java.util.List; +import org.springframework.stereotype.Component; + +import com.baeldung.cloud.openfeign.client.JSONPlaceHolderClient; +import com.baeldung.cloud.openfeign.model.Post; + @Component public class JSONPlaceHolderFallback implements JSONPlaceHolderClient { diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/model/Album.java b/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/model/Album.java similarity index 100% rename from spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/model/Album.java rename to spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/model/Album.java diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/model/Post.java b/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/model/Post.java similarity index 100% rename from spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/model/Post.java rename to spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/model/Post.java diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/model/Todo.java b/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/model/Todo.java similarity index 100% rename from spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/model/Todo.java rename to spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/model/Todo.java diff --git a/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/patcherror/client/UserClient.java b/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/patcherror/client/UserClient.java new file mode 100644 index 0000000000..02e3fbec26 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/patcherror/client/UserClient.java @@ -0,0 +1,16 @@ +package com.baeldung.cloud.openfeign.patcherror.client; + +import com.baeldung.cloud.openfeign.patcherror.model.User; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +@FeignClient(name = "user-client", url = "${user.api.url}") +public interface UserClient { + + @RequestMapping(value = "{userId}", method = RequestMethod.PATCH) + User updateUser(@PathVariable(value = "userId") String userId, @RequestBody User user); + +} \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/patcherror/model/User.java b/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/patcherror/model/User.java new file mode 100644 index 0000000000..dbbf9b7a58 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/patcherror/model/User.java @@ -0,0 +1,34 @@ +package com.baeldung.cloud.openfeign.patcherror.model; + +public class User { + + private String userId; + + private String userName; + + private String email; + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } +} diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/service/JSONPlaceHolderService.java b/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/service/JSONPlaceHolderService.java similarity index 100% rename from spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/service/JSONPlaceHolderService.java rename to spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/service/JSONPlaceHolderService.java index 16e9b1dbde..9a3602df5b 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/service/JSONPlaceHolderService.java +++ b/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/service/JSONPlaceHolderService.java @@ -1,9 +1,9 @@ package com.baeldung.cloud.openfeign.service; -import com.baeldung.cloud.openfeign.model.Post; - import java.util.List; +import com.baeldung.cloud.openfeign.model.Post; + public interface JSONPlaceHolderService { List getPosts(); diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/service/impl/JSONPlaceHolderServiceImpl.java b/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/service/impl/JSONPlaceHolderServiceImpl.java similarity index 99% rename from spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/service/impl/JSONPlaceHolderServiceImpl.java rename to spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/service/impl/JSONPlaceHolderServiceImpl.java index 30348db3c2..4070396991 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/service/impl/JSONPlaceHolderServiceImpl.java +++ b/spring-cloud-modules/spring-cloud-openfeign-2/src/main/java/com/baeldung/cloud/openfeign/service/impl/JSONPlaceHolderServiceImpl.java @@ -1,12 +1,13 @@ package com.baeldung.cloud.openfeign.service.impl; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + import com.baeldung.cloud.openfeign.client.JSONPlaceHolderClient; import com.baeldung.cloud.openfeign.model.Post; import com.baeldung.cloud.openfeign.service.JSONPlaceHolderService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import java.util.List; @Service public class JSONPlaceHolderServiceImpl implements JSONPlaceHolderService { diff --git a/spring-cloud-modules/spring-cloud-openfeign-2/src/main/resources/application.properties b/spring-cloud-modules/spring-cloud-openfeign-2/src/main/resources/application.properties new file mode 100644 index 0000000000..aa0dc6a382 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-openfeign-2/src/main/resources/application.properties @@ -0,0 +1,10 @@ +spring.application.name=openfeign +user.api.url=http://localhost:8082/api/user +feign.okhttp.enabled=true + +server.port=8085 +spring.main.allow-bean-definition-overriding=true +logging.level.com.baeldung.cloud.openfeign.client=DEBUG +feign.hystrix.enabled=true + +spring.cloud.openfeign.client.config.postClient.url=https://jsonplaceholder.typicode.com/posts/ \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/OpenFeignManualTest.java b/spring-cloud-modules/spring-cloud-openfeign-2/src/test/java/com/baeldung/cloud/openfeign/OpenFeignManualTest.java similarity index 99% rename from spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/OpenFeignManualTest.java rename to spring-cloud-modules/spring-cloud-openfeign-2/src/test/java/com/baeldung/cloud/openfeign/OpenFeignManualTest.java index 4eb014de96..b491d621ee 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/OpenFeignManualTest.java +++ b/spring-cloud-modules/spring-cloud-openfeign-2/src/test/java/com/baeldung/cloud/openfeign/OpenFeignManualTest.java @@ -1,17 +1,18 @@ package com.baeldung.cloud.openfeign; -import com.baeldung.cloud.openfeign.model.Post; -import com.baeldung.cloud.openfeign.service.JSONPlaceHolderService; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; + +import java.util.List; + import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; -import java.util.List; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; +import com.baeldung.cloud.openfeign.model.Post; +import com.baeldung.cloud.openfeign.service.JSONPlaceHolderService; @RunWith(SpringRunner.class) @SpringBootTest diff --git a/spring-cloud-modules/spring-cloud-openfeign-2/src/test/java/com/baeldung/cloud/openfeign/SpringContextTest.java b/spring-cloud-modules/spring-cloud-openfeign-2/src/test/java/com/baeldung/cloud/openfeign/SpringContextTest.java new file mode 100644 index 0000000000..4bf35f74f4 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-openfeign-2/src/test/java/com/baeldung/cloud/openfeign/SpringContextTest.java @@ -0,0 +1,16 @@ +package com.baeldung.cloud.openfeign; + + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = ExampleApplication.class) +public class SpringContextTest { + + @Test + public void whenSpringContextIsBootstrapped_thenNoExceptions() { + } +} diff --git a/spring-cloud-modules/spring-cloud-openfeign-2/src/test/java/com/baeldung/cloud/openfeign/patcherror/client/UserClientUnitTest.java b/spring-cloud-modules/spring-cloud-openfeign-2/src/test/java/com/baeldung/cloud/openfeign/patcherror/client/UserClientUnitTest.java new file mode 100644 index 0000000000..fefaef01cc --- /dev/null +++ b/spring-cloud-modules/spring-cloud-openfeign-2/src/test/java/com/baeldung/cloud/openfeign/patcherror/client/UserClientUnitTest.java @@ -0,0 +1,75 @@ +package com.baeldung.cloud.openfeign.patcherror.client; + +import com.baeldung.cloud.openfeign.ExampleApplication; +import com.baeldung.cloud.openfeign.patcherror.model.User; + +import com.github.tomakehurst.wiremock.WireMockServer; +import feign.FeignException; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.HttpStatus; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import static com.github.tomakehurst.wiremock.client.WireMock.*; +import static org.junit.jupiter.api.Assertions.*; + +@ExtendWith(SpringExtension.class) +@SpringBootTest(classes = ExampleApplication.class) +public class UserClientUnitTest { + + @Autowired + private UserClient userClient; + + private WireMockServer wireMockServer; + + @BeforeEach + public void startWireMockServer() { + wireMockServer = new WireMockServer(8082); + configureFor("localhost", 8082); + wireMockServer.start(); + } + + @AfterEach + public void stopWireMockServer() { + wireMockServer.stop(); + } + + @Test + void givenUserExistsAndIsValid_whenUpdateUserCalled_thenReturnSuccess() { + String updatedUserResponse = "{\n" + + " \"userId\": 100001,\n" + + " \"userName\": \"name\",\n" + + " \"email\": \"updated-email@mail.in\"\n" + + "}"; + + stubFor(patch(urlEqualTo("/api/user/".concat("100001"))) + .willReturn(aResponse().withStatus(HttpStatus.OK.value()) + .withHeader("Content-Type", "application/json") + .withBody(updatedUserResponse))); + + User user = new User(); + user.setUserId("100001"); + user.setEmail("updated-email@mail.in"); + User updatedUser = userClient.updateUser("100001", user); + + assertEquals(user.getUserId(), updatedUser.getUserId()); + assertEquals(user.getEmail(), updatedUser.getEmail()); + } + + @Test + void givenUserNotFound_whenUpdateUserCalled_thenReturnNotFoundErrorAndFeignException() { + User user = new User(); + user.setUserId("100002"); + user.setEmail("updated-email@mail.in"); + + stubFor(patch(urlEqualTo("/api/user/".concat("100002"))) + .willReturn(aResponse().withStatus(404))); + + assertThrows(FeignException.class, () -> userClient.updateUser("100002", user)); + } +} diff --git a/spring-cloud-modules/spring-cloud-openfeign/README.md b/spring-cloud-modules/spring-cloud-openfeign/README.md index edda9a8f80..deef716ff4 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/README.md +++ b/spring-cloud-modules/spring-cloud-openfeign/README.md @@ -1,14 +1,10 @@ ### Relevant Articles: -- [Introduction to Spring Cloud OpenFeign](https://www.baeldung.com/spring-cloud-openfeign) - [Differences Between Netflix Feign and OpenFeign](https://www.baeldung.com/netflix-feign-vs-openfeign) - [Provide an OAuth2 Token to a Feign Client](https://www.baeldung.com/spring-cloud-feign-oauth-token) -- [Propagating Exceptions With OpenFeign and Spring](https://www.baeldung.com/spring-openfeign-propagate-exception) - [Feign Client Exception Handling](https://www.baeldung.com/java-feign-client-exception-handling) - [File Upload With Open Feign](https://www.baeldung.com/java-feign-file-upload) -- [Feign Logging Configuration](https://www.baeldung.com/java-feign-logging) - [Retrieve Original Message From Feign ErrorDecoder](https://www.baeldung.com/feign-retrieve-original-message) -- [RequestLine with Feign Client](https://www.baeldung.com/feign-requestline) - [Propagating Exceptions With OpenFeign and Spring](https://www.baeldung.com/spring-openfeign-propagate-exception) - [Post form-url-encoded Data with Spring Cloud Feign](https://www.baeldung.com/spring-cloud-post-form-url-encoded-data) -- [Configuring Spring Cloud FeignClient URL](https://www.baeldung.com/spring-cloud-feignclient-url) +- More articles: [[next -->]](/spring-cloud-modules/spring-cloud-openfeign-2) diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/main/resources/application.properties b/spring-cloud-modules/spring-cloud-openfeign/src/main/resources/application.properties index f4ea32483d..f370752438 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/main/resources/application.properties +++ b/spring-cloud-modules/spring-cloud-openfeign/src/main/resources/application.properties @@ -7,6 +7,4 @@ feign.hystrix.enabled=true spring.security.oauth2.client.registration.keycloak.authorization-grant-type=client_credentials spring.security.oauth2.client.registration.keycloak.client-id=payment-app spring.security.oauth2.client.registration.keycloak.client-secret=863e9de4-33d4-4471-b35e-f8d2434385bb -spring.security.oauth2.client.provider.keycloak.token-uri=http://localhost:8083/auth/realms/master/protocol/openid-connect/token - -spring.cloud.openfeign.client.config.postClient.url=https://jsonplaceholder.typicode.com/posts/ \ No newline at end of file +spring.security.oauth2.client.provider.keycloak.token-uri=http://localhost:8083/auth/realms/master/protocol/openid-connect/token \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/client/FormClientUnitTest.java b/spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/client/FormClientIntegrationTest.java similarity index 98% rename from spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/client/FormClientUnitTest.java rename to spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/client/FormClientIntegrationTest.java index f374e8e0bd..390deb3dfb 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/client/FormClientUnitTest.java +++ b/spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/client/FormClientIntegrationTest.java @@ -29,7 +29,7 @@ import lombok.extern.slf4j.Slf4j; @ExtendWith(SpringExtension.class) @SpringBootTest @Slf4j -class FormClientUnitTest { +class FormClientIntegrationTest { private static WireMockServer wireMockServer; diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/customizederrorhandling/client/ProductClientUnitTest.java b/spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/customizederrorhandling/client/ProductClientIntegrationTest.java similarity index 98% rename from spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/customizederrorhandling/client/ProductClientUnitTest.java rename to spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/customizederrorhandling/client/ProductClientIntegrationTest.java index 385ce900f5..c0d1227f62 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/customizederrorhandling/client/ProductClientUnitTest.java +++ b/spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/customizederrorhandling/client/ProductClientIntegrationTest.java @@ -22,7 +22,7 @@ import com.github.tomakehurst.wiremock.WireMockServer; @RunWith(SpringRunner.class) @SpringBootTest(classes = ExampleApplication.class) -public class ProductClientUnitTest { +public class ProductClientIntegrationTest { @Autowired private ProductClient productClient; diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/customizederrorhandling/controller/ProductControllerUnitTest.java b/spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/customizederrorhandling/controller/ProductControllerIntegrationTest.java similarity index 98% rename from spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/customizederrorhandling/controller/ProductControllerUnitTest.java rename to spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/customizederrorhandling/controller/ProductControllerIntegrationTest.java index 3d103d1333..d0302d3daa 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/customizederrorhandling/controller/ProductControllerUnitTest.java +++ b/spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/customizederrorhandling/controller/ProductControllerIntegrationTest.java @@ -31,7 +31,7 @@ import com.github.tomakehurst.wiremock.client.WireMock; @RunWith(SpringRunner.class) @WebMvcTest(ProductController.class) @ImportAutoConfiguration({FeignAutoConfiguration.class}) -public class ProductControllerUnitTest { +public class ProductControllerIntegrationTest { @Autowired private ProductClient productClient; diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/defaulterrorhandling/client/ProductClientUnitTest.java b/spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/defaulterrorhandling/client/ProductClientIntegrationTest.java similarity index 98% rename from spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/defaulterrorhandling/client/ProductClientUnitTest.java rename to spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/defaulterrorhandling/client/ProductClientIntegrationTest.java index ed4cf75890..09c9466fbf 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/defaulterrorhandling/client/ProductClientUnitTest.java +++ b/spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/defaulterrorhandling/client/ProductClientIntegrationTest.java @@ -25,7 +25,7 @@ import feign.FeignException; @RunWith(SpringRunner.class) @SpringBootTest(classes = ExampleApplication.class) -public class ProductClientUnitTest { +public class ProductClientIntegrationTest { @Autowired private ProductClient productClient; diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/defaulterrorhandling/controller/ProductControllerUnitTest.java b/spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/defaulterrorhandling/controller/ProductControllerIntegrationTest.java similarity index 98% rename from spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/defaulterrorhandling/controller/ProductControllerUnitTest.java rename to spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/defaulterrorhandling/controller/ProductControllerIntegrationTest.java index 7271aa2672..cd776a0eea 100644 --- a/spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/defaulterrorhandling/controller/ProductControllerUnitTest.java +++ b/spring-cloud-modules/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/defaulterrorhandling/controller/ProductControllerIntegrationTest.java @@ -29,7 +29,7 @@ import com.github.tomakehurst.wiremock.client.WireMock; @WebMvcTest(ProductController.class) @ImportAutoConfiguration({FeignAutoConfiguration.class, TestControllerAdvice.class}) @EnableWebMvc -public class ProductControllerUnitTest { +public class ProductControllerIntegrationTest { @Autowired private ProductClient productClient; diff --git a/spring-cloud-modules/spring-cloud-openfeign/src/test/resources/logback-test.xml b/spring-cloud-modules/spring-cloud-openfeign/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..612e4e0e9d --- /dev/null +++ b/spring-cloud-modules/spring-cloud-openfeign/src/test/resources/logback-test.xml @@ -0,0 +1,19 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-task/springcloudtaskbatch/src/test/resources/logback-test.xml b/spring-cloud-modules/spring-cloud-task/springcloudtaskbatch/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..0e8e2b4a06 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-task/springcloudtaskbatch/src/test/resources/logback-test.xml @@ -0,0 +1,15 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-zookeeper/spring-cloud-zookeeper-greeting/src/test/resources/logback-test.xml b/spring-cloud-modules/spring-cloud-zookeeper/spring-cloud-zookeeper-greeting/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..98a596c8ad --- /dev/null +++ b/spring-cloud-modules/spring-cloud-zookeeper/spring-cloud-zookeeper-greeting/src/test/resources/logback-test.xml @@ -0,0 +1,15 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-zookeeper/spring-cloud-zookeeper-helloworld/src/test/resources/logback-test.xml b/spring-cloud-modules/spring-cloud-zookeeper/spring-cloud-zookeeper-helloworld/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..98a596c8ad --- /dev/null +++ b/spring-cloud-modules/spring-cloud-zookeeper/spring-cloud-zookeeper-helloworld/src/test/resources/logback-test.xml @@ -0,0 +1,15 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-zuul-eureka-integration/eureka-server/src/test/resources/logback-test.xml b/spring-cloud-modules/spring-cloud-zuul-eureka-integration/eureka-server/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..a037859a0c --- /dev/null +++ b/spring-cloud-modules/spring-cloud-zuul-eureka-integration/eureka-server/src/test/resources/logback-test.xml @@ -0,0 +1,15 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + \ No newline at end of file diff --git a/spring-core-4/pom.xml b/spring-core-4/pom.xml index 6ba8357a0e..492a2ec5a2 100644 --- a/spring-core-4/pom.xml +++ b/spring-core-4/pom.xml @@ -71,6 +71,11 @@ javax.annotation-api ${annotation-api.version} + + org.apache.commons + commons-text + ${apache-commons-text.version} + @@ -80,6 +85,7 @@ 4.0.0 1.3.2 3.3.2 + 1.10.0 \ No newline at end of file diff --git a/spring-core-4/src/main/java/com/baeldung/escapehtml/HtmlEscapeUtils.java b/spring-core-4/src/main/java/com/baeldung/escapehtml/HtmlEscapeUtils.java new file mode 100644 index 0000000000..b7da2eefb8 --- /dev/null +++ b/spring-core-4/src/main/java/com/baeldung/escapehtml/HtmlEscapeUtils.java @@ -0,0 +1,21 @@ +package com.baeldung.escapehtml; + +import com.google.common.html.HtmlEscapers; +import org.apache.commons.text.StringEscapeUtils; +import org.springframework.web.util.HtmlUtils; + +public class HtmlEscapeUtils { + + public static String escapeWithApacheCommons(String input) { + return StringEscapeUtils.escapeHtml4(input); + } + + public static String escapeWithGuava(String input) { + return HtmlEscapers.htmlEscaper().escape(input); + } + + public static String escapeWithSpring(String input) { + return HtmlUtils.htmlEscape(input); + } + +} diff --git a/spring-core-4/src/test/java/com/baeldung/escapehtml/HtmlEscapeUnitTest.java b/spring-core-4/src/test/java/com/baeldung/escapehtml/HtmlEscapeUnitTest.java new file mode 100644 index 0000000000..92d1138869 --- /dev/null +++ b/spring-core-4/src/test/java/com/baeldung/escapehtml/HtmlEscapeUnitTest.java @@ -0,0 +1,43 @@ +package com.baeldung.escapehtml; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class HtmlEscapeUnitTest { + + @Test + public void whenInputContainAmpersand_thenEscape() { + String input = "AT&T"; + String expected = "AT&T"; + assertEquals(expected, HtmlEscapeUtils.escapeWithApacheCommons(input)); + assertEquals(expected, HtmlEscapeUtils.escapeWithGuava(input)); + assertEquals(expected, HtmlEscapeUtils.escapeWithSpring(input)); + } + + @Test + public void whenInputContainDoubleQuotes_thenEscape() { + String input = "She said, \"Hello!\""; + String expected = "She said, "Hello!""; + assertEquals(expected, HtmlEscapeUtils.escapeWithApacheCommons(input)); + assertEquals(expected, HtmlEscapeUtils.escapeWithGuava(input)); + assertEquals(expected, HtmlEscapeUtils.escapeWithSpring(input)); + } + + @Test + public void whenInputContainManyHtmlSymbols_thenEscape() { + String input = "

This is a test string.

"; + String expected = "<p>This is a <strong>test</strong> string.</p>"; + assertEquals(expected, HtmlEscapeUtils.escapeWithApacheCommons(input)); + assertEquals(expected, HtmlEscapeUtils.escapeWithGuava(input)); + assertEquals(expected, HtmlEscapeUtils.escapeWithSpring(input)); + } + + @Test + public void whenInputContainNoHtmlSymbols_thenEscape() { + String input = "This is a plain text."; + assertEquals(input, HtmlEscapeUtils.escapeWithApacheCommons(input)); + assertEquals(input, HtmlEscapeUtils.escapeWithGuava(input)); + assertEquals(input, HtmlEscapeUtils.escapeWithSpring(input)); + } +} diff --git a/spring-ejb-modules/pom.xml b/spring-ejb-modules/pom.xml index 1ebfb66c32..c5d04dab25 100755 --- a/spring-ejb-modules/pom.xml +++ b/spring-ejb-modules/pom.xml @@ -17,6 +17,7 @@ + spring-ejb-remote spring-ejb-client wildfly diff --git a/spring-integration/pom.xml b/spring-integration/pom.xml index 9882e02c57..abf5cfb3d6 100644 --- a/spring-integration/pom.xml +++ b/spring-integration/pom.xml @@ -90,6 +90,11 @@ jaxb-api ${jaxb-api.version} + + org.postgresql + postgresql + ${postgresql.version} + @@ -126,6 +131,7 @@ 1.1.1 2.10 2.3.0 + 42.3.8 \ No newline at end of file diff --git a/spring-integration/src/main/java/com/baeldung/domain/Order.java b/spring-integration/src/main/java/com/baeldung/domain/Order.java new file mode 100644 index 0000000000..3e26c00f4a --- /dev/null +++ b/spring-integration/src/main/java/com/baeldung/domain/Order.java @@ -0,0 +1,92 @@ +package com.baeldung.domain; + +import java.math.BigDecimal; + +public class Order { + + private Long id; + private String symbol; + private OrderType orderType; + private BigDecimal price; + private BigDecimal quantity; + + public Order() {} + + public Order(Long id, String symbol, OrderType orderType, BigDecimal price, BigDecimal quantity) { + this.id = id; + this.symbol = symbol; + this.orderType = orderType; + this.price = price; + this.quantity = quantity; + } + + /** + * @return the id + */ + public Long getId() { + return id; + } + + /** + * @param id the id to set + */ + public void setId(Long id) { + this.id = id; + } + + /** + * @return the symbol + */ + public String getSymbol() { + return symbol; + } + + /** + * @param symbol the symbol to set + */ + public void setSymbol(String symbol) { + this.symbol = symbol; + } + + /** + * @return the orderType + */ + public OrderType getOrderType() { + return orderType; + } + + /** + * @param orderType the orderType to set + */ + public void setOrderType(OrderType orderType) { + this.orderType = orderType; + } + + /** + * @return the price + */ + public BigDecimal getPrice() { + return price; + } + + /** + * @param price the price to set + */ + public void setPrice(BigDecimal price) { + this.price = price; + } + + /** + * @return the quantity + */ + public BigDecimal getQuantity() { + return quantity; + } + + /** + * @param quantity the quantity to set + */ + public void setQuantity(BigDecimal quantity) { + this.quantity = quantity; + } +} diff --git a/spring-integration/src/main/java/com/baeldung/domain/OrderType.java b/spring-integration/src/main/java/com/baeldung/domain/OrderType.java new file mode 100644 index 0000000000..bb1e5b6abc --- /dev/null +++ b/spring-integration/src/main/java/com/baeldung/domain/OrderType.java @@ -0,0 +1,16 @@ +package com.baeldung.domain; + + +public enum OrderType { + BUY('B'), + SELL('S'); + private final char code; + + OrderType(char code) { + this.code = code; + } + + public char getCode() { + return code; + } +} diff --git a/spring-integration/src/main/java/com/baeldung/subflows/postgresqlnotify/PostgresSubscribableChannel.java b/spring-integration/src/main/java/com/baeldung/subflows/postgresqlnotify/PostgresSubscribableChannel.java new file mode 100644 index 0000000000..3ee77f69dc --- /dev/null +++ b/spring-integration/src/main/java/com/baeldung/subflows/postgresqlnotify/PostgresSubscribableChannel.java @@ -0,0 +1,217 @@ +package com.baeldung.subflows.postgresqlnotify; + +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; + +import javax.sql.DataSource; + +import org.postgresql.PGConnection; +import org.postgresql.PGNotification; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.task.SimpleAsyncTaskExecutor; +import org.springframework.integration.channel.AbstractSubscribableChannel; +import org.springframework.integration.dispatcher.MessageDispatcher; +import org.springframework.integration.dispatcher.UnicastingDispatcher; +import org.springframework.integration.support.MessageBuilder; +import org.springframework.messaging.Message; +import org.springframework.messaging.MessageDeliveryException; +import org.springframework.messaging.MessageHandler; +import org.springframework.messaging.support.ErrorMessage; +import org.springframework.messaging.support.GenericMessage; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + *

This is a simplified backport of the version available on Spring Integration 6.x. for illustration purposes only.

+ *

In particular, this implementation does not persist messages as the full-fledged version does.

+ * + * @see https://github.com/spring-projects/spring-integration/blob/6.0.x/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/channel/PostgresSubscribableChannel.java + * + */ +public class PostgresSubscribableChannel extends AbstractSubscribableChannel { + + private static Logger log = LoggerFactory.getLogger(PostgresSubscribableChannel.class); + + private static final String HEADER_FIELD = "h"; + private static final String BODY_FIELD = "b"; + + private final Supplier connectionProvider; + private final String channelName; + private final MessageDispatcher dispatcher = new UnicastingDispatcher(); + private final DataSource ds; + private CountDownLatch startLatch; + private Executor executor; + private ObjectMapper om; + private NotifierTask notifierTask; + + public PostgresSubscribableChannel(String channelName, Supplier connectionProvider, DataSource ds, ObjectMapper om) { + + this.connectionProvider = connectionProvider; + this.channelName = channelName; + this.ds = ds; + this.executor = new SimpleAsyncTaskExecutor("posgres-subscriber-" + channelName); + this.om = om; + + } + + @Override + protected MessageDispatcher getDispatcher() { + return this.dispatcher; + } + + @Override + public boolean subscribe(MessageHandler handler) { + boolean r = super.subscribe(handler); + if (r && super.getSubscriberCount() == 1) { + log.info("subscribe: starting listener thread..."); + startListenerThread(); + } + return r; + } + + @Override + public boolean unsubscribe(MessageHandler handle) { + boolean r = super.unsubscribe(handle); + if (r && super.getSubscriberCount() == 0) { + log.info("unsubscribe: stopping listener thread..."); + stopListenerThread(); + } + + return r; + } + + private void startListenerThread() { + + startLatch = new CountDownLatch(1); + notifierTask = new NotifierTask(connectionProvider.get()); + executor.execute(notifierTask); + try { + startLatch.await(5, TimeUnit.SECONDS); + } catch (InterruptedException iex) { + throw new RuntimeException(iex); + } + } + + private void stopListenerThread() { + notifierTask.kill(); + } + + @Override + protected boolean doSend(Message message, long timeout) { + try { + String msg = prepareNotifyPayload(message); + + try( Connection c = ds.getConnection()) { + log.debug("doSend:sending message: channel={}", channelName); + c.createStatement().execute("NOTIFY " + channelName + ", '" + msg + "'"); + } + + return true; + } catch (Exception ex) { + throw new MessageDeliveryException(message, "Unable to deliver message: " + ex.getMessage(),ex); + } + } + + protected String prepareNotifyPayload(Message message) throws JsonProcessingException { + Map rawMap = new HashMap<>(); + rawMap.putAll(message.getHeaders()); + JsonNode headerData = om.valueToTree(rawMap); + JsonNode bodyData = om.valueToTree(message.getPayload()); + + ObjectNode msg = om.getNodeFactory() + .objectNode(); + msg.set(HEADER_FIELD, headerData); + msg.set(BODY_FIELD, bodyData); + return om.writeValueAsString(msg); + } + + // Inner class that listens for notifications and dispatches them to subscribers + class NotifierTask implements Runnable { + + private final Connection conn; + private final CountDownLatch stopLatch = new CountDownLatch(1); + + NotifierTask(Connection conn) { + this.conn = conn; + } + + void kill() { + try { + this.conn.close(); + stopLatch.await(10, TimeUnit.SECONDS); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + + @Override + public void run() { + + startLatch.countDown(); + + try (Statement st = conn.createStatement()) { + log.debug("notifierTask: enabling notifications for channel {}", channelName); + st.execute("LISTEN " + channelName); + + PGConnection pgConn = conn.unwrap(PGConnection.class); + + while (!Thread.currentThread() + .isInterrupted()) { + log.debug("notifierTask: wainting for notifications. channel={}", channelName); + PGNotification[] nts = pgConn.getNotifications(); + log.debug("notifierTask: processing {} notification(s)", nts.length); + + for (PGNotification n : nts) { + Message msg = convertNotification(n); + getDispatcher().dispatch(msg); + } + } + } catch (SQLException sex) { + // TODO: Handle exceptions + } finally { + stopLatch.countDown(); + } + } + + @SuppressWarnings("unchecked") + private Message convertNotification(PGNotification n) { + String payload = n.getParameter(); + try { + JsonNode root = om.readTree(payload); + + if (!root.isObject()) { + return new ErrorMessage(new IllegalArgumentException("Message is not a JSON Object")); + } + + Map hdr; + JsonNode headers = root.path(HEADER_FIELD); + + if (headers.isObject()) { + hdr = om.treeToValue(headers, Map.class); + } else { + hdr = Collections.emptyMap(); + } + + JsonNode body = root.path(BODY_FIELD); + return MessageBuilder + .withPayload(body.isTextual()?body.asText():body) + .copyHeaders(hdr) + .build(); + } catch (Exception ex) { + return new ErrorMessage(ex); + } + } + } +} diff --git a/spring-integration/src/main/java/com/baeldung/subflows/postgresqlnotify/PostgresqlPubSubExample.java b/spring-integration/src/main/java/com/baeldung/subflows/postgresqlnotify/PostgresqlPubSubExample.java new file mode 100644 index 0000000000..06da8864bf --- /dev/null +++ b/spring-integration/src/main/java/com/baeldung/subflows/postgresqlnotify/PostgresqlPubSubExample.java @@ -0,0 +1,126 @@ +package com.baeldung.subflows.postgresqlnotify; + +import java.math.BigDecimal; +import java.sql.Connection; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; + +import org.postgresql.ds.PGSimpleDataSource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.PropertySource; +import org.springframework.integration.annotation.Gateway; +import org.springframework.integration.annotation.IntegrationComponentScan; +import org.springframework.integration.annotation.MessagingGateway; +import org.springframework.integration.annotation.ServiceActivator; +import org.springframework.integration.annotation.Transformer; +import org.springframework.integration.channel.DirectChannel; +import org.springframework.integration.channel.PublishSubscribeChannel; +import org.springframework.integration.channel.QueueChannel; +import org.springframework.integration.config.EnableIntegration; +import org.springframework.jdbc.datasource.SingleConnectionDataSource; +import org.springframework.messaging.Message; +import org.springframework.messaging.MessageChannel; +import org.springframework.messaging.SubscribableChannel; + +import com.baeldung.domain.Order; +import com.baeldung.domain.OrderType; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; + +@EnableIntegration +@IntegrationComponentScan +@PropertySource(value = "classpath:/database.properties", ignoreResourceNotFound = false) +public class PostgresqlPubSubExample { + + private static final Logger log = LoggerFactory.getLogger(PostgresqlPubSubExample.class); + + private Map orderSummary = new HashMap<>(); + + private final ObjectMapper om = new ObjectMapper(); + private final Semaphore orderSemaphore = new Semaphore(0); + + + @MessagingGateway + public interface OrdersGateway { + + @Gateway(requestChannel = "orders") + void publish(Order order); + } + + + @Bean + static SubscribableChannel orders(@Value("${db.url}") String url,@Value("${db.username}") String username, @Value("${db.password}")String password) { + + // Connection supplier + SingleConnectionDataSource ds = new SingleConnectionDataSource(url, username, password, true); + Supplier connectionSupplier = () -> { + try { + return ds.getConnection(); + } + catch(SQLException ex) { + throw new RuntimeException(ex); + } + }; + + // DataSource + PGSimpleDataSource pgds = new PGSimpleDataSource(); + pgds.setUrl(url); + pgds.setUser(username); + pgds.setPassword(password); + + return new PostgresSubscribableChannel("orders", connectionSupplier, pgds, new ObjectMapper()); + } + + @Transformer(inputChannel = "orders" , outputChannel = "orderProcessor" ) + Order validatedOrders(Message orderMessage) throws JsonProcessingException { + ObjectNode on = (ObjectNode)orderMessage.getPayload(); + Order order = om.treeToValue(on, Order.class); + return order; + } + + + @ServiceActivator(inputChannel = "orderProcessor") + void processOrder(Order order){ + + log.info("Processing order: id={}, symbol={}, qty={}, price={}", + order.getId(), + order.getSymbol(), + order.getQuantity(), + order.getPrice()); + + BigDecimal orderTotal = order.getQuantity().multiply(order.getPrice()); + if ( order.getOrderType() == OrderType.SELL) { + orderTotal = orderTotal.negate(); + } + + BigDecimal sum = orderSummary.get(order.getSymbol()); + if ( sum == null) { + sum = orderTotal; + } + else { + sum = sum.add(orderTotal); + } + + orderSummary.put(order.getSymbol(), sum); + orderSemaphore.release(); + + } + + + public BigDecimal getTotalBySymbol(String symbol) { + return orderSummary.get(symbol); + } + + public boolean awaitNextMessage(long time, TimeUnit unit) throws InterruptedException { + return orderSemaphore.tryAcquire(time, unit); + } + +} diff --git a/spring-integration/src/main/java/com/baeldung/subflows/routeToRecipients/RouteToRecipientsExample.java b/spring-integration/src/main/java/com/baeldung/subflows/routetorecipients/RouteToRecipientsExample.java similarity index 100% rename from spring-integration/src/main/java/com/baeldung/subflows/routeToRecipients/RouteToRecipientsExample.java rename to spring-integration/src/main/java/com/baeldung/subflows/routetorecipients/RouteToRecipientsExample.java diff --git a/spring-integration/src/test/java/com/baeldung/subflows/postgresqlnotify/PostgresqlPubSubExampleLiveTest.java b/spring-integration/src/test/java/com/baeldung/subflows/postgresqlnotify/PostgresqlPubSubExampleLiveTest.java new file mode 100644 index 0000000000..a70c4b358d --- /dev/null +++ b/spring-integration/src/test/java/com/baeldung/subflows/postgresqlnotify/PostgresqlPubSubExampleLiveTest.java @@ -0,0 +1,40 @@ +package com.baeldung.subflows.postgresqlnotify; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +import java.math.BigDecimal; +import java.util.concurrent.TimeUnit; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; + +import com.baeldung.domain.Order; +import com.baeldung.domain.OrderType; +import com.baeldung.subflows.postgresqlnotify.PostgresqlPubSubExample.OrdersGateway; + +@SpringJUnitConfig(classes = {PostgresqlPubSubExample.class}) +public class PostgresqlPubSubExampleLiveTest { + + @Autowired + PostgresqlPubSubExample processor; + + @Autowired + OrdersGateway ordersGateway; + + @Test + void whenPublishOrder_thenSuccess() throws Exception{ + + Order o = new Order(1l,"BAEL", OrderType.BUY, BigDecimal.valueOf(2.0), BigDecimal.valueOf(5.0)); + ordersGateway.publish(o); + + assertThat(processor.awaitNextMessage(10, TimeUnit.SECONDS)).isTrue(); + + BigDecimal total = processor.getTotalBySymbol("BAEL"); + assertThat(total).isEqualTo(BigDecimal.valueOf(10)); + } + +} diff --git a/spring-integration/src/test/resources/database.properties b/spring-integration/src/test/resources/database.properties new file mode 100644 index 0000000000..d03b3688b5 --- /dev/null +++ b/spring-integration/src/test/resources/database.properties @@ -0,0 +1,3 @@ +db.url=jdbc:postgresql://localhost:5432/baeldung +db.username=baeldung +db.password=SqD64PtsGhDXjn9f diff --git a/spring-jenkins-pipeline/src/test/resources/logback-test.xml b/spring-jenkins-pipeline/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..b9242f40a8 --- /dev/null +++ b/spring-jenkins-pipeline/src/test/resources/logback-test.xml @@ -0,0 +1,14 @@ + + + + + [%d{ISO8601}]-[%thread] %-5level %logger - %msg%n + + + + + + + + + \ No newline at end of file diff --git a/spring-reactive-modules/pom.xml b/spring-reactive-modules/pom.xml index c8c9c84394..e75682da78 100644 --- a/spring-reactive-modules/pom.xml +++ b/spring-reactive-modules/pom.xml @@ -18,6 +18,7 @@ spring-5-data-reactive + spring-5-data-reactive-2 spring-5-reactive spring-5-reactive-2 spring-5-reactive-3 diff --git a/spring-reactive-modules/spring-5-data-reactive-2/README.md b/spring-reactive-modules/spring-5-data-reactive-2/README.md new file mode 100644 index 0000000000..d12e8214cd --- /dev/null +++ b/spring-reactive-modules/spring-5-data-reactive-2/README.md @@ -0,0 +1,9 @@ +## Spring Data Reactive Project + +This module contains articles about reactive Spring 5 Data + +### The Course + +The "REST With Spring" Classes: http://bit.ly/restwithspring + +### Relevant Articles diff --git a/spring-reactive-modules/spring-5-data-reactive-2/pom.xml b/spring-reactive-modules/spring-5-data-reactive-2/pom.xml new file mode 100644 index 0000000000..e5447ac038 --- /dev/null +++ b/spring-reactive-modules/spring-5-data-reactive-2/pom.xml @@ -0,0 +1,77 @@ + + + 4.0.0 + spring-5-data-reactive-2 + spring-5-data-reactive-2 + jar + + + com.baeldung.spring.reactive + spring-reactive-modules + 1.0.0-SNAPSHOT + + + + + 8 + 8 + UTF-8 + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-webflux + + + org.springframework.boot + spring-boot-starter-data-r2dbc + + + org.springframework + spring-webflux + + + org.springframework.boot + spring-boot-starter-test + test + + + com.h2database + h2 + runtime + + + io.r2dbc + r2dbc-h2 + runtime + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + io.projectreactor + reactor-test + test + + + javax.validation + validation-api + 2.0.1.Final + + + + \ No newline at end of file diff --git a/spring-reactive-modules/spring-5-data-reactive-2/src/main/java/com/baeldung/pagination/PaginationApplication.java b/spring-reactive-modules/spring-5-data-reactive-2/src/main/java/com/baeldung/pagination/PaginationApplication.java new file mode 100644 index 0000000000..799c73cfb7 --- /dev/null +++ b/spring-reactive-modules/spring-5-data-reactive-2/src/main/java/com/baeldung/pagination/PaginationApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.pagination; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class PaginationApplication { + + public static void main(String[] args) { + SpringApplication.run(PaginationApplication.class, args); + } + +} diff --git a/spring-reactive-modules/spring-5-data-reactive-2/src/main/java/com/baeldung/pagination/config/CustomWebMvcConfigurationSupport.java b/spring-reactive-modules/spring-5-data-reactive-2/src/main/java/com/baeldung/pagination/config/CustomWebMvcConfigurationSupport.java new file mode 100644 index 0000000000..c8f48ee202 --- /dev/null +++ b/spring-reactive-modules/spring-5-data-reactive-2/src/main/java/com/baeldung/pagination/config/CustomWebMvcConfigurationSupport.java @@ -0,0 +1,32 @@ +package com.baeldung.pagination.config; + +import java.util.List; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.web.PageableHandlerMethodArgumentResolver; +import org.springframework.data.web.SortHandlerMethodArgumentResolver; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; + +@Configuration +public class CustomWebMvcConfigurationSupport extends WebMvcConfigurationSupport { + + @Bean + public PageRequest defaultPageRequest() { + return PageRequest.of(0, 100); + } + + @Override + protected void addArgumentResolvers(List argumentResolvers) { + SortHandlerMethodArgumentResolver argumentResolver = new SortHandlerMethodArgumentResolver(); + argumentResolver.setSortParameter("sort"); + PageableHandlerMethodArgumentResolver resolver = new PageableHandlerMethodArgumentResolver(argumentResolver); + resolver.setFallbackPageable(defaultPageRequest()); + resolver.setPageParameterName("page"); + resolver.setSizeParameterName("size"); + argumentResolvers.add(resolver); + } + +} diff --git a/spring-reactive-modules/spring-5-data-reactive-2/src/main/java/com/baeldung/pagination/config/DatabaseConfig.java b/spring-reactive-modules/spring-5-data-reactive-2/src/main/java/com/baeldung/pagination/config/DatabaseConfig.java new file mode 100644 index 0000000000..10a30f9c7a --- /dev/null +++ b/spring-reactive-modules/spring-5-data-reactive-2/src/main/java/com/baeldung/pagination/config/DatabaseConfig.java @@ -0,0 +1,29 @@ +package com.baeldung.pagination.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.ClassPathResource; +import org.springframework.r2dbc.connection.init.CompositeDatabasePopulator; +import org.springframework.r2dbc.connection.init.ConnectionFactoryInitializer; +import org.springframework.r2dbc.connection.init.ResourceDatabasePopulator; + +import io.r2dbc.spi.ConnectionFactory; + + +@Configuration +public class DatabaseConfig { + + @Bean + public ConnectionFactoryInitializer initializer(ConnectionFactory connectionFactory) { + + ConnectionFactoryInitializer initializer = new ConnectionFactoryInitializer(); + initializer.setConnectionFactory(connectionFactory); + + CompositeDatabasePopulator populator = new CompositeDatabasePopulator(); + populator.addPopulators(new ResourceDatabasePopulator(new ClassPathResource("init.sql"))); + initializer.setDatabasePopulator(populator); + + return initializer; + } + +} diff --git a/spring-reactive-modules/spring-5-data-reactive-2/src/main/java/com/baeldung/pagination/controller/ProductPaginationController.java b/spring-reactive-modules/spring-5-data-reactive-2/src/main/java/com/baeldung/pagination/controller/ProductPaginationController.java new file mode 100644 index 0000000000..077980ecf3 --- /dev/null +++ b/spring-reactive-modules/spring-5-data-reactive-2/src/main/java/com/baeldung/pagination/controller/ProductPaginationController.java @@ -0,0 +1,29 @@ +package com.baeldung.pagination.controller; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.baeldung.pagination.model.Product; +import com.baeldung.pagination.repository.ProductRepository; + +import lombok.RequiredArgsConstructor; +import reactor.core.publisher.Mono; + +@RestController +@RequiredArgsConstructor +public class ProductPaginationController { + + private final ProductRepository productRepository; + + @GetMapping("/products") + public Mono> findAllProducts(Pageable pageable) { + return this.productRepository.findAllBy(pageable) + .collectList() + .zipWith(this.productRepository.count()) + .map(p -> new PageImpl<>(p.getT1(), pageable, p.getT2())); + } + +} diff --git a/spring-reactive-modules/spring-5-data-reactive-2/src/main/java/com/baeldung/pagination/model/Product.java b/spring-reactive-modules/spring-5-data-reactive-2/src/main/java/com/baeldung/pagination/model/Product.java new file mode 100644 index 0000000000..c82e31309c --- /dev/null +++ b/spring-reactive-modules/spring-5-data-reactive-2/src/main/java/com/baeldung/pagination/model/Product.java @@ -0,0 +1,32 @@ +package com.baeldung.pagination.model; + +import java.util.UUID; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +import org.springframework.data.annotation.Id; +import org.springframework.data.relational.core.mapping.Table; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Table +public class Product { + + @Id + @Getter + private UUID id; + + @NotNull + @Size(max = 255, message = "The property 'name' must be less than or equal to 255 characters.") + private String name; + + @NotNull + private double price; +} diff --git a/spring-reactive-modules/spring-5-data-reactive-2/src/main/java/com/baeldung/pagination/repository/ProductRepository.java b/spring-reactive-modules/spring-5-data-reactive-2/src/main/java/com/baeldung/pagination/repository/ProductRepository.java new file mode 100644 index 0000000000..1610d452da --- /dev/null +++ b/spring-reactive-modules/spring-5-data-reactive-2/src/main/java/com/baeldung/pagination/repository/ProductRepository.java @@ -0,0 +1,16 @@ +package com.baeldung.pagination.repository; + +import java.util.UUID; + +import org.springframework.data.domain.Pageable; +import org.springframework.data.repository.reactive.ReactiveSortingRepository; +import org.springframework.stereotype.Repository; + +import com.baeldung.pagination.model.Product; + +import reactor.core.publisher.Flux; + +@Repository +public interface ProductRepository extends ReactiveSortingRepository { + Flux findAllBy(Pageable pageable); +} diff --git a/spring-reactive-modules/spring-5-data-reactive-2/src/main/resources/application.properties b/spring-reactive-modules/spring-5-data-reactive-2/src/main/resources/application.properties new file mode 100644 index 0000000000..e69de29bb2 diff --git a/spring-reactive-modules/spring-5-data-reactive-2/src/main/resources/init.sql b/spring-reactive-modules/spring-5-data-reactive-2/src/main/resources/init.sql new file mode 100644 index 0000000000..043228d3cd --- /dev/null +++ b/spring-reactive-modules/spring-5-data-reactive-2/src/main/resources/init.sql @@ -0,0 +1,15 @@ +create table product +( + id UUID DEFAULT RANDOM_UUID() PRIMARY KEY, + name varchar(50), + price decimal +); + +insert into product(name, price) +values ('product_A', 1.0); +insert into product(name, price) +values ('product_B', 2.0); +insert into product(name, price) +values ('product_C', 3.0); +insert into product(name, price) +values ('product_D', 4.0); diff --git a/spring-reactive-modules/spring-5-data-reactive-2/src/test/java/com/baeldung/pagination/controller/ProductPaginationControllerIntegrationTest.java b/spring-reactive-modules/spring-5-data-reactive-2/src/test/java/com/baeldung/pagination/controller/ProductPaginationControllerIntegrationTest.java new file mode 100644 index 0000000000..a0af1f59ca --- /dev/null +++ b/spring-reactive-modules/spring-5-data-reactive-2/src/test/java/com/baeldung/pagination/controller/ProductPaginationControllerIntegrationTest.java @@ -0,0 +1,122 @@ +package com.baeldung.pagination.controller; + +import static org.assertj.core.api.Assertions.atIndex; +import static org.assertj.core.api.AssertionsForClassTypes.tuple; +import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; + +import java.util.List; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.web.reactive.server.WebTestClient; + +import com.baeldung.pagination.model.Product; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@AutoConfigureWebTestClient +class ProductPaginationControllerIntegrationTest { + + @Autowired + private WebTestClient webClient; + + @Test + void WhenProductEndpointIsHit_thenShouldReturnProductsWithPagination() throws JsonProcessingException { + String response = webClient.get() + .uri("/products") + .exchange() + .expectStatus() + .is2xxSuccessful() + .expectBody(String.class) + .returnResult() + .getResponseBody(); + Assertions.assertNotNull(response); + + JsonNode pageResponse = new ObjectMapper().readValue(response, JsonNode.class); + Assertions.assertNotNull(pageResponse); + Assertions.assertEquals(4, pageResponse.get("totalElements") + .asInt()); + Assertions.assertEquals(1, pageResponse.get("totalPages") + .asInt()); + Assertions.assertTrue(pageResponse.get("last") + .asBoolean()); + Assertions.assertTrue(pageResponse.get("first") + .asBoolean()); + Assertions.assertEquals(100, pageResponse.get("size") + .asInt()); + Assertions.assertEquals(4, pageResponse.get("numberOfElements") + .asInt()); + Assertions.assertEquals(0, pageResponse.get("pageable") + .get("offset") + .asInt()); + Assertions.assertEquals(0, pageResponse.get("pageable") + .get("pageNumber") + .asInt()); + Assertions.assertEquals(100, pageResponse.get("pageable") + .get("pageSize") + .asInt()); + Assertions.assertTrue(pageResponse.get("pageable") + .get("paged") + .asBoolean()); + List content = new ObjectMapper().readValue(String.valueOf(pageResponse.get("content")), new TypeReference>() { + }); + assertThat(content).hasSize(4); + assertThat(content).extracting("name", "price") + .contains(tuple("product_A", 1.0), atIndex(0)) + .contains(tuple("product_B", 2.0), atIndex(1)) + .contains(tuple("product_C", 3.0), atIndex(2)) + .contains(tuple("product_D", 4.0), atIndex(3)); + } + + @Test + void WhenProductEndpointIsHitWithPageSizeAs2AndSortPriceByDesc_thenShouldReturnProductsWithPaginationIgnoring2Products() throws JsonProcessingException { + String response = webClient.get() + .uri("/products?page=1&size=2&sort=price,DESC") + .exchange() + .expectStatus() + .is2xxSuccessful() + .expectBody(String.class) + .returnResult() + .getResponseBody(); + Assertions.assertNotNull(response); + + JsonNode pageResponse = new ObjectMapper().readValue(response, JsonNode.class); + Assertions.assertNotNull(pageResponse); + Assertions.assertEquals(4, pageResponse.get("totalElements") + .asInt()); + Assertions.assertEquals(2, pageResponse.get("totalPages") + .asInt()); + Assertions.assertTrue(pageResponse.get("last") + .asBoolean()); + Assertions.assertFalse(pageResponse.get("first") + .asBoolean()); + Assertions.assertEquals(2, pageResponse.get("size") + .asInt()); + Assertions.assertEquals(2, pageResponse.get("numberOfElements") + .asInt()); + Assertions.assertEquals(2, pageResponse.get("pageable") + .get("offset") + .asInt()); + Assertions.assertEquals(1, pageResponse.get("pageable") + .get("pageNumber") + .asInt()); + Assertions.assertEquals(2, pageResponse.get("pageable") + .get("pageSize") + .asInt()); + Assertions.assertTrue(pageResponse.get("pageable") + .get("paged") + .asBoolean()); + List content = new ObjectMapper().readValue(String.valueOf(pageResponse.get("content")), new TypeReference>() { + }); + assertThat(content).hasSize(2); + assertThat(content).extracting("name", "price") + .contains(tuple("product_B", 2.0), atIndex(0)) + .contains(tuple("product_A", 1.0), atIndex(1)); + } +} \ No newline at end of file diff --git a/spring-security-modules/pom.xml b/spring-security-modules/pom.xml index 4fde64bc7a..ed8279c5f7 100644 --- a/spring-security-modules/pom.xml +++ b/spring-security-modules/pom.xml @@ -51,6 +51,8 @@ spring-security-opa spring-security-pkce spring-security-azuread + spring-security-oauth2-testing + spring-security-saml2 \ No newline at end of file diff --git a/spring-security-modules/spring-security-web-rest-custom/src/main/java/com/baeldung/web/controller/SecurityController4.java b/spring-security-modules/spring-security-web-rest-custom/src/main/java/com/baeldung/web/controller/SecurityController4.java new file mode 100644 index 0000000000..93a2bfcacd --- /dev/null +++ b/spring-security-modules/spring-security-web-rest-custom/src/main/java/com/baeldung/web/controller/SecurityController4.java @@ -0,0 +1,16 @@ +package com.baeldung.web.controller; + +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class SecurityController4 { + + @GetMapping("/user") + public String getUser(@AuthenticationPrincipal UserDetails userDetails) { + return "User Details: " + userDetails.getUsername(); + } + +} diff --git a/spring-security-modules/spring-security-web-rest/README.md b/spring-security-modules/spring-security-web-rest/README.md index a11bc7e8d6..a50f0d315d 100644 --- a/spring-security-modules/spring-security-web-rest/README.md +++ b/spring-security-modules/spring-security-web-rest/README.md @@ -14,3 +14,4 @@ The "Learn Spring Security" Classes: http://github.learnspringsecurity.com - [Servlet 3 Async Support with Spring MVC and Spring Security](https://www.baeldung.com/spring-mvc-async-security) - [Intro to Spring Security Expressions](https://www.baeldung.com/spring-security-expressions) - [Error Handling for REST with Spring](https://www.baeldung.com/exception-handling-for-rest-with-spring) +- [How to Solve 403 Error in Spring Boot POST Request](https://www.baeldung.com/java-spring-fix-403-error) diff --git a/spring-security-modules/spring-security-web-rest/src/main/java/com/baeldung/forbiddenerror/controller/TestController.java b/spring-security-modules/spring-security-web-rest/src/main/java/com/baeldung/forbiddenerror/controller/TestController.java new file mode 100644 index 0000000000..2be0bf016c --- /dev/null +++ b/spring-security-modules/spring-security-web-rest/src/main/java/com/baeldung/forbiddenerror/controller/TestController.java @@ -0,0 +1,14 @@ +package com.baeldung.forbiddenerror.controller; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class TestController { + + @PostMapping("/test-request") + public ResponseEntity testPostRequest() { + return ResponseEntity.ok("POST request successful"); + } +} \ No newline at end of file diff --git a/spring-security-modules/spring-security-web-rest/src/main/java/com/baeldung/forbiddenerror/security/WebSecurityConfig.java b/spring-security-modules/spring-security-web-rest/src/main/java/com/baeldung/forbiddenerror/security/WebSecurityConfig.java new file mode 100644 index 0000000000..8751aa579b --- /dev/null +++ b/spring-security-modules/spring-security-web-rest/src/main/java/com/baeldung/forbiddenerror/security/WebSecurityConfig.java @@ -0,0 +1,44 @@ +package com.baeldung.forbiddenerror.security; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.provisioning.InMemoryUserDetailsManager; +import org.springframework.security.web.SecurityFilterChain; +import static org.springframework.security.config.Customizer.withDefaults; + +@Configuration +@EnableWebSecurity +public class WebSecurityConfig { + + @Bean + public InMemoryUserDetailsManager userDetailsService() { + UserDetails user = User.withUsername("user") + .password(encoder().encode("userPass")) + .roles("USER") + .build(); + return new InMemoryUserDetailsManager(user); + } + + @Bean + public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + http.authorizeRequests(authorizeRequests -> authorizeRequests.anyRequest() + .authenticated()) + .httpBasic(withDefaults()) + .formLogin(withDefaults()) + .csrf(AbstractHttpConfigurer::disable); + return http.build(); + } + + @Bean + public PasswordEncoder encoder() { + return new BCryptPasswordEncoder(); + } + +} \ No newline at end of file diff --git a/spring-web-modules/spring-thymeleaf-2/README.md b/spring-web-modules/spring-thymeleaf-2/README.md index e21b7b6be7..c5db9a8e0f 100644 --- a/spring-web-modules/spring-thymeleaf-2/README.md +++ b/spring-web-modules/spring-thymeleaf-2/README.md @@ -11,4 +11,4 @@ This module contains articles about Spring with Thymeleaf - [Working With Arrays in Thymeleaf](https://www.baeldung.com/thymeleaf-arrays) - [Working with Boolean in Thymeleaf](https://www.baeldung.com/thymeleaf-boolean) - [Working With Custom HTML Attributes in Thymeleaf](https://www.baeldung.com/thymeleaf-custom-html-attributes) -- [[<-- prev]](/spring-thymeleaf) +- More articles: [[<-- prev]](../spring-thymeleaf) [[next -->]](../spring-thymeleaf-3) diff --git a/spring-web-modules/spring-thymeleaf-3/README.md b/spring-web-modules/spring-thymeleaf-3/README.md index 46ddd6c03f..12f300a6a3 100644 --- a/spring-web-modules/spring-thymeleaf-3/README.md +++ b/spring-web-modules/spring-thymeleaf-3/README.md @@ -11,4 +11,4 @@ This module contains articles about Spring with Thymeleaf - [Using Hidden Inputs with Spring and Thymeleaf](https://www.baeldung.com/spring-thymeleaf-hidden-inputs) - [Thymeleaf Variables](https://www.baeldung.com/thymeleaf-variables) - [Displaying Error Messages with Thymeleaf in Spring](https://www.baeldung.com/spring-thymeleaf-error-messages) -- [[next -->]](/spring-thymeleaf-4) +- More articles: [[<-- prev]](../spring-thymeleaf-2) [[next -->]](../spring-thymeleaf-4) diff --git a/spring-web-modules/spring-thymeleaf-4/README.md b/spring-web-modules/spring-thymeleaf-4/README.md index f8dc4c8b4e..b8c18965bc 100644 --- a/spring-web-modules/spring-thymeleaf-4/README.md +++ b/spring-web-modules/spring-thymeleaf-4/README.md @@ -2,26 +2,14 @@ This module contains articles about Spring with Thymeleaf -### Relevant Articles: -- [CSRF Protection with Spring MVC and Thymeleaf](https://www.baeldung.com/csrf-thymeleaf-with-spring-security) -- [Conditionals in Thymeleaf](https://www.baeldung.com/spring-thymeleaf-conditionals) -- [Iteration in Thymeleaf](https://www.baeldung.com/thymeleaf-iteration) -- [Spring with Thymeleaf Pagination for a List](https://www.baeldung.com/spring-thymeleaf-pagination) +## Relevant Articles: -### Build the Project - -mvn clean install - -### Run the Project - -mvn cargo:run -- **note**: starts on port '8082' - -Access the pages using the URLs: - - - http://localhost:8082/spring-thymeleaf-4/ - - http://localhost:8082/spring-thymeleaf-4/addStudent/ - - http://localhost:8082/spring-thymeleaf-4/listStudents/ - -The first URL is the home page of the application. The home page has links to the second and third pages. +- [Changing the Thymeleaf Template Directory in Spring Boot](https://www.baeldung.com/spring-thymeleaf-template-directory) +- [Add a Checked Attribute to Input Conditionally in Thymeleaf](https://www.baeldung.com/thymeleaf-conditional-checked-attribute) +- [Spring MVC Data and Thymeleaf](https://www.baeldung.com/spring-mvc-thymeleaf-data) +- [Upload Image With Spring Boot and Thymeleaf](https://www.baeldung.com/spring-boot-thymeleaf-image-upload) +- [Getting a URL Attribute Value in Thymeleaf](https://www.baeldung.com/thymeleaf-url-attribute-value) +- [Expression Types in Thymeleaf](https://www.baeldung.com/java-thymeleaf-expression-types) +- [Difference Between th:text and th:value in Thymeleaf](https://www.baeldung.com/java-thymeleaf-text-vs-value) +- More articles: [[<-- prev]](../spring-thymeleaf-3) [[next -->]](../spring-thymeleaf-5) diff --git a/spring-web-modules/spring-thymeleaf-4/pom.xml b/spring-web-modules/spring-thymeleaf-4/pom.xml index 163d590c9f..2582044c0f 100644 --- a/spring-web-modules/spring-thymeleaf-4/pom.xml +++ b/spring-web-modules/spring-thymeleaf-4/pom.xml @@ -9,139 +9,33 @@ com.baeldung - parent-spring-5 + parent-boot-2 0.0.1-SNAPSHOT - ../../parent-spring-5 + ../../parent-boot-2 - - org.springframework - spring-context - ${spring.version} - - - - commons-logging - commons-logging - - + org.springframework.boot + spring-boot-starter-web - org.springframework - spring-webmvc - ${spring.version} + org.springframework.boot + spring-boot-starter-thymeleaf - org.springframework.data - spring-data-commons - ${spring-data.version} - - - javax.validation - validation-api - ${javax.validation-version} - - - org.hibernate.validator - hibernate-validator - ${hibernate-validator.version} - - - - org.springframework.security - spring-security-web - ${spring-security.version} - - - org.springframework.security - spring-security-config - ${spring-security.version} - - - - org.thymeleaf - thymeleaf - ${org.thymeleaf-version} - - - org.thymeleaf - thymeleaf-spring5 - ${org.thymeleaf-version} - - - nz.net.ultraq.thymeleaf - thymeleaf-layout-dialect - ${thymeleaf-layout-dialect.version} - - - org.thymeleaf.extras - thymeleaf-extras-java8time - ${org.thymeleaf.extras-version} - - - - javax.servlet - javax.servlet-api - ${javax.servlet-api.version} - provided - - - - org.springframework - spring-test - ${spring.version} - test - - - org.springframework.security - spring-security-test - ${spring-security.version} + org.springframework.boot + spring-boot-starter-test test - - - org.apache.maven.plugins - maven-war-plugin - - false - - - - org.codehaus.cargo - cargo-maven2-plugin - ${cargo-maven2-plugin.version} - - true - - jetty9x - embedded - - - - - - 8082 - - - - - + spring-thymeleaf-4 - 2.3.2.RELEASE - 3.0.11.RELEASE - 3.0.4.RELEASE - 2.4.1 - 2.0.1.Final - 6.0.11.Final - - 1.6.1 + 2.2 \ No newline at end of file diff --git a/spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/Application.java b/spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/Application.java similarity index 100% rename from spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/Application.java rename to spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/Application.java diff --git a/spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/ThymeleafConfig.java b/spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/ThymeleafConfig.java similarity index 100% rename from spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/ThymeleafConfig.java rename to spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/ThymeleafConfig.java diff --git a/spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/attribute/CheckedAttributeController.java b/spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/attribute/CheckedAttributeController.java similarity index 100% rename from spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/attribute/CheckedAttributeController.java rename to spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/attribute/CheckedAttributeController.java diff --git a/spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/attributes/AttributeController.java b/spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/attributes/AttributeController.java similarity index 100% rename from spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/attributes/AttributeController.java rename to spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/attributes/AttributeController.java diff --git a/spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/expression/Dino.java b/spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/expression/Dino.java similarity index 100% rename from spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/expression/Dino.java rename to spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/expression/Dino.java diff --git a/spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/expression/DinoController.java b/spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/expression/DinoController.java similarity index 100% rename from spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/expression/DinoController.java rename to spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/expression/DinoController.java diff --git a/spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/imageupload/UploadController.java b/spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/imageupload/UploadController.java similarity index 100% rename from spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/imageupload/UploadController.java rename to spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/imageupload/UploadController.java diff --git a/spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/mvcdata/BeanConfig.java b/spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/mvcdata/BeanConfig.java similarity index 100% rename from spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/mvcdata/BeanConfig.java rename to spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/mvcdata/BeanConfig.java diff --git a/spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/mvcdata/EmailController.java b/spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/mvcdata/EmailController.java similarity index 100% rename from spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/mvcdata/EmailController.java rename to spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/mvcdata/EmailController.java diff --git a/spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/mvcdata/repository/EmailData.java b/spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/mvcdata/repository/EmailData.java similarity index 100% rename from spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/mvcdata/repository/EmailData.java rename to spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/mvcdata/repository/EmailData.java diff --git a/spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/templatedir/HelloController.java b/spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/templatedir/HelloController.java similarity index 100% rename from spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/templatedir/HelloController.java rename to spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/templatedir/HelloController.java diff --git a/spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/url/UrlController.java b/spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/url/UrlController.java similarity index 100% rename from spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/url/UrlController.java rename to spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/url/UrlController.java diff --git a/spring-web-modules/spring-thymeleaf-5/src/main/resources/application.properties b/spring-web-modules/spring-thymeleaf-4/src/main/resources/application.properties similarity index 100% rename from spring-web-modules/spring-thymeleaf-5/src/main/resources/application.properties rename to spring-web-modules/spring-thymeleaf-4/src/main/resources/application.properties diff --git a/spring-web-modules/spring-thymeleaf-5/src/main/resources/messages.properties b/spring-web-modules/spring-thymeleaf-4/src/main/resources/messages.properties similarity index 100% rename from spring-web-modules/spring-thymeleaf-5/src/main/resources/messages.properties rename to spring-web-modules/spring-thymeleaf-4/src/main/resources/messages.properties diff --git a/spring-web-modules/spring-thymeleaf-5/src/main/resources/templates-2/hello.html b/spring-web-modules/spring-thymeleaf-4/src/main/resources/templates-2/hello.html similarity index 100% rename from spring-web-modules/spring-thymeleaf-5/src/main/resources/templates-2/hello.html rename to spring-web-modules/spring-thymeleaf-4/src/main/resources/templates-2/hello.html diff --git a/spring-web-modules/spring-thymeleaf-5/src/main/resources/templates-3/form.html b/spring-web-modules/spring-thymeleaf-4/src/main/resources/templates-3/form.html similarity index 100% rename from spring-web-modules/spring-thymeleaf-5/src/main/resources/templates-3/form.html rename to spring-web-modules/spring-thymeleaf-4/src/main/resources/templates-3/form.html diff --git a/spring-web-modules/spring-thymeleaf-5/src/main/resources/templates-3/index.html b/spring-web-modules/spring-thymeleaf-4/src/main/resources/templates-3/index.html similarity index 100% rename from spring-web-modules/spring-thymeleaf-5/src/main/resources/templates-3/index.html rename to spring-web-modules/spring-thymeleaf-4/src/main/resources/templates-3/index.html diff --git a/spring-web-modules/spring-thymeleaf-5/src/main/resources/templates-3/result.html b/spring-web-modules/spring-thymeleaf-4/src/main/resources/templates-3/result.html similarity index 100% rename from spring-web-modules/spring-thymeleaf-5/src/main/resources/templates-3/result.html rename to spring-web-modules/spring-thymeleaf-4/src/main/resources/templates-3/result.html diff --git a/spring-web-modules/spring-thymeleaf-5/src/main/resources/templates/attribute/index.html b/spring-web-modules/spring-thymeleaf-4/src/main/resources/templates/attribute/index.html similarity index 100% rename from spring-web-modules/spring-thymeleaf-5/src/main/resources/templates/attribute/index.html rename to spring-web-modules/spring-thymeleaf-4/src/main/resources/templates/attribute/index.html diff --git a/spring-web-modules/spring-thymeleaf-5/src/main/resources/templates/attributes/index.html b/spring-web-modules/spring-thymeleaf-4/src/main/resources/templates/attributes/index.html similarity index 100% rename from spring-web-modules/spring-thymeleaf-5/src/main/resources/templates/attributes/index.html rename to spring-web-modules/spring-thymeleaf-4/src/main/resources/templates/attributes/index.html diff --git a/spring-web-modules/spring-thymeleaf-5/src/main/resources/templates/imageupload/index.html b/spring-web-modules/spring-thymeleaf-4/src/main/resources/templates/imageupload/index.html similarity index 100% rename from spring-web-modules/spring-thymeleaf-5/src/main/resources/templates/imageupload/index.html rename to spring-web-modules/spring-thymeleaf-4/src/main/resources/templates/imageupload/index.html diff --git a/spring-web-modules/spring-thymeleaf-5/src/main/resources/templates/mvcdata/email-bean-data.html b/spring-web-modules/spring-thymeleaf-4/src/main/resources/templates/mvcdata/email-bean-data.html similarity index 100% rename from spring-web-modules/spring-thymeleaf-5/src/main/resources/templates/mvcdata/email-bean-data.html rename to spring-web-modules/spring-thymeleaf-4/src/main/resources/templates/mvcdata/email-bean-data.html diff --git a/spring-web-modules/spring-thymeleaf-5/src/main/resources/templates/mvcdata/email-model-attributes.html b/spring-web-modules/spring-thymeleaf-4/src/main/resources/templates/mvcdata/email-model-attributes.html similarity index 100% rename from spring-web-modules/spring-thymeleaf-5/src/main/resources/templates/mvcdata/email-model-attributes.html rename to spring-web-modules/spring-thymeleaf-4/src/main/resources/templates/mvcdata/email-model-attributes.html diff --git a/spring-web-modules/spring-thymeleaf-5/src/main/resources/templates/mvcdata/email-request-parameters.html b/spring-web-modules/spring-thymeleaf-4/src/main/resources/templates/mvcdata/email-request-parameters.html similarity index 100% rename from spring-web-modules/spring-thymeleaf-5/src/main/resources/templates/mvcdata/email-request-parameters.html rename to spring-web-modules/spring-thymeleaf-4/src/main/resources/templates/mvcdata/email-request-parameters.html diff --git a/spring-web-modules/spring-thymeleaf-5/src/main/resources/templates/mvcdata/email-servlet-context.html b/spring-web-modules/spring-thymeleaf-4/src/main/resources/templates/mvcdata/email-servlet-context.html similarity index 100% rename from spring-web-modules/spring-thymeleaf-5/src/main/resources/templates/mvcdata/email-servlet-context.html rename to spring-web-modules/spring-thymeleaf-4/src/main/resources/templates/mvcdata/email-servlet-context.html diff --git a/spring-web-modules/spring-thymeleaf-5/src/main/resources/templates/mvcdata/email-session-attributes.html b/spring-web-modules/spring-thymeleaf-4/src/main/resources/templates/mvcdata/email-session-attributes.html similarity index 100% rename from spring-web-modules/spring-thymeleaf-5/src/main/resources/templates/mvcdata/email-session-attributes.html rename to spring-web-modules/spring-thymeleaf-4/src/main/resources/templates/mvcdata/email-session-attributes.html diff --git a/spring-web-modules/spring-thymeleaf-5/src/main/resources/templates/url/index.html b/spring-web-modules/spring-thymeleaf-4/src/main/resources/templates/url/index.html similarity index 100% rename from spring-web-modules/spring-thymeleaf-5/src/main/resources/templates/url/index.html rename to spring-web-modules/spring-thymeleaf-4/src/main/resources/templates/url/index.html diff --git a/spring-web-modules/spring-thymeleaf-5/src/test/java/com/baeldung/thymeleaf/mvcdata/EmailControllerUnitTest.java b/spring-web-modules/spring-thymeleaf-4/src/test/java/com/baeldung/thymeleaf/mvcdata/EmailControllerUnitTest.java similarity index 100% rename from spring-web-modules/spring-thymeleaf-5/src/test/java/com/baeldung/thymeleaf/mvcdata/EmailControllerUnitTest.java rename to spring-web-modules/spring-thymeleaf-4/src/test/java/com/baeldung/thymeleaf/mvcdata/EmailControllerUnitTest.java diff --git a/spring-web-modules/spring-thymeleaf-4/src/test/resources/logback-test.xml b/spring-web-modules/spring-thymeleaf-4/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..8d4771e308 --- /dev/null +++ b/spring-web-modules/spring-thymeleaf-4/src/test/resources/logback-test.xml @@ -0,0 +1,12 @@ + + + + + [%d{ISO8601}]-[%thread] %-5level %logger - %msg%n + + + + + + + \ No newline at end of file diff --git a/spring-web-modules/spring-thymeleaf-5/README.md b/spring-web-modules/spring-thymeleaf-5/README.md index 7e2f8c37b4..7b64a4e423 100644 --- a/spring-web-modules/spring-thymeleaf-5/README.md +++ b/spring-web-modules/spring-thymeleaf-5/README.md @@ -2,13 +2,9 @@ This module contains articles about Spring with Thymeleaf -## Relevant Articles: - -- [Changing the Thymeleaf Template Directory in Spring Boot](https://www.baeldung.com/spring-thymeleaf-template-directory) -- [How to Create an Executable JAR with Maven](https://www.baeldung.com/executable-jar-with-maven) -- [Spring MVC Data and Thymeleaf](https://www.baeldung.com/spring-mvc-thymeleaf-data) -- [Upload Image With Spring Boot and Thymeleaf](https://www.baeldung.com/spring-boot-thymeleaf-image-upload) -- [Getting a URL Attribute Value in Thymeleaf](https://www.baeldung.com/thymeleaf-url-attribute-value) -- [Expression Types in Thymeleaf](https://www.baeldung.com/java-thymeleaf-expression-types) -- [Difference Between th:text and th:value in Thymeleaf](https://www.baeldung.com/java-thymeleaf-text-vs-value) -- [[<-- prev]](/spring-thymeleaf) +### Relevant Articles: +- [CSRF Protection with Spring MVC and Thymeleaf](https://www.baeldung.com/csrf-thymeleaf-with-spring-security) +- [Conditionals in Thymeleaf](https://www.baeldung.com/spring-thymeleaf-conditionals) +- [Iteration in Thymeleaf](https://www.baeldung.com/thymeleaf-iteration) +- [Spring with Thymeleaf Pagination for a List](https://www.baeldung.com/spring-thymeleaf-pagination) +- More articles: [[<-- prev]](../spring-thymeleaf-4) diff --git a/spring-web-modules/spring-thymeleaf-5/pom.xml b/spring-web-modules/spring-thymeleaf-5/pom.xml index e7c54d83c9..0717e41bac 100644 --- a/spring-web-modules/spring-thymeleaf-5/pom.xml +++ b/spring-web-modules/spring-thymeleaf-5/pom.xml @@ -9,33 +9,139 @@ com.baeldung - parent-boot-2 + parent-spring-5 0.0.1-SNAPSHOT - ../../parent-boot-2 + ../../parent-spring-5 + - org.springframework.boot - spring-boot-starter-web + org.springframework + spring-context + ${spring.version} + + + + commons-logging + commons-logging + + - org.springframework.boot - spring-boot-starter-thymeleaf + org.springframework + spring-webmvc + ${spring.version} - org.springframework.boot - spring-boot-starter-test + org.springframework.data + spring-data-commons + ${spring-data.version} + + + javax.validation + validation-api + ${javax.validation-version} + + + org.hibernate.validator + hibernate-validator + ${hibernate-validator.version} + + + + org.springframework.security + spring-security-web + ${spring-security.version} + + + org.springframework.security + spring-security-config + ${spring-security.version} + + + + org.thymeleaf + thymeleaf + ${org.thymeleaf-version} + + + org.thymeleaf + thymeleaf-spring5 + ${org.thymeleaf-version} + + + nz.net.ultraq.thymeleaf + thymeleaf-layout-dialect + ${thymeleaf-layout-dialect.version} + + + org.thymeleaf.extras + thymeleaf-extras-java8time + ${org.thymeleaf.extras-version} + + + + javax.servlet + javax.servlet-api + ${javax.servlet-api.version} + provided + + + + org.springframework + spring-test + ${spring.version} + test + + + org.springframework.security + spring-security-test + ${spring-security.version} test - spring-thymeleaf-5 + + + org.apache.maven.plugins + maven-war-plugin + + false + + + + org.codehaus.cargo + cargo-maven2-plugin + ${cargo-maven2-plugin.version} + + true + + jetty9x + embedded + + + + + + 8082 + + + + + - 2.2 + 2.3.2.RELEASE + 3.0.11.RELEASE + 3.0.4.RELEASE + 2.4.1 + 2.0.1.Final + 6.0.11.Final + + 1.6.1 \ No newline at end of file diff --git a/spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/config/InitSecurity.java b/spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/config/InitSecurity.java similarity index 100% rename from spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/config/InitSecurity.java rename to spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/config/InitSecurity.java diff --git a/spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/config/WebApp.java b/spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/config/WebApp.java similarity index 100% rename from spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/config/WebApp.java rename to spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/config/WebApp.java diff --git a/spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/config/WebMVCConfig.java b/spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/config/WebMVCConfig.java similarity index 100% rename from spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/config/WebMVCConfig.java rename to spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/config/WebMVCConfig.java diff --git a/spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/config/WebMVCSecurity.java b/spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/config/WebMVCSecurity.java similarity index 100% rename from spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/config/WebMVCSecurity.java rename to spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/config/WebMVCSecurity.java diff --git a/spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/controller/BookController.java b/spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/controller/BookController.java similarity index 100% rename from spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/controller/BookController.java rename to spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/controller/BookController.java diff --git a/spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/controller/HomeController.java b/spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/controller/HomeController.java similarity index 100% rename from spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/controller/HomeController.java rename to spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/controller/HomeController.java diff --git a/spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/controller/StudentController.java b/spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/controller/StudentController.java similarity index 100% rename from spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/controller/StudentController.java rename to spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/controller/StudentController.java diff --git a/spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/controller/TeacherController.java b/spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/controller/TeacherController.java similarity index 100% rename from spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/controller/TeacherController.java rename to spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/controller/TeacherController.java diff --git a/spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/formatter/NameFormatter.java b/spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/formatter/NameFormatter.java similarity index 100% rename from spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/formatter/NameFormatter.java rename to spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/formatter/NameFormatter.java diff --git a/spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/model/Book.java b/spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/model/Book.java similarity index 100% rename from spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/model/Book.java rename to spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/model/Book.java diff --git a/spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/model/Student.java b/spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/model/Student.java similarity index 100% rename from spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/model/Student.java rename to spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/model/Student.java diff --git a/spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/model/Teacher.java b/spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/model/Teacher.java similarity index 100% rename from spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/model/Teacher.java rename to spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/model/Teacher.java diff --git a/spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/service/BookService.java b/spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/service/BookService.java similarity index 100% rename from spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/service/BookService.java rename to spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/service/BookService.java diff --git a/spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/utils/ArrayUtil.java b/spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/utils/ArrayUtil.java similarity index 100% rename from spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/utils/ArrayUtil.java rename to spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/utils/ArrayUtil.java diff --git a/spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/utils/BookUtils.java b/spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/utils/BookUtils.java similarity index 100% rename from spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/utils/BookUtils.java rename to spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/utils/BookUtils.java diff --git a/spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/utils/StudentUtils.java b/spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/utils/StudentUtils.java similarity index 100% rename from spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/utils/StudentUtils.java rename to spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/utils/StudentUtils.java diff --git a/spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/utils/TeacherUtils.java b/spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/utils/TeacherUtils.java similarity index 100% rename from spring-web-modules/spring-thymeleaf-4/src/main/java/com/baeldung/thymeleaf/utils/TeacherUtils.java rename to spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/utils/TeacherUtils.java diff --git a/spring-web-modules/spring-thymeleaf-4/src/main/resources/logback.xml b/spring-web-modules/spring-thymeleaf-5/src/main/resources/logback.xml similarity index 100% rename from spring-web-modules/spring-thymeleaf-4/src/main/resources/logback.xml rename to spring-web-modules/spring-thymeleaf-5/src/main/resources/logback.xml diff --git a/spring-web-modules/spring-thymeleaf-4/src/main/resources/messages_en.properties b/spring-web-modules/spring-thymeleaf-5/src/main/resources/messages_en.properties similarity index 100% rename from spring-web-modules/spring-thymeleaf-4/src/main/resources/messages_en.properties rename to spring-web-modules/spring-thymeleaf-5/src/main/resources/messages_en.properties diff --git a/spring-web-modules/spring-thymeleaf-4/src/main/webapp/WEB-INF/views/addStudent.html b/spring-web-modules/spring-thymeleaf-5/src/main/webapp/WEB-INF/views/addStudent.html similarity index 100% rename from spring-web-modules/spring-thymeleaf-4/src/main/webapp/WEB-INF/views/addStudent.html rename to spring-web-modules/spring-thymeleaf-5/src/main/webapp/WEB-INF/views/addStudent.html diff --git a/spring-web-modules/spring-thymeleaf-4/src/main/webapp/WEB-INF/views/csrfAttack.html b/spring-web-modules/spring-thymeleaf-5/src/main/webapp/WEB-INF/views/csrfAttack.html similarity index 100% rename from spring-web-modules/spring-thymeleaf-4/src/main/webapp/WEB-INF/views/csrfAttack.html rename to spring-web-modules/spring-thymeleaf-5/src/main/webapp/WEB-INF/views/csrfAttack.html diff --git a/spring-web-modules/spring-thymeleaf-4/src/main/webapp/WEB-INF/views/home.html b/spring-web-modules/spring-thymeleaf-5/src/main/webapp/WEB-INF/views/home.html similarity index 100% rename from spring-web-modules/spring-thymeleaf-4/src/main/webapp/WEB-INF/views/home.html rename to spring-web-modules/spring-thymeleaf-5/src/main/webapp/WEB-INF/views/home.html diff --git a/spring-web-modules/spring-thymeleaf-4/src/main/webapp/WEB-INF/views/listBooks.html b/spring-web-modules/spring-thymeleaf-5/src/main/webapp/WEB-INF/views/listBooks.html similarity index 100% rename from spring-web-modules/spring-thymeleaf-4/src/main/webapp/WEB-INF/views/listBooks.html rename to spring-web-modules/spring-thymeleaf-5/src/main/webapp/WEB-INF/views/listBooks.html diff --git a/spring-web-modules/spring-thymeleaf-4/src/main/webapp/WEB-INF/views/listStudents.html b/spring-web-modules/spring-thymeleaf-5/src/main/webapp/WEB-INF/views/listStudents.html similarity index 100% rename from spring-web-modules/spring-thymeleaf-4/src/main/webapp/WEB-INF/views/listStudents.html rename to spring-web-modules/spring-thymeleaf-5/src/main/webapp/WEB-INF/views/listStudents.html diff --git a/spring-web-modules/spring-thymeleaf-4/src/main/webapp/WEB-INF/views/listTeachers.html b/spring-web-modules/spring-thymeleaf-5/src/main/webapp/WEB-INF/views/listTeachers.html similarity index 100% rename from spring-web-modules/spring-thymeleaf-4/src/main/webapp/WEB-INF/views/listTeachers.html rename to spring-web-modules/spring-thymeleaf-5/src/main/webapp/WEB-INF/views/listTeachers.html diff --git a/spring-web-modules/spring-thymeleaf-4/src/test/java/com/baeldung/thymeleaf/SpringContextTest.java b/spring-web-modules/spring-thymeleaf-5/src/test/java/com/baeldung/thymeleaf/SpringContextTest.java similarity index 100% rename from spring-web-modules/spring-thymeleaf-4/src/test/java/com/baeldung/thymeleaf/SpringContextTest.java rename to spring-web-modules/spring-thymeleaf-5/src/test/java/com/baeldung/thymeleaf/SpringContextTest.java diff --git a/spring-web-modules/spring-thymeleaf-4/src/test/java/com/baeldung/thymeleaf/controller/ControllerIntegrationTest.java b/spring-web-modules/spring-thymeleaf-5/src/test/java/com/baeldung/thymeleaf/controller/ControllerIntegrationTest.java similarity index 100% rename from spring-web-modules/spring-thymeleaf-4/src/test/java/com/baeldung/thymeleaf/controller/ControllerIntegrationTest.java rename to spring-web-modules/spring-thymeleaf-5/src/test/java/com/baeldung/thymeleaf/controller/ControllerIntegrationTest.java diff --git a/spring-web-modules/spring-thymeleaf-4/src/test/java/com/baeldung/thymeleaf/security/csrf/CsrfEnabledIntegrationTest.java b/spring-web-modules/spring-thymeleaf-5/src/test/java/com/baeldung/thymeleaf/security/csrf/CsrfEnabledIntegrationTest.java similarity index 100% rename from spring-web-modules/spring-thymeleaf-4/src/test/java/com/baeldung/thymeleaf/security/csrf/CsrfEnabledIntegrationTest.java rename to spring-web-modules/spring-thymeleaf-5/src/test/java/com/baeldung/thymeleaf/security/csrf/CsrfEnabledIntegrationTest.java diff --git a/spring-web-modules/spring-thymeleaf-attributes/accessing-session-attributes/README.md b/spring-web-modules/spring-thymeleaf-attributes/accessing-session-attributes/README.md new file mode 100644 index 0000000000..d7ece5ff7f --- /dev/null +++ b/spring-web-modules/spring-thymeleaf-attributes/accessing-session-attributes/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [Accessing Session Attributes in Thymeleaf](https://www.baeldung.com/thymeleaf-accessing-session-attributes) diff --git a/spring-web-modules/spring-thymeleaf/README.md b/spring-web-modules/spring-thymeleaf/README.md index 2d1bc848d8..b49095f5b1 100644 --- a/spring-web-modules/spring-thymeleaf/README.md +++ b/spring-web-modules/spring-thymeleaf/README.md @@ -10,8 +10,7 @@ This module contains articles about Spring with Thymeleaf - [How to Work with Dates in Thymeleaf](https://www.baeldung.com/dates-in-thymeleaf) - [Working with Fragments in Thymeleaf](https://www.baeldung.com/spring-thymeleaf-fragments) - [JavaScript Function Call with Thymeleaf](https://www.baeldung.com/thymeleaf-js-function-call) -- [Add a Checked Attribute to Input Conditionally in Thymeleaf](https://www.baeldung.com/thymeleaf-conditional-checked-attribute) -- [[next -->]](/spring-thymeleaf-2) +- [[next -->]](../spring-thymeleaf-2) ### Build the Project diff --git a/testing-modules/jqwik/.gitignore b/testing-modules/jqwik/.gitignore new file mode 100644 index 0000000000..9447111720 --- /dev/null +++ b/testing-modules/jqwik/.gitignore @@ -0,0 +1 @@ +/.jqwik-database diff --git a/testing-modules/jqwik/pom.xml b/testing-modules/jqwik/pom.xml new file mode 100644 index 0000000000..6ef9b61a6a --- /dev/null +++ b/testing-modules/jqwik/pom.xml @@ -0,0 +1,57 @@ + + + 4.0.0 + jqwik + 0.0.1-SNAPSHOT + jqwik + + + com.baeldung + testing-modules + 1.0.0-SNAPSHOT + + + + + net.jqwik + jqwik + 1.7.4 + test + + + org.junit.platform + junit-platform-engine + ${junit-platform.version} + test + + + org.junit.platform + junit-platform-console-standalone + ${junit-platform.version} + test + + + org.junit.jupiter + junit-jupiter-migrationsupport + ${junit-jupiter.version} + test + + + + + + + src/main/resources + true + + + src/test/resources + true + + + + + + diff --git a/testing-modules/jqwik/src/test/java/com/baeldung/jqwik/AdditionLiveTest.java b/testing-modules/jqwik/src/test/java/com/baeldung/jqwik/AdditionLiveTest.java new file mode 100644 index 0000000000..1099dd05ee --- /dev/null +++ b/testing-modules/jqwik/src/test/java/com/baeldung/jqwik/AdditionLiveTest.java @@ -0,0 +1,13 @@ +package com.baeldung.jqwik; + +import net.jqwik.api.ForAll; +import net.jqwik.api.Property; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class AdditionLiveTest { + @Property + public void additionIsCommutative(@ForAll int a, @ForAll int b) { + assertEquals(a + b, b + a); + } +} diff --git a/testing-modules/jqwik/src/test/java/com/baeldung/jqwik/DivisionLiveTest.java b/testing-modules/jqwik/src/test/java/com/baeldung/jqwik/DivisionLiveTest.java new file mode 100644 index 0000000000..f66a402e80 --- /dev/null +++ b/testing-modules/jqwik/src/test/java/com/baeldung/jqwik/DivisionLiveTest.java @@ -0,0 +1,45 @@ +package com.baeldung.jqwik; + +import net.jqwik.api.*; +import net.jqwik.api.constraints.Positive; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class DivisionLiveTest { + @Property + public void divideBySelf(@ForAll int value) { + int result = divide(value, value); + assertEquals(result, 1); + } + + @Property + public void dividePositiveBySelf(@ForAll @Positive int value) { + int result = divide(value, value); + assertEquals(result, 1); + } + + @Property + public void divideNonZeroBySelf(@ForAll("nonZeroNumbers") int value) { + int result = divide(value, value); + assertEquals(result, 1); + } + + @Property + public void divideLargeBySmall(@ForAll @Positive int a, @ForAll @Positive int b) { + Assume.that(a > b); + + int result = divide(a, b); + assertTrue(result >= 1); + } + + @Provide + Arbitrary nonZeroNumbers() { + return Arbitraries.integers() + .filter(v -> v != 0); + } + + private int divide(int a, int b) { + return a / b; + } +} diff --git a/testing-modules/jqwik/src/test/java/com/baeldung/jqwik/ShrinkingLiveTest.java b/testing-modules/jqwik/src/test/java/com/baeldung/jqwik/ShrinkingLiveTest.java new file mode 100644 index 0000000000..cd3396ae37 --- /dev/null +++ b/testing-modules/jqwik/src/test/java/com/baeldung/jqwik/ShrinkingLiveTest.java @@ -0,0 +1,15 @@ +package com.baeldung.jqwik; + +import net.jqwik.api.ForAll; +import net.jqwik.api.Property; +import net.jqwik.api.constraints.Positive; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class ShrinkingLiveTest { + @Property + public void square(@ForAll @Positive int a) { + int result = a * a; + assertTrue(result >= a); + } +} diff --git a/testing-modules/mocks/src/main/java/com/baeldung/jmockit/AdvancedCollaborator.java b/testing-modules/mocks/src/main/java/com/baeldung/jmockit/AdvancedCollaborator.java index 61afccc745..2bf116a49c 100644 --- a/testing-modules/mocks/src/main/java/com/baeldung/jmockit/AdvancedCollaborator.java +++ b/testing-modules/mocks/src/main/java/com/baeldung/jmockit/AdvancedCollaborator.java @@ -7,7 +7,7 @@ public class AdvancedCollaborator { public AdvancedCollaborator(String string) throws Exception{ i = string.length(); } - public String methodThatCallsPrivateMethod(int i){ + public String methodThatCallsProtectedMethod(int i){ return protectedMethod() + i; } public int methodThatReturnsThePrivateField(){ diff --git a/testing-modules/mocks/src/main/java/com/baeldung/jmockit/AppManager.java b/testing-modules/mocks/src/main/java/com/baeldung/jmockit/AppManager.java index 6306a94d29..0ecff9899d 100644 --- a/testing-modules/mocks/src/main/java/com/baeldung/jmockit/AppManager.java +++ b/testing-modules/mocks/src/main/java/com/baeldung/jmockit/AppManager.java @@ -20,7 +20,4 @@ public class AppManager { return new Random().nextInt(7); } - private static Integer stringToInteger(String num) { - return Integer.parseInt(num); - } } diff --git a/testing-modules/mocks/src/test/java/com/baeldung/jmockit/AdvancedCollaboratorIntegrationTest.java b/testing-modules/mocks/src/test/java/com/baeldung/jmockit/AdvancedCollaboratorIntegrationTest.java index ff69a701e7..75cbc41274 100644 --- a/testing-modules/mocks/src/test/java/com/baeldung/jmockit/AdvancedCollaboratorIntegrationTest.java +++ b/testing-modules/mocks/src/test/java/com/baeldung/jmockit/AdvancedCollaboratorIntegrationTest.java @@ -31,7 +31,7 @@ public class AdvancedCollaboratorIntegrationTest { return "mocked: "; } }; - String res = mock.methodThatCallsPrivateMethod(1); + String res = mock.methodThatCallsProtectedMethod(1); assertEquals("mocked: 1", res); } diff --git a/testing-modules/pom.xml b/testing-modules/pom.xml index 8040113a03..108ce29b86 100644 --- a/testing-modules/pom.xml +++ b/testing-modules/pom.xml @@ -23,6 +23,7 @@ groovy-spock hamcrest instancio + jqwik junit-4 junit-5-advanced junit-5-basics @@ -39,8 +40,9 @@ powermock rest-assured rest-testing - selenium-junit-testng - selenium-webdriver + selenide + selenium + selenium-2 spring-mockito spring-testing-2 spring-testing @@ -57,4 +59,4 @@ gatling-java
- \ No newline at end of file + diff --git a/testing-modules/selenide/README.md b/testing-modules/selenide/README.md new file mode 100644 index 0000000000..afe15417f6 --- /dev/null +++ b/testing-modules/selenide/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [Introduction to Selenide](https://www.baeldung.com/selenide) diff --git a/testing-modules/selenide/pom.xml b/testing-modules/selenide/pom.xml new file mode 100644 index 0000000000..99538d2d14 --- /dev/null +++ b/testing-modules/selenide/pom.xml @@ -0,0 +1,63 @@ + + + 4.0.0 + selenide + 0.0.1-SNAPSHOT + selenide + + + com.baeldung + testing-modules + 1.0.0-SNAPSHOT + + + + + com.codeborne + selenide + 6.15.0 + test + + + org.junit.platform + junit-platform-engine + ${junit-platform.version} + test + + + org.junit.platform + junit-platform-console-standalone + ${junit-platform.version} + test + + + org.junit.jupiter + junit-jupiter-migrationsupport + ${junit-jupiter.version} + test + + + + + + + src/main/resources + true + + + src/test/resources + true + + + + + + 6.10 + 4.8.3 + 5.3.2 + + + + diff --git a/testing-modules/selenide/src/test/java/com/baeldung/selenide/PageObjectsLiveTest.java b/testing-modules/selenide/src/test/java/com/baeldung/selenide/PageObjectsLiveTest.java new file mode 100644 index 0000000000..4a7a0c37df --- /dev/null +++ b/testing-modules/selenide/src/test/java/com/baeldung/selenide/PageObjectsLiveTest.java @@ -0,0 +1,60 @@ +package com.baeldung.selenide; + +import com.codeborne.selenide.Selenide; +import com.codeborne.selenide.SelenideElement; +import org.junit.jupiter.api.Test; +import org.openqa.selenium.By; + +import static com.codeborne.selenide.Condition.visible; +import static com.codeborne.selenide.Selenide.$; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class PageObjectsLiveTest { + @Test + public void searchBaeldung() { + SearchFormPage searchFormPage = new SearchFormPage(); + searchFormPage.open(); + searchFormPage.search("Baeldung"); + + SearchResultsPage results = new SearchResultsPage(); + + SearchResult firstResult = results.getResult(0); + assertTrue(firstResult.getText().contains("Baeldung")); + assertTrue(firstResult.getText().contains("In-depth, to-the-point tutorials on Java, Spring, Spring Boot, Security, and REST.")); + } + + public class SearchFormPage { + public void open() { + Selenide.open("http://duckduckgo.com/"); + } + + public void search(String term) { + SelenideElement searchbox = $(By.id("searchbox_input")); + searchbox.click(); + searchbox.sendKeys(term); + searchbox.pressEnter(); + } + } + + public class SearchResultsPage { + public SearchResult getResult(int index) { + SelenideElement result = $(By.id("r1-" + index)); + + result.shouldBe(visible); + + return new SearchResult(result); + } + } + + public class SearchResult { + private SelenideElement result; + + public SearchResult(SelenideElement result) { + this.result = result; + } + + public String getText() { + return result.getText(); + } + } +} diff --git a/testing-modules/selenide/src/test/java/com/baeldung/selenide/SearchLiveTest.java b/testing-modules/selenide/src/test/java/com/baeldung/selenide/SearchLiveTest.java new file mode 100644 index 0000000000..d29dd967d6 --- /dev/null +++ b/testing-modules/selenide/src/test/java/com/baeldung/selenide/SearchLiveTest.java @@ -0,0 +1,39 @@ +package com.baeldung.selenide; + +import com.codeborne.selenide.SelenideElement; +import org.junit.jupiter.api.Test; +import org.openqa.selenium.By; + +import static com.codeborne.selenide.Selenide.*; +import static com.codeborne.selenide.Condition.*; + +public class SearchLiveTest { + + @Test + public void searchBaeldung() throws Exception { + open("https://duckduckgo.com/"); + + SelenideElement searchbox = $(By.id("searchbox_input")); + searchbox.click(); + searchbox.sendKeys("Baeldung"); + searchbox.pressEnter(); + + SelenideElement firstResult = $(By.id("r1-0")); + firstResult.shouldHave(text("Baeldung")); + firstResult.shouldHave(text("In-depth, to-the-point tutorials on Java, Spring, Spring Boot, Security, and REST.")); + } + + @Test + public void searchBaeldungFailing() throws Exception { + open("https://duckduckgo.com/"); + + SelenideElement searchbox = $(By.id("searchbox_input")); + searchbox.click(); + searchbox.sendKeys("Something Else"); + searchbox.pressEnter(); + + SelenideElement firstResult = $(By.id("r1-0")); + firstResult.shouldHave(text("Baeldung")); + firstResult.shouldHave(text("In-depth, to-the-point tutorials on Java, Spring, Spring Boot, Security, and REST.")); + } +} diff --git a/testing-modules/selenium-2/README.md b/testing-modules/selenium-2/README.md new file mode 100644 index 0000000000..5403fb9f06 --- /dev/null +++ b/testing-modules/selenium-2/README.md @@ -0,0 +1,10 @@ +### Relevant Articles: +- [Running Selenium Scripts with JMeter](https://www.baeldung.com/selenium-jmeter) +- [Fixing Selenium WebDriver Executable Path Error](https://www.baeldung.com/java-selenium-webdriver-path-error) +- [Implicit Wait vs Explicit Wait in Selenium Webdriver](https://www.baeldung.com/selenium-implicit-explicit-wait) + +#### Notes: +- to run the live tests for the article *Fixing Selenium WebDriver Executable Path Error*, follow the manual setup described + [Fixing Selenium WebDriver Executable Path Error](https://www.baeldung.com/java-selenium-webdriver-path-error#manual-setup); download the 3 + drivers mentioned and place them in the src/test/resources directory + diff --git a/testing-modules/selenium-junit-testng/ThreadGroup.jmx b/testing-modules/selenium-2/ThreadGroup.jmx similarity index 100% rename from testing-modules/selenium-junit-testng/ThreadGroup.jmx rename to testing-modules/selenium-2/ThreadGroup.jmx diff --git a/testing-modules/selenium-webdriver/pom.xml b/testing-modules/selenium-2/pom.xml similarity index 95% rename from testing-modules/selenium-webdriver/pom.xml rename to testing-modules/selenium-2/pom.xml index 4eac847709..e7a8557562 100644 --- a/testing-modules/selenium-webdriver/pom.xml +++ b/testing-modules/selenium-2/pom.xml @@ -3,9 +3,9 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - selenium-webdriver + selenium-2 0.0.1-SNAPSHOT - selenium-webdriver + selenium-2 com.baeldung diff --git a/testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/setup/AutomatedSetupLiveTest.java b/testing-modules/selenium-2/src/test/java/com/baeldung/selenium/setup/AutomatedSetupLiveTest.java similarity index 100% rename from testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/setup/AutomatedSetupLiveTest.java rename to testing-modules/selenium-2/src/test/java/com/baeldung/selenium/setup/AutomatedSetupLiveTest.java diff --git a/testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/setup/InvalidSetupLiveTest.java b/testing-modules/selenium-2/src/test/java/com/baeldung/selenium/setup/InvalidSetupLiveTest.java similarity index 100% rename from testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/setup/InvalidSetupLiveTest.java rename to testing-modules/selenium-2/src/test/java/com/baeldung/selenium/setup/InvalidSetupLiveTest.java diff --git a/testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/setup/ManualSetupLiveTest.java b/testing-modules/selenium-2/src/test/java/com/baeldung/selenium/setup/ManualSetupLiveTest.java similarity index 100% rename from testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/setup/ManualSetupLiveTest.java rename to testing-modules/selenium-2/src/test/java/com/baeldung/selenium/setup/ManualSetupLiveTest.java diff --git a/testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/wait/ExplicitWaitLiveTest.java b/testing-modules/selenium-2/src/test/java/com/baeldung/selenium/wait/ExplicitWaitLiveTest.java similarity index 93% rename from testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/wait/ExplicitWaitLiveTest.java rename to testing-modules/selenium-2/src/test/java/com/baeldung/selenium/wait/ExplicitWaitLiveTest.java index 65943fbf5e..d9627c2ce2 100644 --- a/testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/wait/ExplicitWaitLiveTest.java +++ b/testing-modules/selenium-2/src/test/java/com/baeldung/selenium/wait/ExplicitWaitLiveTest.java @@ -1,21 +1,23 @@ package com.baeldung.selenium.wait; -import io.github.bonigarcia.wdm.WebDriverManager; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.time.Duration; + import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.openqa.selenium.By; import org.openqa.selenium.ElementNotInteractableException; import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; -import java.time.Duration; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; +import io.github.bonigarcia.wdm.WebDriverManager; final class ExplicitWaitLiveTest { @@ -48,10 +50,8 @@ final class ExplicitWaitLiveTest { @Test void givenPage_whenNavigatingWithoutExplicitWait_thenElementNotInteractable() { driver.navigate().to("https://www.baeldung.com/"); - - driver.findElement(LOCATOR_ABOUT).click(); - - assertThrows(ElementNotInteractableException.class, () -> driver.findElement(LOCATOR_ABOUT_BAELDUNG).click()); + WebElement about = driver.findElement(LOCATOR_ABOUT_BAELDUNG); + assertThrows(ElementNotInteractableException.class, about::click); } @Test diff --git a/testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/wait/FluentWaitLiveTest.java b/testing-modules/selenium-2/src/test/java/com/baeldung/selenium/wait/FluentWaitLiveTest.java similarity index 93% rename from testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/wait/FluentWaitLiveTest.java rename to testing-modules/selenium-2/src/test/java/com/baeldung/selenium/wait/FluentWaitLiveTest.java index c41e5619ac..9de462690d 100644 --- a/testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/wait/FluentWaitLiveTest.java +++ b/testing-modules/selenium-2/src/test/java/com/baeldung/selenium/wait/FluentWaitLiveTest.java @@ -1,22 +1,24 @@ package com.baeldung.selenium.wait; -import io.github.bonigarcia.wdm.WebDriverManager; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.time.Duration; + import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.openqa.selenium.By; import org.openqa.selenium.ElementNotInteractableException; import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.FluentWait; import org.openqa.selenium.support.ui.Wait; -import java.time.Duration; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; +import io.github.bonigarcia.wdm.WebDriverManager; final class FluentWaitLiveTest { @@ -52,10 +54,8 @@ final class FluentWaitLiveTest { @Test void givenPage_whenNavigatingWithoutFluentWait_thenElementNotInteractable() { driver.navigate().to("https://www.baeldung.com/"); - - driver.findElement(LOCATOR_ABOUT).click(); - - assertThrows(ElementNotInteractableException.class, () -> driver.findElement(LOCATOR_ABOUT_BAELDUNG).click()); + WebElement about = driver.findElement(LOCATOR_ABOUT_BAELDUNG); + assertThrows(ElementNotInteractableException.class, about::click); } @Test diff --git a/testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/wait/ImplicitWaitLiveTest.java b/testing-modules/selenium-2/src/test/java/com/baeldung/selenium/wait/ImplicitWaitLiveTest.java similarity index 99% rename from testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/wait/ImplicitWaitLiveTest.java rename to testing-modules/selenium-2/src/test/java/com/baeldung/selenium/wait/ImplicitWaitLiveTest.java index 86c401e13a..cfec83ea96 100644 --- a/testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/wait/ImplicitWaitLiveTest.java +++ b/testing-modules/selenium-2/src/test/java/com/baeldung/selenium/wait/ImplicitWaitLiveTest.java @@ -1,7 +1,9 @@ package com.baeldung.selenium.wait; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.time.Duration; -import io.github.bonigarcia.wdm.WebDriverManager; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -10,9 +12,7 @@ import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.chrome.ChromeOptions; -import java.time.Duration; - -import static org.junit.jupiter.api.Assertions.assertEquals; +import io.github.bonigarcia.wdm.WebDriverManager; final class ImplicitWaitLiveTest { diff --git a/testing-modules/selenium-webdriver/README.md b/testing-modules/selenium-webdriver/README.md deleted file mode 100644 index 055144998e..0000000000 --- a/testing-modules/selenium-webdriver/README.md +++ /dev/null @@ -1,2 +0,0 @@ -### Relevant Articles: -- [Uploading File Using Selenium Webdriver in Java](https://www.baeldung.com/java-selenium-upload-file) diff --git a/testing-modules/selenium-webdriver/1688web.png b/testing-modules/selenium/1688web.png similarity index 100% rename from testing-modules/selenium-webdriver/1688web.png rename to testing-modules/selenium/1688web.png diff --git a/testing-modules/selenium-junit-testng/README.md b/testing-modules/selenium/README.md similarity index 73% rename from testing-modules/selenium-junit-testng/README.md rename to testing-modules/selenium/README.md index 922f5d6a52..0d4a1cd15d 100644 --- a/testing-modules/selenium-junit-testng/README.md +++ b/testing-modules/selenium/README.md @@ -1,18 +1,17 @@ ### Relevant Articles: - [Guide to Selenium with JUnit / TestNG](http://www.baeldung.com/java-selenium-with-junit-and-testng) +- [Clicking Elements in Selenium using JavaScript](https://www.baeldung.com/java-selenium-javascript) +- [Handle Browser Tabs With Selenium](https://www.baeldung.com/java-handle-browser-tabs-selenium) +- [Opening a New Tab Using Selenium WebDriver in Java](https://www.baeldung.com/java-selenium-open-new-tab) +- [Retrieve the Value of an HTML Input in Selenium WebDriver](https://www.baeldung.com/java-selenium-html-input-value) - [Testing with Selenium/WebDriver and the Page Object Pattern](http://www.baeldung.com/selenium-webdriver-page-object) - [Using Cookies With Selenium WebDriver in Java](https://www.baeldung.com/java-selenium-webdriver-cookies) -- [Clicking Elements in Selenium using JavaScript](https://www.baeldung.com/java-selenium-javascript) - [Taking Screenshots With Selenium WebDriver](https://www.baeldung.com/java-selenium-screenshots) -- [Running Selenium Scripts with JMeter](https://www.baeldung.com/selenium-jmeter) -- [Fixing Selenium WebDriver Executable Path Error](https://www.baeldung.com/java-selenium-webdriver-path-error) -- [Handle Browser Tabs With Selenium](https://www.baeldung.com/java-handle-browser-tabs-selenium) -- [Implicit Wait vs Explicit Wait in Selenium Webdriver](https://www.baeldung.com/selenium-implicit-explicit-wait) +- [Uploading File Using Selenium Webdriver in Java](https://www.baeldung.com/java-selenium-upload-file) - [StaleElementReferenceException in Selenium](https://www.baeldung.com/selenium-staleelementreferenceexception) -- [Retrieve the Value of an HTML Input in Selenium WebDriver](https://www.baeldung.com/java-selenium-html-input-value) -- [Opening a New Tab Using Selenium WebDriver in Java](https://www.baeldung.com/java-selenium-open-new-tab) + #### Notes: -- to run the live tests for the article *Fixing Selenium WebDriver Executable Path Error*, follow the manual setup described +- to run the live tests, follow the manual setup described [Fixing Selenium WebDriver Executable Path Error](https://www.baeldung.com/java-selenium-webdriver-path-error#manual-setup); download the 3 drivers mentioned and place them in the src/test/resources directory diff --git a/testing-modules/selenium-junit-testng/pom.xml b/testing-modules/selenium/pom.xml similarity index 95% rename from testing-modules/selenium-junit-testng/pom.xml rename to testing-modules/selenium/pom.xml index 517dc48dde..f852c837a1 100644 --- a/testing-modules/selenium-junit-testng/pom.xml +++ b/testing-modules/selenium/pom.xml @@ -3,9 +3,9 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - selenium-junit-testng + selenium 0.0.1-SNAPSHOT - selenium-junit-testng + selenium com.baeldung diff --git a/testing-modules/selenium-junit-testng/src/main/java/com/baeldung/selenium/SeleniumExample.java b/testing-modules/selenium/src/main/java/com/baeldung/selenium/SeleniumExample.java similarity index 100% rename from testing-modules/selenium-junit-testng/src/main/java/com/baeldung/selenium/SeleniumExample.java rename to testing-modules/selenium/src/main/java/com/baeldung/selenium/SeleniumExample.java diff --git a/testing-modules/selenium-junit-testng/src/main/java/com/baeldung/selenium/config/SeleniumConfig.java b/testing-modules/selenium/src/main/java/com/baeldung/selenium/config/SeleniumConfig.java similarity index 100% rename from testing-modules/selenium-junit-testng/src/main/java/com/baeldung/selenium/config/SeleniumConfig.java rename to testing-modules/selenium/src/main/java/com/baeldung/selenium/config/SeleniumConfig.java diff --git a/testing-modules/selenium-junit-testng/src/main/java/com/baeldung/selenium/models/BaeldungAbout.java b/testing-modules/selenium/src/main/java/com/baeldung/selenium/models/BaeldungAbout.java similarity index 100% rename from testing-modules/selenium-junit-testng/src/main/java/com/baeldung/selenium/models/BaeldungAbout.java rename to testing-modules/selenium/src/main/java/com/baeldung/selenium/models/BaeldungAbout.java diff --git a/testing-modules/selenium-junit-testng/src/main/java/com/baeldung/selenium/pages/BaeldungAboutPage.java b/testing-modules/selenium/src/main/java/com/baeldung/selenium/pages/BaeldungAboutPage.java similarity index 100% rename from testing-modules/selenium-junit-testng/src/main/java/com/baeldung/selenium/pages/BaeldungAboutPage.java rename to testing-modules/selenium/src/main/java/com/baeldung/selenium/pages/BaeldungAboutPage.java diff --git a/testing-modules/selenium-junit-testng/src/main/java/com/baeldung/selenium/pages/BaeldungHomePage.java b/testing-modules/selenium/src/main/java/com/baeldung/selenium/pages/BaeldungHomePage.java similarity index 100% rename from testing-modules/selenium-junit-testng/src/main/java/com/baeldung/selenium/pages/BaeldungHomePage.java rename to testing-modules/selenium/src/main/java/com/baeldung/selenium/pages/BaeldungHomePage.java diff --git a/testing-modules/selenium-junit-testng/src/main/java/com/baeldung/selenium/pages/StartHerePage.java b/testing-modules/selenium/src/main/java/com/baeldung/selenium/pages/StartHerePage.java similarity index 100% rename from testing-modules/selenium-junit-testng/src/main/java/com/baeldung/selenium/pages/StartHerePage.java rename to testing-modules/selenium/src/main/java/com/baeldung/selenium/pages/StartHerePage.java diff --git a/testing-modules/selenium-junit-testng/src/main/java/com/baeldung/selenium/stale/RobustWebDriver.java b/testing-modules/selenium/src/main/java/com/baeldung/selenium/stale/RobustWebDriver.java similarity index 100% rename from testing-modules/selenium-junit-testng/src/main/java/com/baeldung/selenium/stale/RobustWebDriver.java rename to testing-modules/selenium/src/main/java/com/baeldung/selenium/stale/RobustWebDriver.java diff --git a/testing-modules/selenium-junit-testng/src/main/java/com/baeldung/selenium/stale/RobustWebElement.java b/testing-modules/selenium/src/main/java/com/baeldung/selenium/stale/RobustWebElement.java similarity index 100% rename from testing-modules/selenium-junit-testng/src/main/java/com/baeldung/selenium/stale/RobustWebElement.java rename to testing-modules/selenium/src/main/java/com/baeldung/selenium/stale/RobustWebElement.java diff --git a/testing-modules/selenium-junit-testng/src/main/java/com/baeldung/selenium/stale/WebElementUtils.java b/testing-modules/selenium/src/main/java/com/baeldung/selenium/stale/WebElementUtils.java similarity index 100% rename from testing-modules/selenium-junit-testng/src/main/java/com/baeldung/selenium/stale/WebElementUtils.java rename to testing-modules/selenium/src/main/java/com/baeldung/selenium/stale/WebElementUtils.java diff --git a/testing-modules/selenium-junit-testng/src/main/java/com/baeldung/selenium/tabs/TabHelper.java b/testing-modules/selenium/src/main/java/com/baeldung/selenium/tabs/TabHelper.java similarity index 100% rename from testing-modules/selenium-junit-testng/src/main/java/com/baeldung/selenium/tabs/TabHelper.java rename to testing-modules/selenium/src/main/java/com/baeldung/selenium/tabs/TabHelper.java diff --git a/testing-modules/selenium-junit-testng/src/main/resources/logback.xml b/testing-modules/selenium/src/main/resources/logback.xml similarity index 100% rename from testing-modules/selenium-junit-testng/src/main/resources/logback.xml rename to testing-modules/selenium/src/main/resources/logback.xml diff --git a/testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/clickusingjavascript/SeleniumJavaScriptClickLiveTest.java b/testing-modules/selenium/src/test/java/com/baeldung/selenium/clickusingjavascript/SeleniumJavaScriptClickLiveTest.java similarity index 100% rename from testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/clickusingjavascript/SeleniumJavaScriptClickLiveTest.java rename to testing-modules/selenium/src/test/java/com/baeldung/selenium/clickusingjavascript/SeleniumJavaScriptClickLiveTest.java diff --git a/testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/cookies/SeleniumCookiesJUnitLiveTest.java b/testing-modules/selenium/src/test/java/com/baeldung/selenium/cookies/SeleniumCookiesJUnitLiveTest.java similarity index 100% rename from testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/cookies/SeleniumCookiesJUnitLiveTest.java rename to testing-modules/selenium/src/test/java/com/baeldung/selenium/cookies/SeleniumCookiesJUnitLiveTest.java diff --git a/testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/junit/SeleniumWithJUnitLiveTest.java b/testing-modules/selenium/src/test/java/com/baeldung/selenium/junit/SeleniumWithJUnitLiveTest.java similarity index 100% rename from testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/junit/SeleniumWithJUnitLiveTest.java rename to testing-modules/selenium/src/test/java/com/baeldung/selenium/junit/SeleniumWithJUnitLiveTest.java diff --git a/testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/pages/SeleniumPageObjectLiveTest.java b/testing-modules/selenium/src/test/java/com/baeldung/selenium/pages/SeleniumPageObjectLiveTest.java similarity index 100% rename from testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/pages/SeleniumPageObjectLiveTest.java rename to testing-modules/selenium/src/test/java/com/baeldung/selenium/pages/SeleniumPageObjectLiveTest.java diff --git a/testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/screenshot/TakeScreenShotSeleniumLiveTest.java b/testing-modules/selenium/src/test/java/com/baeldung/selenium/screenshot/TakeScreenShotSeleniumLiveTest.java similarity index 100% rename from testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/screenshot/TakeScreenShotSeleniumLiveTest.java rename to testing-modules/selenium/src/test/java/com/baeldung/selenium/screenshot/TakeScreenShotSeleniumLiveTest.java diff --git a/testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/stale/RobustWebElementLiveTest.java b/testing-modules/selenium/src/test/java/com/baeldung/selenium/stale/RobustWebElementLiveTest.java similarity index 100% rename from testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/stale/RobustWebElementLiveTest.java rename to testing-modules/selenium/src/test/java/com/baeldung/selenium/stale/RobustWebElementLiveTest.java diff --git a/testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/stale/StaleElementReferenceLiveTest.java b/testing-modules/selenium/src/test/java/com/baeldung/selenium/stale/StaleElementReferenceLiveTest.java similarity index 100% rename from testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/stale/StaleElementReferenceLiveTest.java rename to testing-modules/selenium/src/test/java/com/baeldung/selenium/stale/StaleElementReferenceLiveTest.java diff --git a/testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/tabs/SeleniumOpenNewTabLiveTest.java b/testing-modules/selenium/src/test/java/com/baeldung/selenium/tabs/SeleniumOpenNewTabLiveTest.java similarity index 100% rename from testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/tabs/SeleniumOpenNewTabLiveTest.java rename to testing-modules/selenium/src/test/java/com/baeldung/selenium/tabs/SeleniumOpenNewTabLiveTest.java diff --git a/testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/tabs/SeleniumTabsLiveTest.java b/testing-modules/selenium/src/test/java/com/baeldung/selenium/tabs/SeleniumTabsLiveTest.java similarity index 100% rename from testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/tabs/SeleniumTabsLiveTest.java rename to testing-modules/selenium/src/test/java/com/baeldung/selenium/tabs/SeleniumTabsLiveTest.java diff --git a/testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/tabs/SeleniumTestBase.java b/testing-modules/selenium/src/test/java/com/baeldung/selenium/tabs/SeleniumTestBase.java similarity index 100% rename from testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/tabs/SeleniumTestBase.java rename to testing-modules/selenium/src/test/java/com/baeldung/selenium/tabs/SeleniumTestBase.java diff --git a/testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/testng/SeleniumWithTestNGLiveTest.java b/testing-modules/selenium/src/test/java/com/baeldung/selenium/testng/SeleniumWithTestNGLiveTest.java similarity index 100% rename from testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/testng/SeleniumWithTestNGLiveTest.java rename to testing-modules/selenium/src/test/java/com/baeldung/selenium/testng/SeleniumWithTestNGLiveTest.java diff --git a/testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/webdriver/SeleniumWebDriverUnitTest.java b/testing-modules/selenium/src/test/java/com/baeldung/selenium/webdriver/SeleniumWebDriverUnitTest.java similarity index 100% rename from testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/webdriver/SeleniumWebDriverUnitTest.java rename to testing-modules/selenium/src/test/java/com/baeldung/selenium/webdriver/SeleniumWebDriverUnitTest.java diff --git a/testing-modules/selenium-webdriver/src/test/java/com/baeldung/selenium/webdriver/fileupload/FileUploadWebDriverUnitTest.java b/testing-modules/selenium/src/test/java/com/baeldung/selenium/webdriver/fileupload/FileUploadWebDriverUnitTest.java similarity index 99% rename from testing-modules/selenium-webdriver/src/test/java/com/baeldung/selenium/webdriver/fileupload/FileUploadWebDriverUnitTest.java rename to testing-modules/selenium/src/test/java/com/baeldung/selenium/webdriver/fileupload/FileUploadWebDriverUnitTest.java index 18853ede56..60a7cce8ad 100644 --- a/testing-modules/selenium-webdriver/src/test/java/com/baeldung/selenium/webdriver/fileupload/FileUploadWebDriverUnitTest.java +++ b/testing-modules/selenium/src/test/java/com/baeldung/selenium/webdriver/fileupload/FileUploadWebDriverUnitTest.java @@ -5,10 +5,8 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.openqa.selenium.By; - import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; - import org.openqa.selenium.firefox.FirefoxDriver; import io.github.bonigarcia.wdm.WebDriverManager; diff --git a/testing-modules/testing-libraries-2/README.md b/testing-modules/testing-libraries-2/README.md index d075c40919..6b66649b38 100644 --- a/testing-modules/testing-libraries-2/README.md +++ b/testing-modules/testing-libraries-2/README.md @@ -5,3 +5,4 @@ - [Code Coverage with SonarQube and JaCoCo](https://www.baeldung.com/sonarqube-jacoco-code-coverage) - [Exclusions from Jacoco Report](https://www.baeldung.com/jacoco-report-exclude) - [Gray Box Testing Using the OAT Technique](https://www.baeldung.com/java-gray-box-orthogonal-array-testing) +- [Unit Testing of System.in With JUnit](https://www.baeldung.com/java-junit-testing-system-in) diff --git a/testing-modules/testing-libraries-2/pom.xml b/testing-modules/testing-libraries-2/pom.xml index 6e8ab599b4..d74ede07db 100644 --- a/testing-modules/testing-libraries-2/pom.xml +++ b/testing-modules/testing-libraries-2/pom.xml @@ -1,6 +1,6 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 testing-libraries-2 testing-libraries-2 @@ -91,6 +91,32 @@ report + + check-coverage + verify + + check + + + + + BUNDLE + + + INSTRUCTION + COVEREDRATIO + 0.70 + + + BRANCH + COVEREDRATIO + 0.68 + + + + + + diff --git a/testing-modules/testing-libraries-2/src/main/java/com/baeldung/jacocoexclusions/service/ProductService.java b/testing-modules/testing-libraries-2/src/main/java/com/baeldung/jacocoexclusions/service/ProductService.java index c87295e642..9a4a734438 100644 --- a/testing-modules/testing-libraries-2/src/main/java/com/baeldung/jacocoexclusions/service/ProductService.java +++ b/testing-modules/testing-libraries-2/src/main/java/com/baeldung/jacocoexclusions/service/ProductService.java @@ -3,7 +3,13 @@ package com.baeldung.jacocoexclusions.service; public class ProductService { private static final double DISCOUNT = 0.25; - public double getSalePrice(double originalPrice) { - return originalPrice - originalPrice * DISCOUNT; +public double getSalePrice(double originalPrice, boolean flag) { + double discount; + if (flag) { + discount = originalPrice - originalPrice * DISCOUNT; + } else { + discount = originalPrice; } + return discount; } +} \ No newline at end of file diff --git a/testing-modules/testing-libraries-2/src/main/java/com/baeldung/systemin/Application.java b/testing-modules/testing-libraries-2/src/main/java/com/baeldung/systemin/Application.java new file mode 100644 index 0000000000..a4607beb0b --- /dev/null +++ b/testing-modules/testing-libraries-2/src/main/java/com/baeldung/systemin/Application.java @@ -0,0 +1,17 @@ +package com.baeldung.systemin; + +import java.util.Scanner; + +public class Application { + + public static final String NAME = "Name: "; + + private Application() { + } + + public static String readName() { + Scanner scanner = new Scanner(System.in); + String input = scanner.next(); + return NAME.concat(input); + } +} diff --git a/testing-modules/testing-libraries-2/src/test/java/com/baeldung/jacocoexclusions/service/ProductServiceUnitTest.java b/testing-modules/testing-libraries-2/src/test/java/com/baeldung/jacocoexclusions/service/ProductServiceUnitTest.java index 609be33640..b51f2b4547 100644 --- a/testing-modules/testing-libraries-2/src/test/java/com/baeldung/jacocoexclusions/service/ProductServiceUnitTest.java +++ b/testing-modules/testing-libraries-2/src/test/java/com/baeldung/jacocoexclusions/service/ProductServiceUnitTest.java @@ -9,7 +9,14 @@ class ProductServiceUnitTest { @Test public void givenOriginalPrice_whenGetSalePrice_thenReturnsDiscountedPrice() { ProductService productService = new ProductService(); - double salePrice = productService.getSalePrice(100); + double salePrice = productService.getSalePrice(100, true); assertEquals(salePrice, 75); } + + @Test + public void givenOriginalPrice_whenGetSalePriceWithFlagFalse_thenReturnsDiscountedPrice() { + ProductService productService = new ProductService(); + double salePrice = productService.getSalePrice(100, false); + assertEquals(salePrice, 100); + } } diff --git a/testing-modules/testing-libraries-2/src/test/java/com/baeldung/systemin/SystemInUnitTest.java b/testing-modules/testing-libraries-2/src/test/java/com/baeldung/systemin/SystemInUnitTest.java new file mode 100644 index 0000000000..8570ae25fe --- /dev/null +++ b/testing-modules/testing-libraries-2/src/test/java/com/baeldung/systemin/SystemInUnitTest.java @@ -0,0 +1,40 @@ +package com.baeldung.systemin; + +import com.github.stefanbirkner.systemlambda.SystemLambda; +import org.junit.jupiter.api.Test; +import uk.org.webcompere.systemstubs.SystemStubs; + +import java.io.ByteArrayInputStream; + +import static com.baeldung.systemin.Application.NAME; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; + +class SystemInUnitTest { + private void provideInput(String data) { + ByteArrayInputStream testIn = new ByteArrayInputStream(data.getBytes()); + System.setIn(testIn); + } + + @Test + void givenName_whenReadNameFromInput_thenReturnCorrectResult() { + provideInput("Baeldung"); + String input = Application.readName(); + assertEquals(NAME.concat("Baeldung"), input); + } + + @Test + void givenName_whenReadWithSystemLambda_thenReturnCorrectResult() throws Exception { + SystemLambda.withTextFromSystemIn("Baeldung") + .execute(() -> assertEquals(NAME.concat("Baeldung"), Application.readName())); + } + + @Test + void givenName_whenReadWithSystemStubs_thenReturnCorrectResult() throws Exception { + SystemStubs.withTextFromSystemIn("Baeldung") + .execute(() -> { + assertThat(Application.readName()) + .isEqualTo(NAME.concat("Baeldung")); + }); + } +} diff --git a/testing-modules/testing-libraries-2/src/test/java/com/baeldung/systemin/SystemRulesUnitTest.java b/testing-modules/testing-libraries-2/src/test/java/com/baeldung/systemin/SystemRulesUnitTest.java new file mode 100644 index 0000000000..1797e79e1a --- /dev/null +++ b/testing-modules/testing-libraries-2/src/test/java/com/baeldung/systemin/SystemRulesUnitTest.java @@ -0,0 +1,22 @@ +package com.baeldung.systemin; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.contrib.java.lang.system.TextFromStandardInputStream; + +import static com.baeldung.systemin.Application.NAME; +import static org.junit.Assert.assertEquals; +import static org.junit.contrib.java.lang.system.TextFromStandardInputStream.emptyStandardInputStream; + +public class SystemRulesUnitTest { + + @Rule + public final TextFromStandardInputStream systemIn = emptyStandardInputStream(); + + @Test + public void givenName_whenReadWithSystemRules_thenReturnCorrectResult() { + systemIn.provideLines("Baeldung"); + assertEquals(NAME.concat("Baeldung"), Application.readName()); + } +} + diff --git a/testing-modules/testing-libraries-2/src/test/java/com/baeldung/systemin/SystemStubsUnitTest.java b/testing-modules/testing-libraries-2/src/test/java/com/baeldung/systemin/SystemStubsUnitTest.java new file mode 100644 index 0000000000..f978dee97c --- /dev/null +++ b/testing-modules/testing-libraries-2/src/test/java/com/baeldung/systemin/SystemStubsUnitTest.java @@ -0,0 +1,19 @@ +package com.baeldung.systemin; + +import org.junit.Rule; +import org.junit.Test; +import uk.org.webcompere.systemstubs.rules.SystemInRule; + +import static com.baeldung.systemin.Application.NAME; +import static org.assertj.core.api.Assertions.assertThat; + +public class SystemStubsUnitTest { + + @Rule + public SystemInRule systemInRule = new SystemInRule("Baeldung"); + + @Test + public void givenName_whenReadWithSystemStubs_thenReturnCorrectResult() { + assertThat(Application.readName()).isEqualTo(NAME.concat("Baeldung")); + } +}