diff --git a/apache-cxf/README.md b/apache-cxf/README.md index f825b85bb3..bedd19a91a 100644 --- a/apache-cxf/README.md +++ b/apache-cxf/README.md @@ -3,7 +3,7 @@ This module contains articles about Apache CXF ## Relevant Articles: -- [Introduction to Apache CXF Aegis Data Binding](https://www.baeldung.com/aegis-data-binding-in-apache-cxf) + - [Apache CXF Support for RESTful Web Services](https://www.baeldung.com/apache-cxf-rest-api) - [A Guide to Apache CXF with Spring](https://www.baeldung.com/apache-cxf-with-spring) - [Introduction to Apache CXF](https://www.baeldung.com/introduction-to-apache-cxf) diff --git a/apache-cxf/cxf-aegis/README.md b/apache-cxf/cxf-aegis/README.md new file mode 100644 index 0000000000..1cdb6efbb5 --- /dev/null +++ b/apache-cxf/cxf-aegis/README.md @@ -0,0 +1,3 @@ +### Relevant Articles: + +- [Introduction to Apache CXF Aegis Data Binding](https://www.baeldung.com/aegis-data-binding-in-apache-cxf) diff --git a/aws-app-sync/src/main/java/com/baeldung/awsappsync/AppSyncClientHelper.java b/aws-app-sync/src/main/java/com/baeldung/awsappsync/AppSyncClientHelper.java index b310e60748..f66ac1841b 100644 --- a/aws-app-sync/src/main/java/com/baeldung/awsappsync/AppSyncClientHelper.java +++ b/aws-app-sync/src/main/java/com/baeldung/awsappsync/AppSyncClientHelper.java @@ -10,8 +10,8 @@ import java.util.Map; public class AppSyncClientHelper { - static String apiUrl = "https://m4i3b6icrrb7livfbypfspiifi.appsync-api.us-east-2.amazonaws.com"; - static String apiKey = "da2-bm4rpatkkrc5jfyhvvq7itjeke"; + static String apiUrl = ""; + static String apiKey = ""; static String API_KEY_HEADER = "x-api-key"; public static WebClient.ResponseSpec getResponseBodySpec(Map requestBody) { diff --git a/aws-app-sync/src/test/java/com/baeldung/awsappsync/AwsAppSyncApplicationTests.java b/aws-app-sync/src/test/java/com/baeldung/awsappsync/AwsAppSyncApplicationTests.java index 22d99959b3..2338cc29a1 100644 --- a/aws-app-sync/src/test/java/com/baeldung/awsappsync/AwsAppSyncApplicationTests.java +++ b/aws-app-sync/src/test/java/com/baeldung/awsappsync/AwsAppSyncApplicationTests.java @@ -1,5 +1,6 @@ package com.baeldung.awsappsync; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.web.reactive.function.client.WebClient; @@ -10,6 +11,7 @@ import java.util.Map; import static org.junit.jupiter.api.Assertions.*; @SpringBootTest +@Disabled class AwsAppSyncApplicationTests { @Test diff --git a/cas/cas-secured-app/pom.xml b/cas/cas-secured-app/pom.xml index 426d65c32b..bcce82c94c 100644 --- a/cas/cas-secured-app/pom.xml +++ b/cas/cas-secured-app/pom.xml @@ -16,10 +16,6 @@ ../../parent-boot-2 - - 2.2.6.RELEASE - - org.springframework.boot diff --git a/core-groovy-2/README.md b/core-groovy-2/README.md index 95a00a1f5b..9f81ac6c16 100644 --- a/core-groovy-2/README.md +++ b/core-groovy-2/README.md @@ -13,4 +13,5 @@ This module contains articles about core Groovy concepts - [Metaprogramming in Groovy](https://www.baeldung.com/groovy-metaprogramming) - [A Quick Guide to Working with Web Services in Groovy](https://www.baeldung.com/groovy-web-services) - [Categories in Groovy](https://www.baeldung.com/groovy-categories) +- [How to Determine the Data Type in Groovy](https://www.baeldung.com/groovy-determine-data-type) - [[<-- Prev]](/core-groovy) diff --git a/core-java-modules/core-java-14/README.md b/core-java-modules/core-java-14/README.md index 13bb468b30..dc80800054 100644 --- a/core-java-modules/core-java-14/README.md +++ b/core-java-modules/core-java-14/README.md @@ -8,3 +8,4 @@ This module contains articles about Java 14. - [Java Text Blocks](https://www.baeldung.com/java-text-blocks) - [Pattern Matching for instanceof in Java 14](https://www.baeldung.com/java-pattern-matching-instanceof) - [Helpful NullPointerExceptions in Java 14](https://www.baeldung.com/java-14-nullpointerexception) +- [Foreign Memory Access API in Java 14](https://www.baeldung.com/java-foreign-memory-access) diff --git a/core-java-modules/core-java-9-improvements/README.md b/core-java-modules/core-java-9-improvements/README.md index c89d0e3c09..3b0bdcd651 100644 --- a/core-java-modules/core-java-9-improvements/README.md +++ b/core-java-modules/core-java-9-improvements/README.md @@ -9,3 +9,4 @@ This module contains articles about the improvements to core Java features intro - [Java 9 Stream API Improvements](https://www.baeldung.com/java-9-stream-api) - [Java 9 java.util.Objects Additions](https://www.baeldung.com/java-9-objects-new) - [Java 9 CompletableFuture API Improvements](https://www.baeldung.com/java-9-completablefuture) +- [Java InputStream to Byte Array and ByteBuffer](https://www.baeldung.com/convert-input-stream-to-array-of-bytes) diff --git a/core-java-modules/core-java-9-improvements/pom.xml b/core-java-modules/core-java-9-improvements/pom.xml index d1c6bac9ec..5cc4fce7a9 100644 --- a/core-java-modules/core-java-9-improvements/pom.xml +++ b/core-java-modules/core-java-9-improvements/pom.xml @@ -33,6 +33,11 @@ guava ${guava.version} + + commons-io + commons-io + ${commons-io.version} + org.junit.platform junit-platform-runner diff --git a/core-java-modules/core-java-9-improvements/src/test/java/com/baeldung/java9/io/conversion/InputStreamToByteArrayUnitTest.java b/core-java-modules/core-java-9-improvements/src/test/java/com/baeldung/java9/io/conversion/InputStreamToByteArrayUnitTest.java new file mode 100644 index 0000000000..b64709be09 --- /dev/null +++ b/core-java-modules/core-java-9-improvements/src/test/java/com/baeldung/java9/io/conversion/InputStreamToByteArrayUnitTest.java @@ -0,0 +1,57 @@ +package com.baeldung.java9.io.conversion; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.apache.commons.io.IOUtils; +import org.junit.Test; + +import com.google.common.io.ByteSource; +import com.google.common.io.ByteStreams; + +public class InputStreamToByteArrayUnitTest { + + @Test + public final void givenUsingPlainJavaOnFixedSizeStream_whenConvertingAnInputStreamToAByteArray_thenCorrect() throws IOException { + final InputStream initialStream = new ByteArrayInputStream(new byte[] { 0, 1, 2 }); + final byte[] targetArray = new byte[initialStream.available()]; + initialStream.read(targetArray); + } + + @Test + public final void givenUsingPlainJavaOnUnknownSizeStream_whenConvertingAnInputStreamToAByteArray_thenCorrect() throws IOException { + final InputStream is = new ByteArrayInputStream(new byte[] { 0, 1, 2 }); + + final ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + int nRead; + final byte[] data = new byte[1024]; + while ((nRead = is.read(data, 0, data.length)) != -1) { + buffer.write(data, 0, nRead); + } + + buffer.flush(); + final byte[] byteArray = buffer.toByteArray(); + } + + @Test + public void givenUsingPlainJava9_whenConvertingAnInputStreamToAByteArray_thenCorrect() throws IOException { + final InputStream is = new ByteArrayInputStream(new byte[] { 0, 1, 2 }); + + byte[] data = is.readAllBytes(); + } + + @Test + public final void givenUsingGuava_whenConvertingAnInputStreamToAByteArray_thenCorrect() throws IOException { + final InputStream initialStream = ByteSource.wrap(new byte[] { 0, 1, 2 }) + .openStream(); + final byte[] targetArray = ByteStreams.toByteArray(initialStream); + } + + @Test + public final void givenUsingCommonsIO_whenConvertingAnInputStreamToAByteArray_thenCorrect() throws IOException { + final InputStream initialStream = new ByteArrayInputStream(new byte[] { 0, 1, 2 }); + final byte[] targetArray = IOUtils.toByteArray(initialStream); + } +} diff --git a/core-java-modules/core-java-io-conversions-2/src/test/java/com/baeldung/inputstreamtobytes/InputStreamToByteBufferUnitTest.java b/core-java-modules/core-java-9-improvements/src/test/java/com/baeldung/java9/io/conversion/InputStreamToByteBufferUnitTest.java similarity index 97% rename from core-java-modules/core-java-io-conversions-2/src/test/java/com/baeldung/inputstreamtobytes/InputStreamToByteBufferUnitTest.java rename to core-java-modules/core-java-9-improvements/src/test/java/com/baeldung/java9/io/conversion/InputStreamToByteBufferUnitTest.java index c10aaae22a..f97352ac27 100644 --- a/core-java-modules/core-java-io-conversions-2/src/test/java/com/baeldung/inputstreamtobytes/InputStreamToByteBufferUnitTest.java +++ b/core-java-modules/core-java-9-improvements/src/test/java/com/baeldung/java9/io/conversion/InputStreamToByteBufferUnitTest.java @@ -1,4 +1,4 @@ -package com.baeldung.inputstreamtobytes; +package com.baeldung.java9.io.conversion; import com.google.common.io.ByteSource; import com.google.common.io.ByteStreams; diff --git a/core-java-modules/core-java-concurrency-advanced-3/README.md b/core-java-modules/core-java-concurrency-advanced-3/README.md index b11cde5158..dfd264116c 100644 --- a/core-java-modules/core-java-concurrency-advanced-3/README.md +++ b/core-java-modules/core-java-concurrency-advanced-3/README.md @@ -11,4 +11,5 @@ This module contains articles about advanced topics about multithreading with co - [Guide to Work Stealing in Java](https://www.baeldung.com/java-work-stealing) - [Asynchronous Programming in Java](https://www.baeldung.com/java-asynchronous-programming) - [Java Thread Deadlock and Livelock](https://www.baeldung.com/java-deadlock-livelock) +- [Guide to AtomicStampedReference in Java](https://www.baeldung.com/java-atomicstampedreference) - [[<-- previous]](/core-java-modules/core-java-concurrency-advanced-2) diff --git a/core-java-modules/core-java-concurrency-advanced-3/src/test/java/com/baeldung/exchanger/ExchangerPipeLineManualTest.java b/core-java-modules/core-java-concurrency-advanced-3/src/test/java/com/baeldung/exchanger/ExchangerPipeLineManualTest.java new file mode 100644 index 0000000000..af8b8b9aa1 --- /dev/null +++ b/core-java-modules/core-java-concurrency-advanced-3/src/test/java/com/baeldung/exchanger/ExchangerPipeLineManualTest.java @@ -0,0 +1,83 @@ +package com.baeldung.exchanger; + +import java.util.Queue; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.Exchanger; +import java.util.concurrent.ExecutionException; +import org.junit.Test; + +import static java.util.concurrent.CompletableFuture.runAsync; + + + +public class ExchangerPipeLineManualTest { + + private static final int BUFFER_SIZE = 100; + + @Test + public void givenData_whenPassedThrough_thenCorrect() throws InterruptedException, ExecutionException { + + Exchanger> readerExchanger = new Exchanger<>(); + Exchanger> writerExchanger = new Exchanger<>(); + int counter = 0; + + Runnable reader = () -> { + Queue readerBuffer = new ConcurrentLinkedQueue<>(); + while (true) { + readerBuffer.add(UUID.randomUUID().toString()); + if (readerBuffer.size() >= BUFFER_SIZE) { + try { + readerBuffer = readerExchanger.exchange(readerBuffer); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException(e); + } + } + } + }; + + Runnable processor = () -> { + Queue processorBuffer = new ConcurrentLinkedQueue<>(); + Queue writerBuffer = new ConcurrentLinkedQueue<>(); + try { + processorBuffer = readerExchanger.exchange(processorBuffer); + while (true) { + writerBuffer.add(processorBuffer.poll()); + if (processorBuffer.isEmpty()) { + try { + processorBuffer = readerExchanger.exchange(processorBuffer); + writerBuffer = writerExchanger.exchange(writerBuffer); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException(e); + } + } + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException(e); + } + }; + + Runnable writer = () -> { + Queue writerBuffer = new ConcurrentLinkedQueue<>(); + try { + writerBuffer = writerExchanger.exchange(writerBuffer); + while (true) { + System.out.println(writerBuffer.poll()); + if (writerBuffer.isEmpty()) { + writerBuffer = writerExchanger.exchange(writerBuffer); + } + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException(e); + } + }; + + CompletableFuture.allOf(runAsync(reader), runAsync(processor), runAsync(writer)).get(); + } + +} diff --git a/core-java-modules/core-java-concurrency-advanced-3/src/test/java/com/baeldung/exchanger/ExchangerUnitTest.java b/core-java-modules/core-java-concurrency-advanced-3/src/test/java/com/baeldung/exchanger/ExchangerUnitTest.java new file mode 100644 index 0000000000..ec567a3563 --- /dev/null +++ b/core-java-modules/core-java-concurrency-advanced-3/src/test/java/com/baeldung/exchanger/ExchangerUnitTest.java @@ -0,0 +1,63 @@ +package com.baeldung.exchanger; + +import static org.junit.Assert.assertEquals; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Exchanger; + +import java.util.concurrent.ExecutionException; +import org.junit.Test; + +import static java.util.concurrent.CompletableFuture.runAsync; + +public class ExchangerUnitTest { + + + @Test + public void givenThreads_whenMessageExchanged_thenCorrect() { + Exchanger exchanger = new Exchanger<>(); + + Runnable taskA = () -> { + try { + String message = exchanger.exchange("from A"); + assertEquals("from B", message); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException(e); + } + }; + + Runnable taskB = () -> { + try { + String message = exchanger.exchange("from B"); + assertEquals("from A", message); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException(e); + } + }; + + CompletableFuture.allOf(runAsync(taskA), runAsync(taskB)).join(); + } + + @Test + public void givenThread_WhenExchangedMessage_thenCorrect() throws InterruptedException, ExecutionException { + Exchanger exchanger = new Exchanger<>(); + + Runnable runner = () -> { + try { + String message = exchanger.exchange("from runner"); + assertEquals("to runner", message); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException(e); + } + }; + + CompletableFuture result = CompletableFuture.runAsync(runner); + String msg = exchanger.exchange("to runner"); + assertEquals("from runner", msg); + result.join(); + } + +} diff --git a/core-java-modules/core-java-concurrency-collections-2/pom.xml b/core-java-modules/core-java-concurrency-collections-2/pom.xml index 65a91c9a9c..7fdd348dc5 100644 --- a/core-java-modules/core-java-concurrency-collections-2/pom.xml +++ b/core-java-modules/core-java-concurrency-collections-2/pom.xml @@ -23,7 +23,12 @@ jmh-generator-annprocess ${jmh.version} - + + org.assertj + assertj-core + ${assertj.version} + test + src @@ -42,6 +47,8 @@ 1.21 28.2-jre + + 3.6.1 \ No newline at end of file diff --git a/core-java-modules/core-java-concurrency-collections-2/src/test/java/com/baeldung/concurrent/queue/TestConcurrentLinkedQueue.java b/core-java-modules/core-java-concurrency-collections-2/src/test/java/com/baeldung/concurrent/queue/TestConcurrentLinkedQueue.java new file mode 100644 index 0000000000..c61becc366 --- /dev/null +++ b/core-java-modules/core-java-concurrency-collections-2/src/test/java/com/baeldung/concurrent/queue/TestConcurrentLinkedQueue.java @@ -0,0 +1,66 @@ +package com.baeldung.concurrent.queue; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThat; + +import java.util.Arrays; +import java.util.Collection; +import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import org.junit.FixMethodOrder; +import org.junit.Test; + +@FixMethodOrder +public class TestConcurrentLinkedQueue { + + @Test + public void givenThereIsExistingCollection_WhenAddedIntoQueue_ThenShouldContainElements() { + Collection elements = Arrays.asList(1, 2, 3, 4, 5); + ConcurrentLinkedQueue concurrentLinkedQueue = new ConcurrentLinkedQueue<>(elements); + assertThat(concurrentLinkedQueue).containsExactly(1, 2, 3, 4, 5); + } + + @Test + public void givenQueueIsEmpty_WhenAccessingTheQueue_ThenQueueReturnsNull() throws InterruptedException { + ExecutorService executorService = Executors.newFixedThreadPool(1); + ConcurrentLinkedQueue concurrentLinkedQueue = new ConcurrentLinkedQueue<>(); + executorService.submit(() -> assertNull("Retrieve object is null", concurrentLinkedQueue.poll())); + TimeUnit.SECONDS.sleep(1); + executorService.awaitTermination(1, TimeUnit.SECONDS); + executorService.shutdown(); + } + + @Test + public void givenProducerOffersElementInQueue_WhenConsumerPollsQueue_ThenItRetrievesElement() throws Exception { + int element = 1; + + ExecutorService executorService = Executors.newFixedThreadPool(2); + ConcurrentLinkedQueue concurrentLinkedQueue = new ConcurrentLinkedQueue<>(); + Runnable offerTask = () -> concurrentLinkedQueue.offer(element); + + Callable pollTask = () -> { + while (concurrentLinkedQueue.peek() != null) { + return concurrentLinkedQueue.poll() + .intValue(); + } + return null; + }; + + executorService.submit(offerTask); + TimeUnit.SECONDS.sleep(1); + + Future returnedElement = executorService.submit(pollTask); + assertThat(returnedElement.get() + .intValue(), is(equalTo(element))); + executorService.awaitTermination(1, TimeUnit.SECONDS); + executorService.shutdown(); + } +} diff --git a/core-java-modules/core-java-concurrency-collections-2/src/test/java/com/baeldung/concurrent/queue/TestLinkedBlockingQueue.java b/core-java-modules/core-java-concurrency-collections-2/src/test/java/com/baeldung/concurrent/queue/TestLinkedBlockingQueue.java new file mode 100644 index 0000000000..7a78bc7b3b --- /dev/null +++ b/core-java-modules/core-java-concurrency-collections-2/src/test/java/com/baeldung/concurrent/queue/TestLinkedBlockingQueue.java @@ -0,0 +1,81 @@ +package com.baeldung.concurrent.queue; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +import java.util.Arrays; +import java.util.Collection; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +import org.junit.FixMethodOrder; +import org.junit.Test; + +@FixMethodOrder +public class TestLinkedBlockingQueue { + + @Test + public void givenThereIsExistingCollection_WhenAddedIntoQueue_ThenShouldContainElements() { + Collection elements = Arrays.asList(1, 2, 3, 4, 5); + LinkedBlockingQueue linkedBlockingQueue = new LinkedBlockingQueue<>(elements); + assertThat(linkedBlockingQueue).containsExactly(1, 2, 3, 4, 5); + } + + @Test + public void givenQueueIsEmpty_WhenAccessingTheQueue_ThenThreadBlocks() throws InterruptedException { + ExecutorService executorService = Executors.newFixedThreadPool(1); + LinkedBlockingQueue linkedBlockingQueue = new LinkedBlockingQueue<>(); + executorService.submit(() -> { + try { + linkedBlockingQueue.take(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + }); + TimeUnit.SECONDS.sleep(1); + executorService.awaitTermination(1, TimeUnit.SECONDS); + executorService.shutdown(); + } + + @Test + public void givenProducerPutsElementInQueue_WhenConsumerAccessQueue_ThenItRetrieve() { + int element = 10; + ExecutorService executorService = Executors.newFixedThreadPool(2); + LinkedBlockingQueue linkedBlockingQueue = new LinkedBlockingQueue<>(); + Runnable putTask = () -> { + try { + linkedBlockingQueue.put(element); + } catch (InterruptedException e) { + e.printStackTrace(); + } + }; + + Callable takeTask = () -> { + try { + return linkedBlockingQueue.take(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + return null; + }; + + executorService.submit(putTask); + Future returnElement = executorService.submit(takeTask); + try { + TimeUnit.SECONDS.sleep(1); + assertThat(returnElement.get() + .intValue(), is(equalTo(element))); + executorService.awaitTermination(1, TimeUnit.SECONDS); + } catch (Exception e) { + e.printStackTrace(); + } + + executorService.shutdown(); + } +} diff --git a/core-java-modules/core-java-exceptions-2/README.md b/core-java-modules/core-java-exceptions-2/README.md index 1b8457acc4..46ffd490be 100644 --- a/core-java-modules/core-java-exceptions-2/README.md +++ b/core-java-modules/core-java-exceptions-2/README.md @@ -9,3 +9,6 @@ This module contains articles about core java exceptions - [java.net.UnknownHostException: Invalid Hostname for Server](https://www.baeldung.com/java-unknownhostexception) - [How to Handle Java SocketException](https://www.baeldung.com/java-socketexception) - [Java Suppressed Exceptions](https://www.baeldung.com/java-suppressed-exceptions) +- [Java – Try with Resources](https://www.baeldung.com/java-try-with-resources) +- [Java Global Exception Handler](https://www.baeldung.com/java-global-exception-handler) +- [How to Find an Exception’s Root Cause in Java](https://www.baeldung.com/java-exception-root-cause) diff --git a/core-java-modules/core-java-exceptions-2/pom.xml b/core-java-modules/core-java-exceptions-2/pom.xml index cf8de3d5b6..915ec1da69 100644 --- a/core-java-modules/core-java-exceptions-2/pom.xml +++ b/core-java-modules/core-java-exceptions-2/pom.xml @@ -23,6 +23,11 @@ ${assertj-core.version} test + + org.apache.commons + commons-lang3 + ${commons.lang3.version} + @@ -30,6 +35,7 @@ UTF-8 + 3.10 3.10.0 diff --git a/core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/globalexceptionhandler/Arithmetic.java b/core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/globalexceptionhandler/Arithmetic.java similarity index 87% rename from core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/globalexceptionhandler/Arithmetic.java rename to core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/globalexceptionhandler/Arithmetic.java index db29198b39..57d022eb13 100644 --- a/core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/globalexceptionhandler/Arithmetic.java +++ b/core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/globalexceptionhandler/Arithmetic.java @@ -1,4 +1,4 @@ -package com.baeldung.exceptions.globalexceptionhandler; +package com.baeldung.globalexceptionhandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/globalexceptionhandler/ArrayIndexOutOfBounds.java b/core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/globalexceptionhandler/ArrayIndexOutOfBounds.java similarity index 92% rename from core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/globalexceptionhandler/ArrayIndexOutOfBounds.java rename to core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/globalexceptionhandler/ArrayIndexOutOfBounds.java index 54c95f224c..b7c8bb1875 100644 --- a/core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/globalexceptionhandler/ArrayIndexOutOfBounds.java +++ b/core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/globalexceptionhandler/ArrayIndexOutOfBounds.java @@ -1,4 +1,4 @@ -package com.baeldung.exceptions.globalexceptionhandler; +package com.baeldung.globalexceptionhandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/globalexceptionhandler/ClassCast.java b/core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/globalexceptionhandler/ClassCast.java similarity index 92% rename from core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/globalexceptionhandler/ClassCast.java rename to core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/globalexceptionhandler/ClassCast.java index 8f8a6cf9e6..1ef8399d3d 100644 --- a/core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/globalexceptionhandler/ClassCast.java +++ b/core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/globalexceptionhandler/ClassCast.java @@ -1,4 +1,4 @@ -package com.baeldung.exceptions.globalexceptionhandler; +package com.baeldung.globalexceptionhandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/globalexceptionhandler/FileNotFound.java b/core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/globalexceptionhandler/FileNotFound.java similarity index 91% rename from core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/globalexceptionhandler/FileNotFound.java rename to core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/globalexceptionhandler/FileNotFound.java index a9f2e5ee84..a94e294016 100644 --- a/core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/globalexceptionhandler/FileNotFound.java +++ b/core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/globalexceptionhandler/FileNotFound.java @@ -1,4 +1,4 @@ -package com.baeldung.exceptions.globalexceptionhandler; +package com.baeldung.globalexceptionhandler; import java.io.BufferedReader; import java.io.File; diff --git a/core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/globalexceptionhandler/GlobalExceptionHandler.java b/core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/globalexceptionhandler/GlobalExceptionHandler.java similarity index 92% rename from core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/globalexceptionhandler/GlobalExceptionHandler.java rename to core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/globalexceptionhandler/GlobalExceptionHandler.java index f2e89f44e3..4d3f7c1a98 100644 --- a/core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/globalexceptionhandler/GlobalExceptionHandler.java +++ b/core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/globalexceptionhandler/GlobalExceptionHandler.java @@ -1,4 +1,4 @@ -package com.baeldung.exceptions.globalexceptionhandler; +package com.baeldung.globalexceptionhandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/globalexceptionhandler/IllegalArgument.java b/core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/globalexceptionhandler/IllegalArgument.java similarity index 87% rename from core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/globalexceptionhandler/IllegalArgument.java rename to core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/globalexceptionhandler/IllegalArgument.java index d54757dfac..cb7f981e17 100644 --- a/core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/globalexceptionhandler/IllegalArgument.java +++ b/core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/globalexceptionhandler/IllegalArgument.java @@ -1,4 +1,4 @@ -package com.baeldung.exceptions.globalexceptionhandler; +package com.baeldung.globalexceptionhandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/globalexceptionhandler/IllegalState.java b/core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/globalexceptionhandler/IllegalState.java similarity index 92% rename from core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/globalexceptionhandler/IllegalState.java rename to core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/globalexceptionhandler/IllegalState.java index 0a812d2b82..105ca155b7 100644 --- a/core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/globalexceptionhandler/IllegalState.java +++ b/core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/globalexceptionhandler/IllegalState.java @@ -1,4 +1,4 @@ -package com.baeldung.exceptions.globalexceptionhandler; +package com.baeldung.globalexceptionhandler; import java.util.ArrayList; import java.util.Iterator; diff --git a/core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/globalexceptionhandler/InterruptedExceptionExample.java b/core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/globalexceptionhandler/InterruptedExceptionExample.java similarity index 91% rename from core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/globalexceptionhandler/InterruptedExceptionExample.java rename to core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/globalexceptionhandler/InterruptedExceptionExample.java index d0c8bb2cd0..3b37168013 100644 --- a/core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/globalexceptionhandler/InterruptedExceptionExample.java +++ b/core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/globalexceptionhandler/InterruptedExceptionExample.java @@ -1,4 +1,4 @@ -package com.baeldung.exceptions.globalexceptionhandler; +package com.baeldung.globalexceptionhandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/globalexceptionhandler/MalformedURL.java b/core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/globalexceptionhandler/MalformedURL.java similarity index 89% rename from core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/globalexceptionhandler/MalformedURL.java rename to core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/globalexceptionhandler/MalformedURL.java index 9a02f005fd..cc1f39ea69 100644 --- a/core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/globalexceptionhandler/MalformedURL.java +++ b/core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/globalexceptionhandler/MalformedURL.java @@ -1,4 +1,4 @@ -package com.baeldung.exceptions.globalexceptionhandler; +package com.baeldung.globalexceptionhandler; import java.net.MalformedURLException; import java.net.URL; diff --git a/core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/globalexceptionhandler/NullPointer.java b/core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/globalexceptionhandler/NullPointer.java similarity index 93% rename from core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/globalexceptionhandler/NullPointer.java rename to core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/globalexceptionhandler/NullPointer.java index 445cbecdc8..6d6a1706a6 100644 --- a/core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/globalexceptionhandler/NullPointer.java +++ b/core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/globalexceptionhandler/NullPointer.java @@ -1,4 +1,4 @@ -package com.baeldung.exceptions.globalexceptionhandler; +package com.baeldung.globalexceptionhandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/globalexceptionhandler/NumberFormat.java b/core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/globalexceptionhandler/NumberFormat.java similarity index 90% rename from core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/globalexceptionhandler/NumberFormat.java rename to core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/globalexceptionhandler/NumberFormat.java index 576fe51f78..7497d023ee 100644 --- a/core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/globalexceptionhandler/NumberFormat.java +++ b/core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/globalexceptionhandler/NumberFormat.java @@ -1,4 +1,4 @@ -package com.baeldung.exceptions.globalexceptionhandler; +package com.baeldung.globalexceptionhandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/globalexceptionhandler/ParseExceptionExample.java b/core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/globalexceptionhandler/ParseExceptionExample.java similarity index 90% rename from core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/globalexceptionhandler/ParseExceptionExample.java rename to core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/globalexceptionhandler/ParseExceptionExample.java index e3b3e04b10..7def606786 100644 --- a/core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/globalexceptionhandler/ParseExceptionExample.java +++ b/core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/globalexceptionhandler/ParseExceptionExample.java @@ -1,4 +1,4 @@ -package com.baeldung.exceptions.globalexceptionhandler; +package com.baeldung.globalexceptionhandler; import java.text.DateFormat; import java.text.ParseException; diff --git a/core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/globalexceptionhandler/StringIndexOutOfBounds.java b/core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/globalexceptionhandler/StringIndexOutOfBounds.java similarity index 91% rename from core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/globalexceptionhandler/StringIndexOutOfBounds.java rename to core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/globalexceptionhandler/StringIndexOutOfBounds.java index 0ee132e568..8652926777 100644 --- a/core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/globalexceptionhandler/StringIndexOutOfBounds.java +++ b/core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/globalexceptionhandler/StringIndexOutOfBounds.java @@ -1,4 +1,4 @@ -package com.baeldung.exceptions.globalexceptionhandler; +package com.baeldung.globalexceptionhandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/rootcausefinder/RootCauseFinder.java b/core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/rootcausefinder/RootCauseFinder.java similarity index 98% rename from core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/rootcausefinder/RootCauseFinder.java rename to core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/rootcausefinder/RootCauseFinder.java index 06610f3874..cb04902dfa 100644 --- a/core-java-modules/core-java-exceptions/src/main/java/com/baeldung/exceptions/rootcausefinder/RootCauseFinder.java +++ b/core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/rootcausefinder/RootCauseFinder.java @@ -1,4 +1,4 @@ -package com.baeldung.exceptions.rootcausefinder; +package com.baeldung.rootcausefinder; import java.time.LocalDate; import java.time.Period; diff --git a/core-java-modules/core-java-exceptions/src/main/java/com/baeldung/trywithresource/AutoCloseableMain.java b/core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/trywithresource/AutoCloseableMain.java similarity index 100% rename from core-java-modules/core-java-exceptions/src/main/java/com/baeldung/trywithresource/AutoCloseableMain.java rename to core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/trywithresource/AutoCloseableMain.java diff --git a/core-java-modules/core-java-exceptions/src/main/java/com/baeldung/trywithresource/AutoCloseableResourcesFirst.java b/core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/trywithresource/AutoCloseableResourcesFirst.java similarity index 100% rename from core-java-modules/core-java-exceptions/src/main/java/com/baeldung/trywithresource/AutoCloseableResourcesFirst.java rename to core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/trywithresource/AutoCloseableResourcesFirst.java diff --git a/core-java-modules/core-java-exceptions/src/main/java/com/baeldung/trywithresource/AutoCloseableResourcesSecond.java b/core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/trywithresource/AutoCloseableResourcesSecond.java similarity index 100% rename from core-java-modules/core-java-exceptions/src/main/java/com/baeldung/trywithresource/AutoCloseableResourcesSecond.java rename to core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/trywithresource/AutoCloseableResourcesSecond.java diff --git a/core-java-modules/core-java-exceptions/src/main/java/com/baeldung/trywithresource/MyResource.java b/core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/trywithresource/MyResource.java similarity index 100% rename from core-java-modules/core-java-exceptions/src/main/java/com/baeldung/trywithresource/MyResource.java rename to core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/trywithresource/MyResource.java diff --git a/core-java-modules/core-java-exceptions/src/test/java/com/baeldung/exceptions/globalexceptionhandler/GlobalExceptionHandlerUnitTest.java b/core-java-modules/core-java-exceptions-2/src/test/java/com/baeldung/globalexceptionhandler/GlobalExceptionHandlerUnitTest.java similarity index 97% rename from core-java-modules/core-java-exceptions/src/test/java/com/baeldung/exceptions/globalexceptionhandler/GlobalExceptionHandlerUnitTest.java rename to core-java-modules/core-java-exceptions-2/src/test/java/com/baeldung/globalexceptionhandler/GlobalExceptionHandlerUnitTest.java index 74ceb3b442..83347f9d9d 100644 --- a/core-java-modules/core-java-exceptions/src/test/java/com/baeldung/exceptions/globalexceptionhandler/GlobalExceptionHandlerUnitTest.java +++ b/core-java-modules/core-java-exceptions-2/src/test/java/com/baeldung/globalexceptionhandler/GlobalExceptionHandlerUnitTest.java @@ -1,4 +1,4 @@ -package com.baeldung.exceptions.globalexceptionhandler; +package com.baeldung.globalexceptionhandler; import org.junit.After; import org.junit.Before; diff --git a/core-java-modules/core-java-exceptions/src/test/java/com/baeldung/exceptions/rootcausefinder/RootCauseFinderUnitTest.java b/core-java-modules/core-java-exceptions-2/src/test/java/com/baeldung/rootcausefinder/RootCauseFinderUnitTest.java similarity index 80% rename from core-java-modules/core-java-exceptions/src/test/java/com/baeldung/exceptions/rootcausefinder/RootCauseFinderUnitTest.java rename to core-java-modules/core-java-exceptions-2/src/test/java/com/baeldung/rootcausefinder/RootCauseFinderUnitTest.java index f42388857a..ccf14c4cba 100644 --- a/core-java-modules/core-java-exceptions/src/test/java/com/baeldung/exceptions/rootcausefinder/RootCauseFinderUnitTest.java +++ b/core-java-modules/core-java-exceptions-2/src/test/java/com/baeldung/rootcausefinder/RootCauseFinderUnitTest.java @@ -1,7 +1,7 @@ -package com.baeldung.exceptions.rootcausefinder; +package com.baeldung.rootcausefinder; -import com.baeldung.exceptions.rootcausefinder.RootCauseFinder.CalculationException; -import com.baeldung.exceptions.rootcausefinder.RootCauseFinder.DateOutOfRangeException; +import com.baeldung.rootcausefinder.RootCauseFinder.CalculationException; +import com.baeldung.rootcausefinder.RootCauseFinder.DateOutOfRangeException; import com.google.common.base.Throwables; import org.apache.commons.lang3.exception.ExceptionUtils; import org.junit.jupiter.api.Assertions; @@ -11,8 +11,7 @@ import java.time.LocalDate; import java.time.format.DateTimeParseException; import java.time.temporal.ChronoUnit; -import static com.baeldung.exceptions.rootcausefinder.RootCauseFinder.AgeCalculator; -import static com.baeldung.exceptions.rootcausefinder.RootCauseFinder.findCauseUsingPlainJava; +import static com.baeldung.rootcausefinder.RootCauseFinder.AgeCalculator; import static org.junit.jupiter.api.Assertions.assertTrue; /** @@ -38,7 +37,7 @@ public class RootCauseFinderUnitTest { try { AgeCalculator.calculateAge("010102"); } catch (CalculationException ex) { - assertTrue(findCauseUsingPlainJava(ex) instanceof DateTimeParseException); + assertTrue(RootCauseFinder.findCauseUsingPlainJava(ex) instanceof DateTimeParseException); } } @@ -47,7 +46,7 @@ public class RootCauseFinderUnitTest { try { AgeCalculator.calculateAge("2020-04-04"); } catch (CalculationException ex) { - assertTrue(findCauseUsingPlainJava(ex) instanceof DateOutOfRangeException); + assertTrue(RootCauseFinder.findCauseUsingPlainJava(ex) instanceof DateOutOfRangeException); } } @@ -56,7 +55,7 @@ public class RootCauseFinderUnitTest { try { AgeCalculator.calculateAge(null); } catch (Exception ex) { - assertTrue(findCauseUsingPlainJava(ex) instanceof IllegalArgumentException); + assertTrue(RootCauseFinder.findCauseUsingPlainJava(ex) instanceof IllegalArgumentException); } } diff --git a/core-java-modules/core-java-exceptions/README.md b/core-java-modules/core-java-exceptions/README.md index b7222540e9..5f47aa69fb 100644 --- a/core-java-modules/core-java-exceptions/README.md +++ b/core-java-modules/core-java-exceptions/README.md @@ -12,9 +12,5 @@ This module contains articles about core java exceptions - [“Sneaky Throws” in Java](https://www.baeldung.com/java-sneaky-throws) - [The StackOverflowError in Java](https://www.baeldung.com/java-stack-overflow-error) - [Checked and Unchecked Exceptions in Java](https://www.baeldung.com/java-checked-unchecked-exceptions) -- [Java – Try with Resources](https://www.baeldung.com/java-try-with-resources) -- [Java Global Exception Handler](https://www.baeldung.com/java-global-exception-handler) - [Common Java Exceptions](https://www.baeldung.com/java-common-exceptions) -- [How to Find an Exception’s Root Cause in Java](https://www.baeldung.com/java-exception-root-cause) -- [Is It a Bad Practice to Catch Throwable?](https://www.baeldung.com/java-catch-throwable-bad-practice) - [[Next -->]](/core-java-modules/core-java-exceptions-2) \ No newline at end of file diff --git a/core-java-modules/core-java-io-conversions-2/README.md b/core-java-modules/core-java-io-conversions-2/README.md index 4a28bf37c5..5cb9c21c54 100644 --- a/core-java-modules/core-java-io-conversions-2/README.md +++ b/core-java-modules/core-java-io-conversions-2/README.md @@ -4,6 +4,5 @@ This module contains articles about core Java input/output(IO) conversions. ### Relevant Articles: - [Java InputStream to String](https://www.baeldung.com/convert-input-stream-to-string) -- [Java InputStream to Byte Array and ByteBuffer](https://www.baeldung.com/convert-input-stream-to-array-of-bytes) - [Java – Write an InputStream to a File](https://www.baeldung.com/convert-input-stream-to-a-file) - More articles: [[<-- prev]](/core-java-modules/core-java-io-conversions) diff --git a/core-java-modules/core-java-io-conversions-2/src/test/java/com/baeldung/inputstreamtostring/JavaInputStreamToXUnitTest.java b/core-java-modules/core-java-io-conversions-2/src/test/java/com/baeldung/inputstreamtostring/JavaInputStreamToXUnitTest.java index eb8c39f2d9..c34c32891f 100644 --- a/core-java-modules/core-java-io-conversions-2/src/test/java/com/baeldung/inputstreamtostring/JavaInputStreamToXUnitTest.java +++ b/core-java-modules/core-java-io-conversions-2/src/test/java/com/baeldung/inputstreamtostring/JavaInputStreamToXUnitTest.java @@ -2,7 +2,6 @@ package com.baeldung.inputstreamtostring; import com.google.common.base.Charsets; import com.google.common.io.ByteSource; -import com.google.common.io.ByteStreams; import com.google.common.io.CharStreams; import com.google.common.io.Files; import org.apache.commons.io.FileUtils; @@ -11,13 +10,26 @@ import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.*; +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.Reader; +import java.io.StringReader; +import java.io.StringWriter; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.nio.file.StandardCopyOption; import java.util.Scanner; import java.util.UUID; +import java.util.stream.Collectors; import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; import static org.hamcrest.Matchers.equalTo; @@ -46,6 +58,18 @@ public class JavaInputStreamToXUnitTest { assertEquals(textBuilder.toString(), originalString); } + @Test + public void givenUsingJava8_whenConvertingAnInputStreamToAString_thenCorrect() { + final String originalString = randomAlphabetic(DEFAULT_SIZE); + final InputStream inputStream = new ByteArrayInputStream(originalString.getBytes()); + + final String text = new BufferedReader(new InputStreamReader(inputStream, Charset.forName(StandardCharsets.UTF_8.name()))) + .lines() + .collect(Collectors.joining("\n")); + + assertThat(text, equalTo(originalString)); + } + @Test public final void givenUsingJava7_whenConvertingAnInputStreamToAString_thenCorrect() throws IOException { final String originalString = randomAlphabetic(DEFAULT_SIZE); @@ -127,42 +151,6 @@ public class JavaInputStreamToXUnitTest { assertThat(result, equalTo(originalString)); } - // tests - InputStream to byte[] - - @Test - public final void givenUsingPlainJavaOnFixedSizeStream_whenConvertingAnInputStreamToAByteArray_thenCorrect() throws IOException { - final InputStream initialStream = new ByteArrayInputStream(new byte[] { 0, 1, 2 }); - final byte[] targetArray = new byte[initialStream.available()]; - initialStream.read(targetArray); - } - - @Test - public final void givenUsingPlainJavaOnUnknownSizeStream_whenConvertingAnInputStreamToAByteArray_thenCorrect() throws IOException { - final InputStream is = new ByteArrayInputStream(new byte[] { 0, 1, 2 }); - - final ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - int nRead; - final byte[] data = new byte[1024]; - while ((nRead = is.read(data, 0, data.length)) != -1) { - buffer.write(data, 0, nRead); - } - - buffer.flush(); - final byte[] byteArray = buffer.toByteArray(); - } - - @Test - public final void givenUsingGuava_whenConvertingAnInputStreamToAByteArray_thenCorrect() throws IOException { - final InputStream initialStream = ByteSource.wrap(new byte[] { 0, 1, 2 }).openStream(); - final byte[] targetArray = ByteStreams.toByteArray(initialStream); - } - - @Test - public final void givenUsingCommonsIO_whenConvertingAnInputStreamToAByteArray_thenCorrect() throws IOException { - final InputStream initialStream = new ByteArrayInputStream(new byte[] { 0, 1, 2 }); - final byte[] targetArray = IOUtils.toByteArray(initialStream); - } - // tests - InputStream to File @Test diff --git a/core-java-modules/core-java-regex/README.md b/core-java-modules/core-java-regex/README.md index 6fdea9f2ca..8830af2c2d 100644 --- a/core-java-modules/core-java-regex/README.md +++ b/core-java-modules/core-java-regex/README.md @@ -10,3 +10,4 @@ - [Difference Between Java Matcher find() and matches()](https://www.baeldung.com/java-matcher-find-vs-matches) - [How to Use Regular Expressions to Replace Tokens in Strings](https://www.baeldung.com/java-regex-token-replacement) - [Regular Expressions \s and \s+ in Java](https://www.baeldung.com/java-regex-s-splus) +- [Validate Phone Numbers With Java Regex](https://www.baeldung.com/java-regex-validate-phone-numbers) diff --git a/core-java-modules/core-java-string-operations-2/src/test/java/com/baeldung/pdf/base64/EncodeDecodeUnitTest.java b/core-java-modules/core-java-string-operations-2/src/test/java/com/baeldung/pdf/base64/EncodeDecodeUnitTest.java index 0fb61ea121..0df6f58136 100644 --- a/core-java-modules/core-java-string-operations-2/src/test/java/com/baeldung/pdf/base64/EncodeDecodeUnitTest.java +++ b/core-java-modules/core-java-string-operations-2/src/test/java/com/baeldung/pdf/base64/EncodeDecodeUnitTest.java @@ -4,8 +4,10 @@ import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; +import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; +import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Paths; @@ -39,6 +41,27 @@ public class EncodeDecodeUnitTest { } + @Test + public void givenJavaBase64_whenEncodedStream_thenDecodedStreamOK() throws IOException { + + try (OutputStream os = java.util.Base64.getEncoder().wrap(new FileOutputStream(OUT_FILE)); + FileInputStream fis = new FileInputStream(IN_FILE)) { + byte[] bytes = new byte[1024]; + int read; + while ((read = fis.read(bytes)) > -1) { + os.write(bytes, 0, read); + } + } + + byte[] encoded = java.util.Base64.getEncoder().encode(inFileBytes); + byte[] encodedOnDisk = Files.readAllBytes(Paths.get(OUT_FILE)); + assertArrayEquals(encoded, encodedOnDisk); + + byte[] decoded = java.util.Base64.getDecoder().decode(encoded); + byte[] decodedOnDisk = java.util.Base64.getDecoder().decode(encodedOnDisk); + assertArrayEquals(decoded, decodedOnDisk); + } + @Test public void givenApacheCommons_givenJavaBase64_whenEncoded_thenDecodedOK() throws IOException { diff --git a/core-kotlin-modules/core-kotlin-collections/README.md b/core-kotlin-modules/core-kotlin-collections/README.md index f0da2b4cfd..66f15e7419 100644 --- a/core-kotlin-modules/core-kotlin-collections/README.md +++ b/core-kotlin-modules/core-kotlin-collections/README.md @@ -9,3 +9,4 @@ This module contains articles about core Kotlin collections. - [Converting a List to Map in Kotlin](https://www.baeldung.com/kotlin-list-to-map) - [Filtering Kotlin Collections](https://www.baeldung.com/kotlin-filter-collection) - [Collection Transformations in Kotlin](https://www.baeldung.com/kotlin-collection-transformations) +- [Difference between fold and reduce in Kotlin](https://www.baeldung.com/kotlin/fold-vs-reduce) diff --git a/core-kotlin-modules/core-kotlin-lang-2/src/main/kotlin/com/baeldung/ifelseexpression/IfElseExpressionExample.kt b/core-kotlin-modules/core-kotlin-lang-2/src/main/kotlin/com/baeldung/ifelseexpression/IfElseExpressionExample.kt new file mode 100644 index 0000000000..f4e42a4f4f --- /dev/null +++ b/core-kotlin-modules/core-kotlin-lang-2/src/main/kotlin/com/baeldung/ifelseexpression/IfElseExpressionExample.kt @@ -0,0 +1,86 @@ +package com.baeldung.ifelseexpression + +fun ifStatementUsage(): String { + val number = 15 + + if (number > 0) { + return "Positive number" + } + return "Positive number not found" +} + +fun ifElseStatementUsage(): String { + val number = -50 + + if (number > 0) { + return "Positive number" + } else { + return "Negative number" + } +} + +fun ifElseExpressionUsage(): String { + val number = -50 + + val result = if (number > 0) { + "Positive number" + } else { + "Negative number" + } + return result +} + +fun ifElseExpressionSingleLineUsage(): String { + val number = -50 + val result = if (number > 0) "Positive number" else "Negative number" + + return result +} + +fun ifElseMultipleExpressionUsage(): Int { + val x = 24 + val y = 73 + + val result = if (x > y) { + println("$x is greater than $y") + x + } else { + println("$x is less than or equal to $y") + y + } + return result +} + +fun ifElseLadderExpressionUsage(): String { + val number = 60 + + val result = if (number < 0) { + "Negative number" + } else if (number in 0..9) { + "Single digit number" + } else if (number in 10..99) { + "Double digit number" + } else { + "Number has more digits" + } + return result +} + +fun ifElseNestedExpressionUsage(): Int { + val x = 37 + val y = 89 + val z = 6 + + val result = if (x > y) { + if (x > z) + x + else + z + } else { + if (y > z) + y + else + z + } + return result +} \ No newline at end of file diff --git a/core-kotlin-modules/core-kotlin-lang-2/src/test/kotlin/com/baeldung/ifelseexpression/IfElseExpressionExampleTest.kt b/core-kotlin-modules/core-kotlin-lang-2/src/test/kotlin/com/baeldung/ifelseexpression/IfElseExpressionExampleTest.kt new file mode 100644 index 0000000000..266e41e07b --- /dev/null +++ b/core-kotlin-modules/core-kotlin-lang-2/src/test/kotlin/com/baeldung/ifelseexpression/IfElseExpressionExampleTest.kt @@ -0,0 +1,43 @@ +package com.baeldung.ifelseexpression + +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertNotEquals + +class IfElseExpressionExampleTest { + + @Test + fun givenNumber_whenIfStatementCalled_thenReturnsString() { + assertEquals("Positive number", ifStatementUsage()) + } + + @Test + fun givenNumber_whenIfElseStatementCalled_thenReturnsString() { + assertEquals("Negative number", ifElseStatementUsage()) + } + + @Test + fun givenNumber_whenIfElseExpressionCalled_thenReturnsString() { + assertEquals("Negative number", ifElseExpressionUsage()) + } + + @Test + fun givenNumber_whenIfElseExpressionSingleLineCalled_thenReturnsString() { + assertEquals("Negative number", ifElseExpressionSingleLineUsage()) + } + + @Test + fun givenNumber_whenIfElseMultipleExpressionCalled_thenReturnsNumber() { + assertEquals(73, ifElseMultipleExpressionUsage()) + } + + @Test + fun givenNumber_whenIfElseLadderExpressionCalled_thenReturnsString() { + assertEquals("Double digit number", ifElseLadderExpressionUsage()) + } + + @Test + fun givenNumber_whenIfElseNestedExpressionCalled_thenReturnsNumber() { + assertEquals(89, ifElseNestedExpressionUsage()) + } +} \ No newline at end of file diff --git a/gradle/gradle-employee-app/README.md b/gradle/gradle-employee-app/README.md new file mode 100644 index 0000000000..1bf7c5e8dd --- /dev/null +++ b/gradle/gradle-employee-app/README.md @@ -0,0 +1,3 @@ +### Relevant Articles: + +- [Building a Java Application With Gradle](https://www.baeldung.com/gradle-building-a-java-app) diff --git a/java-collections-conversions-2/README.md b/java-collections-conversions-2/README.md index 761e56253e..11dddadc5c 100644 --- a/java-collections-conversions-2/README.md +++ b/java-collections-conversions-2/README.md @@ -4,4 +4,5 @@ This module contains articles about conversions among Collection types and array ### Relevant Articles: - [Array to String Conversions](https://www.baeldung.com/java-array-to-string) -- More articles: [[<-- prev]](../java-collections-conversions) \ No newline at end of file +- [Mapping Lists with ModelMapper](https://www.baeldung.com/java-modelmapper-lists) +- More articles: [[<-- prev]](../java-collections-conversions) diff --git a/java-collections-conversions/src/test/java/com/baeldung/convertcollectiontoarraylist/CollectionToArrayListUnitTest.java b/java-collections-conversions/src/test/java/com/baeldung/convertcollectiontoarraylist/CollectionToArrayListUnitTest.java index 15960c300d..b8134de08a 100644 --- a/java-collections-conversions/src/test/java/com/baeldung/convertcollectiontoarraylist/CollectionToArrayListUnitTest.java +++ b/java-collections-conversions/src/test/java/com/baeldung/convertcollectiontoarraylist/CollectionToArrayListUnitTest.java @@ -88,7 +88,7 @@ public class CollectionToArrayListUnitTest { Iterator iterA = a.iterator(); Iterator iterB = b.iterator(); while (iterA.hasNext()) { - // use '==' to test instance identity + // test instance identity assertSame("Foo instances differ!", iterA.next(), iterB.next()); } } diff --git a/java-python-interop/README.md b/java-python-interop/README.md deleted file mode 100644 index dc9573ecde..0000000000 --- a/java-python-interop/README.md +++ /dev/null @@ -1,5 +0,0 @@ -## Java Python Interop - -This module contains articles about Java and Python interoperability. - -### Relevant Articles: diff --git a/jee-7/README.md b/jee-7/README.md index adaee67d74..88359a81ec 100644 --- a/jee-7/README.md +++ b/jee-7/README.md @@ -11,3 +11,4 @@ This module contains articles about JEE 7. - [Introduction to Testing with Arquillian](https://www.baeldung.com/arquillian) - [Java EE 7 Batch Processing](https://www.baeldung.com/java-ee-7-batch-processing) - [The Difference Between CDI and EJB Singleton](https://www.baeldung.com/jee-cdi-vs-ejb-singleton) +- [Invoking a SOAP Web Service in Java](https://www.baeldung.com/java-soap-web-service) diff --git a/jsoup/README.md b/jsoup/README.md index 271d04194d..690afe3099 100644 --- a/jsoup/README.md +++ b/jsoup/README.md @@ -4,6 +4,7 @@ This module contains articles about jsoup. ### Relevant Articles: - [Parsing HTML in Java with Jsoup](https://www.baeldung.com/java-with-jsoup) +- [How to add proxy support to Jsoup?](https://www.baeldung.com/java-jsoup-proxy) ### Build the Project diff --git a/jsoup/src/test/java/com/baeldung/jsonproxy/JsoupProxyIntegrationTest.java b/jsoup/src/test/java/com/baeldung/jsonproxy/JsoupProxyIntegrationTest.java deleted file mode 100644 index 8e854ead6a..0000000000 --- a/jsoup/src/test/java/com/baeldung/jsonproxy/JsoupProxyIntegrationTest.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.baeldung.jsonproxy; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.net.Proxy; - -import org.jsoup.Jsoup; -import org.junit.Test; - -public class JsoupProxyIntegrationTest { - - @Test - public void whenUsingHostAndPort_thenConnect() throws IOException { - Jsoup.connect("https://spring.io/blog") - .proxy("200.216.227.141", 53281) - .get(); - } - - @Test - public void whenUsingProxyClass_thenConnect() throws IOException { - Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("200.216.227.141", 53281)); - - Jsoup.connect("https://spring.io/blog") - .proxy(proxy) - .get(); - } -} diff --git a/kaniko/README.md b/kaniko/README.md new file mode 100644 index 0000000000..a69a3cb683 --- /dev/null +++ b/kaniko/README.md @@ -0,0 +1,3 @@ +### Relevant Articles: + +- [An Introduction to Kaniko](https://www.baeldung.com/ops/kaniko) diff --git a/language-interop/README.md b/language-interop/README.md new file mode 100644 index 0000000000..a28c4a5405 --- /dev/null +++ b/language-interop/README.md @@ -0,0 +1,5 @@ +## Language Interop + +This module contains articles about Java interop with other language integrations. + +### Relevant Articles: diff --git a/java-python-interop/pom.xml b/language-interop/pom.xml similarity index 91% rename from java-python-interop/pom.xml rename to language-interop/pom.xml index 6ee5a0be3b..bdf872a076 100644 --- a/java-python-interop/pom.xml +++ b/language-interop/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 - java-python-interop + language-interop 0.0.1-SNAPSHOT - java-python-interop + language-interop com.baeldung @@ -33,7 +33,7 @@ - java-python-interop + language-interop src/main/resources @@ -52,4 +52,4 @@ 3.6.1 - \ No newline at end of file + diff --git a/java-python-interop/src/main/java/com/baeldung/python/interop/ScriptEngineManagerUtils.java b/language-interop/src/main/java/com/baeldung/language/interop/python/ScriptEngineManagerUtils.java similarity index 95% rename from java-python-interop/src/main/java/com/baeldung/python/interop/ScriptEngineManagerUtils.java rename to language-interop/src/main/java/com/baeldung/language/interop/python/ScriptEngineManagerUtils.java index 981f174c33..7bf07cf598 100644 --- a/java-python-interop/src/main/java/com/baeldung/python/interop/ScriptEngineManagerUtils.java +++ b/language-interop/src/main/java/com/baeldung/language/interop/python/ScriptEngineManagerUtils.java @@ -1,4 +1,4 @@ -package com.baeldung.python.interop; +package com.baeldung.language.interop.python; import java.util.List; diff --git a/java-python-interop/src/main/resources/logback.xml b/language-interop/src/main/resources/logback.xml similarity index 100% rename from java-python-interop/src/main/resources/logback.xml rename to language-interop/src/main/resources/logback.xml diff --git a/java-python-interop/src/test/java/com/baeldung/python/interop/JavaPythonInteropUnitTest.java b/language-interop/src/test/java/com/baeldung/language/interop/python/JavaPythonInteropUnitTest.java similarity index 99% rename from java-python-interop/src/test/java/com/baeldung/python/interop/JavaPythonInteropUnitTest.java rename to language-interop/src/test/java/com/baeldung/language/interop/python/JavaPythonInteropUnitTest.java index 5ec3a2b61f..50e7403470 100644 --- a/java-python-interop/src/test/java/com/baeldung/python/interop/JavaPythonInteropUnitTest.java +++ b/language-interop/src/test/java/com/baeldung/language/interop/python/JavaPythonInteropUnitTest.java @@ -1,4 +1,4 @@ -package com.baeldung.python.interop; +package com.baeldung.language.interop.python; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.empty; diff --git a/java-python-interop/src/test/resources/hello.py b/language-interop/src/test/resources/hello.py similarity index 100% rename from java-python-interop/src/test/resources/hello.py rename to language-interop/src/test/resources/hello.py diff --git a/libraries-concurrency/README.md b/libraries-concurrency/coroutines-with-quasar/README.md similarity index 100% rename from libraries-concurrency/README.md rename to libraries-concurrency/coroutines-with-quasar/README.md diff --git a/libraries-data-2/README.md b/libraries-data-2/README.md index f992186bd9..ce7a1680d1 100644 --- a/libraries-data-2/README.md +++ b/libraries-data-2/README.md @@ -11,7 +11,8 @@ This module contains articles about libraries for data processing in Java. - [Guide to JMapper](https://www.baeldung.com/jmapper) - [An Introduction to SuanShu](https://www.baeldung.com/suanshu) - [Intro to Derive4J](https://www.baeldung.com/derive4j) -More articles: [[<-- prev]](/../libraries-data) +- [Java-R Integration](https://www.baeldung.com/java-r-integration) +- More articles: [[<-- prev]](/../libraries-data) ##### Building the project You can build the project from the command line using: *mvn clean install*, or in an IDE. If you have issues with the derive4j imports in your IDE, you have to add the folder: *target/generated-sources/annotations* to the project build path in your IDE. diff --git a/libraries-data-2/pom.xml b/libraries-data-2/pom.xml index 73c5452f77..cbb24edd3f 100644 --- a/libraries-data-2/pom.xml +++ b/libraries-data-2/pom.xml @@ -116,6 +116,11 @@ slf4j-log4j12 ${slf4j.version} + + com.univocity + univocity-parsers + ${univocity.version} + org.awaitility awaitility @@ -175,6 +180,7 @@ 3.6.2 1.7.25 3.0.0 + 2.8.4 RELEASE 3.0 1.8.1 diff --git a/libraries-data-2/src/main/java/com/baeldung/univocity/OutputService.java b/libraries-data-2/src/main/java/com/baeldung/univocity/OutputService.java new file mode 100644 index 0000000000..b316a602ad --- /dev/null +++ b/libraries-data-2/src/main/java/com/baeldung/univocity/OutputService.java @@ -0,0 +1,80 @@ +package com.baeldung.univocity; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.baeldung.univocity.model.Product; +import com.univocity.parsers.common.processor.BeanWriterProcessor; +import com.univocity.parsers.csv.CsvWriter; +import com.univocity.parsers.csv.CsvWriterSettings; +import com.univocity.parsers.fixed.FixedWidthFields; +import com.univocity.parsers.fixed.FixedWidthWriter; +import com.univocity.parsers.fixed.FixedWidthWriterSettings; +import com.univocity.parsers.tsv.TsvWriter; +import com.univocity.parsers.tsv.TsvWriterSettings; + +public class OutputService { + private Logger logger = LoggerFactory.getLogger(ParsingService.class); + + public enum OutputType { + CSV, TSV, FIXED_WIDTH + }; + + public boolean writeData(List products, OutputType outputType, String outputPath) { + try (Writer outputWriter = new OutputStreamWriter(new FileOutputStream(new File(outputPath)), "UTF-8")) { + switch (outputType) { + case CSV: { + CsvWriter writer = new CsvWriter(outputWriter, new CsvWriterSettings()); + writer.writeRowsAndClose(products); + } + break; + case TSV: { + TsvWriter writer = new TsvWriter(outputWriter, new TsvWriterSettings()); + writer.writeRowsAndClose(products); + } + break; + case FIXED_WIDTH: { + FixedWidthFields fieldLengths = new FixedWidthFields(8, 30, 10); + FixedWidthWriterSettings settings = new FixedWidthWriterSettings(fieldLengths); + FixedWidthWriter writer = new FixedWidthWriter(outputWriter, settings); + writer.writeRowsAndClose(products); + } + break; + default: + logger.warn("Invalid OutputType: " + outputType); + return false; + } + return true; + } catch (IOException e) { + logger.error(e.getMessage()); + return false; + } + } + + public boolean writeBeanToFixedWidthFile(List products, String outputPath) { + try (Writer outputWriter = new OutputStreamWriter(new FileOutputStream(new File(outputPath)), "UTF-8")) { + BeanWriterProcessor rowProcessor = new BeanWriterProcessor(Product.class); + FixedWidthFields fieldLengths = new FixedWidthFields(8, 30, 10); + FixedWidthWriterSettings settings = new FixedWidthWriterSettings(fieldLengths); + settings.setHeaders("product_no", "description", "unit_price"); + settings.setRowWriterProcessor(rowProcessor); + FixedWidthWriter writer = new FixedWidthWriter(outputWriter, settings); + writer.writeHeaders(); + for (Product product : products) { + writer.processRecord(product); + } + writer.close(); + return true; + } catch (IOException e) { + logger.error(e.getMessage()); + return false; + } + } +} diff --git a/libraries-data-2/src/main/java/com/baeldung/univocity/ParsingService.java b/libraries-data-2/src/main/java/com/baeldung/univocity/ParsingService.java new file mode 100644 index 0000000000..a88023b5d3 --- /dev/null +++ b/libraries-data-2/src/main/java/com/baeldung/univocity/ParsingService.java @@ -0,0 +1,85 @@ +package com.baeldung.univocity; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.util.ArrayList; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.baeldung.univocity.model.Product; +import com.univocity.parsers.common.processor.BatchedColumnProcessor; +import com.univocity.parsers.common.processor.BeanListProcessor; +import com.univocity.parsers.csv.CsvParser; +import com.univocity.parsers.csv.CsvParserSettings; +import com.univocity.parsers.fixed.FixedWidthFields; +import com.univocity.parsers.fixed.FixedWidthParser; +import com.univocity.parsers.fixed.FixedWidthParserSettings; + +public class ParsingService { + private Logger logger = LoggerFactory.getLogger(ParsingService.class); + + public List parseCsvFile(String relativePath) { + try (Reader inputReader = new InputStreamReader(new FileInputStream(new File(relativePath)), "UTF-8")) { + CsvParserSettings settings = new CsvParserSettings(); + settings.setMaxCharsPerColumn(100); + settings.setMaxColumns(50); + CsvParser parser = new CsvParser(settings); + List parsedRows = parser.parseAll(inputReader); + return parsedRows; + } catch (IOException e) { + logger.error("IOException opening file: " + relativePath + " " + e.getMessage()); + return new ArrayList(); + } + } + + public List parseFixedWidthFile(String relativePath) { + try (Reader inputReader = new InputStreamReader(new FileInputStream(new File(relativePath)), "UTF-8")) { + FixedWidthFields fieldLengths = new FixedWidthFields(8, 30, 10); + FixedWidthParserSettings settings = new FixedWidthParserSettings(fieldLengths); + + FixedWidthParser parser = new FixedWidthParser(settings); + List parsedRows = parser.parseAll(inputReader); + return parsedRows; + } catch (IOException e) { + logger.error("IOException opening file: " + relativePath + " " + e.getMessage()); + return new ArrayList(); + } + } + + public List parseCsvFileIntoBeans(String relativePath) { + try (Reader inputReader = new InputStreamReader(new FileInputStream(new File(relativePath)), "UTF-8")) { + BeanListProcessor rowProcessor = new BeanListProcessor(Product.class); + CsvParserSettings settings = new CsvParserSettings(); + settings.setHeaderExtractionEnabled(true); + settings.setProcessor(rowProcessor); + CsvParser parser = new CsvParser(settings); + parser.parse(inputReader); + return rowProcessor.getBeans(); + } catch (IOException e) { + logger.error("IOException opening file: " + relativePath + " " + e.getMessage()); + return new ArrayList(); + } + } + + public List parseCsvFileInBatches(String relativePath) { + try (Reader inputReader = new InputStreamReader(new FileInputStream(new File(relativePath)), "UTF-8")) { + CsvParserSettings settings = new CsvParserSettings(); + settings.setProcessor(new BatchedColumnProcessor(5) { + @Override + public void batchProcessed(int rowsInThisBatch) { + } + }); + CsvParser parser = new CsvParser(settings); + List parsedRows = parser.parseAll(inputReader); + return parsedRows; + } catch (IOException e) { + logger.error("IOException opening file: " + relativePath + " " + e.getMessage()); + return new ArrayList(); + } + } +} diff --git a/libraries-data-2/src/main/java/com/baeldung/univocity/model/Product.java b/libraries-data-2/src/main/java/com/baeldung/univocity/model/Product.java new file mode 100644 index 0000000000..dc4a28f62a --- /dev/null +++ b/libraries-data-2/src/main/java/com/baeldung/univocity/model/Product.java @@ -0,0 +1,44 @@ +package com.baeldung.univocity.model; + +import com.univocity.parsers.annotations.Parsed; + +public class Product { + + @Parsed(field = "product_no") + private String productNumber; + + @Parsed + private String description; + + @Parsed(field = "unit_price") + private float unitPrice; + + public String getProductNumber() { + return productNumber; + } + + public void setProductNumber(String productNumber) { + this.productNumber = productNumber; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public float getUnitPrice() { + return unitPrice; + } + + public void setUnitPrice(float unitPrice) { + this.unitPrice = unitPrice; + } + + @Override + public String toString() { + return "Product [Product Number: " + productNumber + ", Description: " + description + ", Unit Price: " + unitPrice + "]"; + } +} diff --git a/libraries-data-2/src/test/java/com/baeldung/univocity/ParsingServiceUnitTest.java b/libraries-data-2/src/test/java/com/baeldung/univocity/ParsingServiceUnitTest.java new file mode 100644 index 0000000000..8cac0bc4b8 --- /dev/null +++ b/libraries-data-2/src/test/java/com/baeldung/univocity/ParsingServiceUnitTest.java @@ -0,0 +1,112 @@ +package com.baeldung.univocity; + +import static org.junit.Assert.assertEquals; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; + +import com.baeldung.univocity.model.Product; + +public class ParsingServiceUnitTest { + + @Test + public void givenCsvFile_thenParsedResultsShouldBeReturned() { + ParsingService parsingService = new ParsingService(); + List productData = parsingService.parseCsvFile("src/test/resources/productList.csv"); + assertEquals(3, productData.size()); + assertEquals(3, productData.get(0).length); + assertEquals("A8993-10", productData.get(0)[0]); + assertEquals("Extra large widget", productData.get(0)[1]); + assertEquals("35.42", productData.get(0)[2]); + assertEquals("D-2938-1", productData.get(1)[0]); + assertEquals("Winding widget \"Deluxe Model\"", productData.get(1)[1]); + assertEquals("245.99", productData.get(1)[2]); + assertEquals("R3212-32", productData.get(2)[0]); + assertEquals("Standard widget", productData.get(2)[1]); + assertEquals("2.34", productData.get(2)[2]); + } + + @Test + public void givenFixedWidthFile_thenParsedResultsShouldBeReturned() { + ParsingService parsingService = new ParsingService(); + List productData = parsingService.parseFixedWidthFile("src/test/resources/productList.txt"); + // Note: any extra spaces on the end will cause a null line to be added + assertEquals(3, productData.size()); + assertEquals(3, productData.get(0).length); + assertEquals("A8993-10", productData.get(0)[0]); + assertEquals("Extra large widget", productData.get(0)[1]); + assertEquals("35.42", productData.get(0)[2]); + assertEquals("D-2938-1", productData.get(1)[0]); + assertEquals("Winding widget \"Deluxe Model\"", productData.get(1)[1]); + assertEquals("245.99", productData.get(1)[2]); + assertEquals("R3212-32", productData.get(2)[0]); + assertEquals("Standard widget", productData.get(2)[1]); + assertEquals("2.34", productData.get(2)[2]); + } + + @Test + public void givenDataAndCsvOutputType_thenCsvFileProduced() { + OutputService outputService = new OutputService(); + List productData = new ArrayList<>(); + productData.add(new Object[] { "1000-3-0", "Widget No. 96", "5.67" }); + productData.add(new Object[] { "G930-M-P", "1/4\" Wocket", ".67" }); + productData.add(new Object[] { "8080-0-M", "No. 54 Jumbo Widget", "35.74" }); + outputService.writeData(productData, OutputService.OutputType.CSV, "src/test/resources/outputProductList.csv"); + + ParsingService parsingService = new ParsingService(); + List writtenData = parsingService.parseCsvFile("src/test/resources/outputProductList.csv"); + assertEquals(3, writtenData.size()); + assertEquals(3, writtenData.get(0).length); + } + + @Test + public void givenDataAndFixedWidthOutputType_thenFixedWidthFileProduced() { + OutputService outputService = new OutputService(); + List productData = new ArrayList<>(); + productData.add(new Object[] { "1000-3-0", "Widget No. 96", "5.67" }); + productData.add(new Object[] { "G930-M-P", "1/4\" Wocket", ".67" }); + productData.add(new Object[] { "8080-0-M", "No. 54 Jumbo Widget", "35.74" }); + outputService.writeData(productData, OutputService.OutputType.FIXED_WIDTH, "src/test/resources/outputProductList.txt"); + + ParsingService parsingService = new ParsingService(); + List writtenData = parsingService.parseFixedWidthFile("src/test/resources/outputProductList.txt"); + assertEquals(3, writtenData.size()); + assertEquals(3, writtenData.get(0).length); + } + + @Test + public void givenCsvFile_thenCsvFileParsedIntoBeans() { + ParsingService parsingService = new ParsingService(); + List products = parsingService.parseCsvFileIntoBeans("src/test/resources/productListWithHeaders.csv"); + assertEquals(2, products.size()); + assertEquals("Product [Product Number: 99-378AG, Description: Wocket Widget #42, Unit Price: 3.56]", products.get(0) + .toString()); + assertEquals("Product [Product Number: TB-333-0, Description: Turbine Widget replacement kit, Unit Price: 800.99]", products.get(1) + .toString()); + } + + @Test + public void givenLisOfProduct_thenWriteFixedWidthFile() { + OutputService outputService = new OutputService(); + Product product = new Product(); + product.setProductNumber("007-PPG0"); + product.setDescription("3/8\" x 1\" Wocket"); + product.setUnitPrice(45.99f); + List products = new ArrayList<>(); + products.add(product); + outputService.writeBeanToFixedWidthFile(products, "src/test/resources/productListWithHeaders.txt"); + ParsingService parsingService = new ParsingService(); + List writtenData = parsingService.parseFixedWidthFile("src/test/resources/productListWithHeaders.txt"); + assertEquals(2, writtenData.size()); + assertEquals(3, writtenData.get(0).length); + } + + @Test + public void givenLargeCsvFile_thenParsedDataShouldBeReturned() { + ParsingService parsingService = new ParsingService(); + List productData = parsingService.parseCsvFileInBatches("src/test/resources/largeProductList.csv"); + assertEquals(36, productData.size()); + } +} diff --git a/libraries-data-2/src/test/resources/largeProductList.csv b/libraries-data-2/src/test/resources/largeProductList.csv new file mode 100644 index 0000000000..2b1813d974 --- /dev/null +++ b/libraries-data-2/src/test/resources/largeProductList.csv @@ -0,0 +1,36 @@ +A8993-10,"Extra large widget",35.42 +D-2938-1,"Winding widget ""Deluxe Model""",245.99 +R3212-32,"Standard widget",2.34 +A8993-10,"Extra large widget",35.42 +D-2938-1,"Winding widget ""Deluxe Model""",245.99 +R3212-32,"Standard widget",2.34 +A8993-10,"Extra large widget",35.42 +D-2938-1,"Winding widget ""Deluxe Model""",245.99 +R3212-32,"Standard widget",2.34 +A8993-10,"Extra large widget",35.42 +D-2938-1,"Winding widget ""Deluxe Model""",245.99 +R3212-32,"Standard widget",2.34 +A8993-10,"Extra large widget",35.42 +D-2938-1,"Winding widget ""Deluxe Model""",245.99 +R3212-32,"Standard widget",2.34 +A8993-10,"Extra large widget",35.42 +D-2938-1,"Winding widget ""Deluxe Model""",245.99 +R3212-32,"Standard widget",2.34 +A8993-10,"Extra large widget",35.42 +D-2938-1,"Winding widget ""Deluxe Model""",245.99 +R3212-32,"Standard widget",2.34 +A8993-10,"Extra large widget",35.42 +D-2938-1,"Winding widget ""Deluxe Model""",245.99 +R3212-32,"Standard widget",2.34 +A8993-10,"Extra large widget",35.42 +D-2938-1,"Winding widget ""Deluxe Model""",245.99 +R3212-32,"Standard widget",2.34 +A8993-10,"Extra large widget",35.42 +D-2938-1,"Winding widget ""Deluxe Model""",245.99 +R3212-32,"Standard widget",2.34 +A8993-10,"Extra large widget",35.42 +D-2938-1,"Winding widget ""Deluxe Model""",245.99 +R3212-32,"Standard widget",2.34 +A8993-10,"Extra large widget",35.42 +D-2938-1,"Winding widget ""Deluxe Model""",245.99 +R3212-32,"Standard widget",2.34 \ No newline at end of file diff --git a/libraries-data-2/src/test/resources/productList.csv b/libraries-data-2/src/test/resources/productList.csv new file mode 100644 index 0000000000..f3a03b6c98 --- /dev/null +++ b/libraries-data-2/src/test/resources/productList.csv @@ -0,0 +1,3 @@ +A8993-10,"Extra large widget",35.42 +D-2938-1,"Winding widget ""Deluxe Model""",245.99 +R3212-32,"Standard widget",2.34 \ No newline at end of file diff --git a/libraries-data-2/src/test/resources/productList.txt b/libraries-data-2/src/test/resources/productList.txt new file mode 100644 index 0000000000..eca4caf55a --- /dev/null +++ b/libraries-data-2/src/test/resources/productList.txt @@ -0,0 +1,3 @@ +A8993-10Extra large widget 35.42 +D-2938-1Winding widget "Deluxe Model" 245.99 +R3212-32Standard widget 2.34 \ No newline at end of file diff --git a/libraries-data-2/src/test/resources/productListWithHeaders.csv b/libraries-data-2/src/test/resources/productListWithHeaders.csv new file mode 100644 index 0000000000..6514a7f0f7 --- /dev/null +++ b/libraries-data-2/src/test/resources/productListWithHeaders.csv @@ -0,0 +1,3 @@ +product_no, description, unit_price +99-378AG,Wocket Widget #42,3.56 +TB-333-0,Turbine Widget replacement kit,800.99 \ No newline at end of file diff --git a/libraries-data-2/src/test/resources/productListWithHeaders.txt b/libraries-data-2/src/test/resources/productListWithHeaders.txt new file mode 100644 index 0000000000..0fced57aed --- /dev/null +++ b/libraries-data-2/src/test/resources/productListWithHeaders.txt @@ -0,0 +1,2 @@ +product_description unit_price +007-PPG03/8" x 1" Wocket 45.99 diff --git a/libraries-http-2/pom.xml b/libraries-http-2/pom.xml index c0a4f6455d..73fe6c66bd 100644 --- a/libraries-http-2/pom.xml +++ b/libraries-http-2/pom.xml @@ -35,6 +35,37 @@ ${mockwebserver.version} test + + + org.eclipse.jetty + jetty-reactive-httpclient + ${jetty.httpclient.version} + + + org.eclipse.jetty + jetty-server + ${jetty.server.version} + + + io.reactivex.rxjava2 + rxjava + ${rxjava2.version} + + + org.springframework + spring-webflux + ${spring.webflux.version} + + + io.projectreactor + reactor-core + ${reactor.version} + + + org.reactivestreams + reactive-streams + ${reactive.stream.version} + @@ -42,6 +73,12 @@ 2.8.5 3.14.2 2.9.8 + 1.0.3 + 9.4.19.v20190610 + 2.2.11 + 5.1.9.RELEASE + 1.0.3 + 3.2.12.RELEASE diff --git a/libraries-http-2/src/main/java/com/baeldung/jetty/httpclient/BlockingSubscriber.java b/libraries-http-2/src/main/java/com/baeldung/jetty/httpclient/BlockingSubscriber.java new file mode 100644 index 0000000000..6986172cd3 --- /dev/null +++ b/libraries-http-2/src/main/java/com/baeldung/jetty/httpclient/BlockingSubscriber.java @@ -0,0 +1,35 @@ +package com.baeldung.jetty.httpclient; + +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +import org.eclipse.jetty.reactive.client.ReactiveResponse; +import org.reactivestreams.Subscriber; +import org.reactivestreams.Subscription; + +public class BlockingSubscriber implements Subscriber { + BlockingQueue sink = new LinkedBlockingQueue<>(1); + + @Override + public void onSubscribe(Subscription subscription) { + subscription.request(1); + } + + @Override + public void onNext(ReactiveResponse response) { + sink.offer(response); + } + + @Override + public void onError(Throwable failure) { + } + + @Override + public void onComplete() { + } + + public ReactiveResponse block() throws InterruptedException { + return sink.poll(5, TimeUnit.SECONDS); + } +} \ No newline at end of file diff --git a/libraries-http-2/src/main/java/com/baeldung/jetty/httpclient/RequestHandler.java b/libraries-http-2/src/main/java/com/baeldung/jetty/httpclient/RequestHandler.java new file mode 100644 index 0000000000..c3dbff9b11 --- /dev/null +++ b/libraries-http-2/src/main/java/com/baeldung/jetty/httpclient/RequestHandler.java @@ -0,0 +1,21 @@ +package com.baeldung.jetty.httpclient; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.handler.AbstractHandler; +import org.eclipse.jetty.util.IO; + +public class RequestHandler extends AbstractHandler { + + @Override + public void handle(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { + jettyRequest.setHandled(true); + response.setContentType(request.getContentType()); + IO.copy(request.getInputStream(), response.getOutputStream()); + } +} \ No newline at end of file diff --git a/libraries-http-2/src/test/java/com/baeldung/jetty/httpclient/AbstractUnitTest.java b/libraries-http-2/src/test/java/com/baeldung/jetty/httpclient/AbstractUnitTest.java new file mode 100644 index 0000000000..4a3e67a7c5 --- /dev/null +++ b/libraries-http-2/src/test/java/com/baeldung/jetty/httpclient/AbstractUnitTest.java @@ -0,0 +1,54 @@ +package com.baeldung.jetty.httpclient; + +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.server.Handler; +import org.eclipse.jetty.server.Server; +import org.junit.After; +import org.junit.Before; + +public abstract class AbstractUnitTest { + + protected HttpClient httpClient; + protected Server server; + protected static final String CONTENT = "Hello World!"; + protected final int port = 9080; + + @Before + public void init() { + startServer(new RequestHandler()); + startClient(); + } + + private void startClient() { + httpClient = new HttpClient(); + try { + httpClient.start(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void startServer(Handler handler) { + server = new Server(port); + server.setHandler(handler); + try { + server.start(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @After + public void dispose() throws Exception { + if (httpClient != null) { + httpClient.stop(); + } + if (server != null) { + server.stop(); + } + } + + protected String uri() { + return "http://localhost:" + port; + } +} \ No newline at end of file diff --git a/libraries-http-2/src/test/java/com/baeldung/jetty/httpclient/ProjectReactorUnitTest.java b/libraries-http-2/src/test/java/com/baeldung/jetty/httpclient/ProjectReactorUnitTest.java new file mode 100644 index 0000000000..6d79773609 --- /dev/null +++ b/libraries-http-2/src/test/java/com/baeldung/jetty/httpclient/ProjectReactorUnitTest.java @@ -0,0 +1,30 @@ +package com.baeldung.jetty.httpclient; + +import org.eclipse.jetty.client.api.Request; +import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.reactive.client.ReactiveRequest; +import org.eclipse.jetty.reactive.client.ReactiveResponse; +import org.junit.Assert; +import org.junit.Test; +import org.reactivestreams.Publisher; + +import reactor.core.publisher.Mono; + +public class ProjectReactorUnitTest extends AbstractUnitTest { + + @Test + public void givenReactiveClient_whenRequested_shouldReturn200() throws Exception { + + Request request = httpClient.newRequest(uri()); + ReactiveRequest reactiveRequest = ReactiveRequest.newBuilder(request) + .build(); + Publisher publisher = reactiveRequest.response(); + + ReactiveResponse response = Mono.from(publisher) + .block(); + + Assert.assertNotNull(response); + Assert.assertEquals(response.getStatus(), HttpStatus.OK_200); + + } +} diff --git a/libraries-http-2/src/test/java/com/baeldung/jetty/httpclient/ReactiveStreamsUnitTest.java b/libraries-http-2/src/test/java/com/baeldung/jetty/httpclient/ReactiveStreamsUnitTest.java new file mode 100644 index 0000000000..3db4553c86 --- /dev/null +++ b/libraries-http-2/src/test/java/com/baeldung/jetty/httpclient/ReactiveStreamsUnitTest.java @@ -0,0 +1,28 @@ +package com.baeldung.jetty.httpclient; + +import org.eclipse.jetty.client.api.Request; +import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.reactive.client.ReactiveRequest; +import org.eclipse.jetty.reactive.client.ReactiveResponse; +import org.junit.Assert; +import org.junit.Test; +import org.reactivestreams.Publisher; + +public class ReactiveStreamsUnitTest extends AbstractUnitTest { + + @Test + public void givenReactiveClient_whenRequested_shouldReturn200() throws Exception { + + Request request = httpClient.newRequest(uri()); + ReactiveRequest reactiveRequest = ReactiveRequest.newBuilder(request) + .build(); + Publisher publisher = reactiveRequest.response(); + + BlockingSubscriber subscriber = new BlockingSubscriber(); + publisher.subscribe(subscriber); + ReactiveResponse response = subscriber.block(); + Assert.assertNotNull(response); + Assert.assertEquals(response.getStatus(), HttpStatus.OK_200); + } + +} diff --git a/libraries-http-2/src/test/java/com/baeldung/jetty/httpclient/RxJava2UnitTest.java b/libraries-http-2/src/test/java/com/baeldung/jetty/httpclient/RxJava2UnitTest.java new file mode 100644 index 0000000000..dabd768702 --- /dev/null +++ b/libraries-http-2/src/test/java/com/baeldung/jetty/httpclient/RxJava2UnitTest.java @@ -0,0 +1,67 @@ +package com.baeldung.jetty.httpclient; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jetty.client.api.Request; +import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.reactive.client.ReactiveRequest; +import org.eclipse.jetty.reactive.client.ReactiveRequest.Event.Type; +import org.eclipse.jetty.reactive.client.ReactiveResponse; +import org.junit.Assert; +import org.junit.Test; +import org.reactivestreams.Publisher; +import org.springframework.http.MediaType; + +import io.reactivex.Flowable; +import io.reactivex.Single; + +public class RxJava2UnitTest extends AbstractUnitTest { + + @Test + public void givenReactiveClient_whenRequestedWithBody_ShouldReturnBody() throws Exception { + + Request request = httpClient.newRequest(uri()); + ReactiveRequest reactiveRequest = ReactiveRequest.newBuilder(request) + .content(ReactiveRequest.Content.fromString(CONTENT, MediaType.TEXT_PLAIN_VALUE, UTF_8)) + .build(); + Publisher publisher = reactiveRequest.response(ReactiveResponse.Content.asString()); + + String responseContent = Single.fromPublisher(publisher) + .blockingGet(); + + Assert.assertEquals(CONTENT, responseContent); + } + + @Test + public void givenReactiveClient_whenRequested_ShouldPrintEvents() throws Exception { + ReactiveRequest request = ReactiveRequest.newBuilder(httpClient, uri()) + .content(ReactiveRequest.Content.fromString(CONTENT, MediaType.TEXT_PLAIN_VALUE, UTF_8)) + .build(); + Publisher requestEvents = request.requestEvents(); + Publisher responseEvents = request.responseEvents(); + + List requestEventTypes = new ArrayList<>(); + List responseEventTypes = new ArrayList<>(); + + Flowable.fromPublisher(requestEvents) + .map(ReactiveRequest.Event::getType) + .subscribe(requestEventTypes::add); + + Flowable.fromPublisher(responseEvents) + .map(ReactiveResponse.Event::getType) + .subscribe(responseEventTypes::add); + + Single response = Single.fromPublisher(request.response()); + int actualStatus = response.blockingGet() + .getStatus(); + + Assert.assertEquals(6, requestEventTypes.size()); + Assert.assertEquals(5, responseEventTypes.size()); + + Assert.assertEquals(actualStatus, HttpStatus.OK_200); + } + +} \ No newline at end of file diff --git a/libraries-http-2/src/test/java/com/baeldung/jetty/httpclient/SpringWebFluxUnitTest.java b/libraries-http-2/src/test/java/com/baeldung/jetty/httpclient/SpringWebFluxUnitTest.java new file mode 100644 index 0000000000..4a1a9bb2b5 --- /dev/null +++ b/libraries-http-2/src/test/java/com/baeldung/jetty/httpclient/SpringWebFluxUnitTest.java @@ -0,0 +1,36 @@ +package com.baeldung.jetty.httpclient; + +import org.eclipse.jetty.client.HttpClient; +import org.junit.Assert; +import org.junit.Test; +import org.springframework.http.MediaType; +import org.springframework.http.client.reactive.ClientHttpConnector; +import org.springframework.http.client.reactive.JettyClientHttpConnector; +import org.springframework.web.reactive.function.BodyInserters; +import org.springframework.web.reactive.function.client.WebClient; + +import reactor.core.publisher.Mono; + +public class SpringWebFluxUnitTest extends AbstractUnitTest { + + @Test + public void givenReactiveClient_whenRequested_shouldReturnResponse() throws Exception { + + HttpClient httpClient = new HttpClient(); + httpClient.start(); + + ClientHttpConnector clientConnector = new JettyClientHttpConnector(httpClient); + WebClient client = WebClient.builder() + .clientConnector(clientConnector) + .build(); + String responseContent = client.post() + .uri(uri()) + .contentType(MediaType.TEXT_PLAIN) + .body(BodyInserters.fromPublisher(Mono.just(CONTENT), String.class)) + .retrieve() + .bodyToMono(String.class) + .block(); + Assert.assertNotNull(responseContent); + Assert.assertEquals(CONTENT, responseContent); + } +} \ No newline at end of file diff --git a/libraries-testing/src/test/java/com/baeldung/dbunit/DataSourceDBUnitTest.java b/libraries-testing/src/test/java/com/baeldung/dbunit/DataSourceDBUnitTest.java index 93c7e9a456..ab3e9f3dbd 100644 --- a/libraries-testing/src/test/java/com/baeldung/dbunit/DataSourceDBUnitTest.java +++ b/libraries-testing/src/test/java/com/baeldung/dbunit/DataSourceDBUnitTest.java @@ -24,6 +24,8 @@ import java.sql.ResultSet; import java.sql.SQLException; import static com.baeldung.dbunit.ConnectionSettings.JDBC_URL; +import static com.baeldung.dbunit.ConnectionSettings.PASSWORD; +import static com.baeldung.dbunit.ConnectionSettings.USER; import static java.util.stream.Collectors.joining; import static org.assertj.core.api.Assertions.assertThat; import static org.dbunit.Assertion.assertEqualsIgnoreCols; @@ -33,12 +35,14 @@ public class DataSourceDBUnitTest extends DataSourceBasedDBTestCase { private static final Logger logger = LoggerFactory.getLogger(DataSourceDBUnitTest.class); + private Connection connection; + @Override protected DataSource getDataSource() { JdbcDataSource dataSource = new JdbcDataSource(); dataSource.setURL(JDBC_URL); - dataSource.setUser("sa"); - dataSource.setPassword(""); + dataSource.setUser(USER); + dataSource.setPassword(PASSWORD); return dataSource; } @@ -62,6 +66,7 @@ public class DataSourceDBUnitTest extends DataSourceBasedDBTestCase { @Before public void setUp() throws Exception { super.setUp(); + connection = getConnection().getConnection(); } @After @@ -71,9 +76,7 @@ public class DataSourceDBUnitTest extends DataSourceBasedDBTestCase { @Test public void givenDataSet_whenSelect_thenFirstTitleIsGreyTShirt() throws SQLException { - final Connection connection = getDataSource().getConnection(); - - final ResultSet rs = connection.createStatement().executeQuery("select * from ITEMS where id = 1"); + ResultSet rs = connection.createStatement().executeQuery("select * from ITEMS where id = 1"); assertThat(rs.next()).isTrue(); assertThat(rs.getString("title")).isEqualTo("Grey T-Shirt"); @@ -81,58 +84,59 @@ public class DataSourceDBUnitTest extends DataSourceBasedDBTestCase { @Test public void givenDataSetEmptySchema_whenDataSetCreated_thenTablesAreEqual() throws Exception { - final IDataSet expectedDataSet = getDataSet(); - final ITable expectedTable = expectedDataSet.getTable("CLIENTS"); - final IDataSet databaseDataSet = getConnection().createDataSet(); - final ITable actualTable = databaseDataSet.getTable("CLIENTS"); + IDataSet expectedDataSet = getDataSet(); + ITable expectedTable = expectedDataSet.getTable("CLIENTS"); + IDataSet databaseDataSet = getConnection().createDataSet(); + ITable actualTable = databaseDataSet.getTable("CLIENTS"); Assertion.assertEquals(expectedTable, actualTable); } @Test public void givenDataSet_whenInsert_thenTableHasNewClient() throws Exception { - try (final InputStream is = getClass().getClassLoader().getResourceAsStream("dbunit/expected-user.xml")) { - final IDataSet expectedDataSet = new FlatXmlDataSetBuilder().build(is); - final ITable expectedTable = expectedDataSet.getTable("CLIENTS"); - final Connection conn = getDataSource().getConnection(); + try (InputStream is = getClass().getClassLoader().getResourceAsStream("dbunit/expected-user.xml")) { + // given + IDataSet expectedDataSet = new FlatXmlDataSetBuilder().build(is); + ITable expectedTable = expectedDataSet.getTable("CLIENTS"); + Connection conn = getDataSource().getConnection(); + // when conn.createStatement() - .executeUpdate( - "INSERT INTO CLIENTS (first_name, last_name) VALUES ('John', 'Jansen')"); - final ITable actualData = getConnection() - .createQueryTable( - "result_name", - "SELECT * FROM CLIENTS WHERE last_name='Jansen'"); + .executeUpdate("INSERT INTO CLIENTS (first_name, last_name) VALUES ('John', 'Jansen')"); + ITable actualData = getConnection() + .createQueryTable("result_name", "SELECT * FROM CLIENTS WHERE last_name='Jansen'"); + // then assertEqualsIgnoreCols(expectedTable, actualData, new String[] { "id" }); } } @Test public void givenDataSet_whenDelete_thenItemIsDeleted() throws Exception { - final Connection connection = getConnection().getConnection(); - - try (final InputStream is = DataSourceDBUnitTest.class.getClassLoader().getResourceAsStream("dbunit/items_exp_delete.xml")) { + try (InputStream is = DataSourceDBUnitTest.class.getClassLoader() + .getResourceAsStream("dbunit/items_exp_delete.xml")) { + // given ITable expectedTable = (new FlatXmlDataSetBuilder().build(is)).getTable("ITEMS"); + // when connection.createStatement().executeUpdate("delete from ITEMS where id = 2"); - final IDataSet databaseDataSet = getConnection().createDataSet(); + // then + IDataSet databaseDataSet = getConnection().createDataSet(); ITable actualTable = databaseDataSet.getTable("ITEMS"); - Assertion.assertEquals(expectedTable, actualTable); } } @Test public void givenDataSet_whenUpdate_thenItemHasNewName() throws Exception { - final Connection connection = getConnection().getConnection(); - - try (final InputStream is = DataSourceDBUnitTest.class.getClassLoader().getResourceAsStream("dbunit/items_exp_rename.xml")) { + try (InputStream is = DataSourceDBUnitTest.class.getClassLoader() + .getResourceAsStream("dbunit/items_exp_rename.xml")) { + // given ITable expectedTable = (new FlatXmlDataSetBuilder().build(is)).getTable("ITEMS"); connection.createStatement().executeUpdate("update ITEMS set title='new name' where id = 1"); - final IDataSet databaseDataSet = getConnection().createDataSet(); + IDataSet databaseDataSet = getConnection().createDataSet(); ITable actualTable = databaseDataSet.getTable("ITEMS"); Assertion.assertEquals(expectedTable, actualTable); @@ -140,22 +144,24 @@ public class DataSourceDBUnitTest extends DataSourceBasedDBTestCase { } @Test - public void givenDataSet_whenInsertUnexpectedData_thenFailOnAllUnexpectedValues() throws Exception { - try (final InputStream is = getClass().getClassLoader().getResourceAsStream("dbunit/expected-multiple-failures.xml")) { - final IDataSet expectedDataSet = new FlatXmlDataSetBuilder().build(is); - final ITable expectedTable = expectedDataSet.getTable("ITEMS"); - final Connection conn = getDataSource().getConnection(); - final DiffCollectingFailureHandler collectingHandler = new DiffCollectingFailureHandler(); + public void givenDataSet_whenInsertUnexpectedData_thenFail() throws Exception { + try (InputStream is = getClass().getClassLoader() + .getResourceAsStream("dbunit/expected-multiple-failures.xml")) { - conn.createStatement().executeUpdate( - "INSERT INTO ITEMS (title, price) VALUES ('Battery', '1000000')"); - final ITable actualData = getConnection().createDataSet().getTable("ITEMS"); + // given + IDataSet expectedDataSet = new FlatXmlDataSetBuilder().build(is); + ITable expectedTable = expectedDataSet.getTable("ITEMS"); + Connection conn = getDataSource().getConnection(); + DiffCollectingFailureHandler collectingHandler = new DiffCollectingFailureHandler(); + // when + conn.createStatement().executeUpdate("INSERT INTO ITEMS (title, price) VALUES ('Battery', '1000000')"); + ITable actualData = getConnection().createDataSet().getTable("ITEMS"); + + // then Assertion.assertEquals(expectedTable, actualData, collectingHandler); if (!collectingHandler.getDiffList().isEmpty()) { - String message = (String) collectingHandler - .getDiffList() - .stream() + String message = (String) collectingHandler.getDiffList().stream() .map(d -> formatDifference((Difference) d)).collect(joining("\n")); logger.error(() -> message); } @@ -163,6 +169,8 @@ public class DataSourceDBUnitTest extends DataSourceBasedDBTestCase { } private static String formatDifference(Difference diff) { - return "expected value in " + diff.getExpectedTable().getTableMetaData().getTableName() + "." + diff.getColumnName() + " row " + diff.getRowIndex() + ":" + diff.getExpectedValue() + ", but was: " + diff.getActualValue(); + return "expected value in " + diff.getExpectedTable().getTableMetaData().getTableName() + "." + diff + .getColumnName() + " row " + diff.getRowIndex() + ":" + diff.getExpectedValue() + ", but was: " + diff + .getActualValue(); } } diff --git a/libraries-testing/src/test/java/com/baeldung/dbunit/OldSchoolDbUnitTest.java b/libraries-testing/src/test/java/com/baeldung/dbunit/OldSchoolDbUnitTest.java index 6243af9676..e2db31283f 100644 --- a/libraries-testing/src/test/java/com/baeldung/dbunit/OldSchoolDbUnitTest.java +++ b/libraries-testing/src/test/java/com/baeldung/dbunit/OldSchoolDbUnitTest.java @@ -31,13 +31,15 @@ public class OldSchoolDbUnitTest { private static IDatabaseTester tester = null; + private Connection connection; + @BeforeClass public static void setUp() throws Exception { tester = initDatabaseTester(); } private static IDatabaseTester initDatabaseTester() throws Exception { - final JdbcDatabaseTester tester = new JdbcDatabaseTester(JDBC_DRIVER, JDBC_URL, USER, PASSWORD); + JdbcDatabaseTester tester = new JdbcDatabaseTester(JDBC_DRIVER, JDBC_URL, USER, PASSWORD); tester.setDataSet(initDataSet()); tester.setSetUpOperation(DatabaseOperation.REFRESH); tester.setTearDownOperation(DatabaseOperation.DELETE_ALL); @@ -45,7 +47,7 @@ public class OldSchoolDbUnitTest { } private static IDataSet initDataSet() throws Exception { - try (final InputStream is = OldSchoolDbUnitTest.class.getClassLoader().getResourceAsStream("dbunit/data.xml")) { + try (InputStream is = OldSchoolDbUnitTest.class.getClassLoader().getResourceAsStream("dbunit/data.xml")) { return new FlatXmlDataSetBuilder().build(is); } } @@ -53,6 +55,7 @@ public class OldSchoolDbUnitTest { @Before public void setup() throws Exception { tester.onSetup(); + connection = tester.getConnection().getConnection(); } @After @@ -62,94 +65,100 @@ public class OldSchoolDbUnitTest { @Test public void givenDataSet_whenSelect_thenFirstTitleIsGreyTShirt() throws Exception { - final Connection connection = tester.getConnection().getConnection(); - - final ResultSet rs = connection.createStatement().executeQuery("select * from ITEMS where id = 1"); + ResultSet rs = connection.createStatement().executeQuery("select * from ITEMS where id = 1"); assertThat(rs.next()).isTrue(); assertThat(rs.getString("title")).isEqualTo("Grey T-Shirt"); } @Test - public void givenDataSet_whenInsert_thenGetResultsAreStillEqualIfIgnoringColumnsWithDifferentProduced() throws Exception { - final Connection connection = tester.getConnection().getConnection(); - final String[] excludedColumns = { "id", "produced" }; - try (final InputStream is = getClass().getClassLoader().getResourceAsStream("dbunit/expected-ignoring-registered_at.xml")) { - final IDataSet expectedDataSet = new FlatXmlDataSetBuilder().build(is); - final ITable expectedTable = DefaultColumnFilter.excludedColumnsTable( - expectedDataSet.getTable("ITEMS"), excludedColumns); + public void givenDataSet_whenInsert_thenGetResultsAreStillEqualIfIgnoringColumnsWithDifferentProduced() + throws Exception { + String[] excludedColumns = { "id", "produced" }; + try (InputStream is = getClass().getClassLoader() + .getResourceAsStream("dbunit/expected-ignoring-registered_at.xml")) { + // given + IDataSet expectedDataSet = new FlatXmlDataSetBuilder().build(is); + ITable expectedTable = DefaultColumnFilter + .excludedColumnsTable(expectedDataSet.getTable("ITEMS"), excludedColumns); - connection.createStatement().executeUpdate( - "INSERT INTO ITEMS (title, price, produced) VALUES('Necklace', 199.99, now())"); - - final IDataSet databaseDataSet = tester.getConnection().createDataSet(); - final ITable actualTable = DefaultColumnFilter.excludedColumnsTable( - databaseDataSet.getTable("ITEMS"), excludedColumns); + // when + connection.createStatement() + .executeUpdate("INSERT INTO ITEMS (title, price, produced) VALUES('Necklace', 199.99, now())"); + // then + IDataSet databaseDataSet = tester.getConnection().createDataSet(); + ITable actualTable = DefaultColumnFilter + .excludedColumnsTable(databaseDataSet.getTable("ITEMS"), excludedColumns); Assertion.assertEquals(expectedTable, actualTable); } } @Test public void givenDataSet_whenDelete_thenItemIsRemoved() throws Exception { - final Connection connection = tester.getConnection().getConnection(); - - try (final InputStream is = OldSchoolDbUnitTest.class.getClassLoader().getResourceAsStream("dbunit/items_exp_delete.xml")) { + try (InputStream is = OldSchoolDbUnitTest.class.getClassLoader() + .getResourceAsStream("dbunit/items_exp_delete.xml")) { + // given ITable expectedTable = new FlatXmlDataSetBuilder().build(is).getTable("ITEMS"); + // when connection.createStatement().executeUpdate("delete from ITEMS where id = 2"); - final IDataSet databaseDataSet = tester.getConnection().createDataSet(); + // then + IDataSet databaseDataSet = tester.getConnection().createDataSet(); ITable actualTable = databaseDataSet.getTable("ITEMS"); - assertEquals(expectedTable, actualTable); } } @Test - public void givenDataSet_whenDelete_thenItemIsRemovedAndResultsEqualIfProducedIsIgnored() throws Exception { - final Connection connection = tester.getConnection().getConnection(); - - try (final InputStream is = OldSchoolDbUnitTest.class.getClassLoader().getResourceAsStream("dbunit/items_exp_delete_no_produced.xml")) { - final ITable expectedTable = new FlatXmlDataSetBuilder().build(is).getTable("ITEMS"); + public void givenDataSet_whenProductIgnoredAndDelete_thenItemIsRemoved() throws Exception { + try (InputStream is = OldSchoolDbUnitTest.class.getClassLoader() + .getResourceAsStream("dbunit/items_exp_delete_no_produced.xml")) { + // given + ITable expectedTable = new FlatXmlDataSetBuilder().build(is).getTable("ITEMS"); + // when connection.createStatement().executeUpdate("delete from ITEMS where id = 2"); - final IDataSet databaseDataSet = tester.getConnection().createDataSet(); + // then + IDataSet databaseDataSet = tester.getConnection().createDataSet(); ITable actualTable = databaseDataSet.getTable("ITEMS"); actualTable = DefaultColumnFilter.excludedColumnsTable(actualTable, new String[] { "produced" }); - assertEquals(expectedTable, actualTable); } } @Test public void givenDataSet_whenUpdate_thenItemHasNewName() throws Exception { - final Connection connection = tester.getConnection().getConnection(); - - try (final InputStream is = OldSchoolDbUnitTest.class.getClassLoader().getResourceAsStream("dbunit/items_exp_rename.xml")) { - final ITable expectedTable = new FlatXmlDataSetBuilder().build(is).getTable("ITEMS"); + try (InputStream is = OldSchoolDbUnitTest.class.getClassLoader() + .getResourceAsStream("dbunit/items_exp_rename.xml")) { + // given + ITable expectedTable = new FlatXmlDataSetBuilder().build(is).getTable("ITEMS"); + // when connection.createStatement().executeUpdate("update ITEMS set title='new name' where id = 1"); - final IDataSet databaseDataSet = tester.getConnection().createDataSet(); + // then + IDataSet databaseDataSet = tester.getConnection().createDataSet(); ITable actualTable = databaseDataSet.getTable("ITEMS"); - assertEquals(expectedTable, actualTable); } } @Test public void givenDataSet_whenUpdateWithNoProduced_thenItemHasNewName() throws Exception { - final Connection connection = tester.getConnection().getConnection(); - - try (final InputStream is = OldSchoolDbUnitTest.class.getClassLoader().getResourceAsStream("dbunit/items_exp_rename_no_produced.xml")) { + try (InputStream is = OldSchoolDbUnitTest.class.getClassLoader() + .getResourceAsStream("dbunit/items_exp_rename_no_produced.xml")) { + // given ITable expectedTable = new FlatXmlDataSetBuilder().build(is).getTable("ITEMS"); expectedTable = DefaultColumnFilter.excludedColumnsTable(expectedTable, new String[] { "produced" }); + // when connection.createStatement().executeUpdate("update ITEMS set title='new name' where id = 1"); - final IDataSet databaseDataSet = tester.getConnection().createDataSet(); + // then + IDataSet databaseDataSet = tester.getConnection().createDataSet(); ITable actualTable = databaseDataSet.getTable("ITEMS"); actualTable = DefaultColumnFilter.excludedColumnsTable(actualTable, new String[] { "produced" }); assertEquals(expectedTable, actualTable); diff --git a/maven-all/README.md b/maven-all/README.md index b20d944b14..b448be2cd0 100644 --- a/maven-all/README.md +++ b/maven-all/README.md @@ -5,3 +5,4 @@ This module contains articles about Apache Maven. Please refer to its submodules ### Relevant Articles - [Apache Maven Tutorial](https://www.baeldung.com/maven) +- [Find Unused Maven Dependencies](https://www.baeldung.com/maven-unused-dependencies) diff --git a/parent-spring-4/pom.xml b/parent-spring-4/pom.xml index 3f9a22fb03..931cad374b 100644 --- a/parent-spring-4/pom.xml +++ b/parent-spring-4/pom.xml @@ -53,7 +53,7 @@ - 4.3.26.RELEASE + 4.3.27.RELEASE 1.6.1 diff --git a/patterns/cqrs-es/pom.xml b/patterns/cqrs-es/pom.xml new file mode 100644 index 0000000000..3c54038837 --- /dev/null +++ b/patterns/cqrs-es/pom.xml @@ -0,0 +1,30 @@ + + 4.0.0 + cqrs-es + 1.0-SNAPSHOT + cqrs-es + + com.baeldung + patterns + 1.0.0-SNAPSHOT + + + 1.8 + 1.8 + + + + org.projectlombok + lombok + 1.18.12 + + + junit + junit + 4.13 + test + + + \ No newline at end of file diff --git a/patterns/cqrs-es/src/main/java/com/baeldung/patterns/cqrs/aggregates/UserAggregate.java b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/cqrs/aggregates/UserAggregate.java new file mode 100644 index 0000000000..96476dc15a --- /dev/null +++ b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/cqrs/aggregates/UserAggregate.java @@ -0,0 +1,30 @@ +package com.baeldung.patterns.cqrs.aggregates; + +import com.baeldung.patterns.cqrs.commands.CreateUserCommand; +import com.baeldung.patterns.cqrs.commands.UpdateUserCommand; +import com.baeldung.patterns.cqrs.repository.UserWriteRepository; +import com.baeldung.patterns.domain.User; + +public class UserAggregate { + + private UserWriteRepository writeRepository; + + public UserAggregate(UserWriteRepository repository) { + this.writeRepository = repository; + } + + public User handleCreateUserCommand(CreateUserCommand command) { + User user = new User(command.getUserId(), command.getFirstName(), command.getLastName()); + writeRepository.addUser(user.getUserid(), user); + return user; + } + + public User handleUpdateUserCommand(UpdateUserCommand command) { + User user = writeRepository.getUser(command.getUserId()); + user.setAddresses(command.getAddresses()); + user.setContacts(command.getContacts()); + writeRepository.addUser(user.getUserid(), user); + return user; + } + +} diff --git a/patterns/cqrs-es/src/main/java/com/baeldung/patterns/cqrs/commands/CreateUserCommand.java b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/cqrs/commands/CreateUserCommand.java new file mode 100644 index 0000000000..362804c610 --- /dev/null +++ b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/cqrs/commands/CreateUserCommand.java @@ -0,0 +1,14 @@ +package com.baeldung.patterns.cqrs.commands; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class CreateUserCommand { + + private String userId; + private String firstName; + private String lastName; + +} diff --git a/patterns/cqrs-es/src/main/java/com/baeldung/patterns/cqrs/commands/UpdateUserCommand.java b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/cqrs/commands/UpdateUserCommand.java new file mode 100644 index 0000000000..58a4889458 --- /dev/null +++ b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/cqrs/commands/UpdateUserCommand.java @@ -0,0 +1,20 @@ +package com.baeldung.patterns.cqrs.commands; + +import java.util.HashSet; +import java.util.Set; + +import com.baeldung.patterns.domain.Address; +import com.baeldung.patterns.domain.Contact; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class UpdateUserCommand { + + private String userId; + private Set
addresses = new HashSet<>(); + private Set contacts = new HashSet<>(); + +} diff --git a/patterns/cqrs-es/src/main/java/com/baeldung/patterns/cqrs/projections/UserProjection.java b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/cqrs/projections/UserProjection.java new file mode 100644 index 0000000000..40a56e727f --- /dev/null +++ b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/cqrs/projections/UserProjection.java @@ -0,0 +1,37 @@ +package com.baeldung.patterns.cqrs.projections; + +import java.util.Set; + +import com.baeldung.patterns.cqrs.queries.AddressByRegionQuery; +import com.baeldung.patterns.cqrs.queries.ContactByTypeQuery; +import com.baeldung.patterns.cqrs.repository.UserReadRepository; +import com.baeldung.patterns.domain.Address; +import com.baeldung.patterns.domain.Contact; +import com.baeldung.patterns.domain.UserAddress; +import com.baeldung.patterns.domain.UserContact; + +public class UserProjection { + + private UserReadRepository repository; + + public UserProjection(UserReadRepository repository) { + this.repository = repository; + } + + public Set handle(ContactByTypeQuery query) throws Exception { + UserContact userContact = repository.getUserContact(query.getUserId()); + if (userContact == null) + throw new Exception("User does not exist."); + return userContact.getContactByType() + .get(query.getContactType()); + } + + public Set
handle(AddressByRegionQuery query) throws Exception { + UserAddress userAddress = repository.getUserAddress(query.getUserId()); + if (userAddress == null) + throw new Exception("User does not exist."); + return userAddress.getAddressByRegion() + .get(query.getState()); + } + +} diff --git a/patterns/cqrs-es/src/main/java/com/baeldung/patterns/cqrs/projectors/UserProjector.java b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/cqrs/projectors/UserProjector.java new file mode 100644 index 0000000000..0344c352d9 --- /dev/null +++ b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/cqrs/projectors/UserProjector.java @@ -0,0 +1,49 @@ +package com.baeldung.patterns.cqrs.projectors; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import com.baeldung.patterns.cqrs.repository.UserReadRepository; +import com.baeldung.patterns.domain.Address; +import com.baeldung.patterns.domain.Contact; +import com.baeldung.patterns.domain.User; +import com.baeldung.patterns.domain.UserAddress; +import com.baeldung.patterns.domain.UserContact; + +public class UserProjector { + + UserReadRepository readRepository = new UserReadRepository(); + + public UserProjector(UserReadRepository readRepository) { + this.readRepository = readRepository; + } + + public void project(User user) { + UserContact userContact = Optional.ofNullable(readRepository.getUserContact(user.getUserid())) + .orElse(new UserContact()); + Map> contactByType = new HashMap<>(); + for (Contact contact : user.getContacts()) { + Set contacts = Optional.ofNullable(contactByType.get(contact.getType())) + .orElse(new HashSet<>()); + contacts.add(contact); + contactByType.put(contact.getType(), contacts); + } + userContact.setContactByType(contactByType); + readRepository.addUserContact(user.getUserid(), userContact); + + UserAddress userAddress = Optional.ofNullable(readRepository.getUserAddress(user.getUserid())) + .orElse(new UserAddress()); + Map> addressByRegion = new HashMap<>(); + for (Address address : user.getAddresses()) { + Set
addresses = Optional.ofNullable(addressByRegion.get(address.getState())) + .orElse(new HashSet<>()); + addresses.add(address); + addressByRegion.put(address.getState(), addresses); + } + userAddress.setAddressByRegion(addressByRegion); + readRepository.addUserAddress(user.getUserid(), userAddress); + } +} diff --git a/patterns/cqrs-es/src/main/java/com/baeldung/patterns/cqrs/queries/AddressByRegionQuery.java b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/cqrs/queries/AddressByRegionQuery.java new file mode 100644 index 0000000000..4a0f0769f2 --- /dev/null +++ b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/cqrs/queries/AddressByRegionQuery.java @@ -0,0 +1,12 @@ +package com.baeldung.patterns.cqrs.queries; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class AddressByRegionQuery { + + private String userId; + private String state; +} diff --git a/patterns/cqrs-es/src/main/java/com/baeldung/patterns/cqrs/queries/ContactByTypeQuery.java b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/cqrs/queries/ContactByTypeQuery.java new file mode 100644 index 0000000000..b6c271b472 --- /dev/null +++ b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/cqrs/queries/ContactByTypeQuery.java @@ -0,0 +1,12 @@ +package com.baeldung.patterns.cqrs.queries; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class ContactByTypeQuery { + + private String userId; + private String contactType; +} diff --git a/patterns/cqrs-es/src/main/java/com/baeldung/patterns/cqrs/repository/UserReadRepository.java b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/cqrs/repository/UserReadRepository.java new file mode 100644 index 0000000000..a7ef2f6f96 --- /dev/null +++ b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/cqrs/repository/UserReadRepository.java @@ -0,0 +1,31 @@ +package com.baeldung.patterns.cqrs.repository; + +import java.util.HashMap; +import java.util.Map; + +import com.baeldung.patterns.domain.UserAddress; +import com.baeldung.patterns.domain.UserContact; + +public class UserReadRepository { + + private Map userAddress = new HashMap<>(); + + private Map userContact = new HashMap<>(); + + public void addUserAddress(String id, UserAddress user) { + userAddress.put(id, user); + } + + public UserAddress getUserAddress(String id) { + return userAddress.get(id); + } + + public void addUserContact(String id, UserContact user) { + userContact.put(id, user); + } + + public UserContact getUserContact(String id) { + return userContact.get(id); + } + +} diff --git a/patterns/cqrs-es/src/main/java/com/baeldung/patterns/cqrs/repository/UserWriteRepository.java b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/cqrs/repository/UserWriteRepository.java new file mode 100644 index 0000000000..8636e36225 --- /dev/null +++ b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/cqrs/repository/UserWriteRepository.java @@ -0,0 +1,20 @@ +package com.baeldung.patterns.cqrs.repository; + +import java.util.HashMap; +import java.util.Map; + +import com.baeldung.patterns.domain.User; + +public class UserWriteRepository { + + private Map store = new HashMap<>(); + + public void addUser(String id, User user) { + store.put(id, user); + } + + public User getUser(String id) { + return store.get(id); + } + +} diff --git a/patterns/cqrs-es/src/main/java/com/baeldung/patterns/crud/repository/UserRepository.java b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/crud/repository/UserRepository.java new file mode 100644 index 0000000000..b22d40e6e0 --- /dev/null +++ b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/crud/repository/UserRepository.java @@ -0,0 +1,20 @@ +package com.baeldung.patterns.crud.repository; + +import java.util.HashMap; +import java.util.Map; + +import com.baeldung.patterns.domain.User; + +public class UserRepository { + + private Map store = new HashMap<>(); + + public void addUser(String id, User user) { + store.put(id, user); + } + + public User getUser(String id) { + return store.get(id); + } + +} diff --git a/patterns/cqrs-es/src/main/java/com/baeldung/patterns/crud/service/UserService.java b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/crud/service/UserService.java new file mode 100644 index 0000000000..d21a796304 --- /dev/null +++ b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/crud/service/UserService.java @@ -0,0 +1,55 @@ +package com.baeldung.patterns.crud.service; + +import java.util.Set; +import java.util.stream.Collectors; + +import com.baeldung.patterns.crud.repository.UserRepository; +import com.baeldung.patterns.domain.Address; +import com.baeldung.patterns.domain.Contact; +import com.baeldung.patterns.domain.User; + +public class UserService { + + private UserRepository repository; + + public UserService(UserRepository repository) { + this.repository = repository; + } + + public void createUser(String userId, String firstName, String lastName) { + User user = new User(userId, firstName, lastName); + repository.addUser(userId, user); + } + + public void updateUser(String userId, Set contacts, Set
addresses) throws Exception { + User user = repository.getUser(userId); + if (user == null) + throw new Exception("User does not exist."); + user.setContacts(contacts); + user.setAddresses(addresses); + repository.addUser(userId, user); + } + + public Set getContactByType(String userId, String contactType) throws Exception { + User user = repository.getUser(userId); + if (user == null) + throw new Exception("User does not exit."); + Set contacts = user.getContacts(); + return contacts.stream() + .filter(c -> c.getType() + .equals(contactType)) + .collect(Collectors.toSet()); + } + + public Set
getAddressByRegion(String userId, String state) throws Exception { + User user = repository.getUser(userId); + if (user == null) + throw new Exception("User does not exist."); + Set
addresses = user.getAddresses(); + return addresses.stream() + .filter(a -> a.getState() + .equals(state)) + .collect(Collectors.toSet()); + } + +} diff --git a/patterns/cqrs-es/src/main/java/com/baeldung/patterns/domain/Address.java b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/domain/Address.java new file mode 100644 index 0000000000..dfaa724434 --- /dev/null +++ b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/domain/Address.java @@ -0,0 +1,14 @@ +package com.baeldung.patterns.domain; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class Address { + + private String city; + private String state; + private String postcode; + +} diff --git a/patterns/cqrs-es/src/main/java/com/baeldung/patterns/domain/Contact.java b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/domain/Contact.java new file mode 100644 index 0000000000..a151cdb4ff --- /dev/null +++ b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/domain/Contact.java @@ -0,0 +1,13 @@ +package com.baeldung.patterns.domain; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class Contact { + + private String type; + private String detail; + +} diff --git a/patterns/cqrs-es/src/main/java/com/baeldung/patterns/domain/User.java b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/domain/User.java new file mode 100644 index 0000000000..8f59723894 --- /dev/null +++ b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/domain/User.java @@ -0,0 +1,22 @@ +package com.baeldung.patterns.domain; + +import java.util.HashSet; +import java.util.Set; + +import lombok.Data; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; + +@Data +@RequiredArgsConstructor +public class User { + @NonNull + private String userid; + @NonNull + private String firstname; + @NonNull + private String lastname; + private Set contacts = new HashSet<>(); + private Set
addresses = new HashSet<>(); + +} diff --git a/patterns/cqrs-es/src/main/java/com/baeldung/patterns/domain/UserAddress.java b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/domain/UserAddress.java new file mode 100644 index 0000000000..8105a53265 --- /dev/null +++ b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/domain/UserAddress.java @@ -0,0 +1,14 @@ +package com.baeldung.patterns.domain; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import lombok.Data; + +@Data +public class UserAddress { + + private Map> addressByRegion = new HashMap<>(); + +} diff --git a/patterns/cqrs-es/src/main/java/com/baeldung/patterns/domain/UserContact.java b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/domain/UserContact.java new file mode 100644 index 0000000000..1768dadc39 --- /dev/null +++ b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/domain/UserContact.java @@ -0,0 +1,14 @@ +package com.baeldung.patterns.domain; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import lombok.Data; + +@Data +public class UserContact { + + private Map> contactByType = new HashMap<>(); + +} diff --git a/patterns/cqrs-es/src/main/java/com/baeldung/patterns/es/events/Event.java b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/es/events/Event.java new file mode 100644 index 0000000000..4718450cac --- /dev/null +++ b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/es/events/Event.java @@ -0,0 +1,15 @@ +package com.baeldung.patterns.es.events; + +import java.util.Date; +import java.util.UUID; + +import lombok.ToString; + +@ToString +public abstract class Event { + + public final UUID id = UUID.randomUUID(); + + public final Date created = new Date(); + +} diff --git a/patterns/cqrs-es/src/main/java/com/baeldung/patterns/es/events/UserAddressAddedEvent.java b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/es/events/UserAddressAddedEvent.java new file mode 100644 index 0000000000..caa640798b --- /dev/null +++ b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/es/events/UserAddressAddedEvent.java @@ -0,0 +1,16 @@ +package com.baeldung.patterns.es.events; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@AllArgsConstructor +@EqualsAndHashCode(callSuper = false) +public class UserAddressAddedEvent extends Event { + + private String city; + private String state; + private String postCode; + +} diff --git a/patterns/cqrs-es/src/main/java/com/baeldung/patterns/es/events/UserAddressRemovedEvent.java b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/es/events/UserAddressRemovedEvent.java new file mode 100644 index 0000000000..f0702d8810 --- /dev/null +++ b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/es/events/UserAddressRemovedEvent.java @@ -0,0 +1,16 @@ +package com.baeldung.patterns.es.events; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@AllArgsConstructor +@EqualsAndHashCode(callSuper = false) +public class UserAddressRemovedEvent extends Event { + + private String city; + private String state; + private String postCode; + +} diff --git a/patterns/cqrs-es/src/main/java/com/baeldung/patterns/es/events/UserContactAddedEvent.java b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/es/events/UserContactAddedEvent.java new file mode 100644 index 0000000000..0bce2f997e --- /dev/null +++ b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/es/events/UserContactAddedEvent.java @@ -0,0 +1,15 @@ +package com.baeldung.patterns.es.events; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@AllArgsConstructor +@EqualsAndHashCode(callSuper = false) +public class UserContactAddedEvent extends Event { + + private String contactType; + private String contactDetails; + +} diff --git a/patterns/cqrs-es/src/main/java/com/baeldung/patterns/es/events/UserContactRemovedEvent.java b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/es/events/UserContactRemovedEvent.java new file mode 100644 index 0000000000..9c043971e7 --- /dev/null +++ b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/es/events/UserContactRemovedEvent.java @@ -0,0 +1,15 @@ +package com.baeldung.patterns.es.events; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@AllArgsConstructor +@EqualsAndHashCode(callSuper = false) +public class UserContactRemovedEvent extends Event { + + private String contactType; + private String contactDetails; + +} diff --git a/patterns/cqrs-es/src/main/java/com/baeldung/patterns/es/events/UserCreatedEvent.java b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/es/events/UserCreatedEvent.java new file mode 100644 index 0000000000..8e725cd667 --- /dev/null +++ b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/es/events/UserCreatedEvent.java @@ -0,0 +1,16 @@ +package com.baeldung.patterns.es.events; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@AllArgsConstructor +@EqualsAndHashCode(callSuper = false) +public class UserCreatedEvent extends Event { + + private String userId; + private String firstName; + private String lastName; + +} diff --git a/patterns/cqrs-es/src/main/java/com/baeldung/patterns/es/repository/EventStore.java b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/es/repository/EventStore.java new file mode 100644 index 0000000000..87914d8c12 --- /dev/null +++ b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/es/repository/EventStore.java @@ -0,0 +1,29 @@ +package com.baeldung.patterns.es.repository; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.baeldung.patterns.es.events.Event; + +public class EventStore { + + private Map> store = new HashMap<>(); + + public void addEvent(String id, Event event) { + List events = store.get(id); + if (events == null) { + events = new ArrayList(); + events.add(event); + store.put(id, events); + } else { + events.add(event); + } + } + + public List getEvents(String id) { + return store.get(id); + } + +} diff --git a/patterns/cqrs-es/src/main/java/com/baeldung/patterns/es/service/UserService.java b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/es/service/UserService.java new file mode 100644 index 0000000000..9650c4294f --- /dev/null +++ b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/es/service/UserService.java @@ -0,0 +1,72 @@ +package com.baeldung.patterns.es.service; + +import java.util.Set; +import java.util.stream.Collectors; + +import com.baeldung.patterns.domain.Address; +import com.baeldung.patterns.domain.Contact; +import com.baeldung.patterns.domain.User; +import com.baeldung.patterns.es.events.UserAddressAddedEvent; +import com.baeldung.patterns.es.events.UserAddressRemovedEvent; +import com.baeldung.patterns.es.events.UserContactAddedEvent; +import com.baeldung.patterns.es.events.UserContactRemovedEvent; +import com.baeldung.patterns.es.events.UserCreatedEvent; +import com.baeldung.patterns.es.repository.EventStore; + +public class UserService { + + private EventStore repository; + + public UserService(EventStore repository) { + this.repository = repository; + } + + public void createUser(String userId, String firstName, String lastName) { + repository.addEvent(userId, new UserCreatedEvent(userId, firstName, lastName)); + } + + public void updateUser(String userId, Set contacts, Set
addresses) throws Exception { + User user = UserUtility.recreateUserState(repository, userId); + if (user == null) + throw new Exception("User does not exist."); + + user.getContacts() + .stream() + .filter(c -> !contacts.contains(c)) + .forEach(c -> repository.addEvent(userId, new UserContactRemovedEvent(c.getType(), c.getDetail()))); + contacts.stream() + .filter(c -> !user.getContacts() + .contains(c)) + .forEach(c -> repository.addEvent(userId, new UserContactAddedEvent(c.getType(), c.getDetail()))); + user.getAddresses() + .stream() + .filter(a -> !addresses.contains(a)) + .forEach(a -> repository.addEvent(userId, new UserAddressRemovedEvent(a.getCity(), a.getState(), a.getPostcode()))); + addresses.stream() + .filter(a -> !user.getAddresses() + .contains(a)) + .forEach(a -> repository.addEvent(userId, new UserAddressAddedEvent(a.getCity(), a.getState(), a.getPostcode()))); + } + + public Set getContactByType(String userId, String contactType) throws Exception { + User user = UserUtility.recreateUserState(repository, userId); + if (user == null) + throw new Exception("User does not exist."); + return user.getContacts() + .stream() + .filter(c -> c.getType() + .equals(contactType)) + .collect(Collectors.toSet()); + } + + public Set
getAddressByRegion(String userId, String state) throws Exception { + User user = UserUtility.recreateUserState(repository, userId); + if (user == null) + throw new Exception("User does not exist."); + return user.getAddresses() + .stream() + .filter(a -> a.getState() + .equals(state)) + .collect(Collectors.toSet()); + } +} diff --git a/patterns/cqrs-es/src/main/java/com/baeldung/patterns/es/service/UserUtility.java b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/es/service/UserUtility.java new file mode 100644 index 0000000000..e44e404588 --- /dev/null +++ b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/es/service/UserUtility.java @@ -0,0 +1,62 @@ +package com.baeldung.patterns.es.service; + +import java.util.List; +import java.util.UUID; + +import com.baeldung.patterns.domain.Address; +import com.baeldung.patterns.domain.Contact; +import com.baeldung.patterns.domain.User; +import com.baeldung.patterns.es.events.Event; +import com.baeldung.patterns.es.events.UserAddressAddedEvent; +import com.baeldung.patterns.es.events.UserAddressRemovedEvent; +import com.baeldung.patterns.es.events.UserContactAddedEvent; +import com.baeldung.patterns.es.events.UserContactRemovedEvent; +import com.baeldung.patterns.es.events.UserCreatedEvent; +import com.baeldung.patterns.es.repository.EventStore; + +public class UserUtility { + + public static User recreateUserState(EventStore store, String userId) { + User user = null; + + List events = store.getEvents(userId); + for (Event event : events) { + if (event instanceof UserCreatedEvent) { + UserCreatedEvent e = (UserCreatedEvent) event; + user = new User(UUID.randomUUID() + .toString(), e.getFirstName(), e.getLastName()); + } + if (event instanceof UserAddressAddedEvent) { + UserAddressAddedEvent e = (UserAddressAddedEvent) event; + Address address = new Address(e.getCity(), e.getState(), e.getPostCode()); + if (user != null) + user.getAddresses() + .add(address); + } + if (event instanceof UserAddressRemovedEvent) { + UserAddressRemovedEvent e = (UserAddressRemovedEvent) event; + Address address = new Address(e.getCity(), e.getState(), e.getPostCode()); + if (user != null) + user.getAddresses() + .remove(address); + } + if (event instanceof UserContactAddedEvent) { + UserContactAddedEvent e = (UserContactAddedEvent) event; + Contact contact = new Contact(e.getContactType(), e.getContactDetails()); + if (user != null) + user.getContacts() + .add(contact); + } + if (event instanceof UserContactRemovedEvent) { + UserContactRemovedEvent e = (UserContactRemovedEvent) event; + Contact contact = new Contact(e.getContactType(), e.getContactDetails()); + if (user != null) + user.getContacts() + .remove(contact); + } + } + + return user; + } + +} diff --git a/patterns/cqrs-es/src/main/java/com/baeldung/patterns/escqrs/aggregates/UserAggregate.java b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/escqrs/aggregates/UserAggregate.java new file mode 100644 index 0000000000..04bfeb634d --- /dev/null +++ b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/escqrs/aggregates/UserAggregate.java @@ -0,0 +1,87 @@ +package com.baeldung.patterns.escqrs.aggregates; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import com.baeldung.patterns.cqrs.commands.CreateUserCommand; +import com.baeldung.patterns.cqrs.commands.UpdateUserCommand; +import com.baeldung.patterns.domain.Address; +import com.baeldung.patterns.domain.Contact; +import com.baeldung.patterns.domain.User; +import com.baeldung.patterns.es.events.Event; +import com.baeldung.patterns.es.events.UserAddressAddedEvent; +import com.baeldung.patterns.es.events.UserAddressRemovedEvent; +import com.baeldung.patterns.es.events.UserContactAddedEvent; +import com.baeldung.patterns.es.events.UserContactRemovedEvent; +import com.baeldung.patterns.es.events.UserCreatedEvent; +import com.baeldung.patterns.es.repository.EventStore; +import com.baeldung.patterns.es.service.UserUtility; + +public class UserAggregate { + + private EventStore writeRepository; + + public UserAggregate(EventStore repository) { + this.writeRepository = repository; + } + + public List handleCreateUserCommand(CreateUserCommand command) { + UserCreatedEvent event = new UserCreatedEvent(command.getUserId(), command.getFirstName(), command.getLastName()); + writeRepository.addEvent(command.getUserId(), event); + return Arrays.asList(event); + } + + public List handleUpdateUserCommand(UpdateUserCommand command) { + User user = UserUtility.recreateUserState(writeRepository, command.getUserId()); + List events = new ArrayList<>(); + + List contactsToRemove = user.getContacts() + .stream() + .filter(c -> !command.getContacts() + .contains(c)) + .collect(Collectors.toList()); + for (Contact contact : contactsToRemove) { + UserContactRemovedEvent contactRemovedEvent = new UserContactRemovedEvent(contact.getType(), contact.getDetail()); + events.add(contactRemovedEvent); + writeRepository.addEvent(command.getUserId(), contactRemovedEvent); + } + + List contactsToAdd = command.getContacts() + .stream() + .filter(c -> !user.getContacts() + .contains(c)) + .collect(Collectors.toList()); + for (Contact contact : contactsToAdd) { + UserContactAddedEvent contactAddedEvent = new UserContactAddedEvent(contact.getType(), contact.getDetail()); + events.add(contactAddedEvent); + writeRepository.addEvent(command.getUserId(), contactAddedEvent); + } + + List
addressesToRemove = user.getAddresses() + .stream() + .filter(a -> !command.getAddresses() + .contains(a)) + .collect(Collectors.toList()); + for (Address address : addressesToRemove) { + UserAddressRemovedEvent addressRemovedEvent = new UserAddressRemovedEvent(address.getCity(), address.getState(), address.getPostcode()); + events.add(addressRemovedEvent); + writeRepository.addEvent(command.getUserId(), addressRemovedEvent); + } + + List
addressesToAdd = command.getAddresses() + .stream() + .filter(a -> !user.getAddresses() + .contains(a)) + .collect(Collectors.toList()); + for (Address address : addressesToAdd) { + UserAddressAddedEvent addressAddedEvent = new UserAddressAddedEvent(address.getCity(), address.getState(), address.getPostcode()); + events.add(addressAddedEvent); + writeRepository.addEvent(command.getUserId(), addressAddedEvent); + } + + return events; + } + +} diff --git a/patterns/cqrs-es/src/main/java/com/baeldung/patterns/escqrs/projectors/UserProjector.java b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/escqrs/projectors/UserProjector.java new file mode 100644 index 0000000000..d388abe7cb --- /dev/null +++ b/patterns/cqrs-es/src/main/java/com/baeldung/patterns/escqrs/projectors/UserProjector.java @@ -0,0 +1,91 @@ +package com.baeldung.patterns.escqrs.projectors; + +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import com.baeldung.patterns.cqrs.repository.UserReadRepository; +import com.baeldung.patterns.domain.Address; +import com.baeldung.patterns.domain.Contact; +import com.baeldung.patterns.domain.UserAddress; +import com.baeldung.patterns.domain.UserContact; +import com.baeldung.patterns.es.events.Event; +import com.baeldung.patterns.es.events.UserAddressAddedEvent; +import com.baeldung.patterns.es.events.UserAddressRemovedEvent; +import com.baeldung.patterns.es.events.UserContactAddedEvent; +import com.baeldung.patterns.es.events.UserContactRemovedEvent; + +public class UserProjector { + + UserReadRepository readRepository = new UserReadRepository(); + + public UserProjector(UserReadRepository readRepository) { + this.readRepository = readRepository; + } + + public void project(String userId, List events) { + + for (Event event : events) { + if (event instanceof UserAddressAddedEvent) + apply(userId, (UserAddressAddedEvent) event); + if (event instanceof UserAddressRemovedEvent) + apply(userId, (UserAddressRemovedEvent) event); + if (event instanceof UserContactAddedEvent) + apply(userId, (UserContactAddedEvent) event); + if (event instanceof UserContactRemovedEvent) + apply(userId, (UserContactRemovedEvent) event); + } + + } + + public void apply(String userId, UserAddressAddedEvent event) { + Address address = new Address(event.getCity(), event.getState(), event.getPostCode()); + UserAddress userAddress = Optional.ofNullable(readRepository.getUserAddress(userId)) + .orElse(new UserAddress()); + Set
addresses = Optional.ofNullable(userAddress.getAddressByRegion() + .get(address.getState())) + .orElse(new HashSet<>()); + addresses.add(address); + userAddress.getAddressByRegion() + .put(address.getState(), addresses); + readRepository.addUserAddress(userId, userAddress); + } + + public void apply(String userId, UserAddressRemovedEvent event) { + Address address = new Address(event.getCity(), event.getState(), event.getPostCode()); + UserAddress userAddress = readRepository.getUserAddress(userId); + if (userAddress != null) { + Set
addresses = userAddress.getAddressByRegion() + .get(address.getState()); + if (addresses != null) + addresses.remove(address); + readRepository.addUserAddress(userId, userAddress); + } + } + + public void apply(String userId, UserContactAddedEvent event) { + Contact contact = new Contact(event.getContactType(), event.getContactDetails()); + UserContact userContact = Optional.ofNullable(readRepository.getUserContact(userId)) + .orElse(new UserContact()); + Set contacts = Optional.ofNullable(userContact.getContactByType() + .get(contact.getType())) + .orElse(new HashSet<>()); + contacts.add(contact); + userContact.getContactByType() + .put(contact.getType(), contacts); + readRepository.addUserContact(userId, userContact); + } + + public void apply(String userId, UserContactRemovedEvent event) { + Contact contact = new Contact(event.getContactType(), event.getContactDetails()); + UserContact userContact = readRepository.getUserContact(userId); + if (userContact != null) { + Set contacts = userContact.getContactByType() + .get(contact.getType()); + if (contacts != null) + contacts.remove(contact); + readRepository.addUserContact(userId, userContact); + } + } +} diff --git a/patterns/cqrs-es/src/test/java/com/baeldung/patterns/cqrs/ApplicationUnitTest.java b/patterns/cqrs-es/src/test/java/com/baeldung/patterns/cqrs/ApplicationUnitTest.java new file mode 100644 index 0000000000..7f68a64274 --- /dev/null +++ b/patterns/cqrs-es/src/test/java/com/baeldung/patterns/cqrs/ApplicationUnitTest.java @@ -0,0 +1,74 @@ +package com.baeldung.patterns.cqrs; + +import static org.junit.Assert.assertEquals; + +import java.util.UUID; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.junit.Before; +import org.junit.Test; + +import com.baeldung.patterns.cqrs.aggregates.UserAggregate; +import com.baeldung.patterns.cqrs.commands.CreateUserCommand; +import com.baeldung.patterns.cqrs.commands.UpdateUserCommand; +import com.baeldung.patterns.cqrs.projections.UserProjection; +import com.baeldung.patterns.cqrs.projectors.UserProjector; +import com.baeldung.patterns.cqrs.queries.AddressByRegionQuery; +import com.baeldung.patterns.cqrs.queries.ContactByTypeQuery; +import com.baeldung.patterns.cqrs.repository.UserReadRepository; +import com.baeldung.patterns.cqrs.repository.UserWriteRepository; +import com.baeldung.patterns.domain.Address; +import com.baeldung.patterns.domain.Contact; +import com.baeldung.patterns.domain.User; + +public class ApplicationUnitTest { + + private UserWriteRepository writeRepository; + private UserReadRepository readRepository; + private UserProjector projector; + private UserAggregate userAggregate; + private UserProjection userProjection; + + @Before + public void setUp() { + writeRepository = new UserWriteRepository(); + readRepository = new UserReadRepository(); + projector = new UserProjector(readRepository); + userAggregate = new UserAggregate(writeRepository); + userProjection = new UserProjection(readRepository); + } + + @Test + public void givenCQRSApplication_whenCommandRun_thenQueryShouldReturnResult() throws Exception { + String userId = UUID.randomUUID() + .toString(); + User user = null; + CreateUserCommand createUserCommand = new CreateUserCommand(userId, "Tom", "Sawyer"); + user = userAggregate.handleCreateUserCommand(createUserCommand); + projector.project(user); + + UpdateUserCommand updateUserCommand = new UpdateUserCommand(user.getUserid(), Stream.of(new Address("New York", "NY", "10001"), new Address("Los Angeles", "CA", "90001")) + .collect(Collectors.toSet()), + Stream.of(new Contact("EMAIL", "tom.sawyer@gmail.com"), new Contact("EMAIL", "tom.sawyer@rediff.com")) + .collect(Collectors.toSet())); + user = userAggregate.handleUpdateUserCommand(updateUserCommand); + projector.project(user); + + updateUserCommand = new UpdateUserCommand(userId, Stream.of(new Address("New York", "NY", "10001"), new Address("Housten", "TX", "77001")) + .collect(Collectors.toSet()), + Stream.of(new Contact("EMAIL", "tom.sawyer@gmail.com"), new Contact("PHONE", "700-000-0001")) + .collect(Collectors.toSet())); + user = userAggregate.handleUpdateUserCommand(updateUserCommand); + projector.project(user); + + ContactByTypeQuery contactByTypeQuery = new ContactByTypeQuery(userId, "EMAIL"); + assertEquals(Stream.of(new Contact("EMAIL", "tom.sawyer@gmail.com")) + .collect(Collectors.toSet()), userProjection.handle(contactByTypeQuery)); + AddressByRegionQuery addressByRegionQuery = new AddressByRegionQuery(userId, "NY"); + assertEquals(Stream.of(new Address("New York", "NY", "10001")) + .collect(Collectors.toSet()), userProjection.handle(addressByRegionQuery)); + + } + +} diff --git a/patterns/cqrs-es/src/test/java/com/baeldung/patterns/crud/ApplicationUnitTest.java b/patterns/cqrs-es/src/test/java/com/baeldung/patterns/crud/ApplicationUnitTest.java new file mode 100644 index 0000000000..3fabfe405d --- /dev/null +++ b/patterns/cqrs-es/src/test/java/com/baeldung/patterns/crud/ApplicationUnitTest.java @@ -0,0 +1,48 @@ +package com.baeldung.patterns.crud; + +import static org.junit.Assert.assertEquals; + +import java.util.UUID; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.junit.Before; +import org.junit.Test; + +import com.baeldung.patterns.crud.repository.UserRepository; +import com.baeldung.patterns.crud.service.UserService; +import com.baeldung.patterns.domain.Address; +import com.baeldung.patterns.domain.Contact; + +public class ApplicationUnitTest { + + private UserRepository repository; + + @Before + public void setUp() { + repository = new UserRepository(); + } + + @Test + public void givenCRUDApplication_whenDataCreated_thenDataCanBeFetched() throws Exception { + UserService service = new UserService(repository); + String userId = UUID.randomUUID() + .toString(); + + service.createUser(userId, "Tom", "Sawyer"); + service.updateUser(userId, Stream.of(new Contact("EMAIL", "tom.sawyer@gmail.com"), new Contact("EMAIL", "tom.sawyer@rediff.com"), new Contact("PHONE", "700-000-0001")) + .collect(Collectors.toSet()), + Stream.of(new Address("New York", "NY", "10001"), new Address("Los Angeles", "CA", "90001"), new Address("Housten", "TX", "77001")) + .collect(Collectors.toSet())); + service.updateUser(userId, Stream.of(new Contact("EMAIL", "tom.sawyer@gmail.com"), new Contact("PHONE", "700-000-0001")) + .collect(Collectors.toSet()), + Stream.of(new Address("New York", "NY", "10001"), new Address("Housten", "TX", "77001")) + .collect(Collectors.toSet())); + + assertEquals(Stream.of(new Contact("EMAIL", "tom.sawyer@gmail.com")) + .collect(Collectors.toSet()), service.getContactByType(userId, "EMAIL")); + assertEquals(Stream.of(new Address("New York", "NY", "10001")) + .collect(Collectors.toSet()), service.getAddressByRegion(userId, "NY")); + } + +} diff --git a/patterns/cqrs-es/src/test/java/com/baeldung/patterns/es/ApplicationUnitTest.java b/patterns/cqrs-es/src/test/java/com/baeldung/patterns/es/ApplicationUnitTest.java new file mode 100644 index 0000000000..61e7b4c05a --- /dev/null +++ b/patterns/cqrs-es/src/test/java/com/baeldung/patterns/es/ApplicationUnitTest.java @@ -0,0 +1,50 @@ +package com.baeldung.patterns.es; + +import static org.junit.Assert.assertEquals; + +import java.util.UUID; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.junit.Before; +import org.junit.Test; + +import com.baeldung.patterns.domain.Address; +import com.baeldung.patterns.domain.Contact; +import com.baeldung.patterns.es.repository.EventStore; +import com.baeldung.patterns.es.service.UserService; + +public class ApplicationUnitTest { + + private EventStore repository; + private UserService service; + + @Before + public void setUp() { + repository = new EventStore(); + service = new UserService(repository); + } + + @Test + public void givenCRUDApplication_whenDataCreated_thenDataCanBeFetched() throws Exception { + String userId = UUID.randomUUID() + .toString(); + + service.createUser(userId, "Tom", "Sawyer"); + service.updateUser(userId, Stream.of(new Contact("EMAIL", "tom.sawyer@gmail.com"), new Contact("EMAIL", "tom.sawyer@rediff.com"), new Contact("PHONE", "700-000-0001")) + .collect(Collectors.toSet()), + Stream.of(new Address("New York", "NY", "10001"), new Address("Los Angeles", "CA", "90001"), new Address("Housten", "TX", "77001")) + .collect(Collectors.toSet())); + service.updateUser(userId, Stream.of(new Contact("EMAIL", "tom.sawyer@gmail.com"), new Contact("PHONE", "700-000-0001")) + .collect(Collectors.toSet()), + Stream.of(new Address("New York", "NY", "10001"), new Address("Housten", "TX", "77001")) + .collect(Collectors.toSet())); + + assertEquals(Stream.of(new Contact("EMAIL", "tom.sawyer@gmail.com")) + .collect(Collectors.toSet()), service.getContactByType(userId, "EMAIL")); + assertEquals(Stream.of(new Address("New York", "NY", "10001")) + .collect(Collectors.toSet()), service.getAddressByRegion(userId, "NY")); + + } + +} diff --git a/patterns/cqrs-es/src/test/java/com/baeldung/patterns/escqrs/ApplicationUnitTest.java b/patterns/cqrs-es/src/test/java/com/baeldung/patterns/escqrs/ApplicationUnitTest.java new file mode 100644 index 0000000000..e0460b2f12 --- /dev/null +++ b/patterns/cqrs-es/src/test/java/com/baeldung/patterns/escqrs/ApplicationUnitTest.java @@ -0,0 +1,76 @@ +package com.baeldung.patterns.escqrs; + +import static org.junit.Assert.assertEquals; + +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.junit.Before; +import org.junit.Test; + +import com.baeldung.patterns.cqrs.commands.CreateUserCommand; +import com.baeldung.patterns.cqrs.commands.UpdateUserCommand; +import com.baeldung.patterns.cqrs.projections.UserProjection; +import com.baeldung.patterns.cqrs.queries.AddressByRegionQuery; +import com.baeldung.patterns.cqrs.queries.ContactByTypeQuery; +import com.baeldung.patterns.cqrs.repository.UserReadRepository; +import com.baeldung.patterns.domain.Address; +import com.baeldung.patterns.domain.Contact; +import com.baeldung.patterns.es.events.Event; +import com.baeldung.patterns.es.repository.EventStore; +import com.baeldung.patterns.escqrs.aggregates.UserAggregate; +import com.baeldung.patterns.escqrs.projectors.UserProjector; + +public class ApplicationUnitTest { + + private EventStore writeRepository; + private UserReadRepository readRepository; + private UserProjector projector; + private UserAggregate userAggregate; + private UserProjection userProjection; + + @Before + public void setUp() { + writeRepository = new EventStore(); + readRepository = new UserReadRepository(); + projector = new UserProjector(readRepository); + userAggregate = new UserAggregate(writeRepository); + userProjection = new UserProjection(readRepository); + } + + @Test + public void givenCQRSApplication_whenCommandRun_thenQueryShouldReturnResult() throws Exception { + String userId = UUID.randomUUID() + .toString(); + List events = null; + CreateUserCommand createUserCommand = new CreateUserCommand(userId, "Kumar", "Chandrakant"); + events = userAggregate.handleCreateUserCommand(createUserCommand); + + projector.project(userId, events); + + UpdateUserCommand updateUserCommand = new UpdateUserCommand(userId, Stream.of(new Address("New York", "NY", "10001"), new Address("Los Angeles", "CA", "90001")) + .collect(Collectors.toSet()), + Stream.of(new Contact("EMAIL", "tom.sawyer@gmail.com"), new Contact("EMAIL", "tom.sawyer@rediff.com")) + .collect(Collectors.toSet())); + events = userAggregate.handleUpdateUserCommand(updateUserCommand); + projector.project(userId, events); + + updateUserCommand = new UpdateUserCommand(userId, Stream.of(new Address("New York", "NY", "10001"), new Address("Housten", "TX", "77001")) + .collect(Collectors.toSet()), + Stream.of(new Contact("EMAIL", "tom.sawyer@gmail.com"), new Contact("PHONE", "700-000-0001")) + .collect(Collectors.toSet())); + events = userAggregate.handleUpdateUserCommand(updateUserCommand); + projector.project(userId, events); + + ContactByTypeQuery contactByTypeQuery = new ContactByTypeQuery(userId, "EMAIL"); + assertEquals(Stream.of(new Contact("EMAIL", "tom.sawyer@gmail.com")) + .collect(Collectors.toSet()), userProjection.handle(contactByTypeQuery)); + AddressByRegionQuery addressByRegionQuery = new AddressByRegionQuery(userId, "NY"); + assertEquals(Stream.of(new Address("New York", "NY", "10001")) + .collect(Collectors.toSet()), userProjection.handle(addressByRegionQuery)); + + } + +} diff --git a/patterns/pom.xml b/patterns/pom.xml index 4c17055231..e1753aba56 100644 --- a/patterns/pom.xml +++ b/patterns/pom.xml @@ -5,13 +5,11 @@ patterns patterns pom - com.baeldung parent-modules 1.0.0-SNAPSHOT - design-patterns-architectural design-patterns-behavioral @@ -21,11 +19,11 @@ design-patterns-functional design-patterns-structural dip + cqrs-es front-controller intercepting-filter solid - @@ -36,7 +34,6 @@ - @@ -53,9 +50,7 @@ - 9.4.0.v20161208 - - + \ No newline at end of file diff --git a/patterns/solid/README.md b/patterns/solid/README.md index ddd2f78b7e..cae346e3c9 100644 --- a/patterns/solid/README.md +++ b/patterns/solid/README.md @@ -1,5 +1,5 @@ ### Relevant Articles: - [A Solid Guide to Solid Principles](https://www.baeldung.com/solid-principles) - +- [Single Responsibility Principle in Java](https://www.baeldung.com/java-single-responsibility-principle) diff --git a/patterns/solid/src/main/java/com/baeldung/o/AbstractCalculatorOperation.java b/patterns/solid/src/main/java/com/baeldung/o/AbstractCalculatorOperation.java new file mode 100644 index 0000000000..798d5e2d95 --- /dev/null +++ b/patterns/solid/src/main/java/com/baeldung/o/AbstractCalculatorOperation.java @@ -0,0 +1,7 @@ +package com.baeldung.o; + +public abstract class AbstractCalculatorOperation { + + abstract void perform(); + +} diff --git a/patterns/solid/src/main/java/com/baeldung/o/Addition.java b/patterns/solid/src/main/java/com/baeldung/o/Addition.java new file mode 100644 index 0000000000..1ad99aad4b --- /dev/null +++ b/patterns/solid/src/main/java/com/baeldung/o/Addition.java @@ -0,0 +1,41 @@ +package com.baeldung.o; + +public class Addition implements CalculatorOperation { + private double left; + private double right; + private double result = 0.0; + + public Addition(double left, double right) { + this.left = left; + this.right = right; + } + + public double getLeft() { + return left; + } + + public void setLeft(double left) { + this.left = left; + } + + public double getRight() { + return right; + } + + public void setRight(double right) { + this.right = right; + } + + public double getResult() { + return result; + } + + public void setResult(double result) { + this.result = result; + } + + @Override + public void perform() { + result = left + right; + } +} diff --git a/patterns/solid/src/main/java/com/baeldung/o/Calculator.java b/patterns/solid/src/main/java/com/baeldung/o/Calculator.java new file mode 100644 index 0000000000..11ace8eb20 --- /dev/null +++ b/patterns/solid/src/main/java/com/baeldung/o/Calculator.java @@ -0,0 +1,14 @@ +package com.baeldung.o; + +import java.security.InvalidParameterException; + +public class Calculator { + + public void calculate(CalculatorOperation operation) { + if (operation == null) { + throw new InvalidParameterException("Can not perform operation"); + } + + operation.perform(); + } +} diff --git a/patterns/solid/src/main/java/com/baeldung/o/CalculatorOperation.java b/patterns/solid/src/main/java/com/baeldung/o/CalculatorOperation.java new file mode 100644 index 0000000000..46648e25d8 --- /dev/null +++ b/patterns/solid/src/main/java/com/baeldung/o/CalculatorOperation.java @@ -0,0 +1,7 @@ +package com.baeldung.o; + +public interface CalculatorOperation { + + void perform(); + +} diff --git a/patterns/solid/src/main/java/com/baeldung/o/Division.java b/patterns/solid/src/main/java/com/baeldung/o/Division.java new file mode 100644 index 0000000000..fbb8a1f523 --- /dev/null +++ b/patterns/solid/src/main/java/com/baeldung/o/Division.java @@ -0,0 +1,43 @@ +package com.baeldung.o; + +public class Division implements CalculatorOperation { + private double left; + private double right; + private double result = 0.0; + + public Division(double left, double right) { + this.left = left; + this.right = right; + } + + public double getLeft() { + return left; + } + + public void setLeft(double left) { + this.left = left; + } + + public double getRight() { + return right; + } + + public void setRight(double right) { + this.right = right; + } + + public double getResult() { + return result; + } + + public void setResult(double result) { + this.result = result; + } + + @Override + public void perform() { + if (right != 0) { + result = left / right; + } + } +} diff --git a/patterns/solid/src/main/java/com/baeldung/o/Subtraction.java b/patterns/solid/src/main/java/com/baeldung/o/Subtraction.java new file mode 100644 index 0000000000..5827d33568 --- /dev/null +++ b/patterns/solid/src/main/java/com/baeldung/o/Subtraction.java @@ -0,0 +1,41 @@ +package com.baeldung.o; + +public class Subtraction implements CalculatorOperation { + private double left; + private double right; + private double result = 0.0; + + public Subtraction(double left, double right) { + this.left = left; + this.right = right; + } + + public double getLeft() { + return left; + } + + public void setLeft(double left) { + this.left = left; + } + + public double getRight() { + return right; + } + + public void setRight(double right) { + this.right = right; + } + + public double getResult() { + return result; + } + + public void setResult(double result) { + this.result = result; + } + + @Override + public void perform() { + result = left - right; + } +} diff --git a/patterns/solid/src/main/test/com/baeldung/o/CalculatorUnitTest.java b/patterns/solid/src/main/test/com/baeldung/o/CalculatorUnitTest.java new file mode 100644 index 0000000000..3ae894e963 --- /dev/null +++ b/patterns/solid/src/main/test/com/baeldung/o/CalculatorUnitTest.java @@ -0,0 +1,44 @@ +package com.baeldung.o; + +import static org.junit.Assert.assertEquals; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class CalculatorUnitTest { + + private static final double RIGHT = 10.0; + private static final double LEFT = 20.0; + private static final double SUM = 30.0; + private static final double SUBTRACTION_RESULT = 10.0; + private static final double DIVISION_RESULT = 2.0; + + private Calculator calculator; + + @BeforeEach + public void setUp() { + calculator = new Calculator(); + } + + @Test + public void whenAddTwoNumber_returnSum() { + Addition addition = new Addition(RIGHT, LEFT); + calculator.calculate(addition); + assertEquals(SUM, addition.getResult(), 0.0); + } + + @Test + public void whenSutractTwoNumber_returnCorrectResult() { + Subtraction subtraction = new Subtraction(LEFT, RIGHT); + calculator.calculate(subtraction); + assertEquals(SUBTRACTION_RESULT, subtraction.getResult(), 0.0); + } + + @Test + public void whenDivideTwoNumber_returnCorrectResult() { + Division division = new Division(LEFT, RIGHT); + calculator.calculate(division); + assertEquals(DIVISION_RESULT, division.getResult(), 0.0); + } + +} diff --git a/persistence-modules/java-jpa-2/README.md b/persistence-modules/java-jpa-2/README.md index 9d46c0d814..4b822c4782 100644 --- a/persistence-modules/java-jpa-2/README.md +++ b/persistence-modules/java-jpa-2/README.md @@ -12,4 +12,5 @@ This module contains articles about the Java Persistence API (JPA) in Java. - [Combining JPA And/Or Criteria Predicates](https://www.baeldung.com/jpa-and-or-criteria-predicates) - [JPA Annotation for the PostgreSQL TEXT Type](https://www.baeldung.com/jpa-annotation-postgresql-text-type) - [Mapping a Single Entity to Multiple Tables in JPA](https://www.baeldung.com/jpa-mapping-single-entity-to-multiple-tables) +- [Constructing a JPA Query Between Unrelated Entities](https://www.baeldung.com/jpa-query-unrelated-entities) - More articles: [[<-- prev]](/java-jpa) diff --git a/persistence-modules/redis/README.md b/persistence-modules/redis/README.md index 668b8d33f8..71d009241a 100644 --- a/persistence-modules/redis/README.md +++ b/persistence-modules/redis/README.md @@ -3,3 +3,4 @@ - [A Guide to Redis with Redisson](http://www.baeldung.com/redis-redisson) - [Introduction to Lettuce – the Java Redis Client](https://www.baeldung.com/java-redis-lettuce) - [List All Available Redis Keys](https://www.baeldung.com/redis-list-available-keys) +- [Spring Data Redis’s Property-Based Configuration](https://www.baeldung.com/spring-data-redis-properties) diff --git a/persistence-modules/spring-boot-persistence-2/README.md b/persistence-modules/spring-boot-persistence-2/README.md index 3ea93db4fe..e0479ffe10 100644 --- a/persistence-modules/spring-boot-persistence-2/README.md +++ b/persistence-modules/spring-boot-persistence-2/README.md @@ -1,4 +1,8 @@ ### Relevant Articles: - [Using JDBI with Spring Boot](https://www.baeldung.com/spring-boot-jdbi) +- [Configuring a Tomcat Connection Pool in Spring Boot](https://www.baeldung.com/spring-boot-tomcat-connection-pool) +- [Integrating Spring Boot with HSQLDB](https://www.baeldung.com/spring-boot-hsqldb) +- [List of In-Memory Databases](http://www.baeldung.com/java-in-memory-databases) - [Oracle Connection Pooling With Spring](https://www.baeldung.com/spring-oracle-connection-pooling) +- More articles: [[<-- prev]](../spring-boot-persistence) diff --git a/persistence-modules/spring-boot-persistence-2/pom.xml b/persistence-modules/spring-boot-persistence-2/pom.xml index 9f456fa8af..33b33d7160 100644 --- a/persistence-modules/spring-boot-persistence-2/pom.xml +++ b/persistence-modules/spring-boot-persistence-2/pom.xml @@ -104,6 +104,22 @@ tomcat-jdbc + + mysql + mysql-connector-java + + + org.xerial + sqlite-jdbc + + + org.apache.derby + derby + + + org.hsqldb + hsqldb + diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothsqldb/application/Application.java b/persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/springboothsqldb/application/Application.java similarity index 96% rename from persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothsqldb/application/Application.java rename to persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/springboothsqldb/application/Application.java index c5a5c291c6..bde8346482 100644 --- a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothsqldb/application/Application.java +++ b/persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/springboothsqldb/application/Application.java @@ -1,12 +1,12 @@ -package com.baeldung.springboothsqldb.application; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class Application { - - public static void main(String[] args) { - SpringApplication.run(Application.class, args); - } -} +package com.baeldung.springboothsqldb.application; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothsqldb/application/controllers/CustomerController.java b/persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/springboothsqldb/application/controllers/CustomerController.java similarity index 92% rename from persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothsqldb/application/controllers/CustomerController.java rename to persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/springboothsqldb/application/controllers/CustomerController.java index 8229a1d1c0..045612a86f 100644 --- a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothsqldb/application/controllers/CustomerController.java +++ b/persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/springboothsqldb/application/controllers/CustomerController.java @@ -1,33 +1,32 @@ -package com.baeldung.springboothsqldb.application.controllers; - -import com.baeldung.springboothsqldb.application.entities.Customer; -import com.baeldung.springboothsqldb.application.repositories.CustomerRepository; -import java.util.List; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.RestController; - -@RestController -public class CustomerController { - - private final CustomerRepository customerRepository; - - @Autowired - public CustomerController(CustomerRepository customerRepository) { - this.customerRepository = customerRepository; - } - - @PostMapping("/customers") - public Customer addCustomer(@RequestBody Customer customer) { - customerRepository.save(customer); - return customer; - } - - @GetMapping("/customers") - public List getCustomers() { - return (List) customerRepository.findAll(); - } -} +package com.baeldung.springboothsqldb.application.controllers; + +import com.baeldung.springboothsqldb.application.entities.Customer; +import com.baeldung.springboothsqldb.application.repositories.CustomerRepository; +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class CustomerController { + + private final CustomerRepository customerRepository; + + @Autowired + public CustomerController(CustomerRepository customerRepository) { + this.customerRepository = customerRepository; + } + + @PostMapping("/customers") + public Customer addCustomer(@RequestBody Customer customer) { + customerRepository.save(customer); + return customer; + } + + @GetMapping("/customers") + public List getCustomers() { + return (List) customerRepository.findAll(); + } +} diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothsqldb/application/entities/Customer.java b/persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/springboothsqldb/application/entities/Customer.java similarity index 95% rename from persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothsqldb/application/entities/Customer.java rename to persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/springboothsqldb/application/entities/Customer.java index 636a80e272..ee2735abb8 100644 --- a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothsqldb/application/entities/Customer.java +++ b/persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/springboothsqldb/application/entities/Customer.java @@ -1,55 +1,55 @@ -package com.baeldung.springboothsqldb.application.entities; - -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.Table; - -@Entity -@Table(name = "customers") -public class Customer { - - @Id - @GeneratedValue(strategy = GenerationType.AUTO) - private long id; - - private String name; - private String email; - - public Customer() {} - - public Customer(String name, String email) { - this.name = name; - this.email = email; - } - - public void setId(long id) { - this.id = id; - } - - public long getId() { - return id; - } - - public void setName(String name) { - this.name = name; - } - - public String getName() { - return name; - } - - public void setEmail(String email) { - this.email = email; - } - - public String getEmail() { - return email; - } - - @Override - public String toString() { - return "Customer{" + "id=" + id + ", name=" + name + ", email=" + email + '}'; - } -} +package com.baeldung.springboothsqldb.application.entities; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +@Entity +@Table(name = "customers") +public class Customer { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private long id; + + private String name; + private String email; + + public Customer() {} + + public Customer(String name, String email) { + this.name = name; + this.email = email; + } + + public void setId(long id) { + this.id = id; + } + + public long getId() { + return id; + } + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getEmail() { + return email; + } + + @Override + public String toString() { + return "Customer{" + "id=" + id + ", name=" + name + ", email=" + email + '}'; + } +} diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothsqldb/application/repositories/CustomerRepository.java b/persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/springboothsqldb/application/repositories/CustomerRepository.java similarity index 97% rename from persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothsqldb/application/repositories/CustomerRepository.java rename to persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/springboothsqldb/application/repositories/CustomerRepository.java index a81aa62c43..cc8a045e83 100644 --- a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/springboothsqldb/application/repositories/CustomerRepository.java +++ b/persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/springboothsqldb/application/repositories/CustomerRepository.java @@ -1,8 +1,8 @@ -package com.baeldung.springboothsqldb.application.repositories; - -import com.baeldung.springboothsqldb.application.entities.Customer; -import org.springframework.data.repository.CrudRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface CustomerRepository extends CrudRepository {} +package com.baeldung.springboothsqldb.application.repositories; + +import com.baeldung.springboothsqldb.application.entities.Customer; +import org.springframework.data.repository.CrudRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface CustomerRepository extends CrudRepository {} diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/tomcatconnectionpool/application/SpringBootConsoleApplication.java b/persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/tomcatconnectionpool/application/SpringBootConsoleApplication.java similarity index 100% rename from persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/tomcatconnectionpool/application/SpringBootConsoleApplication.java rename to persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/tomcatconnectionpool/application/SpringBootConsoleApplication.java diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/tomcatconnectionpool/application/entities/Customer.java b/persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/tomcatconnectionpool/application/entities/Customer.java similarity index 100% rename from persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/tomcatconnectionpool/application/entities/Customer.java rename to persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/tomcatconnectionpool/application/entities/Customer.java diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/tomcatconnectionpool/application/repositories/CustomerRepository.java b/persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/tomcatconnectionpool/application/repositories/CustomerRepository.java similarity index 100% rename from persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/tomcatconnectionpool/application/repositories/CustomerRepository.java rename to persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/tomcatconnectionpool/application/repositories/CustomerRepository.java diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/tomcatconnectionpool/application/runners/CommandLineCrudRunner.java b/persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/tomcatconnectionpool/application/runners/CommandLineCrudRunner.java similarity index 100% rename from persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/tomcatconnectionpool/application/runners/CommandLineCrudRunner.java rename to persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/tomcatconnectionpool/application/runners/CommandLineCrudRunner.java diff --git a/persistence-modules/spring-boot-persistence-2/src/main/resources/persistence-derby.properties b/persistence-modules/spring-boot-persistence-2/src/main/resources/persistence-derby.properties new file mode 100644 index 0000000000..5b5ff05236 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-2/src/main/resources/persistence-derby.properties @@ -0,0 +1,8 @@ +jdbc.driverClassName=org.apache.derby.jdbc.EmbeddedDriver +jdbc.url=jdbc:derby:memory:myD;create=true +jdbc.user=sa +jdbc.pass= + +hibernate.dialect=org.hibernate.dialect.DerbyDialect +hibernate.show_sql=true +hibernate.hbm2ddl.auto=create-drop \ No newline at end of file diff --git a/persistence-modules/spring-boot-persistence-2/src/main/resources/persistence-generic-entity.properties b/persistence-modules/spring-boot-persistence-2/src/main/resources/persistence-generic-entity.properties new file mode 100644 index 0000000000..b19304cb1f --- /dev/null +++ b/persistence-modules/spring-boot-persistence-2/src/main/resources/persistence-generic-entity.properties @@ -0,0 +1,8 @@ +jdbc.driverClassName=org.h2.Driver +jdbc.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1 +jdbc.user=sa +jdbc.pass=sa + +hibernate.dialect=org.hibernate.dialect.H2Dialect +hibernate.show_sql=true +hibernate.hbm2ddl.auto=create-drop diff --git a/persistence-modules/spring-boot-persistence-2/src/main/resources/persistence-hsqldb.properties b/persistence-modules/spring-boot-persistence-2/src/main/resources/persistence-hsqldb.properties new file mode 100644 index 0000000000..d045a8b7e5 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-2/src/main/resources/persistence-hsqldb.properties @@ -0,0 +1,8 @@ +jdbc.driverClassName=org.hsqldb.jdbc.JDBCDriver +jdbc.url=jdbc:hsqldb:mem:myDb +jdbc.user=sa +jdbc.pass= + +hibernate.dialect=org.hibernate.dialect.HSQLDialect +hibernate.show_sql=true +hibernate.hbm2ddl.auto=create-drop \ No newline at end of file diff --git a/persistence-modules/spring-boot-persistence-2/src/main/resources/persistence-sqlite.properties b/persistence-modules/spring-boot-persistence-2/src/main/resources/persistence-sqlite.properties new file mode 100644 index 0000000000..ee16081603 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-2/src/main/resources/persistence-sqlite.properties @@ -0,0 +1,7 @@ +jdbc.driverClassName=org.sqlite.JDBC +jdbc.url=jdbc:sqlite:memory:myDb?cache=shared +jdbc.user=sa +jdbc.pass=sa +hibernate.dialect=com.baeldung.dialect.SQLiteDialect +hibernate.hbm2ddl.auto=create-drop +hibernate.show_sql=true diff --git a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/springboothsqldb/application/tests/CustomerControllerUnitTest.java b/persistence-modules/spring-boot-persistence-2/src/test/java/com/baeldung/springboothsqldb/application/tests/CustomerControllerUnitTest.java similarity index 97% rename from persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/springboothsqldb/application/tests/CustomerControllerUnitTest.java rename to persistence-modules/spring-boot-persistence-2/src/test/java/com/baeldung/springboothsqldb/application/tests/CustomerControllerUnitTest.java index 33891e3d43..be16f8f563 100644 --- a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/springboothsqldb/application/tests/CustomerControllerUnitTest.java +++ b/persistence-modules/spring-boot-persistence-2/src/test/java/com/baeldung/springboothsqldb/application/tests/CustomerControllerUnitTest.java @@ -1,61 +1,61 @@ -package com.baeldung.springboothsqldb.application.tests; - -import com.baeldung.springboothsqldb.application.entities.Customer; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.ObjectWriter; -import com.fasterxml.jackson.databind.SerializationFeature; -import java.nio.charset.Charset; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.http.MediaType; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import org.springframework.test.web.servlet.result.MockMvcResultMatchers; - -@RunWith(SpringRunner.class) -@SpringBootTest -@AutoConfigureMockMvc -public class CustomerControllerUnitTest { - - private static MediaType MEDIA_TYPE_JSON; - - @Autowired - private MockMvc mockMvc; - - @Before - public void setUpJsonMediaType() { - MEDIA_TYPE_JSON = new MediaType(MediaType.APPLICATION_JSON.getType(), MediaType.APPLICATION_JSON.getSubtype(), Charset.forName("utf8")); - - } - - @Test - public void whenPostHttpRequesttoCustomers_thenStatusOK() throws Exception { - Customer customer = new Customer("John", "john@domain.com"); - ObjectMapper mapper = new ObjectMapper(); - mapper.configure(SerializationFeature.WRAP_ROOT_VALUE, false); - ObjectWriter objectWriter = mapper.writer().withDefaultPrettyPrinter(); - String requestJson = objectWriter.writeValueAsString(customer); - - this.mockMvc - .perform(MockMvcRequestBuilders.post("/customers") - .contentType(MEDIA_TYPE_JSON) - .content(requestJson) - ) - - .andExpect(MockMvcResultMatchers.status().isOk()); - } - - @Test - public void whenGetHttpRequesttoCustomers_thenStatusOK() throws Exception { - this.mockMvc - .perform(MockMvcRequestBuilders.get("/customers")) - - .andExpect(MockMvcResultMatchers.content().contentType(MEDIA_TYPE_JSON)) - .andExpect(MockMvcResultMatchers.status().isOk()); - } -} +package com.baeldung.springboothsqldb.application.tests; + +import com.baeldung.springboothsqldb.application.entities.Customer; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; +import com.fasterxml.jackson.databind.SerializationFeature; +import java.nio.charset.Charset; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; + +@RunWith(SpringRunner.class) +@SpringBootTest +@AutoConfigureMockMvc +public class CustomerControllerUnitTest { + + private static MediaType MEDIA_TYPE_JSON; + + @Autowired + private MockMvc mockMvc; + + @Before + public void setUpJsonMediaType() { + MEDIA_TYPE_JSON = new MediaType(MediaType.APPLICATION_JSON.getType(), MediaType.APPLICATION_JSON.getSubtype(), Charset.forName("utf8")); + + } + + @Test + public void whenPostHttpRequesttoCustomers_thenStatusOK() throws Exception { + Customer customer = new Customer("John", "john@domain.com"); + ObjectMapper mapper = new ObjectMapper(); + mapper.configure(SerializationFeature.WRAP_ROOT_VALUE, false); + ObjectWriter objectWriter = mapper.writer().withDefaultPrettyPrinter(); + String requestJson = objectWriter.writeValueAsString(customer); + + this.mockMvc + .perform(MockMvcRequestBuilders.post("/customers") + .contentType(MEDIA_TYPE_JSON) + .content(requestJson) + ) + + .andExpect(MockMvcResultMatchers.status().isOk()); + } + + @Test + public void whenGetHttpRequesttoCustomers_thenStatusOK() throws Exception { + this.mockMvc + .perform(MockMvcRequestBuilders.get("/customers")) + + .andExpect(MockMvcResultMatchers.content().contentType(MEDIA_TYPE_JSON)) + .andExpect(MockMvcResultMatchers.status().isOk()); + } +} diff --git a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/tomcatconnectionpool/test/application/SpringBootTomcatConnectionPoolIntegrationTest.java b/persistence-modules/spring-boot-persistence-2/src/test/java/com/baeldung/tomcatconnectionpool/test/application/SpringBootTomcatConnectionPoolIntegrationTest.java similarity index 100% rename from persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/tomcatconnectionpool/test/application/SpringBootTomcatConnectionPoolIntegrationTest.java rename to persistence-modules/spring-boot-persistence-2/src/test/java/com/baeldung/tomcatconnectionpool/test/application/SpringBootTomcatConnectionPoolIntegrationTest.java diff --git a/persistence-modules/spring-boot-persistence-2/src/test/resources/schema.sql b/persistence-modules/spring-boot-persistence-2/src/test/resources/schema.sql index a0d0eaf62e..8d7db6c9f3 100644 --- a/persistence-modules/spring-boot-persistence-2/src/test/resources/schema.sql +++ b/persistence-modules/spring-boot-persistence-2/src/test/resources/schema.sql @@ -1,3 +1,6 @@ +drop table if exists car_maker; +drop table if exists car_model; + -- -- Car makers table -- diff --git a/persistence-modules/spring-boot-persistence/README.MD b/persistence-modules/spring-boot-persistence/README.MD index 96eb326cbe..d6ef239448 100644 --- a/persistence-modules/spring-boot-persistence/README.MD +++ b/persistence-modules/spring-boot-persistence/README.MD @@ -3,10 +3,8 @@ - [Spring Boot with Multiple SQL Import Files](http://www.baeldung.com/spring-boot-sql-import-files) - [Configuring Separate Spring DataSource for Tests](http://www.baeldung.com/spring-testing-separate-data-source) - [Quick Guide on Loading Initial Data with Spring Boot](http://www.baeldung.com/spring-boot-data-sql-and-schema-sql) -- [Configuring a Tomcat Connection Pool in Spring Boot](https://www.baeldung.com/spring-boot-tomcat-connection-pool) -- [Hibernate Field Naming with Spring Boot](https://www.baeldung.com/hibernate-field-naming-spring-boot) -- [Integrating Spring Boot with HSQLDB](https://www.baeldung.com/spring-boot-hsqldb) - [Configuring a DataSource Programmatically in Spring Boot](https://www.baeldung.com/spring-boot-configure-data-source-programmatic) - [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) -- [List of In-Memory Databases](http://www.baeldung.com/java-in-memory-databases) \ No newline at end of file +- More articles: [[more -->]](../spring-boot-persistence-2) \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa-5/README.md b/persistence-modules/spring-data-jpa-5/README.md index e8f83654df..fa29c82bac 100644 --- a/persistence-modules/spring-data-jpa-5/README.md +++ b/persistence-modules/spring-data-jpa-5/README.md @@ -1,6 +1,7 @@ ### Relevant Articles: -- [Spring JPA @Embedded and @EmbeddedId](TBD) +- [Spring JPA @Embedded and @EmbeddedId](https://www.baeldung.com/spring-jpa-embedded-method-parameters) +- [Generate Database Schema with Spring Data JPA](https://www.baeldung.com/spring-data-jpa-generate-db-schema) ### Eclipse Config After importing the project into Eclipse, you may see the following error: diff --git a/persistence-modules/spring-persistence-simple-2/README.md b/persistence-modules/spring-persistence-simple-2/README.md index a6408df8f2..70eab26d45 100644 --- a/persistence-modules/spring-persistence-simple-2/README.md +++ b/persistence-modules/spring-persistence-simple-2/README.md @@ -1,3 +1,4 @@ ### Relevant Articles: - [Spring JdbcTemplate Unit Testing](https://www.baeldung.com/spring-jdbctemplate-testing) +- [Using a List of Values in a JdbcTemplate IN Clause](https://www.baeldung.com/spring-jdbctemplate-in-list) diff --git a/pom.xml b/pom.xml index 89ac3534b6..2efea40c91 100644 --- a/pom.xml +++ b/pom.xml @@ -377,6 +377,7 @@ atomix aws + aws-app-sync aws-lambda aws-reactive @@ -462,7 +463,6 @@ java-numbers java-numbers-2 java-numbers-3 - java-python-interop java-rmi java-spi java-vavr-stream @@ -496,7 +496,8 @@ kotlin-quasar - libraries-2 + language-interop + libraries-2 libraries-3 libraries-apache-commons libraries-apache-commons-collections @@ -898,7 +899,6 @@ atomix aws - aws-app-sync aws-lambda aws-reactive diff --git a/spring-5-security/README.md b/spring-5-security/README.md index 07f2d48b7f..764d726ff8 100644 --- a/spring-5-security/README.md +++ b/spring-5-security/README.md @@ -9,3 +9,5 @@ This module contains articles about Spring Security 5 - [New Password Storage In Spring Security 5](https://www.baeldung.com/spring-security-5-password-storage) - [Default Password Encoder in Spring Security 5](https://www.baeldung.com/spring-security-5-default-password-encoder) - [Guide to the AuthenticationManagerResolver in Spring Security](https://www.baeldung.com/spring-security-authenticationmanagerresolver) +- [Disable Security for a Profile in Spring Boot](https://www.baeldung.com/spring-security-disable-profile) +- [Manual Logout With Spring Security](https://www.baeldung.com/spring-security-manual-logout) diff --git a/spring-boot-groovy/README.md b/spring-boot-groovy/README.md new file mode 100644 index 0000000000..d2472a11d0 --- /dev/null +++ b/spring-boot-groovy/README.md @@ -0,0 +1,3 @@ +### Relevant Articles: + +- [Building a Simple Web Application with Spring Boot and Groovy](https://www.baeldung.com/spring-boot-groovy-web-app) diff --git a/spring-boot-modules/pom.xml b/spring-boot-modules/pom.xml index 228e7ce481..6caa93158a 100644 --- a/spring-boot-modules/pom.xml +++ b/spring-boot-modules/pom.xml @@ -28,6 +28,7 @@ spring-boot-deployment spring-boot-di spring-boot-camel + spring-boot-ci-cd spring-boot-custom-starter spring-boot-crud @@ -48,6 +49,7 @@ spring-boot-parent spring-boot-performance spring-boot-properties + spring-boot-properties-2 spring-boot-property-exp spring-boot-runtime spring-boot-security diff --git a/spring-boot-modules/spring-boot-ci-cd/.mvn/wrapper/MavenWrapperDownloader.java b/spring-boot-modules/spring-boot-ci-cd/.mvn/wrapper/MavenWrapperDownloader.java new file mode 100644 index 0000000000..b901097f2d --- /dev/null +++ b/spring-boot-modules/spring-boot-ci-cd/.mvn/wrapper/MavenWrapperDownloader.java @@ -0,0 +1,117 @@ +/* + * Copyright 2007-present the original author or 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 + * + * http://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. + */ +import java.net.*; +import java.io.*; +import java.nio.channels.*; +import java.util.Properties; + +public class MavenWrapperDownloader { + + private static final String WRAPPER_VERSION = "0.5.6"; + /** + * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. + */ + private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" + + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; + + /** + * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to + * use instead of the default one. + */ + private static final String MAVEN_WRAPPER_PROPERTIES_PATH = + ".mvn/wrapper/maven-wrapper.properties"; + + /** + * Path where the maven-wrapper.jar will be saved to. + */ + private static final String MAVEN_WRAPPER_JAR_PATH = + ".mvn/wrapper/maven-wrapper.jar"; + + /** + * Name of the property which should be used to override the default download url for the wrapper. + */ + private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; + + public static void main(String args[]) { + System.out.println("- Downloader started"); + File baseDirectory = new File(args[0]); + System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); + + // If the maven-wrapper.properties exists, read it and check if it contains a custom + // wrapperUrl parameter. + File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); + String url = DEFAULT_DOWNLOAD_URL; + if(mavenWrapperPropertyFile.exists()) { + FileInputStream mavenWrapperPropertyFileInputStream = null; + try { + mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); + Properties mavenWrapperProperties = new Properties(); + mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); + url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); + } catch (IOException e) { + System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); + } finally { + try { + if(mavenWrapperPropertyFileInputStream != null) { + mavenWrapperPropertyFileInputStream.close(); + } + } catch (IOException e) { + // Ignore ... + } + } + } + System.out.println("- Downloading from: " + url); + + File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); + if(!outputFile.getParentFile().exists()) { + if(!outputFile.getParentFile().mkdirs()) { + System.out.println( + "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); + } + } + System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); + try { + downloadFileFromURL(url, outputFile); + System.out.println("Done"); + System.exit(0); + } catch (Throwable e) { + System.out.println("- Error downloading"); + e.printStackTrace(); + System.exit(1); + } + } + + private static void downloadFileFromURL(String urlString, File destination) throws Exception { + if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { + String username = System.getenv("MVNW_USERNAME"); + char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); + Authenticator.setDefault(new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(username, password); + } + }); + } + URL website = new URL(urlString); + ReadableByteChannel rbc; + rbc = Channels.newChannel(website.openStream()); + FileOutputStream fos = new FileOutputStream(destination); + fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); + fos.close(); + rbc.close(); + } + +} diff --git a/spring-boot-modules/spring-boot-ci-cd/.mvn/wrapper/maven-wrapper.properties b/spring-boot-modules/spring-boot-ci-cd/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000000..642d572ce9 --- /dev/null +++ b/spring-boot-modules/spring-boot-ci-cd/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar diff --git a/spring-boot-modules/spring-boot-ci-cd/.travis.yml b/spring-boot-modules/spring-boot-ci-cd/.travis.yml new file mode 100644 index 0000000000..8467e11408 --- /dev/null +++ b/spring-boot-modules/spring-boot-ci-cd/.travis.yml @@ -0,0 +1,16 @@ +language: java +jdk: + - openjdk11 +services: + - docker + +before_install: + - echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin + - docker pull openjdk:11-jre-slim-sid + +script: + - ./mvnw clean org.jacoco:jacoco-maven-plugin:prepare-agent install + - ./mvnw heroku:deploy jib:build -P deploy-heroku,deploy-docker + +after_success: + - bash <(curl -s https://codecov.io/bash) \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-ci-cd/README.md b/spring-boot-modules/spring-boot-ci-cd/README.md new file mode 100644 index 0000000000..ee8f106b53 --- /dev/null +++ b/spring-boot-modules/spring-boot-ci-cd/README.md @@ -0,0 +1,7 @@ +# Spring Boot CI/CD + +This module contains articles about CI/CD with Spring Boot + +## Relevant Articles + +- [CI/CD for a Spring Boot Project](https://www.baeldung.com/spring-boot-ci-cd) diff --git a/spring-boot-modules/spring-boot-ci-cd/mvnw b/spring-boot-modules/spring-boot-ci-cd/mvnw new file mode 100755 index 0000000000..41c0f0c23d --- /dev/null +++ b/spring-boot-modules/spring-boot-ci-cd/mvnw @@ -0,0 +1,310 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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 +# +# http://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. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + 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 + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ -n "$MVNW_REPOURL" ]; then + jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/spring-boot-modules/spring-boot-ci-cd/mvnw.cmd b/spring-boot-modules/spring-boot-ci-cd/mvnw.cmd new file mode 100644 index 0000000000..86115719e5 --- /dev/null +++ b/spring-boot-modules/spring-boot-ci-cd/mvnw.cmd @@ -0,0 +1,182 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + +FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/spring-boot-modules/spring-boot-ci-cd/pom.xml b/spring-boot-modules/spring-boot-ci-cd/pom.xml new file mode 100644 index 0000000000..25e45d56f3 --- /dev/null +++ b/spring-boot-modules/spring-boot-ci-cd/pom.xml @@ -0,0 +1,107 @@ + + + 4.0.0 + spring-boot-ci-cd + 0.0.1-SNAPSHOT + spring-boot-ci-cd + jar + + + com.baeldung + parent-boot-2 + 0.0.1-SNAPSHOT + ../../parent-boot-2 + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-actuator + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + org.jacoco + jacoco-maven-plugin + 0.8.5 + + + default-prepare-agent + + prepare-agent + + + + report + test + + report + + + + + + + + + + deploy-heroku + + true + + + + + com.heroku.sdk + heroku-maven-plugin + 3.0.2 + + spring-boot-ci-cd + + java $JAVA_OPTS -jar -Dserver.port=$PORT target/${project.build.finalName}.jar + + + + + + + + deploy-docker + + true + + + + + com.google.cloud.tools + jib-maven-plugin + 2.2.0 + + + registry.hub.docker.com/baeldungjib/baeldung-ci-cd-process + + ${project.version} + latest + + + + + + + + + + \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-ci-cd/src/main/java/com/baeldung/cicd/CiCdApplication.java b/spring-boot-modules/spring-boot-ci-cd/src/main/java/com/baeldung/cicd/CiCdApplication.java new file mode 100644 index 0000000000..8451084148 --- /dev/null +++ b/spring-boot-modules/spring-boot-ci-cd/src/main/java/com/baeldung/cicd/CiCdApplication.java @@ -0,0 +1,12 @@ +package com.baeldung.cicd; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class CiCdApplication { + + public static void main(String[] args) { + SpringApplication.run(CiCdApplication.class, args); + } +} diff --git a/spring-boot-modules/spring-boot-ci-cd/src/main/resources/introduction-config.yml b/spring-boot-modules/spring-boot-ci-cd/src/main/resources/introduction-config.yml new file mode 100644 index 0000000000..02ff36de05 --- /dev/null +++ b/spring-boot-modules/spring-boot-ci-cd/src/main/resources/introduction-config.yml @@ -0,0 +1 @@ +defaultSize: 5 \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-ci-cd/src/test/java/com/baeldung/cicd/CiCdApplicationIntegrationTest.java b/spring-boot-modules/spring-boot-ci-cd/src/test/java/com/baeldung/cicd/CiCdApplicationIntegrationTest.java new file mode 100644 index 0000000000..7ab246faf8 --- /dev/null +++ b/spring-boot-modules/spring-boot-ci-cd/src/test/java/com/baeldung/cicd/CiCdApplicationIntegrationTest.java @@ -0,0 +1,15 @@ +package com.baeldung.cicd; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class CiCdApplicationIntegrationTest { + + @Test + public void contextLoads() { + + } +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-logging-log4j2/README.md b/spring-boot-modules/spring-boot-logging-log4j2/README.md index 76029caef8..aa6bb9b6e1 100644 --- a/spring-boot-modules/spring-boot-logging-log4j2/README.md +++ b/spring-boot-modules/spring-boot-logging-log4j2/README.md @@ -5,4 +5,4 @@ This module contains articles about logging in Spring Boot projects with Log4j 2 ### Relevant Articles: - [Logging in Spring Boot](https://www.baeldung.com/spring-boot-logging) - [Logging to Graylog with Spring Boot](https://www.baeldung.com/graylog-with-spring-boot) - +- [Log Groups in Spring Boot 2.1](https://www.baeldung.com/spring-boot-log-groups) diff --git a/spring-boot-modules/spring-boot-mvc-2/pom.xml b/spring-boot-modules/spring-boot-mvc-2/pom.xml index 3c503eb23d..45202d1e4c 100644 --- a/spring-boot-modules/spring-boot-mvc-2/pom.xml +++ b/spring-boot-modules/spring-boot-mvc-2/pom.xml @@ -87,19 +87,6 @@ - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - jcenter-snapshots jcenter @@ -107,27 +94,12 @@ - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - 3.0.0-SNAPSHOT com.baeldung.swagger2boot.SpringBootSwaggerApplication - 2.2.0.BUILD-SNAPSHOT + 2.2.6.RELEASE 1.4.11.1 diff --git a/spring-boot-modules/spring-boot-parent/spring-boot-with-starter-parent/pom.xml b/spring-boot-modules/spring-boot-parent/spring-boot-with-starter-parent/pom.xml index baba410b39..331a85ec5b 100644 --- a/spring-boot-modules/spring-boot-parent/spring-boot-with-starter-parent/pom.xml +++ b/spring-boot-modules/spring-boot-parent/spring-boot-with-starter-parent/pom.xml @@ -20,7 +20,7 @@ org.springframework.boot spring-boot-starter-data-jpa - ${spring-boot.version} + ${spring-boot-starter-data-jpa.version} @@ -38,7 +38,7 @@ 1.8 - 2.1.5.RELEASE + 2.2.5.RELEASE 4.11 diff --git a/spring-boot-modules/spring-boot-properties-2/README.md b/spring-boot-modules/spring-boot-properties-2/README.md new file mode 100644 index 0000000000..cd0fd5e5ee --- /dev/null +++ b/spring-boot-modules/spring-boot-properties-2/README.md @@ -0,0 +1,10 @@ +## Spring Boot Properties + +This module contains articles about Properties in Spring Boot. + +### Relevant Articles: +- [Load Spring Boot Properties From a JSON File](https://www.baeldung.com/spring-boot-json-properties) +- [A Quick Guide to Spring @Value](https://www.baeldung.com/spring-value-annotation) +- [Using Spring @Value with Defaults](https://www.baeldung.com/spring-value-defaults) +- [How to Inject a Property Value Into a Class Not Managed by Spring?](https://www.baeldung.com/inject-properties-value-non-spring-class) +- More articles: [[<-- prev]](../spring-boot-properties) \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-properties-2/pom.xml b/spring-boot-modules/spring-boot-properties-2/pom.xml new file mode 100644 index 0000000000..bd2a35b19d --- /dev/null +++ b/spring-boot-modules/spring-boot-properties-2/pom.xml @@ -0,0 +1,29 @@ + + + 4.0.0 + spring-boot-properties-2 + spring-boot-properties-2 + jar + Spring Boot Properties Module + 0.0.1-SNAPSHOT + + + com.baeldung + parent-boot-2 + 0.0.1-SNAPSHOT + ../../parent-boot-2 + + + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-web + + + + diff --git a/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/json/ConfigPropertiesDemoApplication.java b/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/json/ConfigPropertiesDemoApplication.java new file mode 100644 index 0000000000..a1e2584b2c --- /dev/null +++ b/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/json/ConfigPropertiesDemoApplication.java @@ -0,0 +1,16 @@ +package com.baeldung.properties.json; + +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.context.annotation.ComponentScan; + +@SpringBootApplication +@ComponentScan(basePackageClasses = {JsonProperties.class, CustomJsonProperties.class}) +public class ConfigPropertiesDemoApplication { + + public static void main(String[] args) { + new SpringApplicationBuilder(ConfigPropertiesDemoApplication.class).initializers(new JsonPropertyContextInitializer()) + .run(); + } + +} diff --git a/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/properties/CustomJsonProperties.java b/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/json/CustomJsonProperties.java similarity index 97% rename from spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/properties/CustomJsonProperties.java rename to spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/json/CustomJsonProperties.java index 084138ec6f..555711c49b 100644 --- a/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/properties/CustomJsonProperties.java +++ b/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/json/CustomJsonProperties.java @@ -1,4 +1,4 @@ -package com.baeldung.properties; +package com.baeldung.properties.json; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; diff --git a/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/properties/JsonProperties.java b/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/json/JsonProperties.java similarity index 92% rename from spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/properties/JsonProperties.java rename to spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/json/JsonProperties.java index 31b3be14b4..6ada770e3b 100644 --- a/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/properties/JsonProperties.java +++ b/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/json/JsonProperties.java @@ -1,12 +1,13 @@ -package com.baeldung.properties; - -import java.util.LinkedHashMap; -import java.util.List; +package com.baeldung.properties.json; +import com.baeldung.properties.json.factory.JsonPropertySourceFactory; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.PropertySource; import org.springframework.stereotype.Component; +import java.util.LinkedHashMap; +import java.util.List; + @Component @PropertySource(value = "classpath:configprops.json", factory = JsonPropertySourceFactory.class) @ConfigurationProperties diff --git a/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/properties/JsonPropertyContextInitializer.java b/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/json/JsonPropertyContextInitializer.java similarity index 98% rename from spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/properties/JsonPropertyContextInitializer.java rename to spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/json/JsonPropertyContextInitializer.java index 0aee149123..e3b713f29b 100644 --- a/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/properties/JsonPropertyContextInitializer.java +++ b/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/json/JsonPropertyContextInitializer.java @@ -1,4 +1,11 @@ -package com.baeldung.properties; +package com.baeldung.properties.json; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.context.ApplicationContextInitializer; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.PropertySource; +import org.springframework.core.io.Resource; import java.io.IOException; import java.util.Collection; @@ -10,14 +17,6 @@ import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; -import org.springframework.context.ApplicationContextInitializer; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.core.env.MapPropertySource; -import org.springframework.core.env.PropertySource; -import org.springframework.core.io.Resource; - -import com.fasterxml.jackson.databind.ObjectMapper; - public class JsonPropertyContextInitializer implements ApplicationContextInitializer { private final static String CUSTOM_PREFIX = "custom."; diff --git a/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/properties/JsonPropertySourceFactory.java b/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/json/factory/JsonPropertySourceFactory.java similarity index 93% rename from spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/properties/JsonPropertySourceFactory.java rename to spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/json/factory/JsonPropertySourceFactory.java index c14d3faea5..dccaae4ad2 100644 --- a/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/properties/JsonPropertySourceFactory.java +++ b/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/json/factory/JsonPropertySourceFactory.java @@ -1,14 +1,13 @@ -package com.baeldung.properties; - -import java.io.IOException; -import java.util.Map; +package com.baeldung.properties.json.factory; +import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.core.env.MapPropertySource; import org.springframework.core.env.PropertySource; import org.springframework.core.io.support.EncodedResource; import org.springframework.core.io.support.PropertySourceFactory; -import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import java.util.Map; public class JsonPropertySourceFactory implements PropertySourceFactory { diff --git a/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/value/ClassNotManagedBySpring.java b/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/value/ClassNotManagedBySpring.java similarity index 95% rename from spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/value/ClassNotManagedBySpring.java rename to spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/value/ClassNotManagedBySpring.java index 0329769d3c..59ee73a07b 100644 --- a/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/value/ClassNotManagedBySpring.java +++ b/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/value/ClassNotManagedBySpring.java @@ -1,4 +1,4 @@ -package com.baeldung.value; +package com.baeldung.properties.value; public class ClassNotManagedBySpring { diff --git a/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/value/CollectionProvider.java b/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/value/CollectionProvider.java new file mode 100644 index 0000000000..6327e688e8 --- /dev/null +++ b/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/value/CollectionProvider.java @@ -0,0 +1,27 @@ +package com.baeldung.properties.value; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.PropertySource; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +@Component +@PropertySource("classpath:values.properties") +public class CollectionProvider { + + private final List values = new ArrayList<>(); + + public Collection getValues() { + return Collections.unmodifiableCollection(values); + } + + @Autowired + public void setValues(@Value("#{'${listOfValues}'.split(',')}") List values) { + this.values.addAll(values); + } +} diff --git a/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/value/InitializerBean.java b/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/value/InitializerBean.java similarity index 94% rename from spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/value/InitializerBean.java rename to spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/value/InitializerBean.java index 8c8634c767..b06cfa12ea 100644 --- a/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/value/InitializerBean.java +++ b/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/value/InitializerBean.java @@ -1,4 +1,4 @@ -package com.baeldung.value; +package com.baeldung.properties.value; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; diff --git a/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/value/PriorityProvider.java b/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/value/PriorityProvider.java new file mode 100644 index 0000000000..892118eb06 --- /dev/null +++ b/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/value/PriorityProvider.java @@ -0,0 +1,22 @@ +package com.baeldung.properties.value; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.PropertySource; +import org.springframework.stereotype.Component; + +@Component +@PropertySource("classpath:values.properties") +public class PriorityProvider { + + private final String priority; + + @Autowired + public PriorityProvider(@Value("${priority:normal}") String priority) { + this.priority = priority; + } + + public String getPriority() { + return priority; + } +} diff --git a/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/value/SomeBean.java b/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/value/SomeBean.java similarity index 88% rename from spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/value/SomeBean.java rename to spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/value/SomeBean.java index 39d5245049..b3346a96dd 100644 --- a/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/value/SomeBean.java +++ b/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/value/SomeBean.java @@ -1,4 +1,4 @@ -package com.baeldung.value; +package com.baeldung.properties.value; public class SomeBean { private int someValue; diff --git a/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/value/ValuesApp.java b/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/value/ValuesApp.java similarity index 98% rename from spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/value/ValuesApp.java rename to spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/value/ValuesApp.java index 80893c1adf..67547199a6 100644 --- a/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/value/ValuesApp.java +++ b/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/value/ValuesApp.java @@ -1,10 +1,4 @@ -package com.baeldung.value; - -import java.util.Arrays; -import java.util.List; -import java.util.Map; - -import javax.annotation.PostConstruct; +package com.baeldung.properties.value; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.ApplicationContext; @@ -13,6 +7,11 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; +import javax.annotation.PostConstruct; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + @Configuration @PropertySource(name = "myProperties", value = "values.properties") public class ValuesApp { diff --git a/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/valuewithdefaults/ValuesWithDefaultsApp.java b/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/value/defaults/ValuesWithDefaultsApp.java similarity index 85% rename from spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/valuewithdefaults/ValuesWithDefaultsApp.java rename to spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/value/defaults/ValuesWithDefaultsApp.java index 589f891e6b..72fa0e03c0 100644 --- a/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/valuewithdefaults/ValuesWithDefaultsApp.java +++ b/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/value/defaults/ValuesWithDefaultsApp.java @@ -1,10 +1,6 @@ -package com.baeldung.valuewithdefaults; - -import java.util.Arrays; -import java.util.List; - -import javax.annotation.PostConstruct; +package com.baeldung.properties.value.defaults; +import org.apache.commons.lang3.ArrayUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; @@ -12,8 +8,9 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.util.Assert; -import com.google.common.collect.Lists; -import com.google.common.primitives.Ints; +import javax.annotation.PostConstruct; +import java.util.Arrays; +import java.util.List; /** * Demonstrates setting defaults for @Value annotation. Note that there are no properties @@ -62,14 +59,13 @@ public class ValuesWithDefaultsApp { Assert.isTrue(intWithDefaultValue == 42); // arrays - List stringListValues = Lists.newArrayList("one", "two", "three"); + List stringListValues = Arrays.asList("one", "two", "three"); Assert.isTrue(Arrays.asList(stringArrayWithDefaults).containsAll(stringListValues)); - List intListValues = Lists.newArrayList(1, 2, 3); - Assert.isTrue(Ints.asList(intArrayWithDefaults).containsAll(intListValues)); + List intListValues = Arrays.asList(1, 2, 3); + Assert.isTrue(Arrays.asList(ArrayUtils.toObject(intArrayWithDefaults)).containsAll(intListValues)); // SpEL Assert.isTrue(spelWithDefaultValue.equals("my default system property value")); - } } diff --git a/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/yaml/YamlApplication.java b/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/yaml/YamlApplication.java new file mode 100644 index 0000000000..f1244925f1 --- /dev/null +++ b/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/yaml/YamlApplication.java @@ -0,0 +1,22 @@ +package com.baeldung.properties.yaml; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class YamlApplication implements CommandLineRunner { + + @Autowired + private YamlFooProperties yamlFooProperties; + + public static void main(String[] args) { + SpringApplication.run(YamlApplication.class, args); + } + + @Override + public void run(String... args) throws Exception { + System.out.println("YAML Properties " + yamlFooProperties); + } +} diff --git a/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/yaml/YamlFooProperties.java b/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/yaml/YamlFooProperties.java new file mode 100644 index 0000000000..264fc865ad --- /dev/null +++ b/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/yaml/YamlFooProperties.java @@ -0,0 +1,42 @@ +package com.baeldung.properties.yaml; + +import com.baeldung.properties.yaml.factory.YamlPropertySourceFactory; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; + +import java.util.List; + +@Configuration +@ConfigurationProperties(prefix = "yaml") +@PropertySource(value = "classpath:foo.yml", factory = YamlPropertySourceFactory.class) +public class YamlFooProperties { + + private String name; + + private List aliases; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List getAliases() { + return aliases; + } + + public void setAliases(List aliases) { + this.aliases = aliases; + } + + @Override + public String toString() { + return "YamlFooProperties{" + + "name='" + name + '\'' + + ", aliases=" + aliases + + '}'; + } +} diff --git a/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/yaml/factory/YamlPropertySourceFactory.java b/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/yaml/factory/YamlPropertySourceFactory.java new file mode 100644 index 0000000000..50201f9377 --- /dev/null +++ b/spring-boot-modules/spring-boot-properties-2/src/main/java/com/baeldung/properties/yaml/factory/YamlPropertySourceFactory.java @@ -0,0 +1,24 @@ +package com.baeldung.properties.yaml.factory; + +import org.springframework.beans.factory.config.YamlPropertiesFactoryBean; +import org.springframework.core.env.PropertiesPropertySource; +import org.springframework.core.env.PropertySource; +import org.springframework.core.io.support.EncodedResource; +import org.springframework.core.io.support.PropertySourceFactory; + +import java.io.IOException; +import java.util.Properties; + +public class YamlPropertySourceFactory implements PropertySourceFactory { + + @Override + public PropertySource createPropertySource(String name, EncodedResource encodedResource) throws IOException { + YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean(); + factory.setResources(encodedResource.getResource()); + + Properties properties = factory.getObject(); + + return new PropertiesPropertySource(encodedResource.getResource().getFilename(), properties); + } + +} diff --git a/spring-boot-modules/spring-boot-properties/src/main/resources/configprops.json b/spring-boot-modules/spring-boot-properties-2/src/main/resources/configprops.json similarity index 100% rename from spring-boot-modules/spring-boot-properties/src/main/resources/configprops.json rename to spring-boot-modules/spring-boot-properties-2/src/main/resources/configprops.json diff --git a/spring-boot-modules/spring-boot-properties-2/src/main/resources/foo.yml b/spring-boot-modules/spring-boot-properties-2/src/main/resources/foo.yml new file mode 100644 index 0000000000..6320510a94 --- /dev/null +++ b/spring-boot-modules/spring-boot-properties-2/src/main/resources/foo.yml @@ -0,0 +1,5 @@ +yaml: + name: foo + aliases: + - abc + - xyz \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-properties-2/src/main/resources/values.properties b/spring-boot-modules/spring-boot-properties-2/src/main/resources/values.properties new file mode 100644 index 0000000000..9c85893d5f --- /dev/null +++ b/spring-boot-modules/spring-boot-properties-2/src/main/resources/values.properties @@ -0,0 +1,4 @@ +value.from.file=Value got from the file +priority=high +listOfValues=A,B,C +valuesMap={key1:'1', key2 : '2', key3 : '3'} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-properties/src/main/resources/valueswithdefaults.properties b/spring-boot-modules/spring-boot-properties-2/src/main/resources/valueswithdefaults.properties similarity index 100% rename from spring-boot-modules/spring-boot-properties/src/main/resources/valueswithdefaults.properties rename to spring-boot-modules/spring-boot-properties-2/src/main/resources/valueswithdefaults.properties diff --git a/spring-boot-modules/spring-boot-properties/src/test/java/com/baeldung/properties/JsonPropertiesIntegrationTest.java b/spring-boot-modules/spring-boot-properties-2/src/test/java/com/baeldung/properties/json/JsonPropertiesIntegrationTest.java similarity index 98% rename from spring-boot-modules/spring-boot-properties/src/test/java/com/baeldung/properties/JsonPropertiesIntegrationTest.java rename to spring-boot-modules/spring-boot-properties-2/src/test/java/com/baeldung/properties/json/JsonPropertiesIntegrationTest.java index 2f0e5ae408..6b00489b5c 100644 --- a/spring-boot-modules/spring-boot-properties/src/test/java/com/baeldung/properties/JsonPropertiesIntegrationTest.java +++ b/spring-boot-modules/spring-boot-properties-2/src/test/java/com/baeldung/properties/json/JsonPropertiesIntegrationTest.java @@ -1,6 +1,4 @@ -package com.baeldung.properties; - -import java.util.Arrays; +package com.baeldung.properties.json; import org.hamcrest.Matchers; import org.junit.Assert; @@ -10,6 +8,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringRunner; +import java.util.Arrays; + @RunWith(SpringRunner.class) @ContextConfiguration(classes = ConfigPropertiesDemoApplication.class, initializers = JsonPropertyContextInitializer.class) public class JsonPropertiesIntegrationTest { diff --git a/spring-boot-modules/spring-boot-properties/src/test/java/com/baeldung/value/ClassNotManagedBySpringIntegrationTest.java b/spring-boot-modules/spring-boot-properties-2/src/test/java/com/baeldung/properties/value/ClassNotManagedBySpringIntegrationTest.java similarity index 96% rename from spring-boot-modules/spring-boot-properties/src/test/java/com/baeldung/value/ClassNotManagedBySpringIntegrationTest.java rename to spring-boot-modules/spring-boot-properties-2/src/test/java/com/baeldung/properties/value/ClassNotManagedBySpringIntegrationTest.java index 689801bece..271242d4e8 100644 --- a/spring-boot-modules/spring-boot-properties/src/test/java/com/baeldung/value/ClassNotManagedBySpringIntegrationTest.java +++ b/spring-boot-modules/spring-boot-properties-2/src/test/java/com/baeldung/properties/value/ClassNotManagedBySpringIntegrationTest.java @@ -1,4 +1,4 @@ -package com.baeldung.value; +package com.baeldung.properties.value; import org.junit.Before; import org.junit.Test; diff --git a/spring-boot-modules/spring-boot-properties-2/src/test/java/com/baeldung/properties/value/CollectionProviderIntegrationTest.java b/spring-boot-modules/spring-boot-properties-2/src/test/java/com/baeldung/properties/value/CollectionProviderIntegrationTest.java new file mode 100644 index 0000000000..b045786a29 --- /dev/null +++ b/spring-boot-modules/spring-boot-properties-2/src/test/java/com/baeldung/properties/value/CollectionProviderIntegrationTest.java @@ -0,0 +1,22 @@ +package com.baeldung.properties.value; + +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 static org.assertj.core.api.Assertions.assertThat; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = CollectionProvider.class) +public class CollectionProviderIntegrationTest { + + @Autowired + private CollectionProvider collectionProvider; + + @Test + public void givenPropertyFileWhenSetterInjectionUsedThenValueInjected() { + assertThat(collectionProvider.getValues()).contains("A", "B", "C"); + } +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-properties-2/src/test/java/com/baeldung/properties/value/PriorityProviderIntegrationTest.java b/spring-boot-modules/spring-boot-properties-2/src/test/java/com/baeldung/properties/value/PriorityProviderIntegrationTest.java new file mode 100644 index 0000000000..d7d1e7d78b --- /dev/null +++ b/spring-boot-modules/spring-boot-properties-2/src/test/java/com/baeldung/properties/value/PriorityProviderIntegrationTest.java @@ -0,0 +1,22 @@ +package com.baeldung.properties.value; + +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 static org.assertj.core.api.Assertions.assertThat; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = PriorityProvider.class) +public class PriorityProviderIntegrationTest { + + @Autowired + private PriorityProvider priorityProvider; + + @Test + public void givenPropertyFileWhenConstructorInjectionUsedThenValueInjected() { + assertThat(priorityProvider.getPriority()).isEqualTo("high"); + } +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-properties-2/src/test/java/com/baeldung/properties/yaml/YamlFooPropertiesIntegrationTest.java b/spring-boot-modules/spring-boot-properties-2/src/test/java/com/baeldung/properties/yaml/YamlFooPropertiesIntegrationTest.java new file mode 100644 index 0000000000..dfe1c830b4 --- /dev/null +++ b/spring-boot-modules/spring-boot-properties-2/src/test/java/com/baeldung/properties/yaml/YamlFooPropertiesIntegrationTest.java @@ -0,0 +1,23 @@ +package com.baeldung.properties.yaml; + +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 static org.assertj.core.api.Assertions.assertThat; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class YamlFooPropertiesIntegrationTest { + + @Autowired + private YamlFooProperties yamlFooProperties; + + @Test + public void whenFactoryProvidedThenYamlPropertiesInjected() { + assertThat(yamlFooProperties.getName()).isEqualTo("foo"); + assertThat(yamlFooProperties.getAliases()).containsExactly("abc", "xyz"); + } +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-properties/README.md b/spring-boot-modules/spring-boot-properties/README.md index f861a01d10..b6685c7587 100644 --- a/spring-boot-modules/spring-boot-properties/README.md +++ b/spring-boot-modules/spring-boot-properties/README.md @@ -5,12 +5,9 @@ This module contains articles about Properties in Spring Boot. ### Relevant Articles: - [Reloading Properties Files in Spring](https://www.baeldung.com/spring-reloading-properties) - [Guide to @ConfigurationProperties in Spring Boot](https://www.baeldung.com/configuration-properties-in-spring-boot) -- [Load Spring Boot Properties From a JSON File](https://www.baeldung.com/spring-boot-json-properties) - [Guide to @EnableConfigurationProperties](https://www.baeldung.com/spring-enable-config-properties) - [Properties with Spring and Spring Boot](https://www.baeldung.com/properties-with-spring) - checkout the `com.baeldung.properties` package for all scenarios of properties injection and usage -- [A Quick Guide to Spring @Value](https://www.baeldung.com/spring-value-annotation) - [Spring YAML Configuration](https://www.baeldung.com/spring-yaml) -- [Using Spring @Value with Defaults](https://www.baeldung.com/spring-value-defaults) -- [How to Inject a Property Value Into a Class Not Managed by Spring?](https://www.baeldung.com/inject-properties-value-non-spring-class) - [Add Build Properties to a Spring Boot Application](https://www.baeldung.com/spring-boot-build-properties) - [IntelliJ – Cannot Resolve Spring Boot Configuration Properties Error](https://www.baeldung.com/intellij-resolve-spring-boot-configuration-properties) +- More articles: [[more -->]](../spring-boot-properties-2) \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/properties/ConfigPropertiesDemoApplication.java b/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/properties/ConfigPropertiesDemoApplication.java index e54f28837d..1e5e88921a 100644 --- a/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/properties/ConfigPropertiesDemoApplication.java +++ b/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/properties/ConfigPropertiesDemoApplication.java @@ -1,5 +1,7 @@ package com.baeldung.properties; +import com.baeldung.buildproperties.Application; +import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.context.annotation.ComponentScan; @@ -7,11 +9,10 @@ import org.springframework.context.annotation.ComponentScan; import com.baeldung.configurationproperties.ConfigProperties; @SpringBootApplication -@ComponentScan(basePackageClasses = { ConfigProperties.class, JsonProperties.class, CustomJsonProperties.class, Database.class }) +@ComponentScan(basePackageClasses = {ConfigProperties.class, AdditionalProperties.class}) public class ConfigPropertiesDemoApplication { public static void main(String[] args) { - new SpringApplicationBuilder(ConfigPropertiesDemoApplication.class).initializers(new JsonPropertyContextInitializer()) - .run(); + SpringApplication.run(ConfigPropertiesDemoApplication.class, args); } } diff --git a/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/properties/Database.java b/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/properties/Database.java deleted file mode 100644 index 6e798672e7..0000000000 --- a/spring-boot-modules/spring-boot-properties/src/main/java/com/baeldung/properties/Database.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.baeldung.properties; - -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Configuration; - -@Configuration -@ConfigurationProperties(prefix = "database") -public class Database { - - private String url; - private String username; - private String password; - - public String getUrl() { - return url; - } - public void setUrl(String url) { - this.url = url; - } - public String getUsername() { - return username; - } - public void setUsername(String username) { - this.username = username; - } - public String getPassword() { - return password; - } - public void setPassword(String password) { - this.password = password; - } - -} diff --git a/spring-boot-modules/spring-boot-properties/src/main/resources/configForProperties.xml b/spring-boot-modules/spring-boot-properties/src/main/resources/configForProperties.xml index bf4452da4a..16db00ace3 100644 --- a/spring-boot-modules/spring-boot-properties/src/main/resources/configForProperties.xml +++ b/spring-boot-modules/spring-boot-properties/src/main/resources/configForProperties.xml @@ -14,8 +14,4 @@ - - - - \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-properties/src/main/resources/database.properties b/spring-boot-modules/spring-boot-properties/src/main/resources/database.properties index eb5703ca72..24bfdf2096 100644 --- a/spring-boot-modules/spring-boot-properties/src/main/resources/database.properties +++ b/spring-boot-modules/spring-boot-properties/src/main/resources/database.properties @@ -1,4 +1,3 @@ - jdbc.url=jdbc:postgresql:/localhost:5432 database.username=foo database.password=bar diff --git a/spring-boot-modules/spring-boot-properties/src/main/resources/database.yml b/spring-boot-modules/spring-boot-properties/src/main/resources/database.yml index 8404d9411a..83432f65bc 100644 --- a/spring-boot-modules/spring-boot-properties/src/main/resources/database.yml +++ b/spring-boot-modules/spring-boot-properties/src/main/resources/database.yml @@ -1,5 +1,6 @@ database: - url: jdbc:postresql:/localhost:5432/instance + jdbc: + url: jdbc:postresql:/localhost:5432 username: foo password: bar secret: foo \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-properties/src/main/resources/values.properties b/spring-boot-modules/spring-boot-properties/src/main/resources/values.properties deleted file mode 100644 index c6db5873fb..0000000000 --- a/spring-boot-modules/spring-boot-properties/src/main/resources/values.properties +++ /dev/null @@ -1,4 +0,0 @@ -value.from.file=Value got from the file -priority=Properties file -listOfValues=A,B,C -valuesMap={key1:'1', key2 : '2', key3 : '3'} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-properties/src/test/java/com/baeldung/configurationproperties/ConfigPropertiesIntegrationTest.java b/spring-boot-modules/spring-boot-properties/src/test/java/com/baeldung/configurationproperties/ConfigPropertiesIntegrationTest.java index 2b0833c387..3b80fa66fe 100644 --- a/spring-boot-modules/spring-boot-properties/src/test/java/com/baeldung/configurationproperties/ConfigPropertiesIntegrationTest.java +++ b/spring-boot-modules/spring-boot-properties/src/test/java/com/baeldung/configurationproperties/ConfigPropertiesIntegrationTest.java @@ -14,17 +14,13 @@ import com.baeldung.properties.AdditionalProperties; import com.baeldung.properties.ConfigPropertiesDemoApplication; @RunWith(SpringRunner.class) -@SpringBootTest(classes = {ConfigPropertiesDemoApplication.class, DatabaseConfigPropertiesApp.class}) -@TestPropertySource(locations = {"classpath:configprops-test.properties", "classpath:database-test.properties"}) +@SpringBootTest(classes = {ConfigPropertiesDemoApplication.class}) +@TestPropertySource(locations = {"classpath:configprops-test.properties"}) public class ConfigPropertiesIntegrationTest { @Autowired private ConfigProperties properties; - @Autowired - @Qualifier("dataSource") - private Database databaseProperties; - @Autowired private AdditionalProperties additionalProperties; @@ -59,10 +55,4 @@ public class ConfigPropertiesIntegrationTest { Assert.assertTrue(additionalProperties.getMax() == 100); } - @Test - public void whenDatabasePropertyQueriedthenReturnsProperty() { - Assert.assertTrue(databaseProperties.getUrl().equals("jdbc:postgresql:/localhost:5432")); - Assert.assertTrue(databaseProperties.getUsername().equals("foo")); - Assert.assertTrue(databaseProperties.getPassword().equals("bar")); - } } diff --git a/spring-boot-modules/spring-boot-properties/src/test/java/com/baeldung/configurationproperties/DatabasePropertiesIntegrationTest.java b/spring-boot-modules/spring-boot-properties/src/test/java/com/baeldung/configurationproperties/DatabasePropertiesIntegrationTest.java index 0b9bd797ae..50a129916f 100644 --- a/spring-boot-modules/spring-boot-properties/src/test/java/com/baeldung/configurationproperties/DatabasePropertiesIntegrationTest.java +++ b/spring-boot-modules/spring-boot-properties/src/test/java/com/baeldung/configurationproperties/DatabasePropertiesIntegrationTest.java @@ -4,26 +4,28 @@ import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit4.SpringRunner; import com.baeldung.properties.ConfigPropertiesDemoApplication; -import com.baeldung.properties.Database; +import com.baeldung.configurationproperties.Database; @RunWith(SpringRunner.class) -@SpringBootTest(classes = ConfigPropertiesDemoApplication.class) -@TestPropertySource("classpath:application.properties") +@SpringBootTest(classes = DatabaseConfigPropertiesApp.class) +@TestPropertySource("classpath:database-test.properties") public class DatabasePropertiesIntegrationTest { @Autowired + @Qualifier("dataSource") private Database database; @Test public void testDatabaseProperties() { Assert.assertNotNull(database); - Assert.assertEquals("jdbc:postgresql:/localhost:5432/instance", database.getUrl()); + Assert.assertEquals("jdbc:postgresql:/localhost:5432", database.getUrl()); Assert.assertEquals("foo", database.getUsername()); Assert.assertEquals("bar", database.getPassword()); } diff --git a/spring-boot-modules/spring-boot-properties/src/test/resources/application.properties b/spring-boot-modules/spring-boot-properties/src/test/resources/application.properties index d4d1df7abc..af38556f81 100644 --- a/spring-boot-modules/spring-boot-properties/src/test/resources/application.properties +++ b/spring-boot-modules/spring-boot-properties/src/test/resources/application.properties @@ -3,6 +3,3 @@ spring.properties.refreshDelay=1000 spring.config.location=file:extra.properties spring.main.allow-bean-definition-overriding=true -database.url=jdbc:postgresql:/localhost:5432/instance -database.username=foo -database.password=bar \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-springdoc/pom.xml b/spring-boot-modules/spring-boot-springdoc/pom.xml index 375cf06c2c..1c1f27b5a5 100644 --- a/spring-boot-modules/spring-boot-springdoc/pom.xml +++ b/spring-boot-modules/spring-boot-springdoc/pom.xml @@ -37,7 +37,7 @@ test - + org.hibernate hibernate-core ${hibernate.version} @@ -53,7 +53,19 @@ org.springdoc springdoc-openapi-data-rest ${springdoc.version} + + + + + org.springframework.restdocs + spring-restdocs-mockmvc + test + + org.springframework.restdocs + spring-restdocs-restassured + test + @@ -62,13 +74,49 @@ org.springframework.boot spring-boot-maven-plugin + + org.asciidoctor + asciidoctor-maven-plugin + ${asciidoctor-plugin.version} + + + generate-docs + package + + process-asciidoc + + + html + book + + ${snippetsDirectory} + + src/main/resources/asciidocs + target/generated-docs + + + + + + + true + src/main/resources + + application.properties + data.sql + schema.sql + + + 1.8 5.2.10.Final 1.2.32 + 1.5.6 + ${project.build.directory}/generated-snippets diff --git a/spring-boot-modules/spring-boot-springdoc/src/main/java/com/baeldung/restdocopenapi/Application.java b/spring-boot-modules/spring-boot-springdoc/src/main/java/com/baeldung/restdocopenapi/Application.java new file mode 100644 index 0000000000..93a28a2b49 --- /dev/null +++ b/spring-boot-modules/spring-boot-springdoc/src/main/java/com/baeldung/restdocopenapi/Application.java @@ -0,0 +1,28 @@ +package com.baeldung.restdocopenapi; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; + +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.info.License; + +@SpringBootApplication() +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + + @Bean + public OpenAPI customOpenAPI(@Value("${springdoc.version}") String appVersion) { + return new OpenAPI().info(new Info().title("Foobar API") + .version(appVersion) + .description("This is a sample Foobar server created using springdocs - a library for OpenAPI 3 with spring boot.") + .termsOfService("http://swagger.io/terms/") + .license(new License().name("Apache 2.0") + .url("http://springdoc.org"))); + } +} diff --git a/spring-boot-modules/spring-boot-springdoc/src/main/java/com/baeldung/restdocopenapi/Foo.java b/spring-boot-modules/spring-boot-springdoc/src/main/java/com/baeldung/restdocopenapi/Foo.java new file mode 100644 index 0000000000..99d63581be --- /dev/null +++ b/spring-boot-modules/spring-boot-springdoc/src/main/java/com/baeldung/restdocopenapi/Foo.java @@ -0,0 +1,93 @@ +package com.baeldung.restdocopenapi; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; + +@Entity +public class Foo { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable = false) + private String title; + + @Column() + private String body; + + + protected Foo() { + } + + public Foo(long id, String title, String body) { + this.id = id; + this.title = title; + this.body = body; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getBody() { + return body; + } + + public void setBody(String body) { + this.body = body; + } + + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result; + result = prime * result + ((id == null) ? 0 : id.hashCode()); + result = prime * result + ((title == null) ? 0 : title.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Foo other = (Foo) obj; + if (id == null) { + if (other.id != null) + return false; + } else if (!id.equals(other.id)) + return false; + if (title == null) { + if (other.title != null) + return false; + } else if (!title.equals(other.title)) + return false; + return true; + } + + @Override + public String toString() { + return "Foo [id=" + id + ", title=" + title + "]"; + } +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-springdoc/src/main/java/com/baeldung/restdocopenapi/FooController.java b/spring-boot-modules/spring-boot-springdoc/src/main/java/com/baeldung/restdocopenapi/FooController.java new file mode 100644 index 0000000000..55c2cccb3c --- /dev/null +++ b/spring-boot-modules/spring-boot-springdoc/src/main/java/com/baeldung/restdocopenapi/FooController.java @@ -0,0 +1,83 @@ +package com.baeldung.restdocopenapi; + +import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo; + +import java.util.List; +import java.util.Optional; + +import javax.validation.Valid; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/foo") +public class FooController { + + @Autowired + FooRepository repository; + + @GetMapping + public ResponseEntity> getAllFoos() { + List fooList = (List) repository.findAll(); + if (fooList.isEmpty()) { + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + return new ResponseEntity<>(fooList, HttpStatus.OK); + } + + @GetMapping(value = "{id}") + public ResponseEntity getFooById(@PathVariable("id") Long id) { + + Optional foo = repository.findById(id); + return foo.isPresent() ? new ResponseEntity<>(foo.get(), HttpStatus.OK) : new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + + @PostMapping + public ResponseEntity addFoo(@RequestBody @Valid Foo foo) { + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.setLocation(linkTo(FooController.class).slash(foo.getId()) + .toUri()); + Foo savedFoo; + try { + savedFoo = repository.save(foo); + } catch (Exception e) { + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + + return new ResponseEntity<>(savedFoo, httpHeaders, HttpStatus.CREATED); + } + + @DeleteMapping("/{id}") + public ResponseEntity deleteFoo(@PathVariable("id") long id) { + try { + repository.deleteById(id); + } catch (Exception e) { + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @PutMapping("/{id}") + public ResponseEntity updateFoo(@PathVariable("id") long id, @RequestBody Foo foo) { + boolean isFooPresent = repository.existsById(Long.valueOf(id)); + + if (!isFooPresent) { + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + + Foo updatedFoo = repository.save(foo); + + return new ResponseEntity<>(updatedFoo, HttpStatus.OK); + } +} diff --git a/spring-boot-modules/spring-boot-springdoc/src/main/java/com/baeldung/restdocopenapi/FooRepository.java b/spring-boot-modules/spring-boot-springdoc/src/main/java/com/baeldung/restdocopenapi/FooRepository.java new file mode 100644 index 0000000000..105b57b2ef --- /dev/null +++ b/spring-boot-modules/spring-boot-springdoc/src/main/java/com/baeldung/restdocopenapi/FooRepository.java @@ -0,0 +1,9 @@ +package com.baeldung.restdocopenapi; + +import org.springframework.data.repository.PagingAndSortingRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface FooRepository extends PagingAndSortingRepository{ + +} diff --git a/spring-boot-modules/spring-boot-springdoc/src/main/java/com/baeldung/restdocopenapi/springdoc/FooBarController.java b/spring-boot-modules/spring-boot-springdoc/src/main/java/com/baeldung/restdocopenapi/springdoc/FooBarController.java new file mode 100644 index 0000000000..8af414c8fd --- /dev/null +++ b/spring-boot-modules/spring-boot-springdoc/src/main/java/com/baeldung/restdocopenapi/springdoc/FooBarController.java @@ -0,0 +1,121 @@ +package com.baeldung.restdocopenapi.springdoc; + +import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo; + +import java.util.List; +import java.util.Optional; + +import javax.validation.Valid; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.baeldung.restdocopenapi.Foo; +import com.baeldung.restdocopenapi.FooRepository; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; + +@RestController +@RequestMapping("/foobar") +@Tag(name = "foobar", description = "the foobar API with documentation annotations") +public class FooBarController { + + @Autowired + FooRepository repository; + + @Operation(summary = "Get all foos") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "found foos", content = { + @Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = Foo.class)))}), + @ApiResponse(responseCode = "404", description = "No Foos found", content = @Content) }) + @GetMapping + public ResponseEntity> getAllFoos() { + List fooList = (List) repository.findAll(); + if (fooList.isEmpty()) { + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + return new ResponseEntity<>(fooList, HttpStatus.OK); + } + + @Operation(summary = "Get a foo by foo id") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "found the foo", content = { + @Content(mediaType = "application/json", schema = @Schema(implementation = Foo.class))}), + @ApiResponse(responseCode = "400", description = "Invalid id supplied", content = @Content), + @ApiResponse(responseCode = "404", description = "Foo not found", content = @Content) }) + @GetMapping(value = "{id}") + public ResponseEntity getFooById(@Parameter(description = "id of foo to be searched") @PathVariable("id") String id) { + + Optional foo = repository.findById(Long.valueOf(id)); + return foo.isPresent() ? new ResponseEntity<>(foo.get(), HttpStatus.OK) : new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + + @Operation(summary = "Create a foo") + @ApiResponses(value = { + @ApiResponse(responseCode = "201", description = "foo created", content = { @ + Content(mediaType = "application/json", schema = @Schema(implementation = Foo.class))}), + @ApiResponse(responseCode = "404", description = "Bad request", content = @Content) }) + @PostMapping + public ResponseEntity addFoo(@Parameter(description = "foo object to be created") @RequestBody @Valid Foo foo) { + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.setLocation(linkTo(FooBarController.class).slash(foo.getId()).toUri()); + Foo savedFoo; + try { + savedFoo = repository.save(foo); + } catch (Exception e) { + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + + return new ResponseEntity<>(savedFoo, httpHeaders, HttpStatus.CREATED); + } + + @Operation(summary = "Delete a foo") + @ApiResponses(value = { + @ApiResponse(responseCode = "204", description = "foo deleted"), + @ApiResponse(responseCode = "404", description = "Bad request", content = @Content) }) + @DeleteMapping("/{id}") + public ResponseEntity deleteFoo(@Parameter(description = "id of foo to be deleted") @PathVariable("id") long id) { + try { + repository.deleteById(id); + } catch (Exception e) { + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Operation(summary = "Update a foo") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "foo updated successfully", content = { + @Content(mediaType = "application/json", schema = @Schema(implementation = Foo.class))}), + @ApiResponse(responseCode = "404", description = "No Foo exists with given id", content = @Content) }) + @PutMapping("/{id}") + public ResponseEntity updateFoo(@Parameter(description = "id of foo to be updated") @PathVariable("id") long id, @RequestBody Foo foo) { + + boolean isFooPresent = repository.existsById(Long.valueOf(id)); + + if (!isFooPresent) { + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + + Foo updatedFoo = repository.save(foo); + + return new ResponseEntity<>(updatedFoo, HttpStatus.OK); + } +} diff --git a/spring-boot-modules/spring-boot-springdoc/src/main/resources/application.properties b/spring-boot-modules/spring-boot-springdoc/src/main/resources/application.properties index 45378e610b..7debdc6503 100644 --- a/spring-boot-modules/spring-boot-springdoc/src/main/resources/application.properties +++ b/spring-boot-modules/spring-boot-springdoc/src/main/resources/application.properties @@ -5,4 +5,9 @@ springdoc.swagger-ui.path=/swagger-ui-custom.html springdoc.api-docs.path=/api-docs # H2 Related Configurations -spring.datasource.url=jdbc:h2:mem:springdoc \ No newline at end of file +spring.datasource.url=jdbc:h2:mem:springdoc + +## for com.baeldung.restdocopenapi ## +springdoc.version=@springdoc.version@ +spring.jpa.hibernate.ddl-auto=none +###################################### \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-springdoc/src/main/resources/asciidocs/fooapi.adoc b/spring-boot-modules/spring-boot-springdoc/src/main/resources/asciidocs/fooapi.adoc new file mode 100644 index 0000000000..90791cbbcf --- /dev/null +++ b/spring-boot-modules/spring-boot-springdoc/src/main/resources/asciidocs/fooapi.adoc @@ -0,0 +1,153 @@ += RESTful Notes API Guide +Baeldung; +:doctype: book +:icons: font +:source-highlighter: highlightjs +:toc: left +:toclevels: 4 +:sectlinks: + +[[overview]] += Overview + +[[overview-http-verbs]] +== HTTP verbs + +RESTful notes tries to adhere as closely as possible to standard HTTP and REST conventions in its +use of HTTP verbs. + +|=== +| Verb | Usage + +| `GET` +| Used to retrieve a resource + +| `POST` +| Used to create a new resource + +| `PUT` +| Used to update an existing resource + +| `DELETE` +| Used to delete an existing resource +|=== + +RESTful notes tries to adhere as closely as possible to standard HTTP and REST conventions in its +use of HTTP status codes. + +|=== +| Status code | Usage + +| `200 OK` +| The request completed successfully + +| `201 Created` +| A new resource has been created successfully. The resource's URI is available from the response's +`Location` header + +| `204 No Content` +| An update to an existing resource has been applied successfully + +| `400 Bad Request` +| The request was malformed. The response body will include an error providing further information + +| `404 Not Found` +| The requested resource did not exist +|=== + +[[overview-hypermedia]] +== Hypermedia + +RESTful Notes uses hypermedia and resources include links to other resources in their +responses. Responses are in http://stateless.co/hal_specification.html[Hypertext Application +from resource to resource. +Language (HAL)] format. Links can be found beneath the `_links` key. Users of the API should +not create URIs themselves, instead they should use the above-described links to navigate + +[[resources]] += Resources + +[[resources-FOO]] +== FOO REST Service + +The FOO provides the entry point into the service. + +[[resources-foo-get]] +=== Accessing the foo GET + +A `GET` request is used to access the foo read. + +==== Request structure + +include::{snippets}/getAFoo/http-request.adoc[] + +==== Path Parameters +include::{snippets}/getAFoo/path-parameters.adoc[] + +==== Example response + +include::{snippets}/getAFoo/http-response.adoc[] + +==== CURL request + +include::{snippets}/getAFoo/curl-request.adoc[] + +[[resources-foo-post]] +=== Accessing the foo POST + +A `POST` request is used to access the foo create. + +==== Request structure + +include::{snippets}/createFoo/http-request.adoc[] + +==== Example response + +include::{snippets}/createFoo/http-response.adoc[] + +==== CURL request + +include::{snippets}/createFoo/curl-request.adoc[] + +[[resources-foo-delete]] +=== Accessing the foo DELETE + +A `DELETE` request is used to access the foo delete. + +==== Request structure + +include::{snippets}/deleteFoo/http-request.adoc[] + +==== Path Parameters +include::{snippets}/deleteFoo/path-parameters.adoc[] + +==== Example response + +include::{snippets}/deleteFoo/http-response.adoc[] + +==== CURL request + +include::{snippets}/deleteFoo/curl-request.adoc[] + +[[resources-foo-put]] +=== Accessing the foo PUT + +A `PUT` request is used to access the foo update. + +==== Request structure + +include::{snippets}/updateFoo/http-request.adoc[] + +==== Path Parameters +include::{snippets}/updateFoo/path-parameters.adoc[] + +==== Example response + +include::{snippets}/updateFoo/http-response.adoc[] + +==== CURL request + +include::{snippets}/updateFoo/curl-request.adoc[] + + + diff --git a/spring-boot-modules/spring-boot-springdoc/src/main/resources/data.sql b/spring-boot-modules/spring-boot-springdoc/src/main/resources/data.sql new file mode 100644 index 0000000000..f80e53b717 --- /dev/null +++ b/spring-boot-modules/spring-boot-springdoc/src/main/resources/data.sql @@ -0,0 +1,4 @@ +INSERT INTO Foo(id, title, body) VALUES (1, 'Foo 1', 'Foo body 1'); +INSERT INTO Foo(id, title, body) VALUES (2, 'Foo 2', 'Foo body 2'); +INSERT INTO Foo(id, title, body) VALUES (3, 'Foo 3', 'Foo body 3'); + diff --git a/spring-boot-modules/spring-boot-springdoc/src/main/resources/schema.sql b/spring-boot-modules/spring-boot-springdoc/src/main/resources/schema.sql new file mode 100644 index 0000000000..e5d33da019 --- /dev/null +++ b/spring-boot-modules/spring-boot-springdoc/src/main/resources/schema.sql @@ -0,0 +1,8 @@ +DROP TABLE IF EXISTS foo; + +CREATE TABLE foo ( + id INTEGER NOT NULL AUTO_INCREMENT, + title VARCHAR(250) NOT NULL, + body VARCHAR(250), + PRIMARY KEY (id) +); \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-springdoc/src/test/java/com/baeldung/restdocopenapi/restdoc/SpringRestDocsUnitTest.java b/spring-boot-modules/spring-boot-springdoc/src/test/java/com/baeldung/restdocopenapi/restdoc/SpringRestDocsUnitTest.java new file mode 100644 index 0000000000..4d37abf78a --- /dev/null +++ b/spring-boot-modules/spring-boot-springdoc/src/test/java/com/baeldung/restdocopenapi/restdoc/SpringRestDocsUnitTest.java @@ -0,0 +1,120 @@ +package com.baeldung.restdocopenapi.restdoc; + +import static org.hamcrest.Matchers.containsString; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.util.StringUtils.collectionToDelimitedString; + +import java.util.HashMap; +import java.util.Map; + +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.hateoas.MediaTypes; +import org.springframework.restdocs.RestDocumentationContextProvider; +import org.springframework.restdocs.RestDocumentationExtension; +import org.springframework.restdocs.constraints.ConstraintDescriptions; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +import com.baeldung.restdocopenapi.Application; +import com.baeldung.restdocopenapi.Foo; +import com.fasterxml.jackson.databind.ObjectMapper; + +@ExtendWith({ RestDocumentationExtension.class, SpringExtension.class }) +@SpringBootTest(classes = Application.class) +public class SpringRestDocsUnitTest { + + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @BeforeEach + public void setup(WebApplicationContext webApplicationContext, RestDocumentationContextProvider restDocumentation) { + this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext) + .apply(documentationConfiguration(restDocumentation)) + .build(); + } + + @Test + public void whenGetFoo_thenSuccessful() throws Exception { + this.mockMvc.perform(get("/foo")) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(content().string(containsString("Foo 1"))) + .andDo(document("getAllFoos")); + } + + @Test + public void whenGetFooById_thenSuccessful() throws Exception { + ConstraintDescriptions desc = new ConstraintDescriptions(Foo.class); + + this.mockMvc.perform(get("/foo/{id}", 1)) + .andExpect(status().isOk()) + .andDo(document("getAFoo", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), + pathParameters(parameterWithName("id").description("id of foo to be searched")), + responseFields(fieldWithPath("id").description("The id of the foo" + collectionToDelimitedString(desc.descriptionsForProperty("id"), ". ")), + fieldWithPath("title").description("The title of the foo"), fieldWithPath("body").description("The body of the foo")))); + } + + @Test + public void whenPostFoo_thenSuccessful() throws Exception { + Map foo = new HashMap<>(); + foo.put("id", 4L); + foo.put("title", "New Foo"); + foo.put("body", "Body of New Foo"); + + this.mockMvc.perform(post("/foo").contentType(MediaTypes.HAL_JSON) + .content(this.objectMapper.writeValueAsString(foo))) + .andExpect(status().isCreated()) + .andDo(document("createFoo", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), requestFields(fieldWithPath("id").description("The id of the foo"), fieldWithPath("title").description("The title of the foo"), + fieldWithPath("body").description("The body of the foo")))); + } + + @Test + public void whenDeleteFoo_thenSuccessful() throws Exception { + this.mockMvc.perform(delete("/foo/{id}", 2)) + .andExpect(status().isNoContent()) + .andDo(document("deleteFoo", pathParameters(parameterWithName("id").description("The id of the foo to delete")))); + } + + @Test + public void whenUpdateFoo_thenSuccessful() throws Exception { + + ConstraintDescriptions desc = new ConstraintDescriptions(Foo.class); + + Map foo = new HashMap<>(); + foo.put("title", "Updated Foo"); + foo.put("body", "Body of Updated Foo"); + + this.mockMvc.perform(put("/foo/{id}", 3).contentType(MediaTypes.HAL_JSON) + .content(this.objectMapper.writeValueAsString(foo))) + .andExpect(status().isOk()) + .andDo(document("updateFoo", pathParameters(parameterWithName("id").description("The id of the foo to update")), + responseFields(fieldWithPath("id").description("The id of the updated foo" + collectionToDelimitedString(desc.descriptionsForProperty("id"), ". ")), + fieldWithPath("title").description("The title of the updated foo"), fieldWithPath("body").description("The body of the updated foo")))); + } + + +} diff --git a/spring-caching/README.md b/spring-caching/README.md index 3efbfe3eaa..52ddc4f3eb 100644 --- a/spring-caching/README.md +++ b/spring-caching/README.md @@ -3,3 +3,4 @@ - [A Guide To Caching in Spring](http://www.baeldung.com/spring-cache-tutorial) - [Spring Cache – Creating a Custom KeyGenerator](http://www.baeldung.com/spring-cache-custom-keygenerator) - [Cache Eviction in Spring Boot](https://www.baeldung.com/spring-boot-evict-cache) +- [Using Multiple Cache Managers in Spring](https://www.baeldung.com/spring-multiple-cache-managers) diff --git a/spring-cloud/spring-cloud-gateway/README.md b/spring-cloud/spring-cloud-gateway/README.md index 9c8e0d443a..90e81fe9a2 100644 --- a/spring-cloud/spring-cloud-gateway/README.md +++ b/spring-cloud/spring-cloud-gateway/README.md @@ -6,3 +6,4 @@ This module contains articles about Spring Cloud Gateway - [Exploring the new Spring Cloud Gateway](http://www.baeldung.com/spring-cloud-gateway) - [Writing Custom Spring Cloud Gateway Filters](https://www.baeldung.com/spring-cloud-custom-gateway-filters) - [Spring Cloud Gateway Routing Predicate Factories](https://www.baeldung.com/spring-cloud-gateway-routing-predicate-factories) +- [Spring Cloud Gateway WebFilter Factories](https://www.baeldung.com/spring-cloud-gateway-webfilter-factories) diff --git a/spring-core-4/README.md b/spring-core-4/README.md index f882c77179..592f4cd011 100644 --- a/spring-core-4/README.md +++ b/spring-core-4/README.md @@ -4,4 +4,6 @@ This module contains articles about core Spring functionality ## Relevant Articles: +- [Creating Spring Beans Through Factory Methods](https://www.baeldung.com/spring-beans-factory-methods) +- [How to dynamically Autowire a Bean in Spring](https://www.baeldung.com/spring-dynamic-autowire) - More articles: [[<-- prev]](/spring-core-3) diff --git a/spring-kafka/pom.xml b/spring-kafka/pom.xml index d60a2ee506..2b4a0914e6 100644 --- a/spring-kafka/pom.xml +++ b/spring-kafka/pom.xml @@ -33,7 +33,7 @@ - 2.2.7.RELEASE + 2.3.7.RELEASE \ No newline at end of file diff --git a/spring-security-modules/spring-security-mvc-boot-2/README.md b/spring-security-modules/spring-security-mvc-boot-2/README.md index 3c95086d21..7c53d03698 100644 --- a/spring-security-modules/spring-security-mvc-boot-2/README.md +++ b/spring-security-modules/spring-security-mvc-boot-2/README.md @@ -10,4 +10,5 @@ The "REST With Spring" Classes: http://github.learnspringsecurity.com - [Multiple Authentication Providers in Spring Security](https://www.baeldung.com/spring-security-multiple-auth-providers) - [Two Login Pages with Spring Security](https://www.baeldung.com/spring-security-two-login-pages) - [HTTPS using Self-Signed Certificate in Spring Boot](https://www.baeldung.com/spring-boot-https-self-signed-certificate) -- [Spring Security: Exploring JDBC Authentication](https://www.baeldung.com/spring-security-jdbc-authentication) \ No newline at end of file +- [Spring Security: Exploring JDBC Authentication](https://www.baeldung.com/spring-security-jdbc-authentication) +- [Spring Security Custom Logout Handler](https://www.baeldung.com/spring-security-custom-logout-handler) diff --git a/spring-security-modules/spring-security-okta/README.md b/spring-security-modules/spring-security-okta/README.md new file mode 100644 index 0000000000..6ea4817e19 --- /dev/null +++ b/spring-security-modules/spring-security-okta/README.md @@ -0,0 +1,3 @@ +### Relevant Articles: + +- [Spring Security With Okta](https://www.baeldung.com/spring-security-okta) diff --git a/spring-soap/README.md b/spring-soap/README.md index c23f0bc6f0..ca5f58c67e 100644 --- a/spring-soap/README.md +++ b/spring-soap/README.md @@ -5,3 +5,4 @@ This module contains articles about SOAP APIs with Spring ### Relevant articles: - [Creating a SOAP Web Service with Spring](https://www.baeldung.com/spring-boot-soap-web-service) +- [Invoking a SOAP Web Service in Spring](https://www.baeldung.com/spring-soap-web-service) diff --git a/spring-thymeleaf-3/src/main/java/com/baeldung/thymeleaf/currencies/CurrenciesController.java b/spring-thymeleaf-3/src/main/java/com/baeldung/thymeleaf/currencies/CurrenciesController.java new file mode 100644 index 0000000000..206cf32683 --- /dev/null +++ b/spring-thymeleaf-3/src/main/java/com/baeldung/thymeleaf/currencies/CurrenciesController.java @@ -0,0 +1,22 @@ +package com.baeldung.thymeleaf.currencies; + +import java.util.List; +import java.util.Locale; +import java.util.Set; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; + +@Controller +public class CurrenciesController { + + @GetMapping(value = "/currency") + public String exchange( + @RequestParam(value = "amount", required = false) String amount, + @RequestParam(value = "amountList", required = false) List amountList, + Locale locale) { + + return "currencies/currencies"; + } +} diff --git a/spring-thymeleaf-3/src/main/resources/templates/currencies/currencies.html b/spring-thymeleaf-3/src/main/resources/templates/currencies/currencies.html new file mode 100644 index 0000000000..c2f44265dd --- /dev/null +++ b/spring-thymeleaf-3/src/main/resources/templates/currencies/currencies.html @@ -0,0 +1,21 @@ + + + + + Currency table + + +

Currency format by Locale

+

+ +

Currency Arrays format by Locale

+

+ +

Remove decimal values

+

+ +

Replace decimal points

+

+ + \ No newline at end of file diff --git a/spring-thymeleaf-3/src/test/java/com/baeldung/thymeleaf/currencies/CurrenciesControllerIntegrationTest.java b/spring-thymeleaf-3/src/test/java/com/baeldung/thymeleaf/currencies/CurrenciesControllerIntegrationTest.java new file mode 100644 index 0000000000..02bf8a9ee0 --- /dev/null +++ b/spring-thymeleaf-3/src/test/java/com/baeldung/thymeleaf/currencies/CurrenciesControllerIntegrationTest.java @@ -0,0 +1,68 @@ +package com.baeldung.thymeleaf.currencies; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; + +@RunWith(SpringRunner.class) +@SpringBootTest +@AutoConfigureMockMvc(printOnlyOnFailure = false) +public class CurrenciesControllerIntegrationTest { + + @Autowired + private MockMvc mockMvc; + + @Test + public void whenCallCurrencyWithSpanishLocale_ThenReturnProperCurrency() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/currency") + .header("Accept-Language", "es-ES") + .param("amount", "10032.5")) + .andExpect(status().isOk()) + .andExpect(content().string(containsString("10.032,50 €"))); + } + + @Test + public void whenCallCurrencyWithUSALocale_ThenReturnProperCurrency() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/currency") + .header("Accept-Language", "en-US") + .param("amount", "10032.5")) + .andExpect(status().isOk()) + .andExpect(content().string(containsString("$10,032.50"))); + } + + @Test + public void whenCallCurrencyWithRomanianLocaleWithArrays_ThenReturnLocaleCurrencies() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/currency") + .header("Accept-Language", "ro-RO") + .param("amountList", "10", "20", "30")) + .andExpect(status().isOk()) + .andExpect(content().string(containsString("10,00 RON, 20,00 RON, 30,00 RON"))); + } + + @Test + public void whenCallCurrencyWithUSALocaleWithoutDecimal_ThenReturnCurrencyWithoutTrailingZeros() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/currency") + .header("Accept-Language", "en-US") + .param("amount", "10032")) + .andExpect(status().isOk()) + .andExpect(content().string(containsString("$10,032"))); + } + + @Test + public void whenCallCurrencyWithUSALocale_ThenReturnReplacedDecimalPoint() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/currency") + .header("Accept-Language", "en-US") + .param("amount", "1.5")) + .andExpect(status().isOk()) + .andExpect(content().string(containsString("1,5"))); + } +} diff --git a/terraform/README.md b/terraform/README.md index 19abd2ff20..b2a9539727 100644 --- a/terraform/README.md +++ b/terraform/README.md @@ -1,3 +1,4 @@ ### Relevant Articles: - [Introduction to Terraform](https://www.baeldung.com/ops/terraform-intro) +- [Best Practices When Using Terraform](https://www.baeldung.com/ops/terraform-best-practices) diff --git a/testing-modules/assertion-libraries/README.md b/testing-modules/assertion-libraries/README.md index d69457fdeb..ca4cc86f7e 100644 --- a/testing-modules/assertion-libraries/README.md +++ b/testing-modules/assertion-libraries/README.md @@ -10,4 +10,4 @@ - [Custom Assertions with AssertJ](http://www.baeldung.com/assertj-custom-assertion) - [Using Conditions with AssertJ Assertions](http://www.baeldung.com/assertj-conditions) - [AssertJ Exception Assertions](http://www.baeldung.com/assertj-exception-assertion) - +- [Asserting Log Messages With JUnit](https://www.baeldung.com/junit-asserting-logs) diff --git a/testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/clickusingjavascript/SeleniumJavaScriptClickTest.java b/testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/clickusingjavascript/SeleniumJavaScriptClickTest.java new file mode 100644 index 0000000000..6d2ab8ef1f --- /dev/null +++ b/testing-modules/selenium-junit-testng/src/test/java/com/baeldung/selenium/clickusingjavascript/SeleniumJavaScriptClickTest.java @@ -0,0 +1,61 @@ +package java.com.baeldung.selenium.clickusingjavascript; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.JavascriptExecutor; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.chrome.ChromeDriver; +import org.openqa.selenium.support.ui.ExpectedConditions; +import org.openqa.selenium.support.ui.WebDriverWait; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class SeleniumJavaScriptClickTest { + + private WebDriver driver; + private WebDriverWait wait; + + @Before + public void setUp() { + System.setProperty("webdriver.chrome.driver", "chromedriver.exe"); + driver = new ChromeDriver(); + wait = new WebDriverWait(driver, 5000); + } + + @After + public void cleanUp() { + driver.close(); + } + + @Test + public void whenSearchForSeleniumArticles_thenReturnNotEmptyResults() { + driver.get("https://baeldung.com"); + String title = driver.getTitle(); + assertEquals("Baeldung | Java, Spring and Web Development tutorials", title); + + wait.until(ExpectedConditions.elementToBeClickable(By.className("menu-search"))); + WebElement searchButton = driver.findElement(By.className("menu-search")); + clickElement(searchButton); + + wait.until(ExpectedConditions.elementToBeClickable(By.id("search"))); + WebElement searchInput = driver.findElement(By.id("search")); + searchInput.sendKeys("Selenium"); + + wait.until(ExpectedConditions.elementToBeClickable(By.className("btn-search"))); + WebElement seeSearchResultsButton = driver.findElement(By.className("btn-search")); + clickElement(seeSearchResultsButton); + + int seleniumPostsCount = driver.findElements(By.className("post")).size(); + assertTrue(seleniumPostsCount > 0); + } + + private void clickElement(WebElement element) { + JavascriptExecutor executor = (JavascriptExecutor) driver; + executor.executeScript("arguments[0].click();", element); + } + +}