diff --git a/core-java-modules/core-java-17/README.md b/core-java-modules/core-java-17/README.md index d77a487932..9f39b0289f 100644 --- a/core-java-modules/core-java-17/README.md +++ b/core-java-modules/core-java-17/README.md @@ -5,4 +5,4 @@ - [Introduction to HexFormat in Java 17](https://www.baeldung.com/java-hexformat) - [New Features in Java 17](https://www.baeldung.com/java-17-new-features) - [Random Number Generators in Java 17](https://www.baeldung.com/java-17-random-number-generators) -- [Sealed Classes and Interfaces in Java 17](https://www.baeldung.com/java-sealed-classes-interfaces) +- [Sealed Classes and Interfaces in Java](https://www.baeldung.com/java-sealed-classes-interfaces) diff --git a/core-java-modules/core-java-collections-list-4/src/test/java/com/baeldung/list/aslistvssingletonlist/ArraysAsListVsSingletonListUnitTest.java b/core-java-modules/core-java-collections-list-4/src/test/java/com/baeldung/list/aslistvssingletonlist/ArraysAsListVsSingletonListUnitTest.java new file mode 100644 index 0000000000..b12693ab14 --- /dev/null +++ b/core-java-modules/core-java-collections-list-4/src/test/java/com/baeldung/list/aslistvssingletonlist/ArraysAsListVsSingletonListUnitTest.java @@ -0,0 +1,48 @@ +package com.baeldung.list.aslistvssingletonlist; + +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType; + +class ArraysAsListVsSingletonListUnitTest { + + @Test + void givenListFromArraysAsList_whenChangingStructureAndElement_thenGetExpectedResult() { + List arraysAsList = Arrays.asList("ONE"); + assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy( + () -> arraysAsList.add("TWO") + ); + + arraysAsList.set(0, "A brand new string"); + assertThat(arraysAsList.get(0)).isEqualTo("A brand new string"); + } + + @Test + void givenSingletonList_whenChangingStructureAndElement_thenThrowException() { + List singletonList = Collections.singletonList("ONE"); + assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy( + () -> singletonList.add("TWO") + ); + assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy( + () -> singletonList.set(0, "A brand new string") + ); + } + + @Test + void givenAnArray_whengetListByArraysAsList_thenTheListIsBackedByTheArray() { + String[] theArray = new String[] { "ONE", "TWO" }; + List theList = Arrays.asList(theArray); + //changing the list, the array is changed too + theList.set(0, "ONE [changed in list]"); + assertThat(theArray[0]).isEqualTo("ONE [changed in list]"); + + //changing the array, the list is changed too + theArray[1] = "TWO [changed in array]"; + assertThat(theList.get(1)).isEqualTo("TWO [changed in array]"); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-collections-list-4/src/test/java/com/baeldung/list/replace/ReplaceUsingIndexInArrayListUnitTest.java b/core-java-modules/core-java-collections-list-4/src/test/java/com/baeldung/list/replace/ReplaceUsingIndexInArrayListUnitTest.java new file mode 100644 index 0000000000..ad6d0fee43 --- /dev/null +++ b/core-java-modules/core-java-collections-list-4/src/test/java/com/baeldung/list/replace/ReplaceUsingIndexInArrayListUnitTest.java @@ -0,0 +1,21 @@ +package com.baeldung.list.replace; + +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class ReplaceUsingIndexInArrayListUnitTest { + + private static final List EXPECTED = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5)); + + @Test void givenArrayList_updateUsingSet() { + List aList = new ArrayList<>(Arrays.asList(1, 2, 7, 4, 5)); + aList.set(2, 3); + assertThat(aList).isEqualTo(EXPECTED); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-concurrency-advanced-2/README.md b/core-java-modules/core-java-concurrency-advanced-2/README.md index 0e3d25689f..ca3ab715ea 100644 --- a/core-java-modules/core-java-concurrency-advanced-2/README.md +++ b/core-java-modules/core-java-concurrency-advanced-2/README.md @@ -11,7 +11,6 @@ This module contains articles about advanced topics about multithreading with co - [Java CyclicBarrier vs CountDownLatch](https://www.baeldung.com/java-cyclicbarrier-countdownlatch) - [Guide to the Fork/Join Framework in Java](https://www.baeldung.com/java-fork-join) - [Guide to ThreadLocalRandom in Java](https://www.baeldung.com/java-thread-local-random) -- [The Thread.join() Method in Java](https://www.baeldung.com/java-thread-join) - [Passing Parameters to Java Threads](https://www.baeldung.com/java-thread-parameters) [[<-- previous]](/core-java-modules/core-java-concurrency-advanced)[[next -->]](/core-java-modules/core-java-concurrency-advanced-3) diff --git a/core-java-modules/core-java-concurrency-advanced-4/src/main/java/com/baeldung/atomicvsvolatile/SafeAtomicCounter.java b/core-java-modules/core-java-concurrency-advanced-4/src/main/java/com/baeldung/atomicvsvolatile/SafeAtomicCounter.java new file mode 100644 index 0000000000..196662e3ea --- /dev/null +++ b/core-java-modules/core-java-concurrency-advanced-4/src/main/java/com/baeldung/atomicvsvolatile/SafeAtomicCounter.java @@ -0,0 +1,16 @@ +package com.baeldung.atomicvsvolatile; + +import java.util.concurrent.atomic.AtomicInteger; + +public class SafeAtomicCounter { + + private final AtomicInteger counter = new AtomicInteger(0); + + public int getValue() { + return counter.get(); + } + + public void increment() { + counter.incrementAndGet(); + } +} diff --git a/core-java-modules/core-java-concurrency-advanced-4/src/main/java/com/baeldung/atomicvsvolatile/UnsafeCounter.java b/core-java-modules/core-java-concurrency-advanced-4/src/main/java/com/baeldung/atomicvsvolatile/UnsafeCounter.java new file mode 100644 index 0000000000..48094672e1 --- /dev/null +++ b/core-java-modules/core-java-concurrency-advanced-4/src/main/java/com/baeldung/atomicvsvolatile/UnsafeCounter.java @@ -0,0 +1,14 @@ +package com.baeldung.atomicvsvolatile; + +public class UnsafeCounter { + + private int counter; + + public int getValue() { + return counter; + } + + public void increment() { + counter++; + } +} diff --git a/core-java-modules/core-java-concurrency-advanced-4/src/main/java/com/baeldung/atomicvsvolatile/UnsafeVolatileCounter.java b/core-java-modules/core-java-concurrency-advanced-4/src/main/java/com/baeldung/atomicvsvolatile/UnsafeVolatileCounter.java new file mode 100644 index 0000000000..6d06d5b12a --- /dev/null +++ b/core-java-modules/core-java-concurrency-advanced-4/src/main/java/com/baeldung/atomicvsvolatile/UnsafeVolatileCounter.java @@ -0,0 +1,14 @@ +package com.baeldung.atomicvsvolatile; + +public class UnsafeVolatileCounter { + + private volatile int counter; + + public int getValue() { + return counter; + } + + public void increment() { + counter++; + } +} diff --git a/core-java-modules/core-java-concurrency-advanced-4/src/test/java/com/baeldung/atomicvsvolatile/SafeAtomicCounterUnitTest.java b/core-java-modules/core-java-concurrency-advanced-4/src/test/java/com/baeldung/atomicvsvolatile/SafeAtomicCounterUnitTest.java new file mode 100644 index 0000000000..4eb65db716 --- /dev/null +++ b/core-java-modules/core-java-concurrency-advanced-4/src/test/java/com/baeldung/atomicvsvolatile/SafeAtomicCounterUnitTest.java @@ -0,0 +1,25 @@ +package com.baeldung.atomicvsvolatile; + +import static org.junit.Assert.assertEquals; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.stream.IntStream; +import org.junit.Test; + +public class SafeAtomicCounterUnitTest { + + private static final int INCREMENT_COUNTER = 1000; + private static final int TIMEOUT = 100; + private static final int POOL_SIZE = 3; + + @Test + public void givenMultiThread_whenSafeAtomicCounterIncrement() throws InterruptedException { + ExecutorService service = Executors.newFixedThreadPool(POOL_SIZE); + SafeAtomicCounter safeCounter = new SafeAtomicCounter(); + IntStream.range(0, INCREMENT_COUNTER).forEach(count -> service.submit(safeCounter::increment)); + service.awaitTermination(TIMEOUT, TimeUnit.MILLISECONDS); + assertEquals(INCREMENT_COUNTER, safeCounter.getValue()); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-concurrency-advanced/README.md b/core-java-modules/core-java-concurrency-advanced/README.md index 0da59c88fb..947ed15e9e 100644 --- a/core-java-modules/core-java-concurrency-advanced/README.md +++ b/core-java-modules/core-java-concurrency-advanced/README.md @@ -12,5 +12,4 @@ This module contains articles about advanced topics about multithreading with co - [Guide to the Java Phaser](https://www.baeldung.com/java-phaser) - [An Introduction to Atomic Variables in Java](https://www.baeldung.com/java-atomic-variables) - [CyclicBarrier in Java](https://www.baeldung.com/java-cyclic-barrier) -- [Guide to the Volatile Keyword in Java](https://www.baeldung.com/java-volatile) - More Articles: [[next -->]](/core-java-modules/core-java-concurrency-advanced-2) diff --git a/core-java-modules/core-java-concurrency-basic-2/README.md b/core-java-modules/core-java-concurrency-basic-2/README.md index af46046709..c9f1c11a89 100644 --- a/core-java-modules/core-java-concurrency-basic-2/README.md +++ b/core-java-modules/core-java-concurrency-basic-2/README.md @@ -5,10 +5,7 @@ This module contains articles about basic Java concurrency ### Relevant Articles: - [How to Delay Code Execution in Java](https://www.baeldung.com/java-delay-code-execution) -- [wait and notify() Methods in Java](https://www.baeldung.com/java-wait-notify) - [Difference Between Wait and Sleep in Java](https://www.baeldung.com/java-wait-and-sleep) -- [Guide to the Synchronized Keyword in Java](https://www.baeldung.com/java-synchronized) -- [Life Cycle of a Thread in Java](https://www.baeldung.com/java-thread-lifecycle) - [Guide to AtomicMarkableReference](https://www.baeldung.com/java-atomicmarkablereference) - [Why are Local Variables Thread-Safe in Java](https://www.baeldung.com/java-local-variables-thread-safe) - [How to Stop Execution After a Certain Time in Java](https://www.baeldung.com/java-stop-execution-after-certain-time) diff --git a/core-java-modules/core-java-concurrency-basic/README.md b/core-java-modules/core-java-concurrency-basic/README.md index 846687b8dd..f1aa748c6b 100644 --- a/core-java-modules/core-java-concurrency-basic/README.md +++ b/core-java-modules/core-java-concurrency-basic/README.md @@ -3,8 +3,6 @@ This module contains articles about basic Java concurrency ### Relevant Articles: -- [Guide To CompletableFuture](https://www.baeldung.com/java-completablefuture) -- [A Guide to the Java ExecutorService](https://www.baeldung.com/java-executor-service-tutorial) - [Guide to java.util.concurrent.Future](https://www.baeldung.com/java-future) - [Overview of the java.util.concurrent](https://www.baeldung.com/java-util-concurrent) - [Implementing a Runnable vs Extending a Thread](https://www.baeldung.com/java-runnable-vs-extending-thread) @@ -12,5 +10,4 @@ This module contains articles about basic Java concurrency - [ExecutorService – Waiting for Threads to Finish](https://www.baeldung.com/java-executor-wait-for-threads) - [Runnable vs. Callable in Java](https://www.baeldung.com/java-runnable-callable) - [What is Thread-Safety and How to Achieve it?](https://www.baeldung.com/java-thread-safety) -- [How to Start a Thread in Java](https://www.baeldung.com/java-start-thread) - [[Next -->]](/core-java-modules/core-java-concurrency-basic-2) diff --git a/core-java-modules/core-java-concurrency-simple/README.md b/core-java-modules/core-java-concurrency-simple/README.md new file mode 100644 index 0000000000..861d9e7792 --- /dev/null +++ b/core-java-modules/core-java-concurrency-simple/README.md @@ -0,0 +1,18 @@ +### Mockito Articles that are also part of the e-book + +This module contains articles about Java Concurrency that are also part of an Ebook. + +## Relevant articles: + +- [Life Cycle of a Thread in Java](https://www.baeldung.com/java-thread-lifecycle) +- [How to Start a Thread in Java](https://www.baeldung.com/java-start-thread) +- [Thread's wait and notify() Methods in Java](https://www.baeldung.com/java-wait-notify) +- [The Thread.join() Method in Java](https://www.baeldung.com/java-thread-join) +- [Guide to the Synchronized Keyword in Java](https://www.baeldung.com/java-synchronized) +- [Guide to the Volatile Keyword in Java](https://www.baeldung.com/java-volatile) +- [A Guide to the Java ExecutorService](https://www.baeldung.com/java-executor-service-tutorial) +- [Guide To CompletableFuture](https://www.baeldung.com/java-completablefuture) + +### NOTE: + +Since this is a module tied to an e-book, it should **not** be moved or used to store the code for any further article. diff --git a/core-java-modules/core-java-concurrency-simple/pom.xml b/core-java-modules/core-java-concurrency-simple/pom.xml new file mode 100644 index 0000000000..153d76d0d5 --- /dev/null +++ b/core-java-modules/core-java-concurrency-simple/pom.xml @@ -0,0 +1,26 @@ + + 4.0.0 + java-concurrency-simple + 0.1.0-SNAPSHOT + java-concurrency-simple + jar + + + com.baeldung.core-java-modules + core-java-modules + 0.0.1-SNAPSHOT + + + + java-concurrency-simple + + + src/main/resources + true + + + + + \ No newline at end of file diff --git a/core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/Scheduledexecutorservice/ScheduledExecutorServiceDemo.java b/core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/Scheduledexecutorservice/ScheduledExecutorServiceDemo.java similarity index 100% rename from core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/Scheduledexecutorservice/ScheduledExecutorServiceDemo.java rename to core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/Scheduledexecutorservice/ScheduledExecutorServiceDemo.java diff --git a/core-java-modules/core-java-concurrency-advanced/src/main/java/com/baeldung/concurrent/daemon/MultipleThreadsExample.java b/core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/daemon/MultipleThreadsExample.java similarity index 100% rename from core-java-modules/core-java-concurrency-advanced/src/main/java/com/baeldung/concurrent/daemon/MultipleThreadsExample.java rename to core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/daemon/MultipleThreadsExample.java diff --git a/core-java-modules/core-java-concurrency-advanced/src/main/java/com/baeldung/concurrent/daemon/NewThread.java b/core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/daemon/NewThread.java similarity index 100% rename from core-java-modules/core-java-concurrency-advanced/src/main/java/com/baeldung/concurrent/daemon/NewThread.java rename to core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/daemon/NewThread.java diff --git a/core-java-modules/core-java-concurrency-advanced/src/main/java/com/baeldung/concurrent/daemon/SingleThreadExample.java b/core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/daemon/SingleThreadExample.java similarity index 100% rename from core-java-modules/core-java-concurrency-advanced/src/main/java/com/baeldung/concurrent/daemon/SingleThreadExample.java rename to core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/daemon/SingleThreadExample.java diff --git a/core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/executorservice/DelayedCallable.java b/core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/executorservice/DelayedCallable.java similarity index 100% rename from core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/executorservice/DelayedCallable.java rename to core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/executorservice/DelayedCallable.java diff --git a/core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/executorservice/ExecutorServiceDemo.java b/core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/executorservice/ExecutorServiceDemo.java similarity index 100% rename from core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/executorservice/ExecutorServiceDemo.java rename to core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/executorservice/ExecutorServiceDemo.java diff --git a/core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/executorservice/Task.java b/core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/executorservice/Task.java similarity index 100% rename from core-java-modules/core-java-concurrency-basic/src/main/java/com/baeldung/concurrent/executorservice/Task.java rename to core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/executorservice/Task.java diff --git a/core-java-modules/core-java-concurrency-basic-2/src/main/java/com/baeldung/concurrent/synchronize/BaeldungSynchronizedBlocks.java b/core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/synchronize/BaeldungSynchronizedBlocks.java similarity index 100% rename from core-java-modules/core-java-concurrency-basic-2/src/main/java/com/baeldung/concurrent/synchronize/BaeldungSynchronizedBlocks.java rename to core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/synchronize/BaeldungSynchronizedBlocks.java diff --git a/core-java-modules/core-java-concurrency-basic-2/src/main/java/com/baeldung/concurrent/synchronize/BaeldungSynchronizedMethods.java b/core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/synchronize/BaeldungSynchronizedMethods.java similarity index 100% rename from core-java-modules/core-java-concurrency-basic-2/src/main/java/com/baeldung/concurrent/synchronize/BaeldungSynchronizedMethods.java rename to core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/synchronize/BaeldungSynchronizedMethods.java diff --git a/core-java-modules/core-java-concurrency-basic-2/src/main/java/com/baeldung/concurrent/threadlifecycle/BlockedState.java b/core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/threadlifecycle/BlockedState.java similarity index 100% rename from core-java-modules/core-java-concurrency-basic-2/src/main/java/com/baeldung/concurrent/threadlifecycle/BlockedState.java rename to core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/threadlifecycle/BlockedState.java diff --git a/core-java-modules/core-java-concurrency-basic-2/src/main/java/com/baeldung/concurrent/threadlifecycle/NewState.java b/core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/threadlifecycle/NewState.java similarity index 100% rename from core-java-modules/core-java-concurrency-basic-2/src/main/java/com/baeldung/concurrent/threadlifecycle/NewState.java rename to core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/threadlifecycle/NewState.java diff --git a/core-java-modules/core-java-concurrency-basic-2/src/main/java/com/baeldung/concurrent/threadlifecycle/RunnableState.java b/core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/threadlifecycle/RunnableState.java similarity index 100% rename from core-java-modules/core-java-concurrency-basic-2/src/main/java/com/baeldung/concurrent/threadlifecycle/RunnableState.java rename to core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/threadlifecycle/RunnableState.java diff --git a/core-java-modules/core-java-concurrency-basic-2/src/main/java/com/baeldung/concurrent/threadlifecycle/TerminatedState.java b/core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/threadlifecycle/TerminatedState.java similarity index 100% rename from core-java-modules/core-java-concurrency-basic-2/src/main/java/com/baeldung/concurrent/threadlifecycle/TerminatedState.java rename to core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/threadlifecycle/TerminatedState.java diff --git a/core-java-modules/core-java-concurrency-basic-2/src/main/java/com/baeldung/concurrent/threadlifecycle/TimedWaitingState.java b/core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/threadlifecycle/TimedWaitingState.java similarity index 100% rename from core-java-modules/core-java-concurrency-basic-2/src/main/java/com/baeldung/concurrent/threadlifecycle/TimedWaitingState.java rename to core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/threadlifecycle/TimedWaitingState.java diff --git a/core-java-modules/core-java-concurrency-basic-2/src/main/java/com/baeldung/concurrent/threadlifecycle/WaitingState.java b/core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/threadlifecycle/WaitingState.java similarity index 100% rename from core-java-modules/core-java-concurrency-basic-2/src/main/java/com/baeldung/concurrent/threadlifecycle/WaitingState.java rename to core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/threadlifecycle/WaitingState.java diff --git a/core-java-modules/core-java-concurrency-advanced/src/main/java/com/baeldung/concurrent/volatilekeyword/SharedObject.java b/core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/volatilekeyword/SharedObject.java similarity index 100% rename from core-java-modules/core-java-concurrency-advanced/src/main/java/com/baeldung/concurrent/volatilekeyword/SharedObject.java rename to core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/volatilekeyword/SharedObject.java diff --git a/core-java-modules/core-java-concurrency-advanced/src/main/java/com/baeldung/concurrent/volatilekeyword/TaskRunner.java b/core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/volatilekeyword/TaskRunner.java similarity index 100% rename from core-java-modules/core-java-concurrency-advanced/src/main/java/com/baeldung/concurrent/volatilekeyword/TaskRunner.java rename to core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/volatilekeyword/TaskRunner.java diff --git a/core-java-modules/core-java-concurrency-basic-2/src/main/java/com/baeldung/concurrent/waitandnotify/Data.java b/core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/waitandnotify/Data.java similarity index 100% rename from core-java-modules/core-java-concurrency-basic-2/src/main/java/com/baeldung/concurrent/waitandnotify/Data.java rename to core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/waitandnotify/Data.java diff --git a/core-java-modules/core-java-concurrency-basic-2/src/main/java/com/baeldung/concurrent/waitandnotify/NetworkDriver.java b/core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/waitandnotify/NetworkDriver.java similarity index 100% rename from core-java-modules/core-java-concurrency-basic-2/src/main/java/com/baeldung/concurrent/waitandnotify/NetworkDriver.java rename to core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/waitandnotify/NetworkDriver.java diff --git a/core-java-modules/core-java-concurrency-basic-2/src/main/java/com/baeldung/concurrent/waitandnotify/Receiver.java b/core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/waitandnotify/Receiver.java similarity index 100% rename from core-java-modules/core-java-concurrency-basic-2/src/main/java/com/baeldung/concurrent/waitandnotify/Receiver.java rename to core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/waitandnotify/Receiver.java diff --git a/core-java-modules/core-java-concurrency-basic-2/src/main/java/com/baeldung/concurrent/waitandnotify/Sender.java b/core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/waitandnotify/Sender.java similarity index 100% rename from core-java-modules/core-java-concurrency-basic-2/src/main/java/com/baeldung/concurrent/waitandnotify/Sender.java rename to core-java-modules/core-java-concurrency-simple/src/main/java/com/baeldung/concurrent/waitandnotify/Sender.java diff --git a/core-java-modules/core-java-concurrency-basic/src/test/java/com/baeldung/completablefuture/CompletableFutureLongRunningUnitTest.java b/core-java-modules/core-java-concurrency-simple/src/test/java/com/baeldung/completablefuture/CompletableFutureLongRunningUnitTest.java similarity index 100% rename from core-java-modules/core-java-concurrency-basic/src/test/java/com/baeldung/completablefuture/CompletableFutureLongRunningUnitTest.java rename to core-java-modules/core-java-concurrency-simple/src/test/java/com/baeldung/completablefuture/CompletableFutureLongRunningUnitTest.java diff --git a/core-java-modules/core-java-concurrency-basic/src/test/java/com/baeldung/concurrent/executorservice/Java8ExecutorServiceIntegrationTest.java b/core-java-modules/core-java-concurrency-simple/src/test/java/com/baeldung/concurrent/executorservice/Java8ExecutorServiceIntegrationTest.java similarity index 100% rename from core-java-modules/core-java-concurrency-basic/src/test/java/com/baeldung/concurrent/executorservice/Java8ExecutorServiceIntegrationTest.java rename to core-java-modules/core-java-concurrency-simple/src/test/java/com/baeldung/concurrent/executorservice/Java8ExecutorServiceIntegrationTest.java diff --git a/core-java-modules/core-java-concurrency-basic/src/test/java/com/baeldung/concurrent/executorservice/WaitingForThreadsToFinishManualTest.java b/core-java-modules/core-java-concurrency-simple/src/test/java/com/baeldung/concurrent/executorservice/WaitingForThreadsToFinishManualTest.java similarity index 100% rename from core-java-modules/core-java-concurrency-basic/src/test/java/com/baeldung/concurrent/executorservice/WaitingForThreadsToFinishManualTest.java rename to core-java-modules/core-java-concurrency-simple/src/test/java/com/baeldung/concurrent/executorservice/WaitingForThreadsToFinishManualTest.java diff --git a/core-java-modules/core-java-concurrency-basic-2/src/test/java/com/baeldung/concurrent/synchronize/BaeldungSychronizedBlockUnitTest.java b/core-java-modules/core-java-concurrency-simple/src/test/java/com/baeldung/concurrent/synchronize/BaeldungSychronizedBlockUnitTest.java similarity index 100% rename from core-java-modules/core-java-concurrency-basic-2/src/test/java/com/baeldung/concurrent/synchronize/BaeldungSychronizedBlockUnitTest.java rename to core-java-modules/core-java-concurrency-simple/src/test/java/com/baeldung/concurrent/synchronize/BaeldungSychronizedBlockUnitTest.java diff --git a/core-java-modules/core-java-concurrency-basic-2/src/test/java/com/baeldung/concurrent/synchronize/BaeldungSynchronizeMethodsUnitTest.java b/core-java-modules/core-java-concurrency-simple/src/test/java/com/baeldung/concurrent/synchronize/BaeldungSynchronizeMethodsUnitTest.java similarity index 100% rename from core-java-modules/core-java-concurrency-basic-2/src/test/java/com/baeldung/concurrent/synchronize/BaeldungSynchronizeMethodsUnitTest.java rename to core-java-modules/core-java-concurrency-simple/src/test/java/com/baeldung/concurrent/synchronize/BaeldungSynchronizeMethodsUnitTest.java diff --git a/core-java-modules/core-java-concurrency-advanced/src/test/java/com/baeldung/concurrent/volatilekeyword/SharedObjectManualTest.java b/core-java-modules/core-java-concurrency-simple/src/test/java/com/baeldung/concurrent/volatilekeyword/SharedObjectManualTest.java similarity index 100% rename from core-java-modules/core-java-concurrency-advanced/src/test/java/com/baeldung/concurrent/volatilekeyword/SharedObjectManualTest.java rename to core-java-modules/core-java-concurrency-simple/src/test/java/com/baeldung/concurrent/volatilekeyword/SharedObjectManualTest.java diff --git a/core-java-modules/core-java-concurrency-basic-2/src/test/java/com/baeldung/concurrent/waitandnotify/NetworkIntegrationTest.java b/core-java-modules/core-java-concurrency-simple/src/test/java/com/baeldung/concurrent/waitandnotify/NetworkIntegrationTest.java similarity index 100% rename from core-java-modules/core-java-concurrency-basic-2/src/test/java/com/baeldung/concurrent/waitandnotify/NetworkIntegrationTest.java rename to core-java-modules/core-java-concurrency-simple/src/test/java/com/baeldung/concurrent/waitandnotify/NetworkIntegrationTest.java diff --git a/core-java-modules/core-java-concurrency-advanced-2/src/test/java/com/baeldung/thread/join/ThreadJoinUnitTest.java b/core-java-modules/core-java-concurrency-simple/src/test/java/com/baeldung/thread/join/ThreadJoinUnitTest.java similarity index 100% rename from core-java-modules/core-java-concurrency-advanced-2/src/test/java/com/baeldung/thread/join/ThreadJoinUnitTest.java rename to core-java-modules/core-java-concurrency-simple/src/test/java/com/baeldung/thread/join/ThreadJoinUnitTest.java diff --git a/core-java-modules/core-java-date-operations-2/src/main/java/com/baeldung/timeago/version7/TimeAgoCalculator.java b/core-java-modules/core-java-date-operations-2/src/main/java/com/baeldung/timeago/version7/TimeAgoCalculator.java index e09880f1ee..00f1d75029 100644 --- a/core-java-modules/core-java-date-operations-2/src/main/java/com/baeldung/timeago/version7/TimeAgoCalculator.java +++ b/core-java-modules/core-java-date-operations-2/src/main/java/com/baeldung/timeago/version7/TimeAgoCalculator.java @@ -2,6 +2,7 @@ package com.baeldung.timeago.version7; import java.util.Date; import java.util.TimeZone; +import java.util.Calendar; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; @@ -12,16 +13,30 @@ import org.joda.time.format.PeriodFormatterBuilder; public class TimeAgoCalculator { + private static long getCurrentTime() { + Calendar calendar = Calendar.getInstance(); + calendar.set(2020, 1, 1, 12, 0, 0); + return calendar.getTimeInMillis(); + //We return a fixed date and time in order to avoid issues related to getting time from local in unit tests. + //return System.currentTimeMillis(); + } + + private static long getCurrentTimeByTimeZone(TimeZone zone) { + Calendar calendar = Calendar.getInstance(zone); + calendar.set(2020, 1, 1, 12, 0, 0); + return calendar.getTimeInMillis(); + //We return a fixed date and time in order to avoid issues related to getting time from local in unit tests. + //return Calendar.getInstance(zone).getTimeInMillis(); + } + public static String calculateTimeAgoByTimeGranularity(Date pastTime, TimeGranularity granularity) { - Date currentTime = new Date(); - long timeDifferenceInMillis = currentTime.getTime() - pastTime.getTime(); + long timeDifferenceInMillis = getCurrentTime() - pastTime.getTime(); return timeDifferenceInMillis / granularity.toMillis() + " " + granularity.name() .toLowerCase() + " ago"; } public static String calculateHumanFriendlyTimeAgo(Date pastTime) { - Date currentTime = new Date(); - long timeDifferenceInMillis = currentTime.getTime() - pastTime.getTime(); + long timeDifferenceInMillis = getCurrentTime() - pastTime.getTime(); if (timeDifferenceInMillis / TimeGranularity.DECADES.toMillis() > 0) return "several decades ago"; else if (timeDifferenceInMillis / TimeGranularity.YEARS.toMillis() > 0) @@ -41,7 +56,7 @@ public class TimeAgoCalculator { } public static String calculateExactTimeAgoWithJodaTime(Date pastTime) { - Period period = new Period(new DateTime(pastTime.getTime()), new DateTime()); + Period period = new Period(new DateTime(pastTime.getTime()), new DateTime(getCurrentTime())); PeriodFormatter formatter = new PeriodFormatterBuilder().appendYears() .appendSuffix(" year ", " years ") .appendSeparator("and ") @@ -67,7 +82,7 @@ public class TimeAgoCalculator { } public static String calculateHumanFriendlyTimeAgoWithJodaTime(Date pastTime) { - Period period = new Period(new DateTime(pastTime.getTime()), new DateTime()); + Period period = new Period(new DateTime(pastTime.getTime()), new DateTime(getCurrentTime())); if (period.getYears() != 0) return "several years ago"; else if (period.getMonths() != 0) @@ -86,7 +101,7 @@ public class TimeAgoCalculator { public static String calculateZonedTimeAgoWithJodaTime(Date pastTime, TimeZone zone) { DateTimeZone dateTimeZone = DateTimeZone.forID(zone.getID()); - Period period = new Period(new DateTime(pastTime.getTime(), dateTimeZone), new DateTime(dateTimeZone)); + Period period = new Period(new DateTime(pastTime.getTime(), dateTimeZone), new DateTime(getCurrentTimeByTimeZone(zone))); return PeriodFormat.getDefault() .print(period); } diff --git a/core-java-modules/core-java-date-operations-2/src/main/java/com/baeldung/timeago/version8/TimeAgoCalculator.java b/core-java-modules/core-java-date-operations-2/src/main/java/com/baeldung/timeago/version8/TimeAgoCalculator.java index 392cfa54fa..4395e70ba1 100644 --- a/core-java-modules/core-java-date-operations-2/src/main/java/com/baeldung/timeago/version8/TimeAgoCalculator.java +++ b/core-java-modules/core-java-date-operations-2/src/main/java/com/baeldung/timeago/version8/TimeAgoCalculator.java @@ -12,9 +12,17 @@ import org.ocpsoft.prettytime.PrettyTime; public class TimeAgoCalculator { + private static LocalDateTime getCurrentTimeByTimeZone(ZoneId zone) { + LocalDateTime localDateTime = LocalDateTime.of(2020, 1, 1, 12, 0, 0); + return localDateTime.atZone(zone) + .toLocalDateTime(); + //We return a fixed date and time in order to avoid issues related to getting time from local in unit tests. + //return LocalDateTime.now(zone); + } + public static String calculateTimeAgoWithPeriodAndDuration(LocalDateTime pastTime, ZoneId zone) { - Period period = Period.between(pastTime.toLocalDate(), LocalDate.now(zone)); - Duration duration = Duration.between(pastTime, LocalDateTime.now(zone)); + Period period = Period.between(pastTime.toLocalDate(), getCurrentTimeByTimeZone(zone).toLocalDate()); + Duration duration = Duration.between(pastTime, getCurrentTimeByTimeZone(zone)); if (period.getYears() != 0) return "several years ago"; else if (period.getMonths() != 0) diff --git a/core-java-modules/core-java-date-operations-2/src/test/java/com/baeldung/timeago/version7/TimeAgoCalculatorUnitTest.java b/core-java-modules/core-java-date-operations-2/src/test/java/com/baeldung/timeago/version7/TimeAgoCalculatorUnitTest.java index b41533aa7e..d006b72ed2 100644 --- a/core-java-modules/core-java-date-operations-2/src/test/java/com/baeldung/timeago/version7/TimeAgoCalculatorUnitTest.java +++ b/core-java-modules/core-java-date-operations-2/src/test/java/com/baeldung/timeago/version7/TimeAgoCalculatorUnitTest.java @@ -1,56 +1,64 @@ package com.baeldung.timeago.version7; import java.util.Date; +import java.util.Calendar; import org.junit.Assert; import org.junit.Test; public class TimeAgoCalculatorUnitTest { - // fixing tests in BAEL-5647 - //@Test + private long getCurrentTime() { + Calendar calendar = Calendar.getInstance(); + calendar.set(2020, 1, 1, 12, 0, 0); + return calendar.getTimeInMillis(); + //We return a fixed date and time in order to avoid issues related to getting time from local in unit tests. + //return System.currentTimeMillis(); + } + + @Test public void timeAgoByTimeGranularityTest() { long DAY_IN_MILLIS = 1000 * 60 * 60 * 24; - Assert.assertEquals("5 seconds ago", TimeAgoCalculator.calculateTimeAgoByTimeGranularity(new Date(System.currentTimeMillis() - (5 * 1000)), TimeGranularity.SECONDS)); - Assert.assertEquals("5 minutes ago", TimeAgoCalculator.calculateTimeAgoByTimeGranularity(new Date(System.currentTimeMillis() - (5 * 60 * 1000)), TimeGranularity.MINUTES)); - Assert.assertEquals("5 hours ago", TimeAgoCalculator.calculateTimeAgoByTimeGranularity(new Date(System.currentTimeMillis() - (5 * 60 * 60 * 1000)), TimeGranularity.HOURS)); - Assert.assertEquals("5 days ago", TimeAgoCalculator.calculateTimeAgoByTimeGranularity(new Date(System.currentTimeMillis() - (5 * DAY_IN_MILLIS)), TimeGranularity.DAYS)); - Assert.assertEquals("5 months ago", TimeAgoCalculator.calculateTimeAgoByTimeGranularity(new Date(System.currentTimeMillis() - (5 * DAY_IN_MILLIS * 30)), TimeGranularity.MONTHS)); - Assert.assertEquals("5 weeks ago", TimeAgoCalculator.calculateTimeAgoByTimeGranularity(new Date(System.currentTimeMillis() - (5 * DAY_IN_MILLIS * 7)), TimeGranularity.WEEKS)); - Assert.assertEquals("5 years ago", TimeAgoCalculator.calculateTimeAgoByTimeGranularity(new Date(System.currentTimeMillis() - (5 * DAY_IN_MILLIS * 365)), TimeGranularity.YEARS)); - Assert.assertEquals("5 decades ago", TimeAgoCalculator.calculateTimeAgoByTimeGranularity(new Date(System.currentTimeMillis() - (5 * DAY_IN_MILLIS * 365 * 10)), TimeGranularity.DECADES)); + Assert.assertEquals("5 seconds ago", TimeAgoCalculator.calculateTimeAgoByTimeGranularity(new Date(getCurrentTime() - (5 * 1000)), TimeGranularity.SECONDS)); + Assert.assertEquals("5 minutes ago", TimeAgoCalculator.calculateTimeAgoByTimeGranularity(new Date(getCurrentTime() - (5 * 60 * 1000)), TimeGranularity.MINUTES)); + Assert.assertEquals("5 hours ago", TimeAgoCalculator.calculateTimeAgoByTimeGranularity(new Date(getCurrentTime() - (5 * 60 * 60 * 1000)), TimeGranularity.HOURS)); + Assert.assertEquals("5 days ago", TimeAgoCalculator.calculateTimeAgoByTimeGranularity(new Date(getCurrentTime() - (5 * DAY_IN_MILLIS)), TimeGranularity.DAYS)); + Assert.assertEquals("5 months ago", TimeAgoCalculator.calculateTimeAgoByTimeGranularity(new Date(getCurrentTime() - (5 * DAY_IN_MILLIS * 30)), TimeGranularity.MONTHS)); + Assert.assertEquals("5 weeks ago", TimeAgoCalculator.calculateTimeAgoByTimeGranularity(new Date(getCurrentTime() - (5 * DAY_IN_MILLIS * 7)), TimeGranularity.WEEKS)); + Assert.assertEquals("5 years ago", TimeAgoCalculator.calculateTimeAgoByTimeGranularity(new Date(getCurrentTime() - (5 * DAY_IN_MILLIS * 365)), TimeGranularity.YEARS)); + Assert.assertEquals("5 decades ago", TimeAgoCalculator.calculateTimeAgoByTimeGranularity(new Date(getCurrentTime() - (5 * DAY_IN_MILLIS * 365 * 10)), TimeGranularity.DECADES)); } - //@Test + @Test public void humanFriendlyTimeAgoTest() { long DAY_IN_MILLIS = 1000 * 60 * 60 * 24; - Assert.assertEquals("moments ago", TimeAgoCalculator.calculateHumanFriendlyTimeAgo(new Date(System.currentTimeMillis() - (5 * 1000)))); - Assert.assertEquals("several minutes ago", TimeAgoCalculator.calculateHumanFriendlyTimeAgo(new Date(System.currentTimeMillis() - (5 * 60 * 1000)))); - Assert.assertEquals("several hours ago", TimeAgoCalculator.calculateHumanFriendlyTimeAgo(new Date(System.currentTimeMillis() - (5 * 60 * 60 * 1000)))); - Assert.assertEquals("several days ago", TimeAgoCalculator.calculateHumanFriendlyTimeAgo(new Date(System.currentTimeMillis() - (5 * DAY_IN_MILLIS)))); - Assert.assertEquals("several months ago", TimeAgoCalculator.calculateHumanFriendlyTimeAgo(new Date(System.currentTimeMillis() - (5 * DAY_IN_MILLIS * 30)))); - Assert.assertEquals("several weeks ago", TimeAgoCalculator.calculateHumanFriendlyTimeAgo(new Date(System.currentTimeMillis() - (3 * DAY_IN_MILLIS * 7)))); - Assert.assertEquals("several years ago", TimeAgoCalculator.calculateHumanFriendlyTimeAgo(new Date(System.currentTimeMillis() - (5 * DAY_IN_MILLIS * 365)))); - Assert.assertEquals("several decades ago", TimeAgoCalculator.calculateHumanFriendlyTimeAgo(new Date(System.currentTimeMillis() - (5 * DAY_IN_MILLIS * 365 * 10)))); + Assert.assertEquals("moments ago", TimeAgoCalculator.calculateHumanFriendlyTimeAgo(new Date(getCurrentTime() - (5 * 1000)))); + Assert.assertEquals("several minutes ago", TimeAgoCalculator.calculateHumanFriendlyTimeAgo(new Date(getCurrentTime() - (5 * 60 * 1000)))); + Assert.assertEquals("several hours ago", TimeAgoCalculator.calculateHumanFriendlyTimeAgo(new Date(getCurrentTime() - (5 * 60 * 60 * 1000)))); + Assert.assertEquals("several days ago", TimeAgoCalculator.calculateHumanFriendlyTimeAgo(new Date(getCurrentTime() - (5 * DAY_IN_MILLIS)))); + Assert.assertEquals("several months ago", TimeAgoCalculator.calculateHumanFriendlyTimeAgo(new Date(getCurrentTime() - (5 * DAY_IN_MILLIS * 30)))); + Assert.assertEquals("several weeks ago", TimeAgoCalculator.calculateHumanFriendlyTimeAgo(new Date(getCurrentTime() - (3 * DAY_IN_MILLIS * 7)))); + Assert.assertEquals("several years ago", TimeAgoCalculator.calculateHumanFriendlyTimeAgo(new Date(getCurrentTime() - (5 * DAY_IN_MILLIS * 365)))); + Assert.assertEquals("several decades ago", TimeAgoCalculator.calculateHumanFriendlyTimeAgo(new Date(getCurrentTime() - (5 * DAY_IN_MILLIS * 365 * 10)))); } - //@Test + @Test public void calculateExactTimeAgoWithJodaTimeTest() { - Assert.assertEquals("5 hours and 15 minutes and 3 seconds", TimeAgoCalculator.calculateExactTimeAgoWithJodaTime(new Date(System.currentTimeMillis() - (5 * 60 * 60 * 1000 + 15 * 60 * 1000 + 3 * 1000)))); - Assert.assertEquals("5 hours and 1 minute and 1 second", TimeAgoCalculator.calculateExactTimeAgoWithJodaTime(new Date(System.currentTimeMillis() - (5 * 60 * 60 * 1000 + 1 * 60 * 1000 + 1 * 1000)))); - Assert.assertEquals("2 days and 1 minute and 1 second", TimeAgoCalculator.calculateExactTimeAgoWithJodaTime(new Date(System.currentTimeMillis() - (2 * 24 * 60 * 60 * 1000 + 1 * 60 * 1000 + 1 * 1000)))); + Assert.assertEquals("5 hours and 15 minutes and 3 seconds", TimeAgoCalculator.calculateExactTimeAgoWithJodaTime(new Date(getCurrentTime() - (5 * 60 * 60 * 1000 + 15 * 60 * 1000 + 3 * 1000)))); + Assert.assertEquals("5 hours and 1 minute and 1 second", TimeAgoCalculator.calculateExactTimeAgoWithJodaTime(new Date(getCurrentTime() - (5 * 60 * 60 * 1000 + 1 * 60 * 1000 + 1 * 1000)))); + Assert.assertEquals("2 days and 1 minute and 1 second", TimeAgoCalculator.calculateExactTimeAgoWithJodaTime(new Date(getCurrentTime() - (2 * 24 * 60 * 60 * 1000 + 1 * 60 * 1000 + 1 * 1000)))); } - //@Test + @Test public void calculateHumanFriendlyTimeAgoWithJodaTimeTest() { long DAY_IN_MILLIS = 1000 * 60 * 60 * 24; - Assert.assertEquals("moments ago", TimeAgoCalculator.calculateHumanFriendlyTimeAgoWithJodaTime(new Date(System.currentTimeMillis() - (5 * 1000)))); - Assert.assertEquals("several minutes ago", TimeAgoCalculator.calculateHumanFriendlyTimeAgoWithJodaTime(new Date(System.currentTimeMillis() - (5 * 60 * 1000)))); - Assert.assertEquals("several hours ago", TimeAgoCalculator.calculateHumanFriendlyTimeAgoWithJodaTime(new Date(System.currentTimeMillis() - (5 * 60 * 60 * 1000)))); - Assert.assertEquals("several days ago", TimeAgoCalculator.calculateHumanFriendlyTimeAgoWithJodaTime(new Date(System.currentTimeMillis() - (5 * DAY_IN_MILLIS)))); - Assert.assertEquals("several months ago", TimeAgoCalculator.calculateHumanFriendlyTimeAgoWithJodaTime(new Date(System.currentTimeMillis() - (5 * DAY_IN_MILLIS * 30)))); - Assert.assertEquals("several weeks ago", TimeAgoCalculator.calculateHumanFriendlyTimeAgoWithJodaTime(new Date(System.currentTimeMillis() - (3 * DAY_IN_MILLIS * 7)))); - Assert.assertEquals("several years ago", TimeAgoCalculator.calculateHumanFriendlyTimeAgoWithJodaTime(new Date(System.currentTimeMillis() - (5 * DAY_IN_MILLIS * 365)))); + Assert.assertEquals("moments ago", TimeAgoCalculator.calculateHumanFriendlyTimeAgoWithJodaTime(new Date(getCurrentTime() - (5 * 1000)))); + Assert.assertEquals("several minutes ago", TimeAgoCalculator.calculateHumanFriendlyTimeAgoWithJodaTime(new Date(getCurrentTime() - (5 * 60 * 1000)))); + Assert.assertEquals("several hours ago", TimeAgoCalculator.calculateHumanFriendlyTimeAgoWithJodaTime(new Date(getCurrentTime() - (5 * 60 * 60 * 1000)))); + Assert.assertEquals("several days ago", TimeAgoCalculator.calculateHumanFriendlyTimeAgoWithJodaTime(new Date(getCurrentTime() - (5 * DAY_IN_MILLIS)))); + Assert.assertEquals("several months ago", TimeAgoCalculator.calculateHumanFriendlyTimeAgoWithJodaTime(new Date(getCurrentTime() - (5 * DAY_IN_MILLIS * 30)))); + Assert.assertEquals("several weeks ago", TimeAgoCalculator.calculateHumanFriendlyTimeAgoWithJodaTime(new Date(getCurrentTime() - (3 * DAY_IN_MILLIS * 7)))); + Assert.assertEquals("several years ago", TimeAgoCalculator.calculateHumanFriendlyTimeAgoWithJodaTime(new Date(getCurrentTime() - (5 * DAY_IN_MILLIS * 365)))); } } diff --git a/core-java-modules/core-java-date-operations-2/src/test/java/com/baeldung/timeago/version8/TimeAgoCalculatorUnitTest.java b/core-java-modules/core-java-date-operations-2/src/test/java/com/baeldung/timeago/version8/TimeAgoCalculatorUnitTest.java index 5fb8512a7e..81ad547a50 100644 --- a/core-java-modules/core-java-date-operations-2/src/test/java/com/baeldung/timeago/version8/TimeAgoCalculatorUnitTest.java +++ b/core-java-modules/core-java-date-operations-2/src/test/java/com/baeldung/timeago/version8/TimeAgoCalculatorUnitTest.java @@ -1,7 +1,9 @@ package com.baeldung.timeago.version8; +import java.time.Duration; import java.time.Instant; import java.time.LocalDateTime; +import java.time.Period; import java.time.ZoneId; import org.junit.Assert; @@ -9,16 +11,22 @@ import org.junit.Test; public class TimeAgoCalculatorUnitTest { - // fixing test in BAEL-5647 - //@Test + private LocalDateTime getCurrentTime() { + LocalDateTime localDateTime = LocalDateTime.of(2020, 1, 1, 12, 0, 0); + return localDateTime.atZone(ZoneId.systemDefault()) + .toLocalDateTime(); + //We return a fixed date and time in order to avoid issues related to getting time from local in unit tests. + //return LocalDateTime.now(zone); + } + + @Test public void calculateTimeAgoWithPeriodAndDurationTest() { - long DAY_IN_MILLIS = 1000 * 60 * 60 * 24; - Assert.assertEquals("moments ago", TimeAgoCalculator.calculateTimeAgoWithPeriodAndDuration(LocalDateTime.ofInstant(Instant.ofEpochMilli(System.currentTimeMillis()), ZoneId.systemDefault()), ZoneId.systemDefault())); - Assert.assertEquals("several seconds ago", TimeAgoCalculator.calculateTimeAgoWithPeriodAndDuration(LocalDateTime.ofInstant(Instant.ofEpochMilli(System.currentTimeMillis() - (5 * 1000)), ZoneId.systemDefault()), ZoneId.systemDefault())); - Assert.assertEquals("several minutes ago", TimeAgoCalculator.calculateTimeAgoWithPeriodAndDuration(LocalDateTime.ofInstant(Instant.ofEpochMilli(System.currentTimeMillis() - (5 * 60 * 1000)), ZoneId.systemDefault()), ZoneId.systemDefault())); - Assert.assertEquals("several hours ago", TimeAgoCalculator.calculateTimeAgoWithPeriodAndDuration(LocalDateTime.ofInstant(Instant.ofEpochMilli(System.currentTimeMillis() - (5 * 60 * 60 * 1000)), ZoneId.systemDefault()), ZoneId.systemDefault())); - Assert.assertEquals("several days ago", TimeAgoCalculator.calculateTimeAgoWithPeriodAndDuration(LocalDateTime.ofInstant(Instant.ofEpochMilli(System.currentTimeMillis() - (5 * DAY_IN_MILLIS)), ZoneId.systemDefault()), ZoneId.systemDefault())); - Assert.assertEquals("several months ago", TimeAgoCalculator.calculateTimeAgoWithPeriodAndDuration(LocalDateTime.ofInstant(Instant.ofEpochMilli(System.currentTimeMillis() - (5 * DAY_IN_MILLIS * 30)), ZoneId.systemDefault()), ZoneId.systemDefault())); - Assert.assertEquals("several years ago", TimeAgoCalculator.calculateTimeAgoWithPeriodAndDuration(LocalDateTime.ofInstant(Instant.ofEpochMilli(System.currentTimeMillis() - (5 * DAY_IN_MILLIS * 365)), ZoneId.systemDefault()), ZoneId.systemDefault())); + Assert.assertEquals("moments ago", TimeAgoCalculator.calculateTimeAgoWithPeriodAndDuration(getCurrentTime(), ZoneId.systemDefault())); + Assert.assertEquals("several seconds ago", TimeAgoCalculator.calculateTimeAgoWithPeriodAndDuration(getCurrentTime().minus(Duration.ofSeconds(5)), ZoneId.systemDefault())); + Assert.assertEquals("several minutes ago", TimeAgoCalculator.calculateTimeAgoWithPeriodAndDuration(getCurrentTime().minus(Duration.ofMinutes(5)), ZoneId.systemDefault())); + Assert.assertEquals("several hours ago", TimeAgoCalculator.calculateTimeAgoWithPeriodAndDuration(getCurrentTime().minus(Duration.ofHours(5)), ZoneId.systemDefault())); + Assert.assertEquals("several days ago", TimeAgoCalculator.calculateTimeAgoWithPeriodAndDuration(getCurrentTime().minus(Period.ofDays(5)), ZoneId.systemDefault())); + Assert.assertEquals("several months ago", TimeAgoCalculator.calculateTimeAgoWithPeriodAndDuration(getCurrentTime().minus(Period.ofMonths(5)), ZoneId.systemDefault())); + Assert.assertEquals("several years ago", TimeAgoCalculator.calculateTimeAgoWithPeriodAndDuration(getCurrentTime().minus(Period.ofYears(5)), ZoneId.systemDefault())); } } diff --git a/core-java-modules/core-java-exceptions-4/src/main/java/com/baeldung/exception/currentstacktrace/DumpStackTraceDemo.java b/core-java-modules/core-java-exceptions-4/src/main/java/com/baeldung/exception/currentstacktrace/DumpStackTraceDemo.java new file mode 100644 index 0000000000..fb67814312 --- /dev/null +++ b/core-java-modules/core-java-exceptions-4/src/main/java/com/baeldung/exception/currentstacktrace/DumpStackTraceDemo.java @@ -0,0 +1,18 @@ +package com.baeldung.exception.currentstacktrace; + +public class DumpStackTraceDemo +{ + public static void main(String[] args) { + methodA(); + } + + public static void methodA() { + try { + int num1 = 5/0; // java.lang.ArithmeticException: divide by zero + } + catch (Exception e) { + e.printStackTrace(); + } + } + +} diff --git a/core-java-modules/core-java-exceptions-4/src/main/java/com/baeldung/exception/currentstacktrace/StackTraceUsingThreadDemo.java b/core-java-modules/core-java-exceptions-4/src/main/java/com/baeldung/exception/currentstacktrace/StackTraceUsingThreadDemo.java new file mode 100644 index 0000000000..a681fedd4f --- /dev/null +++ b/core-java-modules/core-java-exceptions-4/src/main/java/com/baeldung/exception/currentstacktrace/StackTraceUsingThreadDemo.java @@ -0,0 +1,16 @@ +package com.baeldung.exception.currentstacktrace; + +public class StackTraceUsingThreadDemo { + + public static void main(String[] args) { + methodA(); + } + + public static StackTraceElement[] methodA() { + return methodB(); + } + + public static StackTraceElement[] methodB() { + return Thread.currentThread().getStackTrace(); + } +} diff --git a/core-java-modules/core-java-exceptions-4/src/main/java/com/baeldung/exception/currentstacktrace/StackTraceUsingThrowableDemo.java b/core-java-modules/core-java-exceptions-4/src/main/java/com/baeldung/exception/currentstacktrace/StackTraceUsingThrowableDemo.java new file mode 100644 index 0000000000..fbc08596c6 --- /dev/null +++ b/core-java-modules/core-java-exceptions-4/src/main/java/com/baeldung/exception/currentstacktrace/StackTraceUsingThrowableDemo.java @@ -0,0 +1,21 @@ +package com.baeldung.exception.currentstacktrace; + +public class StackTraceUsingThrowableDemo { + + public static void main(String[] args) { + methodA(); + } + + public static StackTraceElement[] methodA() { + try { + methodB(); + } catch (Throwable t) { + return t.getStackTrace(); + } + return null; + } + + public static void methodB() throws Throwable { + throw new Throwable("A test exception"); + } +} diff --git a/core-java-modules/core-java-exceptions-4/src/test/java/com/baeldung/exception/currentstacktrace/CurrentStacktraceDemoUnitTest.java b/core-java-modules/core-java-exceptions-4/src/test/java/com/baeldung/exception/currentstacktrace/CurrentStacktraceDemoUnitTest.java new file mode 100644 index 0000000000..849884204d --- /dev/null +++ b/core-java-modules/core-java-exceptions-4/src/test/java/com/baeldung/exception/currentstacktrace/CurrentStacktraceDemoUnitTest.java @@ -0,0 +1,49 @@ +package com.baeldung.exception.currentstacktrace; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import com.baeldung.exception.currentstacktrace.StackTraceUsingThreadDemo; +import com.baeldung.exception.currentstacktrace.StackTraceUsingThrowableDemo; + +public class CurrentStacktraceDemoUnitTest { + + @Test + public void whenElementIsFecthedUsingThread_thenCorrectMethodAndClassIsReturned() { + StackTraceElement[] stackTrace = new StackTraceUsingThreadDemo().methodA(); + + StackTraceElement elementZero = stackTrace[0]; + assertEquals("java.lang.Thread", elementZero.getClassName()); + assertEquals("getStackTrace", elementZero.getMethodName()); + + StackTraceElement elementOne = stackTrace[1]; + assertEquals("com.baeldung.exception.currentstacktrace.StackTraceUsingThreadDemo", elementOne.getClassName()); + assertEquals("methodB", elementOne.getMethodName()); + + StackTraceElement elementTwo = stackTrace[2]; + assertEquals("com.baeldung.exception.currentstacktrace.StackTraceUsingThreadDemo", elementTwo.getClassName()); + assertEquals("methodA", elementTwo.getMethodName()); + + StackTraceElement elementThree = stackTrace[3]; + assertEquals("com.baeldung.exception.currentstacktrace.CurrentStacktraceDemoUnitTest", elementThree.getClassName()); + assertEquals("whenElementIsFecthedUsingThread_thenCorrectMethodAndClassIsReturned", elementThree.getMethodName()); + } + + @Test + public void whenElementIsFecthedUsingThrowable_thenCorrectMethodAndClassIsReturned() { + StackTraceElement[] stackTrace = new StackTraceUsingThrowableDemo().methodA(); + + StackTraceElement elementZero = stackTrace[0]; + assertEquals("com.baeldung.exception.currentstacktrace.StackTraceUsingThrowableDemo", elementZero.getClassName()); + assertEquals("methodB", elementZero.getMethodName()); + + StackTraceElement elementOne = stackTrace[1]; + assertEquals("com.baeldung.exception.currentstacktrace.StackTraceUsingThrowableDemo", elementOne.getClassName()); + assertEquals("methodA", elementOne.getMethodName()); + + StackTraceElement elementThree = stackTrace[2]; + assertEquals("com.baeldung.exception.currentstacktrace.CurrentStacktraceDemoUnitTest", elementThree.getClassName()); + assertEquals("whenElementIsFecthedUsingThrowable_thenCorrectMethodAndClassIsReturned", elementThree.getMethodName()); + } +} diff --git a/core-java-modules/core-java-lang-oop-constructors/src/main/java/com/baeldung/initializerblock/instanceblock/InstanceBlockExample.java b/core-java-modules/core-java-lang-oop-constructors/src/main/java/com/baeldung/initializerblock/instanceblock/InstanceBlockExample.java new file mode 100644 index 0000000000..c17fd8d3e6 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-constructors/src/main/java/com/baeldung/initializerblock/instanceblock/InstanceBlockExample.java @@ -0,0 +1,22 @@ +package com.baeldung.initializerblock.instanceblock; + +public class InstanceBlockExample { + + { + System.out.println("Instance initializer block 1"); + } + + { + System.out.println("Instance initializer block 2"); + } + + public InstanceBlockExample() { + System.out.println("Class constructor"); + } + + public static void main(String[] args) { + InstanceBlockExample iib = new InstanceBlockExample(); + System.out.println("Main Method"); + } +} + diff --git a/core-java-modules/core-java-lang-oop-constructors/src/main/java/com/baeldung/initializerblock/staticblock/StaticBlockExample.java b/core-java-modules/core-java-lang-oop-constructors/src/main/java/com/baeldung/initializerblock/staticblock/StaticBlockExample.java new file mode 100644 index 0000000000..a409b6d7c8 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-constructors/src/main/java/com/baeldung/initializerblock/staticblock/StaticBlockExample.java @@ -0,0 +1,17 @@ +package com.baeldung.initializerblock.staticblock; + +public class StaticBlockExample { + + static { + System.out.println("static block 1"); + } + + static { + System.out.println("static block 2"); + } + + public static void main(String[] args) { + System.out.println("Main Method"); + } +} + diff --git a/core-java-modules/core-java-networking-2/src/test/java/com/baeldung/url/auth/HttpClientUnitTest.java b/core-java-modules/core-java-networking-2/src/test/java/com/baeldung/url/auth/HttpClientLiveTest.java similarity index 97% rename from core-java-modules/core-java-networking-2/src/test/java/com/baeldung/url/auth/HttpClientUnitTest.java rename to core-java-modules/core-java-networking-2/src/test/java/com/baeldung/url/auth/HttpClientLiveTest.java index 0ccb6e5a54..01d580bc65 100644 --- a/core-java-modules/core-java-networking-2/src/test/java/com/baeldung/url/auth/HttpClientUnitTest.java +++ b/core-java-modules/core-java-networking-2/src/test/java/com/baeldung/url/auth/HttpClientLiveTest.java @@ -4,7 +4,7 @@ import static org.junit.Assert.assertTrue; import org.junit.Test; -public class HttpClientUnitTest { +public class HttpClientLiveTest { @Test public void sendRquestWithAuthHeader() throws Exception { diff --git a/core-java-modules/core-java-numbers-5/pom.xml b/core-java-modules/core-java-numbers-5/pom.xml index f236d28ccb..bab1e4d622 100644 --- a/core-java-modules/core-java-numbers-5/pom.xml +++ b/core-java-modules/core-java-numbers-5/pom.xml @@ -22,4 +22,22 @@ + + + org.junit.jupiter + junit-jupiter-engine + ${junit-jupiter.version} + test + + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + + + com.google.guava + guava + ${guava.version} + + \ No newline at end of file diff --git a/core-java-modules/core-java-numbers-5/src/main/java/com/baeldung/intrange/IntRangeApacheCommons.java b/core-java-modules/core-java-numbers-5/src/main/java/com/baeldung/intrange/IntRangeApacheCommons.java new file mode 100644 index 0000000000..0a82f934a7 --- /dev/null +++ b/core-java-modules/core-java-numbers-5/src/main/java/com/baeldung/intrange/IntRangeApacheCommons.java @@ -0,0 +1,26 @@ +package com.baeldung.intrange; + +import org.apache.commons.lang3.Range; + +public class IntRangeApacheCommons { + + public static boolean isInClosedRange(Integer number, Integer lowerBound, Integer upperBound) { + final Range range = Range.between(lowerBound, upperBound); + return range.contains(number); + } + + public static boolean isInOpenRange(Integer number, Integer lowerBound, Integer upperBound) { + final Range range = Range.between(lowerBound + 1, upperBound - 1); + return range.contains(number); + } + + public static boolean isInOpenClosedRange(Integer number, Integer lowerBound, Integer upperBound) { + final Range range = Range.between(lowerBound + 1, upperBound); + return range.contains(number); + } + + public static boolean isInClosedOpenRange(Integer number, Integer lowerBound, Integer upperBound) { + final Range range = Range.between(lowerBound, upperBound - 1); + return range.contains(number); + } +} diff --git a/core-java-modules/core-java-numbers-5/src/main/java/com/baeldung/intrange/IntRangeGoogleGuava.java b/core-java-modules/core-java-numbers-5/src/main/java/com/baeldung/intrange/IntRangeGoogleGuava.java new file mode 100644 index 0000000000..d4cadfa050 --- /dev/null +++ b/core-java-modules/core-java-numbers-5/src/main/java/com/baeldung/intrange/IntRangeGoogleGuava.java @@ -0,0 +1,26 @@ +package com.baeldung.intrange; + +import com.google.common.collect.Range; + +public class IntRangeGoogleGuava { + + public static boolean isInClosedRange(Integer number, Integer lowerBound, Integer upperBound) { + final Range range = Range.closed(lowerBound, upperBound); + return range.contains(number); + } + + public static boolean isInOpenRange(Integer number, Integer lowerBound, Integer upperBound) { + final Range range = Range.open(lowerBound, upperBound); + return range.contains(number); + } + + public static boolean isInOpenClosedRange(Integer number, Integer lowerBound, Integer upperBound) { + final Range range = Range.openClosed(lowerBound, upperBound); + return range.contains(number); + } + + public static boolean isInClosedOpenRange(Integer number, Integer lowerBound, Integer upperBound) { + final Range range = Range.closedOpen(lowerBound, upperBound); + return range.contains(number); + } +} diff --git a/core-java-modules/core-java-numbers-5/src/main/java/com/baeldung/intrange/IntRangeOperators.java b/core-java-modules/core-java-numbers-5/src/main/java/com/baeldung/intrange/IntRangeOperators.java new file mode 100644 index 0000000000..77e32161e0 --- /dev/null +++ b/core-java-modules/core-java-numbers-5/src/main/java/com/baeldung/intrange/IntRangeOperators.java @@ -0,0 +1,20 @@ +package com.baeldung.intrange; + +public class IntRangeOperators { + + public static boolean isInClosedRange(Integer number, Integer lowerBound, Integer upperBound) { + return (lowerBound <= number && number <= upperBound); + } + + public static boolean isInOpenRange(Integer number, Integer lowerBound, Integer upperBound) { + return (lowerBound < number && number < upperBound); + } + + public static boolean isInOpenClosedRange(Integer number, Integer lowerBound, Integer upperBound) { + return (lowerBound < number && number <= upperBound); + } + + public static boolean isInClosedOpenRange(Integer number, Integer lowerBound, Integer upperBound) { + return (lowerBound <= number && number < upperBound); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-numbers-5/src/main/java/com/baeldung/intrange/IntRangeValueRange.java b/core-java-modules/core-java-numbers-5/src/main/java/com/baeldung/intrange/IntRangeValueRange.java new file mode 100644 index 0000000000..cdce555341 --- /dev/null +++ b/core-java-modules/core-java-numbers-5/src/main/java/com/baeldung/intrange/IntRangeValueRange.java @@ -0,0 +1,26 @@ +package com.baeldung.intrange; + +import java.time.temporal.ValueRange; + +public class IntRangeValueRange { + + public static boolean isInClosedRange(Integer number, Integer lowerBound, Integer upperBound) { + final ValueRange range = ValueRange.of(lowerBound, upperBound); + return range.isValidIntValue(number); + } + + public static boolean isInOpenRange(Integer number, Integer lowerBound, Integer upperBound) { + final ValueRange range = ValueRange.of(lowerBound + 1, upperBound - 1); + return range.isValidIntValue(number); + } + + public static boolean isInOpenClosedRange(Integer number, Integer lowerBound, Integer upperBound) { + final ValueRange range = ValueRange.of(lowerBound + 1, upperBound); + return range.isValidIntValue(number); + } + + public static boolean isInClosedOpenRange(Integer number, Integer lowerBound, Integer upperBound) { + final ValueRange range = ValueRange.of(lowerBound, upperBound - 1); + return range.isValidIntValue(number); + } +} diff --git a/core-java-modules/core-java-numbers-5/src/test/java/com/baeldung/intrange/IntRangeApacheCommonsUnitTest.java b/core-java-modules/core-java-numbers-5/src/test/java/com/baeldung/intrange/IntRangeApacheCommonsUnitTest.java new file mode 100644 index 0000000000..d3b15d0e42 --- /dev/null +++ b/core-java-modules/core-java-numbers-5/src/test/java/com/baeldung/intrange/IntRangeApacheCommonsUnitTest.java @@ -0,0 +1,97 @@ +package com.baeldung.intrange; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +public class IntRangeApacheCommonsUnitTest { + + @Test + void givenIntRangeApacheCommons_whenIsInClosedRange_thenSuccess() { + // when + boolean resultLowerBound = IntRangeApacheCommons.isInClosedRange(10, 10, 20); + boolean resultUpperBound = IntRangeApacheCommons.isInClosedRange(20, 10, 20); + + // then + assertTrue(resultLowerBound); + assertTrue(resultUpperBound); + } + + @Test + void givenIntRangeApacheCommons_whenIsNotInClosedRange_thenFailure() { + // when + boolean resultLowerBound = IntRangeApacheCommons.isInClosedRange(8, 10, 20); + boolean resultUpperBound = IntRangeApacheCommons.isInClosedRange(22, 10, 20); + + // then + assertFalse(resultLowerBound); + assertFalse(resultUpperBound); + } + + @Test + void givenIntRangeApacheCommons_whenIsInOpenRange_thenSuccess() { + // when + boolean resultLowerBound = IntRangeApacheCommons.isInOpenRange(11, 10, 20); + boolean resultUpperBound = IntRangeApacheCommons.isInOpenRange(19, 10, 20); + + // then + assertTrue(resultLowerBound); + assertTrue(resultUpperBound); + } + + @Test + void givenIntRangeApacheCommons_whenIsNotInOpenRange_thenFailure() { + // when + boolean resultLowerBound = IntRangeApacheCommons.isInOpenRange(10, 10, 20); + boolean resultUpperBound = IntRangeApacheCommons.isInOpenRange(20, 10, 20); + + // then + assertFalse(resultLowerBound); + assertFalse(resultUpperBound); + } + + @Test + void givenIntRangeApacheCommons_whenIsInOpenClosedRange_thenSuccess() { + // when + boolean resultLowerBound = IntRangeApacheCommons.isInOpenClosedRange(11, 10, 20); + boolean resultUpperBound = IntRangeApacheCommons.isInOpenClosedRange(20, 10, 20); + + // then + assertTrue(resultLowerBound); + assertTrue(resultUpperBound); + } + + @Test + void givenIntRangeApacheCommons_whenIsNotInOpenClosedRange_thenFailure() { + // when + boolean resultLowerBound = IntRangeApacheCommons.isInOpenClosedRange(10, 10, 20); + boolean resultUpperBound = IntRangeApacheCommons.isInOpenClosedRange(21, 10, 20); + + // then + assertFalse(resultLowerBound); + assertFalse(resultUpperBound); + } + + @Test + void givenIntRangeApacheCommons_whenIsInClosedOpenRange_thenSuccess() { + // when + boolean resultLowerBound = IntRangeApacheCommons.isInClosedOpenRange(10, 10, 20); + boolean resultUpperBound = IntRangeApacheCommons.isInClosedOpenRange(19, 10, 20); + + // then + assertTrue(resultLowerBound); + assertTrue(resultUpperBound); + } + + @Test + void givenIntRangeApacheCommons_whenIsNotInClosedOpenRange_thenFailure() { + // when + boolean resultLowerBound = IntRangeApacheCommons.isInClosedOpenRange(9, 10, 20); + boolean resultUpperBound = IntRangeApacheCommons.isInClosedOpenRange(20, 10, 20); + + // then + assertFalse(resultLowerBound); + assertFalse(resultUpperBound); + } +} diff --git a/core-java-modules/core-java-numbers-5/src/test/java/com/baeldung/intrange/IntRangeGoogleGuavaUnitTest.java b/core-java-modules/core-java-numbers-5/src/test/java/com/baeldung/intrange/IntRangeGoogleGuavaUnitTest.java new file mode 100644 index 0000000000..9abdc20d31 --- /dev/null +++ b/core-java-modules/core-java-numbers-5/src/test/java/com/baeldung/intrange/IntRangeGoogleGuavaUnitTest.java @@ -0,0 +1,87 @@ +package com.baeldung.intrange; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +public class IntRangeGoogleGuavaUnitTest { + + @Test + void givenIntRangeGoogleGuava_whenIsInOpenRange_thenSuccess() { + // when + boolean result = IntRangeGoogleGuava.isInOpenRange(14, 10, 20); + + //then + assertTrue(result); + } + + @Test + void givenIntRangeGoogleGuava_whenIsNotInOpenRange_thenFailure() { + // when + boolean resultLowerBound = IntRangeGoogleGuava.isInOpenRange(10, 10, 20); + boolean resultUpperBound = IntRangeGoogleGuava.isInOpenRange(20, 10, 20); + + // then + assertFalse(resultLowerBound); + assertFalse(resultUpperBound); + } + + @Test + void givenIntRangeGoogleGuava_whenIsInClosedRange_thenSuccess() { + // when + boolean resultLowerBound = IntRangeGoogleGuava.isInClosedRange(-10, -10, 5); + boolean resultUpperBound = IntRangeGoogleGuava.isInClosedRange(5, -10, 5); + + // then + assertTrue(resultLowerBound); + assertTrue(resultUpperBound); + } + + @Test + void givenIntRangeGoogleGuava_whenIsNotInClosedRange_thenFailure() { + // when + boolean resultLowerBound = IntRangeGoogleGuava.isInClosedRange(-11, -10, 5); + boolean resultUpperBound = IntRangeGoogleGuava.isInClosedRange(6, -10, 5); + + //then + assertFalse(resultLowerBound); + assertFalse(resultUpperBound); + } + + @Test + void givenIntRangeGoogleGuava_whenIsInOpenClosedRange_thenSuccess() { + // when + boolean result = IntRangeGoogleGuava.isInOpenClosedRange(20, 10, 20); + + // then + assertTrue(result); + } + + @Test + void givenIntRangeGoogleGuava_whenIsNotInOpenClosedRange_thenFailure() { + // when + boolean result = IntRangeGoogleGuava.isInOpenClosedRange(10, 10, 20); + + // then + assertFalse(result); + } + + @Test + void givenIntRangeGoogleGuava_whenIsInClosedOpenRange_thenSuccess() { + // when + boolean result = IntRangeGoogleGuava.isInClosedOpenRange(10, 10, 20); + + // then + assertTrue(result); + } + + @Test + void givenIntRangeGoogleGuava_whenIsNotInClosedOpenRange_thenFailure() { + // when + boolean result = IntRangeGoogleGuava.isInClosedOpenRange(20, 10, 20); + + // then + assertFalse(result); + } +} diff --git a/core-java-modules/core-java-numbers-5/src/test/java/com/baeldung/intrange/IntRangeOperatorsUnitTest.java b/core-java-modules/core-java-numbers-5/src/test/java/com/baeldung/intrange/IntRangeOperatorsUnitTest.java new file mode 100644 index 0000000000..76abeb1ee3 --- /dev/null +++ b/core-java-modules/core-java-numbers-5/src/test/java/com/baeldung/intrange/IntRangeOperatorsUnitTest.java @@ -0,0 +1,87 @@ +package com.baeldung.intrange; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +public class IntRangeOperatorsUnitTest { + + @Test + void givenIntRangeOperators_whenIsInOpenRange_thenSuccess() { + // when + boolean result = IntRangeOperators.isInOpenRange(11, 10, 20); + + //then + assertTrue(result); + } + + @Test + void givenIntRangeOperators_whenIsNotInOpenRange_thenFailure() { + // when + boolean resultLowerBound = IntRangeOperators.isInOpenRange(10, 10, 20); + boolean resultUpperBound = IntRangeOperators.isInOpenRange(20, 10, 20); + + // then + assertFalse(resultLowerBound); + assertFalse(resultUpperBound); + } + + @Test + void givenIntRangeOperators_whenIsInClosedRange_thenSuccess() { + // when + boolean resultLowerBound = IntRangeOperators.isInClosedRange(-10, -10, 5); + boolean resultUpperBound = IntRangeOperators.isInClosedRange(5, -10, 5); + + // then + assertTrue(resultUpperBound); + assertTrue(resultLowerBound); + } + + @Test + void givenIntRangeOperators_whenIsNotInClosedRange_thenFailure() { + // when + boolean resultLowerBound = IntRangeOperators.isInClosedRange(-11, -10, 5); + boolean resultUpperBound = IntRangeOperators.isInClosedRange(6, -10, 5); + + // then + assertFalse(resultLowerBound); + assertFalse(resultUpperBound); + } + + @Test + void givenIntRangeOperators_whenIsInOpenClosedRange_thenSuccess() { + // when + boolean result = IntRangeOperators.isInOpenClosedRange(20, 10, 20); + + // then + assertTrue(result); + } + + @Test + void givenIntRangeOperators_whenIsNotInOpenClosedRange_thenFailure() { + // when + boolean result = IntRangeOperators.isInOpenClosedRange(10, 10, 20); + + // then + assertFalse(result); + } + + @Test + void givenIntRangeOperators_whenIsInClosedOpenRange_thenSuccess() { + // when + boolean result = IntRangeOperators.isInClosedOpenRange(10, 10, 20); + + // then + assertTrue(result); + } + + @Test + void givenIntRangeOperators_whenIsNotInClosedOpenRange_thenFailure() { + // when + boolean result = IntRangeOperators.isInClosedOpenRange(20, 10, 20); + + // then + assertFalse(result); + } +} diff --git a/core-java-modules/core-java-numbers-5/src/test/java/com/baeldung/intrange/IntRangeValueRangeUnitTest.java b/core-java-modules/core-java-numbers-5/src/test/java/com/baeldung/intrange/IntRangeValueRangeUnitTest.java new file mode 100644 index 0000000000..dc2105c675 --- /dev/null +++ b/core-java-modules/core-java-numbers-5/src/test/java/com/baeldung/intrange/IntRangeValueRangeUnitTest.java @@ -0,0 +1,97 @@ +package com.baeldung.intrange; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +public class IntRangeValueRangeUnitTest { + + @Test + void givenIntRangeValueRange_whenIsInClosedRange_thenSuccess() { + // when + boolean resultLowerBound = IntRangeValueRange.isInClosedRange(10, 10, 20); + boolean resultUpperBound = IntRangeValueRange.isInClosedRange(20, 10, 20); + + // then + assertTrue(resultLowerBound); + assertTrue(resultUpperBound); + } + + @Test + void givenIntRangeValueRange_whenIsNotInClosedRange_thenFailure() { + // when + boolean resultLowerBound = IntRangeValueRange.isInClosedRange(9, 10, 20); + boolean resultUpperBound = IntRangeValueRange.isInClosedRange(21, 10, 20); + + // then + assertFalse(resultLowerBound); + assertFalse(resultUpperBound); + } + + @Test + void givenIntRangeValueRange_whenIsInOpenRange_thenSuccess() { + // when + boolean resultLowerBound = IntRangeValueRange.isInOpenRange(11, 10, 20); + boolean resultUpperBound = IntRangeValueRange.isInOpenRange(19, 10, 20); + + // then + assertTrue(resultLowerBound); + assertTrue(resultUpperBound); + } + + @Test + void givenIntRangeValueRange_whenIsNotInOpenRange_thenFailure() { + // when + boolean resultLowerBound = IntRangeValueRange.isInOpenRange(10, 10, 20); + boolean resultUpperBound = IntRangeValueRange.isInOpenRange(20, 10, 20); + + // then + assertFalse(resultLowerBound); + assertFalse(resultUpperBound); + } + + @Test + void givenIntRangeValueRange_whenIsInOpenClosedRange_thenSuccess() { + // when + boolean resultLowerBound = IntRangeValueRange.isInOpenClosedRange(11, 10, 20); + boolean resultUpperBound = IntRangeValueRange.isInOpenClosedRange(20, 10, 20); + + // then + assertTrue(resultLowerBound); + assertTrue(resultUpperBound); + } + + @Test + void givenIntRangeValueRange_whenIsNotInOpenClosedRange_thenFailure() { + // when + boolean resultLowerBound = IntRangeValueRange.isInOpenClosedRange(10, 10, 20); + boolean resultUpperBound = IntRangeValueRange.isInOpenClosedRange(21, 10, 20); + + // then + assertFalse(resultLowerBound); + assertFalse(resultUpperBound); + } + + @Test + void givenIntRangeValueRange_whenIsInClosedOpenRange_thenSuccess() { + // when + boolean resultLowerBound = IntRangeValueRange.isInClosedOpenRange(10, 10, 20); + boolean resultUpperBound = IntRangeValueRange.isInClosedOpenRange(19, 10, 20); + + // then + assertTrue(resultLowerBound); + assertTrue(resultUpperBound); + } + + @Test + void givenIntRangeValueRange_whenIsNotInClosedOpenRange_thenFailure() { + // when + boolean resultLowerBound = IntRangeValueRange.isInClosedOpenRange(9, 10, 20); + boolean resultUpperBound = IntRangeValueRange.isInClosedOpenRange(20, 10, 20); + + // then + assertFalse(resultLowerBound); + assertFalse(resultUpperBound); + } +} diff --git a/core-java-modules/core-java-string-operations-4/README.md b/core-java-modules/core-java-string-operations-4/README.md index ac52ee4ab5..07af6d23c9 100644 --- a/core-java-modules/core-java-string-operations-4/README.md +++ b/core-java-modules/core-java-string-operations-4/README.md @@ -8,3 +8,4 @@ - [Check if a String Ends with a Certain Pattern in Java](https://www.baeldung.com/java-string-ends-pattern) - [Check if a Character is a Vowel in Java](https://www.baeldung.com/java-check-character-vowel) - [How to Truncate a String in Java](https://www.baeldung.com/java-truncating-strings) +- [Remove Whitespace From a String in Java](https://www.baeldung.com/java-string-remove-whitespace) diff --git a/core-java-modules/pom.xml b/core-java-modules/pom.xml index c650f064ab..981374a4ef 100644 --- a/core-java-modules/pom.xml +++ b/core-java-modules/pom.xml @@ -42,6 +42,7 @@ core-java-collections-maps-2 core-java-collections-maps-3 core-java-collections-maps-5 + core-java-concurrency-simple core-java-concurrency-2 core-java-concurrency-advanced core-java-concurrency-advanced-2 diff --git a/gradle-modules/gradle-7/conditional-dependency-demo/.gitignore b/gradle-modules/gradle-7/conditional-dependency-demo/.gitignore new file mode 100644 index 0000000000..c2065bc262 --- /dev/null +++ b/gradle-modules/gradle-7/conditional-dependency-demo/.gitignore @@ -0,0 +1,37 @@ +HELP.md +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ diff --git a/gradle-modules/gradle-7/conditional-dependency-demo/build.gradle.kts b/gradle-modules/gradle-7/conditional-dependency-demo/build.gradle.kts new file mode 100644 index 0000000000..95601a160d --- /dev/null +++ b/gradle-modules/gradle-7/conditional-dependency-demo/build.gradle.kts @@ -0,0 +1,21 @@ +plugins { + id("org.springframework.boot") version "2.7.2" + id("io.spring.dependency-management") version "1.0.11.RELEASE" + id("java") +} + +group = "com.baeldung.gradle" +version = "0.0.1-SNAPSHOT" + +repositories { + mavenCentral() +} + +dependencies { + implementation("org.springframework.boot:spring-boot-starter:2.7.2") + testImplementation("org.springframework.boot:spring-boot-starter-test:2.7.2") +} + +tasks.getByName("test") { + useJUnitPlatform() +} diff --git a/gradle-modules/gradle-7/conditional-dependency-demo/consumer1/build.gradle.kts b/gradle-modules/gradle-7/conditional-dependency-demo/consumer1/build.gradle.kts new file mode 100644 index 0000000000..9858c5b139 --- /dev/null +++ b/gradle-modules/gradle-7/conditional-dependency-demo/consumer1/build.gradle.kts @@ -0,0 +1,25 @@ +plugins { + id("java") +} + +group = "com.baeldung.gradle" +version = "0.0.1-SNAPSHOT" + +repositories { + mavenCentral() +} + +dependencies { + testImplementation("org.junit.jupiter:junit-jupiter-api:5.7.0") + testRuntimeOnly ("org.junit.jupiter:junit-jupiter-engine:5.7.0") + + if(project.hasProperty("isLocal")) { + implementation("com.baeldung.gradle:provider1") + } else { + implementation("com.baeldung.gradle:provider2") + } +} + +tasks.getByName("test") { + useJUnitPlatform() +} diff --git a/gradle-modules/gradle-7/conditional-dependency-demo/consumer2/build.gradle.kts b/gradle-modules/gradle-7/conditional-dependency-demo/consumer2/build.gradle.kts new file mode 100644 index 0000000000..2031aea59c --- /dev/null +++ b/gradle-modules/gradle-7/conditional-dependency-demo/consumer2/build.gradle.kts @@ -0,0 +1,30 @@ +plugins { + id("java") +} + +group = "com.baeldung.gradle" +version = "0.0.1-SNAPSHOT" + +repositories { + mavenCentral() +} + +configurations.all { + resolutionStrategy.dependencySubstitution { + if (project.hasProperty("isLocal")) + substitute(project(":provider1")) + .using(project(":provider2")) + .because("Project property override(isLocal).") + } +} + +dependencies { + implementation(project(":provider1")) + + testImplementation("org.junit.jupiter:junit-jupiter-api:5.7.0") + testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.7.0") +} + +tasks.getByName("test") { + useJUnitPlatform() +} diff --git a/gradle-modules/gradle-7/conditional-dependency-demo/gradle/wrapper/gradle-wrapper.jar b/gradle-modules/gradle-7/conditional-dependency-demo/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000..41d9927a4d Binary files /dev/null and b/gradle-modules/gradle-7/conditional-dependency-demo/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle-modules/gradle-7/conditional-dependency-demo/gradle/wrapper/gradle-wrapper.properties b/gradle-modules/gradle-7/conditional-dependency-demo/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000..00e33edef6 --- /dev/null +++ b/gradle-modules/gradle-7/conditional-dependency-demo/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.1-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradle-modules/gradle-7/conditional-dependency-demo/gradlew b/gradle-modules/gradle-7/conditional-dependency-demo/gradlew new file mode 100755 index 0000000000..1b6c787337 --- /dev/null +++ b/gradle-modules/gradle-7/conditional-dependency-demo/gradlew @@ -0,0 +1,234 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gradle-modules/gradle-7/conditional-dependency-demo/gradlew.bat b/gradle-modules/gradle-7/conditional-dependency-demo/gradlew.bat new file mode 100644 index 0000000000..107acd32c4 --- /dev/null +++ b/gradle-modules/gradle-7/conditional-dependency-demo/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/gradle-modules/gradle-7/conditional-dependency-demo/provider1/build.gradle.kts b/gradle-modules/gradle-7/conditional-dependency-demo/provider1/build.gradle.kts new file mode 100644 index 0000000000..d3dcd96b08 --- /dev/null +++ b/gradle-modules/gradle-7/conditional-dependency-demo/provider1/build.gradle.kts @@ -0,0 +1,19 @@ +plugins { + id("java") +} + +group = "com.baeldung.gradle" +version = "0.0.1-SNAPSHOT" + +repositories { + mavenCentral() +} + +dependencies { + testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.0") + testRuntimeOnly ("org.junit.jupiter:junit-jupiter-engine:5.9.0") +} + +tasks.getByName("test") { + useJUnitPlatform() +} diff --git a/gradle-modules/gradle-7/conditional-dependency-demo/provider2/build.gradle.kts b/gradle-modules/gradle-7/conditional-dependency-demo/provider2/build.gradle.kts new file mode 100644 index 0000000000..d3dcd96b08 --- /dev/null +++ b/gradle-modules/gradle-7/conditional-dependency-demo/provider2/build.gradle.kts @@ -0,0 +1,19 @@ +plugins { + id("java") +} + +group = "com.baeldung.gradle" +version = "0.0.1-SNAPSHOT" + +repositories { + mavenCentral() +} + +dependencies { + testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.0") + testRuntimeOnly ("org.junit.jupiter:junit-jupiter-engine:5.9.0") +} + +tasks.getByName("test") { + useJUnitPlatform() +} diff --git a/gradle-modules/gradle-7/conditional-dependency-demo/settings.gradle.kts b/gradle-modules/gradle-7/conditional-dependency-demo/settings.gradle.kts new file mode 100644 index 0000000000..b6a25cf09d --- /dev/null +++ b/gradle-modules/gradle-7/conditional-dependency-demo/settings.gradle.kts @@ -0,0 +1,5 @@ +rootProject.name = "conditional-dependency-demo" +include("provider1") +include("provider2") +include("consumer1") +include("consumer2") diff --git a/gradle-modules/gradle-7/conditional-dependency-demo/src/main/java/com/baeldung/gradle/conditionaldependencydemo/ConditionalDependencyDemoApplication.java b/gradle-modules/gradle-7/conditional-dependency-demo/src/main/java/com/baeldung/gradle/conditionaldependencydemo/ConditionalDependencyDemoApplication.java new file mode 100644 index 0000000000..7921b72143 --- /dev/null +++ b/gradle-modules/gradle-7/conditional-dependency-demo/src/main/java/com/baeldung/gradle/conditionaldependencydemo/ConditionalDependencyDemoApplication.java @@ -0,0 +1,15 @@ +package com.baeldung.gradle.conditionaldependencydemo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +import java.util.Arrays; + +@SpringBootApplication +public class ConditionalDependencyDemoApplication { + + public static void main(String[] args) { + SpringApplication.run(ConditionalDependencyDemoApplication.class, args); + } + +} diff --git a/gradle-modules/gradle-7/conditional-dependency-demo/src/main/resources/application.properties b/gradle-modules/gradle-7/conditional-dependency-demo/src/main/resources/application.properties new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/gradle-modules/gradle-7/conditional-dependency-demo/src/main/resources/application.properties @@ -0,0 +1 @@ + diff --git a/gradle-modules/gradle-7/conditional-dependency-demo/src/test/java/com/baeldung/gradle/conditionaldependencydemo/ConditionalDependencyDemoApplicationTests.java b/gradle-modules/gradle-7/conditional-dependency-demo/src/test/java/com/baeldung/gradle/conditionaldependencydemo/ConditionalDependencyDemoApplicationTests.java new file mode 100644 index 0000000000..788dbd962a --- /dev/null +++ b/gradle-modules/gradle-7/conditional-dependency-demo/src/test/java/com/baeldung/gradle/conditionaldependencydemo/ConditionalDependencyDemoApplicationTests.java @@ -0,0 +1,13 @@ +package com.baeldung.gradle.conditionaldependencydemo; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class ConditionalDependencyDemoApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/gradle-modules/settings.gradle b/gradle-modules/settings.gradle index f6e0614a10..34dbd0cf53 100644 --- a/gradle-modules/settings.gradle +++ b/gradle-modules/settings.gradle @@ -2,3 +2,4 @@ rootProject.name = 'gradle-modules' include 'gradle' include 'gradle-5' include 'gradle-6' +include 'gradle-7' diff --git a/jackson-modules/jackson/README.md b/jackson-modules/jackson-core/README.md similarity index 100% rename from jackson-modules/jackson/README.md rename to jackson-modules/jackson-core/README.md diff --git a/jackson-modules/jackson/pom.xml b/jackson-modules/jackson-core/pom.xml similarity index 96% rename from jackson-modules/jackson/pom.xml rename to jackson-modules/jackson-core/pom.xml index 9df0f40874..667e48c88d 100644 --- a/jackson-modules/jackson/pom.xml +++ b/jackson-modules/jackson-core/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 - jackson + jackson-core 0.0.1-SNAPSHOT - jackson + jackson-core com.baeldung diff --git a/jackson-modules/jackson/src/main/java/com/baeldung/jackson/deserialization/jacksoninject/Person.java b/jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/deserialization/jacksoninject/Person.java similarity index 100% rename from jackson-modules/jackson/src/main/java/com/baeldung/jackson/deserialization/jacksoninject/Person.java rename to jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/deserialization/jacksoninject/Person.java diff --git a/jackson-modules/jackson/src/main/java/com/baeldung/jackson/deserialization/jsonanysetter/Inventory.java b/jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/deserialization/jsonanysetter/Inventory.java similarity index 100% rename from jackson-modules/jackson/src/main/java/com/baeldung/jackson/deserialization/jsonanysetter/Inventory.java rename to jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/deserialization/jsonanysetter/Inventory.java diff --git a/jackson-modules/jackson/src/main/java/com/baeldung/jackson/deserialization/jsondeserialize/Book.java b/jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/deserialization/jsondeserialize/Book.java similarity index 100% rename from jackson-modules/jackson/src/main/java/com/baeldung/jackson/deserialization/jsondeserialize/Book.java rename to jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/deserialization/jsondeserialize/Book.java diff --git a/jackson-modules/jackson/src/main/java/com/baeldung/jackson/deserialization/jsondeserialize/CustomDateDeserializer.java b/jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/deserialization/jsondeserialize/CustomDateDeserializer.java similarity index 100% rename from jackson-modules/jackson/src/main/java/com/baeldung/jackson/deserialization/jsondeserialize/CustomDateDeserializer.java rename to jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/deserialization/jsondeserialize/CustomDateDeserializer.java diff --git a/jackson-modules/jackson/src/main/java/com/baeldung/jackson/domain/Person.java b/jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/domain/Person.java similarity index 100% rename from jackson-modules/jackson/src/main/java/com/baeldung/jackson/domain/Person.java rename to jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/domain/Person.java diff --git a/jackson-modules/jackson/src/main/java/com/baeldung/jackson/inheritance/Event.java b/jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/inheritance/Event.java similarity index 100% rename from jackson-modules/jackson/src/main/java/com/baeldung/jackson/inheritance/Event.java rename to jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/inheritance/Event.java diff --git a/jackson-modules/jackson/src/main/java/com/baeldung/jackson/inheritance/IgnoranceAnnotationStructure.java b/jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/inheritance/IgnoranceAnnotationStructure.java similarity index 100% rename from jackson-modules/jackson/src/main/java/com/baeldung/jackson/inheritance/IgnoranceAnnotationStructure.java rename to jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/inheritance/IgnoranceAnnotationStructure.java diff --git a/jackson-modules/jackson/src/main/java/com/baeldung/jackson/inheritance/IgnoranceMixinOrIntrospection.java b/jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/inheritance/IgnoranceMixinOrIntrospection.java similarity index 100% rename from jackson-modules/jackson/src/main/java/com/baeldung/jackson/inheritance/IgnoranceMixinOrIntrospection.java rename to jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/inheritance/IgnoranceMixinOrIntrospection.java diff --git a/jackson-modules/jackson/src/main/java/com/baeldung/jackson/inheritance/ItemIdAddedToUser.java b/jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/inheritance/ItemIdAddedToUser.java similarity index 100% rename from jackson-modules/jackson/src/main/java/com/baeldung/jackson/inheritance/ItemIdAddedToUser.java rename to jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/inheritance/ItemIdAddedToUser.java diff --git a/jackson-modules/jackson/src/main/java/com/baeldung/jackson/inheritance/ItemIdRemovedFromUser.java b/jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/inheritance/ItemIdRemovedFromUser.java similarity index 100% rename from jackson-modules/jackson/src/main/java/com/baeldung/jackson/inheritance/ItemIdRemovedFromUser.java rename to jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/inheritance/ItemIdRemovedFromUser.java diff --git a/jackson-modules/jackson/src/main/java/com/baeldung/jackson/inheritance/SubTypeConstructorStructure.java b/jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/inheritance/SubTypeConstructorStructure.java similarity index 100% rename from jackson-modules/jackson/src/main/java/com/baeldung/jackson/inheritance/SubTypeConstructorStructure.java rename to jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/inheritance/SubTypeConstructorStructure.java diff --git a/jackson-modules/jackson/src/main/java/com/baeldung/jackson/inheritance/SubTypeConversionStructure.java b/jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/inheritance/SubTypeConversionStructure.java similarity index 100% rename from jackson-modules/jackson/src/main/java/com/baeldung/jackson/inheritance/SubTypeConversionStructure.java rename to jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/inheritance/SubTypeConversionStructure.java diff --git a/jackson-modules/jackson/src/main/java/com/baeldung/jackson/inheritance/TypeInfoAnnotatedStructure.java b/jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/inheritance/TypeInfoAnnotatedStructure.java similarity index 100% rename from jackson-modules/jackson/src/main/java/com/baeldung/jackson/inheritance/TypeInfoAnnotatedStructure.java rename to jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/inheritance/TypeInfoAnnotatedStructure.java diff --git a/jackson-modules/jackson/src/main/java/com/baeldung/jackson/inheritance/TypeInfoStructure.java b/jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/inheritance/TypeInfoStructure.java similarity index 100% rename from jackson-modules/jackson/src/main/java/com/baeldung/jackson/inheritance/TypeInfoStructure.java rename to jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/inheritance/TypeInfoStructure.java diff --git a/jackson-modules/jackson/src/main/java/com/baeldung/jackson/jacksonvsgson/ActorJackson.java b/jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/jacksonvsgson/ActorJackson.java similarity index 100% rename from jackson-modules/jackson/src/main/java/com/baeldung/jackson/jacksonvsgson/ActorJackson.java rename to jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/jacksonvsgson/ActorJackson.java diff --git a/jackson-modules/jackson/src/main/java/com/baeldung/jackson/jacksonvsgson/ActorJacksonSerializer.java b/jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/jacksonvsgson/ActorJacksonSerializer.java similarity index 100% rename from jackson-modules/jackson/src/main/java/com/baeldung/jackson/jacksonvsgson/ActorJacksonSerializer.java rename to jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/jacksonvsgson/ActorJacksonSerializer.java diff --git a/jackson-modules/jackson/src/main/java/com/baeldung/jackson/jacksonvsgson/Movie.java b/jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/jacksonvsgson/Movie.java similarity index 100% rename from jackson-modules/jackson/src/main/java/com/baeldung/jackson/jacksonvsgson/Movie.java rename to jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/jacksonvsgson/Movie.java diff --git a/jackson-modules/jackson/src/main/java/com/baeldung/jackson/jacksonvsgson/MovieWithNullValue.java b/jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/jacksonvsgson/MovieWithNullValue.java similarity index 100% rename from jackson-modules/jackson/src/main/java/com/baeldung/jackson/jacksonvsgson/MovieWithNullValue.java rename to jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/jacksonvsgson/MovieWithNullValue.java diff --git a/jackson-modules/jackson/src/main/java/com/baeldung/jackson/jsonnode/GetAllKeysFromJSON.java b/jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/jsonnode/GetAllKeysFromJSON.java similarity index 100% rename from jackson-modules/jackson/src/main/java/com/baeldung/jackson/jsonnode/GetAllKeysFromJSON.java rename to jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/jsonnode/GetAllKeysFromJSON.java diff --git a/jackson-modules/jackson/src/main/java/com/baeldung/jackson/node/JsonNodeIterator.java b/jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/node/JsonNodeIterator.java similarity index 100% rename from jackson-modules/jackson/src/main/java/com/baeldung/jackson/node/JsonNodeIterator.java rename to jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/node/JsonNodeIterator.java diff --git a/jackson-modules/jackson/src/main/java/com/baeldung/jackson/optionalwithjackson/Book.java b/jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/optionalwithjackson/Book.java similarity index 100% rename from jackson-modules/jackson/src/main/java/com/baeldung/jackson/optionalwithjackson/Book.java rename to jackson-modules/jackson-core/src/main/java/com/baeldung/jackson/optionalwithjackson/Book.java diff --git a/jackson-modules/jackson/src/main/resources/example1.json b/jackson-modules/jackson-core/src/main/resources/example1.json similarity index 100% rename from jackson-modules/jackson/src/main/resources/example1.json rename to jackson-modules/jackson-core/src/main/resources/example1.json diff --git a/jackson-modules/jackson/src/main/resources/example2.json b/jackson-modules/jackson-core/src/main/resources/example2.json similarity index 100% rename from jackson-modules/jackson/src/main/resources/example2.json rename to jackson-modules/jackson-core/src/main/resources/example2.json diff --git a/jackson-modules/jackson/src/main/resources/logback.xml b/jackson-modules/jackson-core/src/main/resources/logback.xml similarity index 100% rename from jackson-modules/jackson/src/main/resources/logback.xml rename to jackson-modules/jackson-core/src/main/resources/logback.xml diff --git a/jackson-modules/jackson/src/test/java/com/baeldung/jackson/dtos/Address.java b/jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/dtos/Address.java similarity index 100% rename from jackson-modules/jackson/src/test/java/com/baeldung/jackson/dtos/Address.java rename to jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/dtos/Address.java diff --git a/jackson-modules/jackson/src/test/java/com/baeldung/jackson/dtos/MyDto.java b/jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/dtos/MyDto.java similarity index 100% rename from jackson-modules/jackson/src/test/java/com/baeldung/jackson/dtos/MyDto.java rename to jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/dtos/MyDto.java diff --git a/jackson-modules/jackson/src/test/java/com/baeldung/jackson/dtos/Person.java b/jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/dtos/Person.java similarity index 100% rename from jackson-modules/jackson/src/test/java/com/baeldung/jackson/dtos/Person.java rename to jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/dtos/Person.java diff --git a/jackson-modules/jackson/src/test/java/com/baeldung/jackson/dtos/User.java b/jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/dtos/User.java similarity index 100% rename from jackson-modules/jackson/src/test/java/com/baeldung/jackson/dtos/User.java rename to jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/dtos/User.java diff --git a/jackson-modules/jackson/src/test/java/com/baeldung/jackson/inheritance/IgnoranceUnitTest.java b/jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/inheritance/IgnoranceUnitTest.java similarity index 100% rename from jackson-modules/jackson/src/test/java/com/baeldung/jackson/inheritance/IgnoranceUnitTest.java rename to jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/inheritance/IgnoranceUnitTest.java diff --git a/jackson-modules/jackson/src/test/java/com/baeldung/jackson/inheritance/ItemIdRemovedFromUserUnitTest.java b/jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/inheritance/ItemIdRemovedFromUserUnitTest.java similarity index 100% rename from jackson-modules/jackson/src/test/java/com/baeldung/jackson/inheritance/ItemIdRemovedFromUserUnitTest.java rename to jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/inheritance/ItemIdRemovedFromUserUnitTest.java diff --git a/jackson-modules/jackson/src/test/java/com/baeldung/jackson/inheritance/SubTypeHandlingUnitTest.java b/jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/inheritance/SubTypeHandlingUnitTest.java similarity index 100% rename from jackson-modules/jackson/src/test/java/com/baeldung/jackson/inheritance/SubTypeHandlingUnitTest.java rename to jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/inheritance/SubTypeHandlingUnitTest.java diff --git a/jackson-modules/jackson/src/test/java/com/baeldung/jackson/inheritance/TypeInfoInclusionUnitTest.java b/jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/inheritance/TypeInfoInclusionUnitTest.java similarity index 100% rename from jackson-modules/jackson/src/test/java/com/baeldung/jackson/inheritance/TypeInfoInclusionUnitTest.java rename to jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/inheritance/TypeInfoInclusionUnitTest.java diff --git a/jackson-modules/jackson/src/test/java/com/baeldung/jackson/jacksonvsgson/JacksonDeserializeUnitTest.java b/jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/jacksonvsgson/JacksonDeserializeUnitTest.java similarity index 100% rename from jackson-modules/jackson/src/test/java/com/baeldung/jackson/jacksonvsgson/JacksonDeserializeUnitTest.java rename to jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/jacksonvsgson/JacksonDeserializeUnitTest.java diff --git a/jackson-modules/jackson/src/test/java/com/baeldung/jackson/jacksonvsgson/JacksonSerializeUnitTest.java b/jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/jacksonvsgson/JacksonSerializeUnitTest.java similarity index 100% rename from jackson-modules/jackson/src/test/java/com/baeldung/jackson/jacksonvsgson/JacksonSerializeUnitTest.java rename to jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/jacksonvsgson/JacksonSerializeUnitTest.java diff --git a/jackson-modules/jackson/src/test/java/com/baeldung/jackson/jsoncompare/JsonCompareUnitTest.java b/jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/jsoncompare/JsonCompareUnitTest.java similarity index 100% rename from jackson-modules/jackson/src/test/java/com/baeldung/jackson/jsoncompare/JsonCompareUnitTest.java rename to jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/jsoncompare/JsonCompareUnitTest.java diff --git a/jackson-modules/jackson/src/test/java/com/baeldung/jackson/jsonnode/GetAllKeysFromJSONUnitTest.java b/jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/jsonnode/GetAllKeysFromJSONUnitTest.java similarity index 100% rename from jackson-modules/jackson/src/test/java/com/baeldung/jackson/jsonnode/GetAllKeysFromJSONUnitTest.java rename to jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/jsonnode/GetAllKeysFromJSONUnitTest.java diff --git a/jackson-modules/jackson/src/test/java/com/baeldung/jackson/node/ExampleStructure.java b/jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/node/ExampleStructure.java similarity index 100% rename from jackson-modules/jackson/src/test/java/com/baeldung/jackson/node/ExampleStructure.java rename to jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/node/ExampleStructure.java diff --git a/jackson-modules/jackson/src/test/java/com/baeldung/jackson/node/JsonNodeIteratorUnitTest.java b/jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/node/JsonNodeIteratorUnitTest.java similarity index 100% rename from jackson-modules/jackson/src/test/java/com/baeldung/jackson/node/JsonNodeIteratorUnitTest.java rename to jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/node/JsonNodeIteratorUnitTest.java diff --git a/jackson-modules/jackson/src/test/java/com/baeldung/jackson/node/NodeBean.java b/jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/node/NodeBean.java similarity index 100% rename from jackson-modules/jackson/src/test/java/com/baeldung/jackson/node/NodeBean.java rename to jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/node/NodeBean.java diff --git a/jackson-modules/jackson/src/test/java/com/baeldung/jackson/node/NodeOperationUnitTest.java b/jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/node/NodeOperationUnitTest.java similarity index 100% rename from jackson-modules/jackson/src/test/java/com/baeldung/jackson/node/NodeOperationUnitTest.java rename to jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/node/NodeOperationUnitTest.java diff --git a/jackson-modules/jackson/src/test/java/com/baeldung/jackson/optionalwithjackson/OptionalTypeUnitTest.java b/jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/optionalwithjackson/OptionalTypeUnitTest.java similarity index 100% rename from jackson-modules/jackson/src/test/java/com/baeldung/jackson/optionalwithjackson/OptionalTypeUnitTest.java rename to jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/optionalwithjackson/OptionalTypeUnitTest.java diff --git a/jackson-modules/jackson/src/test/java/com/baeldung/jackson/sandbox/JacksonPrettyPrintUnitTest.java b/jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/sandbox/JacksonPrettyPrintUnitTest.java similarity index 100% rename from jackson-modules/jackson/src/test/java/com/baeldung/jackson/sandbox/JacksonPrettyPrintUnitTest.java rename to jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/sandbox/JacksonPrettyPrintUnitTest.java diff --git a/jackson-modules/jackson/src/test/java/com/baeldung/jackson/sandbox/SandboxUnitTest.java b/jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/sandbox/SandboxUnitTest.java similarity index 100% rename from jackson-modules/jackson/src/test/java/com/baeldung/jackson/sandbox/SandboxUnitTest.java rename to jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/sandbox/SandboxUnitTest.java diff --git a/jackson-modules/jackson/src/test/java/com/baeldung/jackson/sandbox/TestElement.java b/jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/sandbox/TestElement.java similarity index 100% rename from jackson-modules/jackson/src/test/java/com/baeldung/jackson/sandbox/TestElement.java rename to jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/sandbox/TestElement.java diff --git a/jackson-modules/jackson/src/test/java/com/baeldung/jackson/test/UnitTestSuite.java b/jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/test/UnitTestSuite.java similarity index 100% rename from jackson-modules/jackson/src/test/java/com/baeldung/jackson/test/UnitTestSuite.java rename to jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/test/UnitTestSuite.java diff --git a/jackson-modules/jackson/src/test/java/com/baeldung/jackson/try1/IEntity.java b/jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/try1/IEntity.java similarity index 100% rename from jackson-modules/jackson/src/test/java/com/baeldung/jackson/try1/IEntity.java rename to jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/try1/IEntity.java diff --git a/jackson-modules/jackson/src/test/java/com/baeldung/jackson/try1/RestLoaderRequest.java b/jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/try1/RestLoaderRequest.java similarity index 100% rename from jackson-modules/jackson/src/test/java/com/baeldung/jackson/try1/RestLoaderRequest.java rename to jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/try1/RestLoaderRequest.java diff --git a/jackson-modules/jackson/src/test/java/com/baeldung/jackson/try1/RestLoaderRequestDeserializer.java b/jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/try1/RestLoaderRequestDeserializer.java similarity index 100% rename from jackson-modules/jackson/src/test/java/com/baeldung/jackson/try1/RestLoaderRequestDeserializer.java rename to jackson-modules/jackson-core/src/test/java/com/baeldung/jackson/try1/RestLoaderRequestDeserializer.java diff --git a/jackson-modules/jackson/src/test/resources/author-jsonpropertyorder-schema.json b/jackson-modules/jackson-core/src/test/resources/author-jsonpropertyorder-schema.json similarity index 100% rename from jackson-modules/jackson/src/test/resources/author-jsonpropertyorder-schema.json rename to jackson-modules/jackson-core/src/test/resources/author-jsonpropertyorder-schema.json diff --git a/jackson-modules/jackson/src/test/resources/node_example.json b/jackson-modules/jackson-core/src/test/resources/node_example.json similarity index 100% rename from jackson-modules/jackson/src/test/resources/node_example.json rename to jackson-modules/jackson-core/src/test/resources/node_example.json diff --git a/jackson-modules/pom.xml b/jackson-modules/pom.xml index 14e34a41bf..7a7e08714f 100644 --- a/jackson-modules/pom.xml +++ b/jackson-modules/pom.xml @@ -14,11 +14,11 @@ ../parent-java - - jackson + jackson-annotations jackson-conversions jackson-conversions-2 + jackson-core jackson-custom-conversions jackson-exceptions diff --git a/maven-modules/README.md b/maven-modules/README.md index 19f0473a58..29a69d37e4 100644 --- a/maven-modules/README.md +++ b/maven-modules/README.md @@ -8,3 +8,4 @@ This module contains articles about Apache Maven. Please refer to its submodules - [Apache Maven Standard Directory Layout](https://www.baeldung.com/maven-directory-structure) - [Multi-Module Project with Maven](https://www.baeldung.com/maven-multi-module) - [Maven Packaging Types](https://www.baeldung.com/maven-packaging-types) +- [Maven Snapshot Repository vs Release Repository](https://www.baeldung.com/maven-snapshot-release-repository) diff --git a/maven-modules/maven-generate-war/pom.xml b/maven-modules/maven-generate-war/pom.xml index 51eb54846c..cf8952e72f 100644 --- a/maven-modules/maven-generate-war/pom.xml +++ b/maven-modules/maven-generate-war/pom.xml @@ -11,11 +11,10 @@ Spring boot project to demonstrate war file generation - org.springframework.boot - spring-boot-starter-parent - 2.5.4 - - + com.baeldung + parent-boot-2 + 0.0.1-SNAPSHOT + ../../parent-boot-2 @@ -58,12 +57,24 @@ + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + ${maven.compiler.source.version} + ${maven.compiler.target.version} + + 11 2.17.1 + 3.10.1 + 11 + 11 \ No newline at end of file diff --git a/maven-modules/maven-generate-war/src/test/java/com/baeldung/MavenGenerateWarApplicationTests.java b/maven-modules/maven-generate-war/src/test/java/com/baeldung/SpringContextTest.java similarity index 81% rename from maven-modules/maven-generate-war/src/test/java/com/baeldung/MavenGenerateWarApplicationTests.java rename to maven-modules/maven-generate-war/src/test/java/com/baeldung/SpringContextTest.java index 71f4908d38..e8be16fd3a 100644 --- a/maven-modules/maven-generate-war/src/test/java/com/baeldung/MavenGenerateWarApplicationTests.java +++ b/maven-modules/maven-generate-war/src/test/java/com/baeldung/SpringContextTest.java @@ -4,7 +4,7 @@ import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; @SpringBootTest -class MavenGenerateWarApplicationTests { +class SpringContextTest { @Test void contextLoads() { diff --git a/persistence-modules/apache-derby/pom.xml b/persistence-modules/apache-derby/pom.xml index f7f5ca7503..98901b5d80 100644 --- a/persistence-modules/apache-derby/pom.xml +++ b/persistence-modules/apache-derby/pom.xml @@ -16,14 +16,19 @@ org.apache.derby derby - 10.13.1.1 + ${derby.version} org.apache.derby derbyclient - 10.13.1.1 + ${derbyclient.version} + + 10.13.1.1 + 10.13.1.1 + + \ No newline at end of file diff --git a/persistence-modules/core-java-persistence-2/pom.xml b/persistence-modules/core-java-persistence-2/pom.xml index d6109d2ae9..1d9852ae53 100644 --- a/persistence-modules/core-java-persistence-2/pom.xml +++ b/persistence-modules/core-java-persistence-2/pom.xml @@ -44,12 +44,12 @@ org.jooq jooq - 3.11.11 + ${jooq.version} org.json json - 20220320 + ${json.version} @@ -57,6 +57,8 @@ 8.4.1.jre11 10.2.0.4.0 8.0.22 + 3.11.11 + 20220320 \ No newline at end of file diff --git a/persistence-modules/fauna/pom.xml b/persistence-modules/fauna/pom.xml index 8c985e0b7c..90fa596406 100644 --- a/persistence-modules/fauna/pom.xml +++ b/persistence-modules/fauna/pom.xml @@ -3,11 +3,9 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - com.baeldung fauna - 0.0.1-SNAPSHOT fauna - Blogging Service built with FaunaDB + Code snippets for FaunaDB articles com.baeldung @@ -28,7 +26,7 @@ com.faunadb faunadb-java - 4.2.0 + ${faunadb.version} compile @@ -41,6 +39,13 @@ spring-security-test test + + + + org.projectlombok + lombok + provided + @@ -55,6 +60,7 @@ 17 3.17.0 + 4.2.0 \ No newline at end of file diff --git a/persistence-modules/fauna/src/main/java/com/baeldung/healthapp/FaunaClients.java b/persistence-modules/fauna/src/main/java/com/baeldung/healthapp/FaunaClients.java new file mode 100644 index 0000000000..c4e1d52b5b --- /dev/null +++ b/persistence-modules/fauna/src/main/java/com/baeldung/healthapp/FaunaClients.java @@ -0,0 +1,42 @@ +package com.baeldung.healthapp; + +import java.net.MalformedURLException; +import java.util.HashMap; +import java.util.Map; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +import com.faunadb.client.FaunaClient; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@ConfigurationProperties +@Component +public class FaunaClients { + + private final Map faunaConnections = new HashMap<>(); + private final Map faunaSecrets = new HashMap<>(); + + public FaunaClient getFaunaClient(String region) throws MalformedURLException { + + String faunaUrl = faunaConnections.get(region); + String faunaSecret = faunaSecrets.get(region); + + log.info("Creating Fauna Client for Region:{} with URL:{}", region, faunaUrl); + + return FaunaClient.builder() + .withEndpoint(faunaUrl) + .withSecret(faunaSecret) + .build(); + } + + public Map getFaunaConnections() { + return faunaConnections; + } + + public Map getFaunaSecrets() { + return faunaSecrets; + } +} diff --git a/persistence-modules/fauna/src/main/java/com/baeldung/healthapp/FaunaHealthApplication.java b/persistence-modules/fauna/src/main/java/com/baeldung/healthapp/FaunaHealthApplication.java new file mode 100644 index 0000000000..ac09e4cd36 --- /dev/null +++ b/persistence-modules/fauna/src/main/java/com/baeldung/healthapp/FaunaHealthApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.healthapp; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class FaunaHealthApplication { + + public static void main(String[] args) { + SpringApplication.run(FaunaHealthApplication.class, args); + } + +} diff --git a/persistence-modules/fauna/src/main/java/com/baeldung/healthapp/domain/HealthData.java b/persistence-modules/fauna/src/main/java/com/baeldung/healthapp/domain/HealthData.java new file mode 100644 index 0000000000..9ee320c3d5 --- /dev/null +++ b/persistence-modules/fauna/src/main/java/com/baeldung/healthapp/domain/HealthData.java @@ -0,0 +1,17 @@ +package com.baeldung.healthapp.domain; + +import java.time.ZonedDateTime; + +public record HealthData( + + String userId, + + float temperature, + float pulseRate, + int bpSystolic, + int bpDiastolic, + + double latitude, + double longitude, + ZonedDateTime timestamp) { +} diff --git a/persistence-modules/fauna/src/main/java/com/baeldung/healthapp/service/DefaultGeoLocationService.java b/persistence-modules/fauna/src/main/java/com/baeldung/healthapp/service/DefaultGeoLocationService.java new file mode 100644 index 0000000000..b643714972 --- /dev/null +++ b/persistence-modules/fauna/src/main/java/com/baeldung/healthapp/service/DefaultGeoLocationService.java @@ -0,0 +1,12 @@ +package com.baeldung.healthapp.service; + +import org.springframework.stereotype.Component; + +@Component +public class DefaultGeoLocationService implements GeoLocationService { + + @Override + public String getRegion(double latitude, double longitude) { + return "EU"; + } +} diff --git a/persistence-modules/fauna/src/main/java/com/baeldung/healthapp/service/DefaultHealthService.java b/persistence-modules/fauna/src/main/java/com/baeldung/healthapp/service/DefaultHealthService.java new file mode 100644 index 0000000000..8e44b4b243 --- /dev/null +++ b/persistence-modules/fauna/src/main/java/com/baeldung/healthapp/service/DefaultHealthService.java @@ -0,0 +1,58 @@ +package com.baeldung.healthapp.service; + +import static com.faunadb.client.query.Language.Collection; +import static com.faunadb.client.query.Language.Create; +import static com.faunadb.client.query.Language.Now; +import static com.faunadb.client.query.Language.Obj; +import static com.faunadb.client.query.Language.Value; + +import java.net.MalformedURLException; +import java.util.Map; +import java.util.concurrent.ExecutionException; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.baeldung.healthapp.FaunaClients; +import com.baeldung.healthapp.domain.HealthData; +import com.faunadb.client.FaunaClient; +import com.faunadb.client.types.Value; + +import lombok.extern.slf4j.Slf4j; + +@Component +@Slf4j +public class DefaultHealthService implements HealthService { + + @Autowired + private GeoLocationService geoLocationService; + + @Autowired + private FaunaClients faunaClients; + + @Override + public void process(HealthData healthData) throws MalformedURLException, InterruptedException, ExecutionException { + + String region = geoLocationService.getRegion( // + healthData.latitude(), // + healthData.longitude()); + + FaunaClient faunaClient = faunaClients.getFaunaClient(region); + + Value queryResponse = faunaClient.query( + Create(Collection("healthdata"), + Obj("data", + Obj(Map.of( + "userId", Value(healthData.userId()), + "temperature", Value(healthData.temperature()), + "pulseRate", Value(healthData.pulseRate()), + "bpSystolic", Value(healthData.bpSystolic()), + "bpDiastolic", Value(healthData.bpDiastolic()), + "latitude", Value(healthData.latitude()), + "longitude", Value(healthData.longitude()), + "timestamp", Now())))) + ).get(); + + log.info("Query response received from Fauna: {}", queryResponse); + } +} diff --git a/persistence-modules/fauna/src/main/java/com/baeldung/healthapp/service/GeoLocationService.java b/persistence-modules/fauna/src/main/java/com/baeldung/healthapp/service/GeoLocationService.java new file mode 100644 index 0000000000..43a3204610 --- /dev/null +++ b/persistence-modules/fauna/src/main/java/com/baeldung/healthapp/service/GeoLocationService.java @@ -0,0 +1,6 @@ +package com.baeldung.healthapp.service; + +public interface GeoLocationService { + + String getRegion(double latitude, double longitude); +} diff --git a/persistence-modules/fauna/src/main/java/com/baeldung/healthapp/service/HealthService.java b/persistence-modules/fauna/src/main/java/com/baeldung/healthapp/service/HealthService.java new file mode 100644 index 0000000000..eadf12cc08 --- /dev/null +++ b/persistence-modules/fauna/src/main/java/com/baeldung/healthapp/service/HealthService.java @@ -0,0 +1,10 @@ +package com.baeldung.healthapp.service; + +import java.net.MalformedURLException; +import java.util.concurrent.ExecutionException; + +import com.baeldung.healthapp.domain.HealthData; + +public interface HealthService { + void process(HealthData healthData) throws MalformedURLException, InterruptedException, ExecutionException; +} diff --git a/persistence-modules/fauna/src/main/resources/application.properties b/persistence-modules/fauna/src/main/resources/application.properties index e69de29bb2..0f50dfa8b3 100644 --- a/persistence-modules/fauna/src/main/resources/application.properties +++ b/persistence-modules/fauna/src/main/resources/application.properties @@ -0,0 +1,10 @@ +# Fauna Blog Service +fauna.region=EU +fauna.secret= + +# Fauna Health App +fauna-connections.EU=https://db.eu.fauna.com/ +fauna-secrets.EU=eu-secret + +fauna-connections.US=https://db.us.fauna.com/ +fauna-secrets.US=us-secret \ No newline at end of file diff --git a/persistence-modules/fauna/src/test/java/com/baeldung/healthapp/service/DefaultHealthServiceManualTest.java b/persistence-modules/fauna/src/test/java/com/baeldung/healthapp/service/DefaultHealthServiceManualTest.java new file mode 100644 index 0000000000..f77eb623b6 --- /dev/null +++ b/persistence-modules/fauna/src/test/java/com/baeldung/healthapp/service/DefaultHealthServiceManualTest.java @@ -0,0 +1,55 @@ +package com.baeldung.healthapp.service; + +import static org.mockito.Mockito.when; + +import java.net.MalformedURLException; +import java.time.ZonedDateTime; +import java.util.concurrent.ExecutionException; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; + +import com.baeldung.healthapp.FaunaHealthApplication; +import com.baeldung.healthapp.domain.HealthData; + +@SpringBootTest(classes = FaunaHealthApplication.class) +class DefaultHealthServiceManualTest { + + @Autowired + private DefaultHealthService defaultHealthService; + + @MockBean + private GeoLocationService geoLocationService; + + @Test + void givenEURegion_whenProcess_thenRequestSentToEURegion() throws MalformedURLException, InterruptedException, ExecutionException { + + HealthData healthData = new HealthData("user-1-eu", // + 37.5f, // + 99f, // + 120, 80, // + 51.50, -0.07, // + ZonedDateTime.now()); + + when(geoLocationService.getRegion(51.50, -0.07)).thenReturn("EU"); + + defaultHealthService.process(healthData); + } + + @Test + void givenUSRegion_whenProcess_thenRequestSentToUSRegion() throws MalformedURLException, InterruptedException, ExecutionException { + + HealthData healthData = new HealthData("user-1-us", // + 38.0f, // + 100f, // + 115, 85, // + 40.75, -74.30, // + ZonedDateTime.now()); + + when(geoLocationService.getRegion(40.75, -74.30)).thenReturn("US"); + + defaultHealthService.process(healthData); + } +} diff --git a/persistence-modules/hibernate-annotations/pom.xml b/persistence-modules/hibernate-annotations/pom.xml index e984078f9a..6c02b6c685 100644 --- a/persistence-modules/hibernate-annotations/pom.xml +++ b/persistence-modules/hibernate-annotations/pom.xml @@ -84,10 +84,8 @@ 1.10.6.RELEASE 5.6.7.Final true - 2.1.7.RELEASE 2.1.212 9.0.0.M26 - 2.3.4 \ No newline at end of file diff --git a/persistence-modules/hibernate-enterprise/pom.xml b/persistence-modules/hibernate-enterprise/pom.xml index 18d1a4f3a6..833f19c673 100644 --- a/persistence-modules/hibernate-enterprise/pom.xml +++ b/persistence-modules/hibernate-enterprise/pom.xml @@ -82,7 +82,6 @@ 6.0.6 2.2.3 0.9 - 2.3.4 \ No newline at end of file diff --git a/persistence-modules/hibernate-exceptions/README.md b/persistence-modules/hibernate-exceptions/README.md index 4acd6cd363..0225d3a753 100644 --- a/persistence-modules/hibernate-exceptions/README.md +++ b/persistence-modules/hibernate-exceptions/README.md @@ -6,4 +6,4 @@ - [Hibernate’s “Object References an Unsaved Transient Instance” Error](https://www.baeldung.com/hibernate-unsaved-transient-instance-error) - [EntityNotFoundException in Hibernate](https://www.baeldung.com/hibernate-entitynotfoundexception) - [Hibernate’s “Not-Null Property References a Null or Transient Value” Error](https://www.baeldung.com/hibernate-not-null-error) -- [Hibernate's “Detached Entity Passed to Persist” Error](https://www.baeldung.com/hibernate-detached-entity-passed-to-persist) +- [Hibernate’s “Detached Entity Passed to Persist” Error](https://www.baeldung.com/hibernate-detached-entity-passed-to-persist) diff --git a/persistence-modules/java-cassandra/src/main/java/com/baeldung/cassandra/batch/repository/ProductRepository.java b/persistence-modules/java-cassandra/src/main/java/com/baeldung/cassandra/batch/repository/ProductRepository.java index 106db133d1..9df145e064 100644 --- a/persistence-modules/java-cassandra/src/main/java/com/baeldung/cassandra/batch/repository/ProductRepository.java +++ b/persistence-modules/java-cassandra/src/main/java/com/baeldung/cassandra/batch/repository/ProductRepository.java @@ -62,12 +62,13 @@ public class ProductRepository { executeStatement(createTable.build(), keyspace); } - + /** - * Insert two variant Product into same table using a batch query. - * - * @param Product - */ + * Insert two variant Product into same table using a batch query. + * + * @param productVariant1 + * @param productVariant2 + */ public void insertProductVariantBatch(Product productVariant1,Product productVariant2) { UUID productId = UUID.randomUUID(); BoundStatement productBoundStatement1 = this.getProductVariantInsertStatement(productVariant1,productId); @@ -83,7 +84,7 @@ public class ProductRepository { /** * Insert two same Product into related tables using a batch query. * - * @param book + * @param product */ public void insertProductBatch(Product product) { UUID productId = UUID.randomUUID(); diff --git a/persistence-modules/java-cassandra/src/main/java/com/baeldung/cassandra/java/client/repository/KeyspaceRepository.java b/persistence-modules/java-cassandra/src/main/java/com/baeldung/cassandra/java/client/repository/KeyspaceRepository.java index f15558f040..943ecf8b28 100644 --- a/persistence-modules/java-cassandra/src/main/java/com/baeldung/cassandra/java/client/repository/KeyspaceRepository.java +++ b/persistence-modules/java-cassandra/src/main/java/com/baeldung/cassandra/java/client/repository/KeyspaceRepository.java @@ -16,13 +16,13 @@ public class KeyspaceRepository { /** * Method used to create any keyspace - schema. * - * @param schemaName the name of the schema. - * @param replicatioonStrategy the replication strategy. + * @param keyspaceName the name of the keyspaceName. + * @param replicationStrategy the replication strategy. * @param numberOfReplicas the number of replicas. * */ - public void createKeyspace(String keyspaceName, String replicatioonStrategy, int numberOfReplicas) { - StringBuilder sb = new StringBuilder("CREATE KEYSPACE IF NOT EXISTS ").append(keyspaceName).append(" WITH replication = {").append("'class':'").append(replicatioonStrategy).append("','replication_factor':").append(numberOfReplicas).append("};"); + public void createKeyspace(String keyspaceName, String replicationStrategy, int numberOfReplicas) { + StringBuilder sb = new StringBuilder("CREATE KEYSPACE IF NOT EXISTS ").append(keyspaceName).append(" WITH replication = {").append("'class':'").append(replicationStrategy).append("','replication_factor':").append(numberOfReplicas).append("};"); final String query = sb.toString(); @@ -37,7 +37,7 @@ public class KeyspaceRepository { * Method used to delete the specified schema. * It results in the immediate, irreversable removal of the keyspace, including all tables and data contained in the keyspace. * - * @param schemaName the name of the keyspace to delete. + * @param keyspaceName the name of the keyspace to delete. */ public void deleteKeyspace(String keyspaceName) { StringBuilder sb = new StringBuilder("DROP KEYSPACE ").append(keyspaceName); diff --git a/persistence-modules/java-jpa-3/pom.xml b/persistence-modules/java-jpa-3/pom.xml index b67b8bf608..c6930d6291 100644 --- a/persistence-modules/java-jpa-3/pom.xml +++ b/persistence-modules/java-jpa-3/pom.xml @@ -65,7 +65,7 @@ org.testcontainers postgresql - 1.16.0 + ${testcontainers.version} test diff --git a/persistence-modules/java-mongodb-2/pom.xml b/persistence-modules/java-mongodb-2/pom.xml index 9475a86bee..cabe544850 100644 --- a/persistence-modules/java-mongodb-2/pom.xml +++ b/persistence-modules/java-mongodb-2/pom.xml @@ -33,13 +33,13 @@ org.testcontainers mongodb - 1.16.3 + ${testcontainers.version} test org.testcontainers junit-jupiter - 1.16.3 + ${testcontainers.version} test diff --git a/persistence-modules/java-mongodb-queries/pom.xml b/persistence-modules/java-mongodb-queries/pom.xml index aa3003bef6..8293103859 100644 --- a/persistence-modules/java-mongodb-queries/pom.xml +++ b/persistence-modules/java-mongodb-queries/pom.xml @@ -16,12 +16,12 @@ org.mongodb mongodb-driver-sync - 4.6.0 + ${mongodb.version} org.junit.jupiter junit-jupiter-api - 5.8.1 + ${junit.version} compile @@ -29,6 +29,8 @@ 8 8 + 4.6.0 + 5.8.1 \ No newline at end of file diff --git a/persistence-modules/java-mongodb/pom.xml b/persistence-modules/java-mongodb/pom.xml index 88f0d18a5b..2e366d8368 100644 --- a/persistence-modules/java-mongodb/pom.xml +++ b/persistence-modules/java-mongodb/pom.xml @@ -33,13 +33,13 @@ org.testcontainers mongodb - 1.16.3 + ${testcontainers.version} test org.testcontainers junit-jupiter - 1.16.3 + ${testcontainers.version} test diff --git a/persistence-modules/pom.xml b/persistence-modules/pom.xml index ee4807933a..d549f7e2de 100644 --- a/persistence-modules/pom.xml +++ b/persistence-modules/pom.xml @@ -111,6 +111,8 @@ 5.2.17.Final 42.2.20 + 2.3.4 + 1.16.3 \ No newline at end of file diff --git a/persistence-modules/querydsl/pom.xml b/persistence-modules/querydsl/pom.xml index c4b01d787c..c97dcdd93d 100644 --- a/persistence-modules/querydsl/pom.xml +++ b/persistence-modules/querydsl/pom.xml @@ -136,7 +136,6 @@ 5.2.5.Final 1.0.0.Final 4.1.4 - 2.3.4 1.6 1.4 1.1.3 diff --git a/persistence-modules/spring-hibernate-5/pom.xml b/persistence-modules/spring-hibernate-5/pom.xml index 3f5d00733d..e559fe1394 100644 --- a/persistence-modules/spring-hibernate-5/pom.xml +++ b/persistence-modules/spring-hibernate-5/pom.xml @@ -136,7 +136,6 @@ 8.0.7-dmr 9.0.0.M26 1.1 - 2.3.4 2.3.0.1 2.3.1 diff --git a/pom.xml b/pom.xml index a4f6a744ea..2264caa99f 100644 --- a/pom.xml +++ b/pom.xml @@ -1381,7 +1381,7 @@ 1.2 2.3.1 1.2 - 2.13.0 + 2.13.3 1.4 1.8.1 5.8.1 diff --git a/quarkus-modules/quarkus-vs-springboot/README.md b/quarkus-modules/quarkus-vs-springboot/README.md index 05eaabb923..13c0b8ab5f 100644 --- a/quarkus-modules/quarkus-vs-springboot/README.md +++ b/quarkus-modules/quarkus-vs-springboot/README.md @@ -6,6 +6,9 @@ To follow this tutorial, you will need the following things: - Maven (Embedded, IDE, or local installation) - Docker (https://www.docker.com/) - Jmeter (https://jmeter.apache.org/) +- wrk (https://github.com/wg/wrk) +- hyperfoil (https://hyperfoil.io/) +- lua (https://www.lua.org/) To create this test, I used some custom features from Jmeter. You can install the Jmeter plugin manager here: https://loadium.com/blog/how-to-install-use-jmeter-plugin. After that, please install the following plugins: @@ -17,31 +20,32 @@ The test file is `load_test.jmx` in case of any change need. You can open it wit $jmeter_home/bin/jmeter -n -t load_test.jmx -l log.csv -e -o ./report ``` -Just remember to change the variable `jmeter_home` with the path to the JMeter folder. The path to the data files is relative, so either keep them in the same folder as the test or use Jmeter GUI to change it. +Just remember to change the variable `jmeter_home` with the path to the JMeter folder. The path to the data files is relative, so either keep them in the same folder as the test or use Jmeter GUI to change it. Rememeber that as mentioned in the article, we cannot consider the response times recorded by Jmeter due to the Coordinated Omission Problem. Open the VisualVM application and select your application to start monitoring before running the test, and of course, start the sample application first. ## Spring Boot To build the application, you only need to run the following command in the Spring project root: ``` -./mvnw package -f pom.xml +./mvnw clean package -f pom.xml ``` Or this one in case you want to build the native one: ``` -./mvnw -DskipTests package -Pnative -f pom.xml +./mvnw clean package -Pnative -f pom.xml ``` In this case, you will need to have the `GRAALVM_HOME` env variable defined. You only need this if you want to build the image locally. Otherwise, you can build it using docker by leveraging the Spring Boot maven plugin. It will pull a docker image of the GraalVM, and with that, it will create the native image of the app. To do that, run: ``` -./mvnw spring-boot:build-image +./mvnw clean package spring-boot:build-image -Pnative -f pom.xml ``` -You can also create a docker image with the JVM version of the app running the script `build_jvm_docker.sh` or: +You can also create a docker image with the JVM version one of the app running the script `build.sh` or: ``` -docker build -f src/main/docker/Dockerfile.jvm -t spring-project:0.1-SNAPSHOT . +./mvnw clean package spring-boot:build-image -f pom.xml + ``` -You can execute the script `start_app.sh` or `start_jvm.sh` to run the application locally. In this case, you will need the Postgres DB. You can run it in docker with the command: +You can execute the script `start_app.sh` or `start_jvm.sh` to run the application locally. In this case, you will need the Mysql DB. You can run it in docker with the command: ``` -docker run -e POSTGRES_PASSWORD=example -p 5432:5432 postgres +docker run --name mysqldb --network=host -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=baeldung -d mysql:5.7.38 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci ``` You can also run both application and DB from docker, using: ``` @@ -67,7 +71,7 @@ And to the JVM version: To start the application locally, use either the scripts `start_app.sh` and `start_jvm.sh` with the docker DB: ``` -docker run -e POSTGRES_PASSWORD=example -p 5432:5432 postgres +docker run --name mysqldb --network=host -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=baeldung -d mysql:5.7.38 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci ``` Or use the script to build the docker image of the application, running: ```bash @@ -94,6 +98,38 @@ docker-compose -f src/main/docker/quarkus.yml up Now you have all you need to reproduce the tests with your machine. +## Wrk +Another option to execute the load test is to use the wrk. This library is capable of generation a pretty high load only using a single core. To install it you only have to checkout the project compile it (using make) and define the `wrk_home` envvar. To run the test use: + +``` +./run_test_wrk.sh +``` +You will need to have installed lua in your machine. + +### Tips +If you want to run the applications in your machine you can use the following command to restrict the CPUs available to the app: + +``` +cpulimit -l 300 -p ## 300 means at most 3 cores. +``` + +This will make sure the load is on the application and not in the DB. +## Hyperfoil + +To the hyperfoil test to get a report regarding the performance of the application, its throughput and response time. You can run the `docker_run.sh` from the hyperfoil folder, or the following: + +``` +docker run -it -v volume:/benchmarks:Z -v tmp/reports:/tmp/reports:Z --network=host quay.io/hyperfoil/hyperfoil cli +``` +And then: +``` +start-local && upload /benchmarks/benchmark.hf.yaml && run benchmark +``` +Optionally, we can extract a html report from it, by running: +``` +report --destination=/tmp/reports +``` + ### Relevant Articles: - [Spring Boot vs Quarkus](https://www.baeldung.com/spring-boot-vs-quarkus) diff --git a/quarkus-modules/quarkus-vs-springboot/hyperfoil/docker_run.sh b/quarkus-modules/quarkus-vs-springboot/hyperfoil/docker_run.sh new file mode 100644 index 0000000000..ee0ee35a29 --- /dev/null +++ b/quarkus-modules/quarkus-vs-springboot/hyperfoil/docker_run.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +SCRIPTPATH="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" + +docker run -it -v $SCRIPTPATH/volume:/benchmarks:Z -v $SCRIPTPATH/tmp/reports:/tmp/reports:Z --network=host quay.io/hyperfoil/hyperfoil cli + +#start-local && upload /benchmarks/benchmark.hf.yaml && run benchmark + +# step 1 run: start-local +# step 2 run (Run this every time the file is modified): upload /benchmarks/benchmark.hf.yaml +# step 3 run: run benchmark +# step 4 run: stats +# step 5 run: report --destination=/tmp/reports diff --git a/quarkus-modules/quarkus-vs-springboot/hyperfoil/volume/benchmark.hf.yaml b/quarkus-modules/quarkus-vs-springboot/hyperfoil/volume/benchmark.hf.yaml new file mode 100644 index 0000000000..598c61249e --- /dev/null +++ b/quarkus-modules/quarkus-vs-springboot/hyperfoil/volume/benchmark.hf.yaml @@ -0,0 +1,86 @@ +name: benchmark +http: + host: http://localhost:8080 + sharedConnections: 100 +phases: + - main: + constantRate: + startAfter: rampup + usersPerSec: 3300 + maxSessions: 6000 + duration: 5m + forks: + - post_zipcode: &post_zipcode + scenario: + - fetchIndex: + - randomCsvRow: + file: /benchmarks/zip_code_database.csv + removeQuotes: true + columns: + 0: zip + 1: type + 3: city + 6: state + 7: county + 8: timezone + - httpRequest: + sla: + - blockedRatio: 500 + POST: /zipcode + headers: + Content-Type: application/json;charset=UTF-8 + Accept: application/json + body: | + { + "zip" : "${zip}", + "type" : "${type}", + "city" : "${city}", + "state" : "${state}", + "county" : "${county}", + "timezone" : "${timezone}" + } + - get_zipcode: &get_zipcode + scenario: + - fetchIndex: + - randomCsvRow: + file: /benchmarks/zip_code_database.csv + removeQuotes: true + columns: + 0: zipcode + - httpRequest: + sla: + - blockedRatio: 500 + headers: + accept: application/json + GET: /zipcode/${zipcode} + - get_zipcode_by_city: &get_zipcode_by_city + scenario: + - fetchDetails: + - randomCsvRow: + file: /benchmarks/cities.csv + removeQuotes: true + columns: + 0: city + - httpRequest: + sla: + - blockedRatio: 500 + headers: + accept: application/json + GET: /zipcode/by_city?city=${city} + - spike: + constantRate: + startAfter: main + usersPerSec: 4400 + duration: 2m + forks: + - get_zipcode_by_city: *get_zipcode_by_city + - get_zipcode: *get_zipcode + + - rampup: + increasingRate: + initialUsersPerSec: 3 + targetUsersPerSec: 2500 + duration: 1m + forks: + - post_zipcode: *post_zipcode + - get_zipcode: *get_zipcode diff --git a/quarkus-modules/quarkus-vs-springboot/cities.csv b/quarkus-modules/quarkus-vs-springboot/hyperfoil/volume/cities.csv similarity index 100% rename from quarkus-modules/quarkus-vs-springboot/cities.csv rename to quarkus-modules/quarkus-vs-springboot/hyperfoil/volume/cities.csv diff --git a/quarkus-modules/quarkus-vs-springboot/jmeter/cities.csv b/quarkus-modules/quarkus-vs-springboot/jmeter/cities.csv new file mode 100644 index 0000000000..3b7016f3b5 --- /dev/null +++ b/quarkus-modules/quarkus-vs-springboot/jmeter/cities.csv @@ -0,0 +1,136 @@ +Holtsville +Adjuntas +Aguada +Aguadilla +Maricao +Anasco +Angeles +Arecibo +Bajadero +Barceloneta +Boqueron +Cabo Rojo +Penuelas +Camuy +Castaner +Rosario +Sabana Grande +Ciales +Utuado +Dorado +Ensenada +Florida +Garrochales +Guanica +Guayanilla +Hatillo +Hormigueros +Isabela +Jayuya +Lajas +Lares +Las Marias +Manati +Moca +Rincon +Quebradillas +Mayaguez +San German +San Sebastian +Morovis +Sabana Hoyos +San Antonio +Vega Alta +Vega Baja +Yauco +Aguas Buenas +Aguirre +Aibonito +Maunabo +Arroyo +Mercedita +Ponce +Naguabo +Naranjito +Orocovis +Palmer +Patillas +Caguas +Canovanas +Ceiba +Cayey +Fajardo +Cidra +Puerto Real +Punta Santiago +Roosevelt Roads +Rio Blanco +Rio Grande +Salinas +San Lorenzo +Santa Isabel +Vieques +Villalba +Yabucoa +Coamo +Las Piedras +Loiza +Luquillo +Culebra +Juncos +Gurabo +Coto Laurel +Comerio +Corozal +Guayama +La Plata +Humacao +Barranquitas +Juana Diaz +St Thomas +Christiansted +St John +Frederiksted +Kingshill +San Juan +Fort Buchanan +Toa Baja +Sabana Seca +Toa Alta +Bayamon +Catano +Guaynabo +Trujillo Alto +Saint Just +Carolina +Agawam +Amherst +Barre +Belchertown +Blandford +Bondsville +Brimfield +Chester +Chesterfield +Chicopee +Cummington +Easthampton +East Longmeadow +East Otis +Feeding Hills +Gilbertville +Goshen +Granby +Granville +Hadley +Hampden +Hardwick +Hatfield +Haydenville +Holyoke +Huntington +Leeds +Leverett +Ludlow +Monson +North Amherst \ No newline at end of file diff --git a/quarkus-modules/quarkus-vs-springboot/load_test.jmx b/quarkus-modules/quarkus-vs-springboot/jmeter/load_test.jmx similarity index 100% rename from quarkus-modules/quarkus-vs-springboot/load_test.jmx rename to quarkus-modules/quarkus-vs-springboot/jmeter/load_test.jmx diff --git a/quarkus-modules/quarkus-vs-springboot/run_test.sh b/quarkus-modules/quarkus-vs-springboot/jmeter/run_test_jmeter.sh similarity index 100% rename from quarkus-modules/quarkus-vs-springboot/run_test.sh rename to quarkus-modules/quarkus-vs-springboot/jmeter/run_test_jmeter.sh diff --git a/quarkus-modules/quarkus-vs-springboot/quarkus-project/build.sh b/quarkus-modules/quarkus-vs-springboot/quarkus-project/build.sh index 85761adab0..22b6d5c9d4 100644 --- a/quarkus-modules/quarkus-vs-springboot/quarkus-project/build.sh +++ b/quarkus-modules/quarkus-vs-springboot/quarkus-project/build.sh @@ -2,12 +2,14 @@ SCRIPTPATH="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" -./mvnw quarkus:add-extension -Dextensions=container-image-docker +mvn quarkus:add-extension -Dextensions=container-image-docker if [ "$1" = "native" ]; then - ./mvnw package -Pnative -Dquarkus.native.container-build=true -f $SCRIPTPATH/pom.xml && + mvn clean package -Pnative -Dquarkus.native.container-build=true -f $SCRIPTPATH/pom.xml && docker build -f $SCRIPTPATH/src/main/docker/Dockerfile.native -t quarkus-project:0.1-SNAPSHOT $SCRIPTPATH/. +elif [ "$1" = "local-native" ]; then + mvn clean package -DskipTests -Pnative -f $SCRIPTPATH/pom.xml else - ./mvnw package -Dquarkus.container-build=true -f $SCRIPTPATH/pom.xml && + mvn clean package -Dquarkus.container-build=true -f $SCRIPTPATH/pom.xml && docker build -f $SCRIPTPATH/src/main/docker/Dockerfile.jvm -t quarkus-project:0.1-SNAPSHOT $SCRIPTPATH/. fi \ No newline at end of file diff --git a/quarkus-modules/quarkus-vs-springboot/quarkus-project/pom.xml b/quarkus-modules/quarkus-vs-springboot/quarkus-project/pom.xml index eeeb9d3256..8f28fde4a6 100644 --- a/quarkus-modules/quarkus-vs-springboot/quarkus-project/pom.xml +++ b/quarkus-modules/quarkus-vs-springboot/quarkus-project/pom.xml @@ -1,150 +1,143 @@ - - 4.0.0 - quarkus-project - 0.1-SNAPSHOT - - - com.baeldung - quarkus-vs-springboot - 1.0-SNAPSHOT - - - - - - ${quarkus.platform.group-id} - ${quarkus.platform.artifact-id} - ${quarkus.platform.version} - pom - import - - - - + 4.0.0 + + com.baeldung + quarkus-vs-springboot + 1.0-SNAPSHOT + + quarkus-project + 0.1-SNAPSHOT + + 3.10.1 + true + 11 + 11 + UTF-8 + UTF-8 + quarkus-bom + io.quarkus.platform + 2.9.2.Final + 3.0.0-M6 + + - - io.quarkus - quarkus-hibernate-reactive-panache - - - io.quarkus - quarkus-resteasy-reactive - - - io.quarkus - quarkus-resteasy-reactive-jackson - - - io.quarkus - quarkus-reactive-pg-client - - - io.quarkus - quarkus-arc - - - io.quarkus - quarkus-container-image-docker - - - io.quarkus - quarkus-junit5 - test - - - io.rest-assured - rest-assured - test - + + ${quarkus.platform.group-id} + ${quarkus.platform.artifact-id} + ${quarkus.platform.version} + pom + import + - - + + + + io.quarkus + quarkus-hibernate-reactive-panache + + + io.quarkus + quarkus-resteasy-reactive + + + io.quarkus + quarkus-resteasy-reactive-jackson + + + io.quarkus + quarkus-reactive-mysql-client + + + io.quarkus + quarkus-arc + + + io.quarkus + quarkus-container-image-docker + + + io.quarkus + quarkus-junit5 + test + + + io.rest-assured + rest-assured + test + + + + + + ${quarkus.platform.group-id} + quarkus-maven-plugin + ${quarkus.platform.version} + true + + + + build + generate-code + generate-code-tests + + + + + + maven-compiler-plugin + ${compiler-plugin.version} + + ${maven.compiler.parameters} + + + + maven-surefire-plugin + ${surefire-plugin.version} + + false + + org.jboss.logmanager.LogManager + + + + + + + + native + + + native + + + - - ${quarkus.platform.group-id} - quarkus-maven-plugin - ${quarkus.platform.version} - true - - - - build - generate-code - generate-code-tests - - - - - - maven-compiler-plugin - ${compiler-plugin.version} + + maven-failsafe-plugin + ${surefire-plugin.version} + + + + integration-test + verify + - ${maven.compiler.parameters} + + ${project.build.directory}/${project.build.finalName}-runner + org.jboss.logmanager.LogManager + - - - maven-surefire-plugin - ${surefire-plugin.version} - - false - - org.jboss.logmanager.LogManager - - - + + + - - - - native - - - native - - - - - - maven-failsafe-plugin - ${surefire-plugin.version} - - - - integration-test - verify - - - - ${project.build.directory}/${project.build.finalName}-runner - org.jboss.logmanager.LogManager - - - - - - - - - -H:+AllowVMInspection - native - - - - - - 3.8.1 - true - 11 - 11 - UTF-8 - UTF-8 - quarkus-bom - io.quarkus.platform - 2.2.2.Final - 3.0.0-M4 - - - \ No newline at end of file + + + -H:+AllowVMInspection + native + + + + diff --git a/quarkus-modules/quarkus-vs-springboot/quarkus-project/src/main/docker/Dockerfile.jvm b/quarkus-modules/quarkus-vs-springboot/quarkus-project/src/main/docker/Dockerfile.jvm index e5d6d4d851..63ba538a4a 100644 --- a/quarkus-modules/quarkus-vs-springboot/quarkus-project/src/main/docker/Dockerfile.jvm +++ b/quarkus-modules/quarkus-vs-springboot/quarkus-project/src/main/docker/Dockerfile.jvm @@ -41,7 +41,8 @@ RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \ && echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/conf/security/java.security # Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size. -ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" +ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.port=5000 -Dcom.sun.management.jmxremote.rmi.port=5001 -Dcom.sun.management.jmxremote.host=0.0.0.0 -Djava.rmi.server.hostname=0.0.0.0" + # We make four distinct layers so if there are application changes the library layers can be re-used COPY --chown=1001 target/quarkus-app/lib/ /deployments/lib/ COPY --chown=1001 target/quarkus-app/*.jar /deployments/ diff --git a/quarkus-modules/quarkus-vs-springboot/quarkus-project/src/main/docker/quarkus.yml b/quarkus-modules/quarkus-vs-springboot/quarkus-project/src/main/docker/quarkus.yml index 00bdcf9292..60e35b6cca 100644 --- a/quarkus-modules/quarkus-vs-springboot/quarkus-project/src/main/docker/quarkus.yml +++ b/quarkus-modules/quarkus-vs-springboot/quarkus-project/src/main/docker/quarkus.yml @@ -1,23 +1,25 @@ version: '3.1' - services: db: - image: postgres + image: mysql:5.7.38 ports: - - '5432:5432' + - '3306:3306' environment: - POSTGRES_PASSWORD: example + MYSQL_ROOT_PASSWORD: root + MYSQL_DATABASE: baeldung + command: [ 'mysqld', '--character-set-server=utf8mb4', '--collation-server=utf8mb4_unicode_ci' ] + healthcheck: + test: mysqladmin ping -h 127.0.0.1 -u $$MYSQL_USER --password=$$MYSQL_PASSWORD app: image: quarkus-project:0.1-SNAPSHOT - ports: - - '8080:8080' + network_mode: "host" environment: - DB_URL: postgresql://db:5432/postgres - links: - - "db" + DB_URL: mysql://localhost:3306/baeldung?useSSL=true&requireSSL=true + HOST_HOSTNAME: ${EXTERNAL_IP} depends_on: - - "db" -networks: - default: - driver: bridge - + db: + condition: service_healthy + deploy: + resources: + limits: + cpus: '3.00' diff --git a/quarkus-modules/quarkus-vs-springboot/quarkus-project/src/main/java/com/baeldung/quarkus_project/ZipCodeRepo.java b/quarkus-modules/quarkus-vs-springboot/quarkus-project/src/main/java/com/baeldung/quarkus_project/ZipCodeRepo.java index 74f46c33ea..f6736a6e9e 100644 --- a/quarkus-modules/quarkus-vs-springboot/quarkus-project/src/main/java/com/baeldung/quarkus_project/ZipCodeRepo.java +++ b/quarkus-modules/quarkus-vs-springboot/quarkus-project/src/main/java/com/baeldung/quarkus_project/ZipCodeRepo.java @@ -1,6 +1,7 @@ package com.baeldung.quarkus_project; import io.quarkus.hibernate.reactive.panache.PanacheRepositoryBase; +import io.quarkus.hibernate.reactive.panache.common.runtime.ReactiveTransactional; import io.smallrye.mutiny.Multi; import io.smallrye.mutiny.Uni; @@ -13,7 +14,8 @@ public class ZipCodeRepo implements PanacheRepositoryBase { return find("city = ?1", city).stream(); } + @ReactiveTransactional public Uni save(ZipCode zipCode) { - return zipCode.persistAndFlush(); + return zipCode.persist(); } } diff --git a/quarkus-modules/quarkus-vs-springboot/quarkus-project/src/main/java/com/baeldung/quarkus_project/ZipCodeResource.java b/quarkus-modules/quarkus-vs-springboot/quarkus-project/src/main/java/com/baeldung/quarkus_project/ZipCodeResource.java index b4d41fd855..cb9b0226f3 100644 --- a/quarkus-modules/quarkus-vs-springboot/quarkus-project/src/main/java/com/baeldung/quarkus_project/ZipCodeResource.java +++ b/quarkus-modules/quarkus-vs-springboot/quarkus-project/src/main/java/com/baeldung/quarkus_project/ZipCodeResource.java @@ -2,9 +2,8 @@ package com.baeldung.quarkus_project; import io.smallrye.mutiny.Multi; import io.smallrye.mutiny.Uni; -import org.jboss.logging.Logger; -import javax.transaction.Transactional; +import javax.persistence.PersistenceException; import javax.ws.rs.*; import javax.ws.rs.core.MediaType; @@ -22,7 +21,7 @@ public class ZipCodeResource { @GET @Path("/{zipcode}") public Uni findById(@PathParam("zipcode") String zipcode) { - return zipRepo.findById(zipcode); + return getById(zipcode); } @GET @@ -32,12 +31,17 @@ public class ZipCodeResource { } @POST - @Transactional public Uni create(ZipCode zipCode) { - return zipRepo.findById(zipCode.getZip()) + return getById(zipCode.getZip()) .onItem() .ifNull() - .switchTo(createZipCode(zipCode)); + .switchTo(createZipCode(zipCode)) + .onFailure(PersistenceException.class) + .recoverWithUni(() -> getById(zipCode.getZip())); + } + + private Uni getById(String zipCode) { + return zipRepo.findById(zipCode); } private Uni createZipCode(ZipCode zipCode) { diff --git a/quarkus-modules/quarkus-vs-springboot/quarkus-project/src/main/resources/application.properties b/quarkus-modules/quarkus-vs-springboot/quarkus-project/src/main/resources/application.properties index 918a129500..7c1bee8da5 100644 --- a/quarkus-modules/quarkus-vs-springboot/quarkus-project/src/main/resources/application.properties +++ b/quarkus-modules/quarkus-vs-springboot/quarkus-project/src/main/resources/application.properties @@ -1,9 +1,12 @@ -quarkus.datasource.db-kind=postgresql -quarkus.datasource.username=postgres -quarkus.datasource.password=example +quarkus.datasource.db-kind=mysql +quarkus.datasource.username=root +quarkus.datasource.password=root -quarkus.datasource.reactive.url=${DB_URL:postgresql://localhost:5432/postgres} -quarkus.datasource.reactive.max-size=20 +quarkus.datasource.reactive.url=${DB_URL:mysql://localhost:3306/baeldung?useSSL=true&requireSSL=true} +quarkus.datasource.reactive.max-size=95 +quarkus.datasource.reactive.mysql.ssl-mode=required #quarkus.hibernate-orm.log.sql=true quarkus.hibernate-orm.database.generation=drop-and-create +quarkus.native.enable-vm-inspection=true +quarkus.datasource.reactive.trust-all=true \ No newline at end of file diff --git a/quarkus-modules/quarkus-vs-springboot/spring-project/build.sh b/quarkus-modules/quarkus-vs-springboot/spring-project/build.sh new file mode 100755 index 0000000000..d8e131d244 --- /dev/null +++ b/quarkus-modules/quarkus-vs-springboot/spring-project/build.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +SCRIPTPATH="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" + +if [ "$1" = "native" ]; then + mvn clean package -DskipTests spring-boot:build-image -Pnative -f $SCRIPTPATH/pom.xml +elif [ "$1" = "local-native" ]; then + mvn clean package -DskipTests -Plocal-native -f $SCRIPTPATH/pom.xml +else + mvn clean package -DskipTests spring-boot:build-image -f $SCRIPTPATH/pom.xml +fi \ No newline at end of file diff --git a/quarkus-modules/quarkus-vs-springboot/spring-project/build_jvm_docker.sh b/quarkus-modules/quarkus-vs-springboot/spring-project/build_jvm_docker.sh deleted file mode 100644 index c7ee730ec7..0000000000 --- a/quarkus-modules/quarkus-vs-springboot/spring-project/build_jvm_docker.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash - -SCRIPTPATH="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" - -docker build -f $SCRIPTPATH/src/main/docker/Dockerfile.jvm -t spring-project:0.1-SNAPSHOT $SCRIPTPATH/. - diff --git a/quarkus-modules/quarkus-vs-springboot/spring-project/pom.xml b/quarkus-modules/quarkus-vs-springboot/spring-project/pom.xml index 7f0fa4c8c6..408c223e9f 100644 --- a/quarkus-modules/quarkus-vs-springboot/spring-project/pom.xml +++ b/quarkus-modules/quarkus-vs-springboot/spring-project/pom.xml @@ -10,8 +10,8 @@ org.springframework.boot spring-boot-starter-parent - 2.6.0 - + 2.6.9 + @@ -29,14 +29,9 @@ ${spring-native.version} - io.r2dbc - r2dbc-postgresql - runtime - - - org.postgresql - postgresql - runtime + com.github.jasync-sql + jasync-r2dbc-mysql + 2.0.8 org.springframework.boot @@ -48,131 +43,210 @@ reactor-test test + + + org.testcontainers + testcontainers + test + + + + org.testcontainers + r2dbc + test + + + + org.testcontainers + mysql + test + + + + mysql + mysql-connector-java + test + + + + org.testcontainers + junit-jupiter + test + + + + + + org.testcontainers + testcontainers-bom + 1.17.2 + pom + import + + + + org.springframework.boot spring-boot-maven-plugin - ${repackage.classifier} + exec + + true + paketobuildpacks/builder:tiny - true + false + true - org.springframework.experimental - spring-aot-maven-plugin - ${spring-native.version} - - - test-generate - - test-generate - - - - generate - - generate - - - + maven-surefire-plugin + ${surefire-plugin.version} + + + **/*IT + + - spring-releases - Spring Releases + spring-release + Spring release https://repo.spring.io/release - - false - - - - - spring-milestones - Spring Milestones - https://repo.spring.io/libs-milestone-local - - false - - spring-releases - Spring Releases + spring-release + Spring release https://repo.spring.io/release - - false - - - - - spring-milestones - Spring Milestones - https://repo.spring.io/libs-milestone-local - - false - native - - exec - 0.9.3 - - org.graalvm.buildtools - junit-platform-native - ${native-buildtools.version} + org.junit.platform + junit-platform-launcher + test + + org.springframework.boot + spring-boot-maven-plugin + + + true + + + paketobuildpacks/builder:tiny + + true + true + + + + + + org.springframework.experimental + spring-aot-maven-plugin + + + test-generate + + test-generate + + + + generate + + generate + + + + + + + + + local-native + + exec + 0.9.11 + + + + org.junit.platform + junit-platform-launcher + test + + + + + + org.springframework.experimental + spring-aot-maven-plugin + + + test-generate + + test-generate + + + + generate + + generate + + + + org.graalvm.buildtools native-maven-plugin ${native-buildtools.version} + true -H:+AllowVMInspection - - test-native - test - - test - - build-native - package build + package + + + test-native + + test + + test org.apache.maven.plugins maven-surefire-plugin + 3.0.0-M6 -DspringAot=true -agentlib:native-image-agent=access-filter-file=src/test/resources/access-filter.json,config-merge-dir=target/classes/META-INF/native-image @@ -185,9 +259,8 @@ 11 - - 0.11.0-RC1 - 2.17.1 + 0.12.1 + 3.0.0-M6 - \ No newline at end of file + diff --git a/quarkus-modules/quarkus-vs-springboot/spring-project/src/main/docker/Dockerfile.jvm b/quarkus-modules/quarkus-vs-springboot/spring-project/src/main/docker/Dockerfile.jvm deleted file mode 100644 index ca3f3cca76..0000000000 --- a/quarkus-modules/quarkus-vs-springboot/spring-project/src/main/docker/Dockerfile.jvm +++ /dev/null @@ -1,12 +0,0 @@ -FROM openjdk:11 - -ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' - -COPY --chown=1001 target/spring-project-0.1-SNAPSHOT-exec.jar /spring-app/ - -WORKDIR /spring-app - -EXPOSE 8080 -USER 1001 - -ENTRYPOINT ["java", "-jar", "spring-project-0.1-SNAPSHOT-exec.jar" ] \ No newline at end of file diff --git a/quarkus-modules/quarkus-vs-springboot/spring-project/src/main/docker/spring.yml b/quarkus-modules/quarkus-vs-springboot/spring-project/src/main/docker/spring.yml index 2214e0a898..347b5dfe2f 100644 --- a/quarkus-modules/quarkus-vs-springboot/spring-project/src/main/docker/spring.yml +++ b/quarkus-modules/quarkus-vs-springboot/spring-project/src/main/docker/spring.yml @@ -2,21 +2,25 @@ version: '3.1' services: db: - image: postgres + image: mysql:5.7.38 ports: - - '5432:5432' + - '3306:3306' environment: - POSTGRES_PASSWORD: example + MYSQL_ROOT_PASSWORD: root + MYSQL_DATABASE: baeldung + command: [ 'mysqld', '--character-set-server=utf8mb4', '--collation-server=utf8mb4_unicode_ci' ] + healthcheck: + test: mysqladmin ping -h 127.0.0.1 -u $$MYSQL_USER --password=$$MYSQL_PASSWORD app: - image: spring-project:0.1-SNAPSHOT - ports: - - '8080:8080' + image: docker.io/library/spring-project:0.1-SNAPSHOT + network_mode: "host" environment: - DB_URL: r2dbc:postgresql://db:5432/postgres - links: - - "db" + DB_URL: r2dbc:mysql://localhost:3306/baeldung?useSSL=true&requireSSL=true + HOST_HOSTNAME: ${EXTERNAL_IP} depends_on: - - "db" -networks: - default: - driver: bridge \ No newline at end of file + db: + condition: service_healthy + deploy: + resources: + limits: + cpus: '3.00' diff --git a/quarkus-modules/quarkus-vs-springboot/spring-project/src/main/java/com/baeldung/spring_project/Startup.java b/quarkus-modules/quarkus-vs-springboot/spring-project/src/main/java/com/baeldung/spring_project/Startup.java index 48cf7e8ed1..e8544da8db 100644 --- a/quarkus-modules/quarkus-vs-springboot/spring-project/src/main/java/com/baeldung/spring_project/Startup.java +++ b/quarkus-modules/quarkus-vs-springboot/spring-project/src/main/java/com/baeldung/spring_project/Startup.java @@ -1,21 +1,22 @@ package com.baeldung.spring_project; -import com.baeldung.spring_project.domain.ZIPRepo; import io.r2dbc.spi.ConnectionFactory; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.core.io.ByteArrayResource; +import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories; import org.springframework.r2dbc.connection.R2dbcTransactionManager; import org.springframework.r2dbc.connection.init.ConnectionFactoryInitializer; import org.springframework.r2dbc.connection.init.ResourceDatabasePopulator; import org.springframework.transaction.ReactiveTransactionManager; @SpringBootApplication +@EnableR2dbcRepositories public class Startup { public static void main(String[] args) { - SpringApplication.run(Startup.class, args).getBean(ZIPRepo.class).findById(""); + SpringApplication.run(Startup.class, args); } @Bean @@ -34,4 +35,5 @@ public class Startup { @Bean ReactiveTransactionManager transactionManager(ConnectionFactory connectionFactory) { return new R2dbcTransactionManager(connectionFactory); } + } diff --git a/quarkus-modules/quarkus-vs-springboot/spring-project/src/main/java/com/baeldung/spring_project/ZipCodeApi.java b/quarkus-modules/quarkus-vs-springboot/spring-project/src/main/java/com/baeldung/spring_project/ZipCodeApi.java index 263ce67e21..8d1f07b7b9 100644 --- a/quarkus-modules/quarkus-vs-springboot/spring-project/src/main/java/com/baeldung/spring_project/ZipCodeApi.java +++ b/quarkus-modules/quarkus-vs-springboot/spring-project/src/main/java/com/baeldung/spring_project/ZipCodeApi.java @@ -2,11 +2,14 @@ package com.baeldung.spring_project; import com.baeldung.spring_project.domain.ZIPRepo; import com.baeldung.spring_project.domain.ZipCode; -import org.springframework.transaction.annotation.Transactional; +import org.springframework.dao.DataAccessResourceFailureException; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.r2dbc.UncategorizedR2dbcException; import org.springframework.web.bind.annotation.*; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import java.util.function.Function; import java.util.function.Supplier; @RestController @@ -21,7 +24,7 @@ public class ZipCodeApi { @GetMapping("/{zipcode}") public Mono findById(@PathVariable String zipcode) { - return zipRepo.findById(zipcode); + return getById(zipcode); } @GetMapping("/by_city") @@ -29,10 +32,23 @@ public class ZipCodeApi { return zipRepo.findByCity(city); } - @Transactional @PostMapping public Mono create(@RequestBody ZipCode zipCode) { - return zipRepo.findById(zipCode.getZip()).switchIfEmpty(Mono.defer(createZipCode(zipCode))); + return getById(zipCode.getZip()) + .switchIfEmpty(Mono.defer(createZipCode(zipCode))) + .onErrorResume(this::isKeyDuplicated, this.recoverWith(zipCode)); + } + + private Mono getById(String zipCode) { + return zipRepo.findById(zipCode); + } + + private boolean isKeyDuplicated(Throwable ex) { + return ex instanceof DataIntegrityViolationException || ex instanceof UncategorizedR2dbcException; + } + + private Function> recoverWith(ZipCode zipCode) { + return throwable -> zipRepo.findById(zipCode.getZip()); } private Supplier> createZipCode(ZipCode zipCode) { diff --git a/quarkus-modules/quarkus-vs-springboot/spring-project/src/main/resources/application.properties b/quarkus-modules/quarkus-vs-springboot/spring-project/src/main/resources/application.properties index 1d49b67fda..e303baf6f6 100644 --- a/quarkus-modules/quarkus-vs-springboot/spring-project/src/main/resources/application.properties +++ b/quarkus-modules/quarkus-vs-springboot/spring-project/src/main/resources/application.properties @@ -1,5 +1,7 @@ -spring.r2dbc.url=${DB_URL:r2dbc:postgresql://localhost:5432/postgres} -spring.r2dbc.username=postgres -spring.r2dbc.password=example -spring.r2dbc.pool.enabled=true -spring.r2dbc.pool.maxSize=20 \ No newline at end of file +spring.r2dbc.url=${DB_URL:r2dbc:mysql://localhost:3306/baeldung?useSSL=true&requireSSL=true} +spring.r2dbc.properties.sslMode=required +spring.r2dbc.username=root +spring.r2dbc.password=root +spring.r2dbc.pool.enabled=true +spring.r2dbc.pool.maxSize=95 + diff --git a/quarkus-modules/quarkus-vs-springboot/spring-project/src/test/java/com/baeldung/spring_project/StartupIT.java b/quarkus-modules/quarkus-vs-springboot/spring-project/src/test/java/com/baeldung/spring_project/StartupIT.java index 7487e5aa7f..7715fdc1d2 100644 --- a/quarkus-modules/quarkus-vs-springboot/spring-project/src/test/java/com/baeldung/spring_project/StartupIT.java +++ b/quarkus-modules/quarkus-vs-springboot/spring-project/src/test/java/com/baeldung/spring_project/StartupIT.java @@ -1,9 +1,20 @@ package com.baeldung.spring_project; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; import org.springframework.boot.test.context.SpringBootTest; +import org.testcontainers.junit.jupiter.Testcontainers; -@SpringBootTest +import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; + +@SpringBootTest( + webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, + properties = { "spring.r2dbc.url=r2dbc:tc:mysql:///baeldung?TC_IMAGE_TAG=5.7.34"} +) +@TestInstance(value = PER_CLASS) +@Testcontainers +@Disabled class StartupIT { @Test diff --git a/quarkus-modules/quarkus-vs-springboot/wrk/cities.csv b/quarkus-modules/quarkus-vs-springboot/wrk/cities.csv new file mode 100644 index 0000000000..3b7016f3b5 --- /dev/null +++ b/quarkus-modules/quarkus-vs-springboot/wrk/cities.csv @@ -0,0 +1,136 @@ +Holtsville +Adjuntas +Aguada +Aguadilla +Maricao +Anasco +Angeles +Arecibo +Bajadero +Barceloneta +Boqueron +Cabo Rojo +Penuelas +Camuy +Castaner +Rosario +Sabana Grande +Ciales +Utuado +Dorado +Ensenada +Florida +Garrochales +Guanica +Guayanilla +Hatillo +Hormigueros +Isabela +Jayuya +Lajas +Lares +Las Marias +Manati +Moca +Rincon +Quebradillas +Mayaguez +San German +San Sebastian +Morovis +Sabana Hoyos +San Antonio +Vega Alta +Vega Baja +Yauco +Aguas Buenas +Aguirre +Aibonito +Maunabo +Arroyo +Mercedita +Ponce +Naguabo +Naranjito +Orocovis +Palmer +Patillas +Caguas +Canovanas +Ceiba +Cayey +Fajardo +Cidra +Puerto Real +Punta Santiago +Roosevelt Roads +Rio Blanco +Rio Grande +Salinas +San Lorenzo +Santa Isabel +Vieques +Villalba +Yabucoa +Coamo +Las Piedras +Loiza +Luquillo +Culebra +Juncos +Gurabo +Coto Laurel +Comerio +Corozal +Guayama +La Plata +Humacao +Barranquitas +Juana Diaz +St Thomas +Christiansted +St John +Frederiksted +Kingshill +San Juan +Fort Buchanan +Toa Baja +Sabana Seca +Toa Alta +Bayamon +Catano +Guaynabo +Trujillo Alto +Saint Just +Carolina +Agawam +Amherst +Barre +Belchertown +Blandford +Bondsville +Brimfield +Chester +Chesterfield +Chicopee +Cummington +Easthampton +East Longmeadow +East Otis +Feeding Hills +Gilbertville +Goshen +Granby +Granville +Hadley +Hampden +Hardwick +Hatfield +Haydenville +Holyoke +Huntington +Leeds +Leverett +Ludlow +Monson +North Amherst \ No newline at end of file diff --git a/quarkus-modules/quarkus-vs-springboot/wrk/generator.lua b/quarkus-modules/quarkus-vs-springboot/wrk/generator.lua new file mode 100644 index 0000000000..a1973072d9 --- /dev/null +++ b/quarkus-modules/quarkus-vs-springboot/wrk/generator.lua @@ -0,0 +1,65 @@ +local require = require +local json = require "json" + +math.randomseed(os.time()) + +-- read csv lines +function ParseCSVLine(line,sep) + local res = {} + local pos = 1 + sep = sep or ',' + while true do + local c = string.sub(line,pos,pos) + if (c == "") then break end + if (c == '"') then + local txt = "" + repeat + local startp,endp = string.find(line,'^%b""',pos) + txt = txt..string.sub(line,startp+1,endp-1) + pos = endp + 1 + c = string.sub(line,pos,pos) + if (c == '"') then txt = txt..'"' end + until (c ~= '"') + table.insert(res,txt) + assert(c == sep or c == "") + pos = pos + 1 + else + local startp,endp = string.find(line,sep,pos) + if (startp) then + table.insert(res,string.sub(line,pos,startp-1)) + pos = endp + 1 + else + table.insert(res,string.sub(line,pos)) + break + end + end + end + return res +end + +loadFile = function() + local filename = "zip_code_database.csv" + + local data = {} + local count = 0 + local sep = "," + + for line in io.lines(filename) do + local values = ParseCSVLine(line,sep) + data[count + 1] = { zip=values[1], type=values[2], city=values[4], state=values[7], county=values[8], timezone=values[9] } + count = count + 1 + end + + return data +end + +generator = function() + local data = loadFile() + return coroutine.create(function() + for k,v in pairs(data) do + coroutine.yield(json.stringify(v)) + end + end) +end + +return generator() \ No newline at end of file diff --git a/quarkus-modules/quarkus-vs-springboot/wrk/get_by_city.lua b/quarkus-modules/quarkus-vs-springboot/wrk/get_by_city.lua new file mode 100644 index 0000000000..b101e3bbda --- /dev/null +++ b/quarkus-modules/quarkus-vs-springboot/wrk/get_by_city.lua @@ -0,0 +1,79 @@ +local require = require +local json = require "json" + +math.randomseed(os.clock()*100000000000) + +function ParseCSVLine(line,sep) + local res = {} + local pos = 1 + sep = sep or ',' + while true do + local c = string.sub(line,pos,pos) + if (c == "") then break end + if (c == '"') then + local txt = "" + repeat + local startp,endp = string.find(line,'^%b""',pos) + txt = txt..string.sub(line,startp+1,endp-1) + pos = endp + 1 + c = string.sub(line,pos,pos) + if (c == '"') then txt = txt..'"' end + until (c ~= '"') + table.insert(res,txt) + assert(c == sep or c == "") + pos = pos + 1 + else + local startp,endp = string.find(line,sep,pos) + if (startp) then + table.insert(res,string.sub(line,pos,startp-1)) + pos = endp + 1 + else + table.insert(res,string.sub(line,pos)) + break + end + end + end + return res +end + +loadFile = function() + local filename = "cities.csv" + + local data = {} + local count = 0 + local sep = "," + + for line in io.lines(filename) do + local values = ParseCSVLine(line,sep) + data[count + 1] = values[1] + count = count + 1 + end + + return data +end + +local data = loadFile() + +local urlencode = function (str) + str = string.gsub (str, "([^0-9a-zA-Z !'()*._~-])", -- locale independent + function (c) return string.format ("%%%02X", string.byte(c)) end) + str = string.gsub (str, " ", "+") + return str +end + +request = function() + url_path = "/zipcode/by_city?city=" .. urlencode(data[math.random(1, 136)]) + + local headers = { ["Content-Type"] = "application/json;charset=UTF-8" } + + return wrk.format("GET", url_path, headers, nil) +end + +done = function(summary, latency, requests) + io.write("--------------GET CITY ZIPCODES----------------\n") + for _, p in pairs({ 50, 90, 99, 99.999 }) do + n = latency:percentile(p) + io.write(string.format("%g%%,%d\n", p, n)) + end + io.write("-----------------------------------------------\n\n") +end \ No newline at end of file diff --git a/quarkus-modules/quarkus-vs-springboot/wrk/get_zipcode.lua b/quarkus-modules/quarkus-vs-springboot/wrk/get_zipcode.lua new file mode 100644 index 0000000000..f2abf607c2 --- /dev/null +++ b/quarkus-modules/quarkus-vs-springboot/wrk/get_zipcode.lua @@ -0,0 +1,77 @@ +local require = require +local json = require "json" + +math.randomseed(os.clock()*100000000000) + +function ParseCSVLine(line,sep) + local res = {} + local pos = 1 + sep = sep or ',' + while true do + local c = string.sub(line,pos,pos) + if (c == "") then break end + if (c == '"') then + local txt = "" + repeat + local startp,endp = string.find(line,'^%b""',pos) + txt = txt..string.sub(line,startp+1,endp-1) + pos = endp + 1 + c = string.sub(line,pos,pos) + if (c == '"') then txt = txt..'"' end + + until (c ~= '"') + table.insert(res,txt) + assert(c == sep or c == "") + pos = pos + 1 + else + local startp,endp = string.find(line,sep,pos) + if (startp) then + table.insert(res,string.sub(line,pos,startp-1)) + pos = endp + 1 + else + table.insert(res,string.sub(line,pos)) + break + end + end + end + return res +end + +loadFile = function() + local filename = "zip_code_database.csv" + + local data = {} + local count = 0 + local sep = "," + + for line in io.lines(filename) do + local values = ParseCSVLine(line,sep) + data[count + 1] = values[1] + count = count + 1 + end + + return data +end + +local data = loadFile() + +request = function() + + local value = data[math.random(1, 12079)] + + url_path = "/zipcode/" .. value + + local headers = { ["Content-Type"] = "application/json;charset=UTF-8" } + + return wrk.format("GET", url_path, headers, nil) +end + + +done = function(summary, latency, requests) + io.write("--------------GET ZIPCODE----------------\n") + for _, p in pairs({ 50, 90, 99, 99.999 }) do + n = latency:percentile(p) + io.write(string.format("%g%%,%d\n", p, n)) + end + io.write("-----------------------------------------\n\n") +end diff --git a/quarkus-modules/quarkus-vs-springboot/wrk/json.lua b/quarkus-modules/quarkus-vs-springboot/wrk/json.lua new file mode 100644 index 0000000000..6f023a9294 --- /dev/null +++ b/quarkus-modules/quarkus-vs-springboot/wrk/json.lua @@ -0,0 +1,133 @@ +local json = {} + +local function kind_of(obj) + if type(obj) ~= 'table' then return type(obj) end + local i = 1 + for _ in pairs(obj) do + if obj[i] ~= nil then i = i + 1 else return 'table' end + end + if i == 1 then return 'table' else return 'array' end +end + +local function escape_str(s) + local in_char = {'\\', '"', '/', '\b', '\f', '\n', '\r', '\t'} + local out_char = {'\\', '"', '/', 'b', 'f', 'n', 'r', 't'} + for i, c in ipairs(in_char) do + s = s:gsub(c, '\\' .. out_char[i]) + end + return s +end + +local function skip_delim(str, pos, delim, err_if_missing) + pos = pos + #str:match('^%s*', pos) + if str:sub(pos, pos) ~= delim then + if err_if_missing then + error('Expected ' .. delim .. ' near position ' .. pos) + end + return pos, false + end + return pos + 1, true +end + +local function parse_str_val(str, pos, val) + val = val or '' + local early_end_error = 'End of input found while parsing string.' + if pos > #str then error(early_end_error) end + local c = str:sub(pos, pos) + if c == '"' then return val, pos + 1 end + if c ~= '\\' then return parse_str_val(str, pos + 1, val .. c) end + local esc_map = {b = '\b', f = '\f', n = '\n', r = '\r', t = '\t'} + local nextc = str:sub(pos + 1, pos + 1) + if not nextc then error(early_end_error) end + return parse_str_val(str, pos + 2, val .. (esc_map[nextc] or nextc)) +end + +local function parse_num_val(str, pos) + local num_str = str:match('^-?%d+%.?%d*[eE]?[+-]?%d*', pos) + local val = tonumber(num_str) + if not val then error('Error parsing number at position ' .. pos .. '.') end + return val, pos + #num_str +end + +function json.stringify(obj, as_key) + local s = {} + local kind = kind_of(obj) + if kind == 'array' then + if as_key then error('Can\'t encode array as key.') end + s[#s + 1] = '[' + for i, val in ipairs(obj) do + if i > 1 then s[#s + 1] = ', ' end + s[#s + 1] = json.stringify(val) + end + s[#s + 1] = ']' + elseif kind == 'table' then + if as_key then error('Can\'t encode table as key.') end + s[#s + 1] = '{' + for k, v in pairs(obj) do + if #s > 1 then s[#s + 1] = ', ' end + s[#s + 1] = json.stringify(k, true) + s[#s + 1] = ':' + s[#s + 1] = json.stringify(v) + end + s[#s + 1] = '}' + elseif kind == 'string' then + return '"' .. escape_str(obj) .. '"' + elseif kind == 'number' then + if as_key then return '"' .. tostring(obj) .. '"' end + return tostring(obj) + elseif kind == 'boolean' then + return tostring(obj) + elseif kind == 'nil' then + return 'null' + else + error('Unjsonifiable type: ' .. kind .. '.') + end + return table.concat(s) +end + +json.null = {} + +function json.parse(str, pos, end_delim) + pos = pos or 1 + if pos > #str then error('Reached unexpected end of input.') end + local pos = pos + #str:match('^%s*', pos) + local first = str:sub(pos, pos) + if first == '{' then + local obj, key, delim_found = {}, true, true + pos = pos + 1 + while true do + key, pos = json.parse(str, pos, '}') + if key == nil then return obj, pos end + if not delim_found then error('Comma missing between object items.') end + pos = skip_delim(str, pos, ':', true) + obj[key], pos = json.parse(str, pos) + pos, delim_found = skip_delim(str, pos, ',') + end + elseif first == '[' then + local arr, val, delim_found = {}, true, true + pos = pos + 1 + while true do + val, pos = json.parse(str, pos, ']') + if val == nil then return arr, pos end + if not delim_found then error('Comma missing between array items.') end + arr[#arr + 1] = val + pos, delim_found = skip_delim(str, pos, ',') + end + elseif first == '"' then + return parse_str_val(str, pos + 1) + elseif first == '-' or first:match('%d') then + return parse_num_val(str, pos) + elseif first == end_delim then + return nil, pos + 1 + else + local literals = {['true'] = true, ['false'] = false, ['null'] = json.null} + for lit_str, lit_val in pairs(literals) do + local lit_end = pos + #lit_str - 1 + if str:sub(pos, lit_end) == lit_str then return lit_val, lit_end + 1 end + end + local pos_info_str = 'position ' .. pos .. ': ' .. str:sub(pos, pos + 10) + error('Invalid json syntax starting at ' .. pos_info_str) + end +end + +return json diff --git a/quarkus-modules/quarkus-vs-springboot/wrk/post_zipcode.lua b/quarkus-modules/quarkus-vs-springboot/wrk/post_zipcode.lua new file mode 100644 index 0000000000..b8e60da015 --- /dev/null +++ b/quarkus-modules/quarkus-vs-springboot/wrk/post_zipcode.lua @@ -0,0 +1,73 @@ +local require = require +local json = require "json" + +math.randomseed(os.clock()*100000000000) + +function ParseCSVLine(line,sep) + local res = {} + local pos = 1 + sep = sep or ',' + while true do + local c = string.sub(line,pos,pos) + if (c == "") then break end + if (c == '"') then + local txt = "" + repeat + local startp,endp = string.find(line,'^%b""',pos) + txt = txt..string.sub(line,startp+1,endp-1) + pos = endp + 1 + c = string.sub(line,pos,pos) + if (c == '"') then txt = txt..'"' end + + until (c ~= '"') + table.insert(res,txt) + assert(c == sep or c == "") + pos = pos + 1 + else + local startp,endp = string.find(line,sep,pos) + if (startp) then + table.insert(res,string.sub(line,pos,startp-1)) + pos = endp + 1 + else + table.insert(res,string.sub(line,pos)) + break + end + end + end + return res +end + +loadFile = function() + local filename = "zip_code_database.csv" + + local data = {} + local count = 0 + local sep = "," + + for line in io.lines(filename) do + local values = ParseCSVLine(line,sep) + data[count + 1] = { zip=values[1], type=values[2], city=values[4], state=values[7], county=values[8], timezone=values[9] } + count = count + 1 + end + + return data +end + +local data = loadFile() + +request = function() + local url_path = "/zipcode" + local val = data[math.random(1, 12079)] + + local headers = { ["Content-Type"] = "application/json;charset=UTF-8" } + return wrk.format("POST", url_path, headers, json.stringify(val)) +end + +done = function(summary, latency, requests) + io.write("--------------POST ZIPCODE----------------\n") + for _, p in pairs({ 50, 75, 90, 99, 99.999 }) do + n = latency:percentile(p) + io.write(string.format("%g%%,%d\n", p, n)) + end + io.write("------------------------------------------\n\n") +end \ No newline at end of file diff --git a/quarkus-modules/quarkus-vs-springboot/wrk/run_test_wrk.sh b/quarkus-modules/quarkus-vs-springboot/wrk/run_test_wrk.sh new file mode 100755 index 0000000000..0d565d0688 --- /dev/null +++ b/quarkus-modules/quarkus-vs-springboot/wrk/run_test_wrk.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +$wrk_home/wrk -t1 -c5 -d1m -s ./post_zipcode.lua --timeout 2m -H 'Host: localhost' http://localhost:8080 & sleep 60 + +$wrk_home/wrk -t1 -c20 -d5m -s ./post_zipcode.lua --timeout 2m -H 'Host: localhost' http://localhost:8080 & sleep 60 + +$wrk_home/wrk -t1 -c20 -d5m -s ./get_by_city.lua --timeout 2m -H 'Host: localhost' http://localhost:8080 \ & +$wrk_home/wrk -t1 -c20 -d5m -s ./get_zipcode.lua --timeout 2m -H 'Host: localhost' http://localhost:8080 \ & sleep 120 + +$wrk_home/wrk -t2 -c10 -d3m -s ./get_by_city.lua --timeout 2m -H 'Host: localhost' http://localhost:8080 \ & +$wrk_home/wrk -t2 -c10 -d3m -s ./get_zipcode.lua --timeout 2m -H 'Host: localhost' http://localhost:8080 \ & + +wait + diff --git a/quarkus-modules/quarkus/README.md b/quarkus-modules/quarkus/README.md index 94b71dd954..9e45cb1c81 100644 --- a/quarkus-modules/quarkus/README.md +++ b/quarkus-modules/quarkus/README.md @@ -1,4 +1,4 @@ ## Relevant Articles: -- [Guide to QuarkusIO](https://www.baeldung.com/quarkus-io) +- [Guide to Quarkus](https://www.baeldung.com/quarkus-io) - [Testing Quarkus Applications](https://www.baeldung.com/java-quarkus-testing) diff --git a/spring-5-reactive-modules/spring-5-reactive-3/README.md b/spring-5-reactive-modules/spring-5-reactive-3/README.md index da44bf98fc..044b3db5f4 100644 --- a/spring-5-reactive-modules/spring-5-reactive-3/README.md +++ b/spring-5-reactive-modules/spring-5-reactive-3/README.md @@ -3,4 +3,5 @@ This module contains articles about reactive Spring 5. - [Logging a Reactive Sequence](https://www.baeldung.com/spring-reactive-sequence-logging) +- [Reading Flux Into a Single InputStream Using Spring Reactive WebClient](https://www.baeldung.com/spring-reactive-read-flux-into-inputstream) - More articles: [[<-- prev]](../spring-5-reactive-2) diff --git a/spring-5-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctions.java b/spring-5-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctions.java index 34abada2f1..b7bb53600e 100644 --- a/spring-5-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctions.java +++ b/spring-5-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctions.java @@ -24,11 +24,12 @@ public class ExploreSpring5URLPatternUsingRouterFunctions { private RouterFunction routingFunction() { - return route(GET("/p?ths"), serverRequest -> ok().body(fromValue("/p?ths"))).andRoute(GET("/test/{*id}"), serverRequest -> ok().body(fromValue(serverRequest.pathVariable("id")))) - .andRoute(GET("/*card"), serverRequest -> ok().body(fromValue("/*card path was accessed"))) + return route(GET("/t?st"), serverRequest -> ok().body(fromValue("Path /t?st is accessed"))).andRoute(GET("/test/{*id}"), serverRequest -> ok().body(fromValue(serverRequest.pathVariable("id")))) + .andRoute(GET("/baeldung/*Id"), serverRequest -> ok().body(fromValue("/baeldung/*Id path was accessed"))) .andRoute(GET("/{var1}_{var2}"), serverRequest -> ok().body(fromValue(serverRequest.pathVariable("var1") + " , " + serverRequest.pathVariable("var2")))) .andRoute(GET("/{baeldung:[a-z]+}"), serverRequest -> ok().body(fromValue("/{baeldung:[a-z]+} was accessed and baeldung=" + serverRequest.pathVariable("baeldung")))) - .and(RouterFunctions.resources("/files/{*filepaths}", new ClassPathResource("files/"))); + .and(RouterFunctions.resources("/files/{*filepaths}", new ClassPathResource("files/"))) + .and(RouterFunctions.resources("/resources/**", new ClassPathResource("resources/"))); } WebServer start() throws Exception { diff --git a/spring-5-reactive-modules/spring-5-reactive/src/main/resources/resources/test/test.txt b/spring-5-reactive-modules/spring-5-reactive/src/main/resources/resources/test/test.txt new file mode 100644 index 0000000000..30d74d2584 --- /dev/null +++ b/spring-5-reactive-modules/spring-5-reactive/src/main/resources/resources/test/test.txt @@ -0,0 +1 @@ +test \ No newline at end of file diff --git a/spring-5-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctionsIntegrationTest.java b/spring-5-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctionsIntegrationTest.java index 91721d2cef..a77a67c6ba 100644 --- a/spring-5-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctionsIntegrationTest.java +++ b/spring-5-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctionsIntegrationTest.java @@ -27,12 +27,12 @@ public class ExploreSpring5URLPatternUsingRouterFunctionsIntegrationTest { @Test public void givenRouter_whenGetPathWithSingleCharWildcard_thenGotPathPattern() throws Exception { client.get() - .uri("/paths") + .uri("/test") .exchange() .expectStatus() .isOk() .expectBody(String.class) - .isEqualTo("/p?ths"); + .isEqualTo("Path /t?st is accessed"); } @Test @@ -50,12 +50,12 @@ public class ExploreSpring5URLPatternUsingRouterFunctionsIntegrationTest { public void givenRouter_whenGetMultipleCharWildcard_thenGotPathPattern() throws Exception { client.get() - .uri("/wildcard") + .uri("/baeldung/tutorialId") .exchange() .expectStatus() .isOk() .expectBody(String.class) - .isEqualTo("/*card path was accessed"); + .isEqualTo("/baeldung/*Id path was accessed"); } @Test @@ -107,4 +107,14 @@ public class ExploreSpring5URLPatternUsingRouterFunctionsIntegrationTest { .isEqualTo("hello"); } + @Test + public void givenRouter_whenAccess_thenGot() throws Exception { + client.get() + .uri("/resources/test/test.txt") + .exchange() + .expectStatus() + .isOk() + .expectBody(String.class) + .isEqualTo("test"); + } } diff --git a/spring-5-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/reactive/urlmatch/PathPatternsUsingHandlerMethodIntegrationTest.java b/spring-5-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/reactive/urlmatch/PathPatternsUsingHandlerMethodIntegrationTest.java index d4c1cfe4c8..0b4607b54a 100644 --- a/spring-5-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/reactive/urlmatch/PathPatternsUsingHandlerMethodIntegrationTest.java +++ b/spring-5-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/reactive/urlmatch/PathPatternsUsingHandlerMethodIntegrationTest.java @@ -27,13 +27,21 @@ public class PathPatternsUsingHandlerMethodIntegrationTest { @Test public void givenHandlerMethod_whenMultipleURIVariablePattern_then200() { - client.get() - .uri("/spring5/ab/cd") + client.get() + .uri("/spring5/baeldung/tutorial") .exchange() .expectStatus() .is2xxSuccessful() .expectBody() - .equals("/ab/cd"); + .equals("/baeldung/tutorial"); + + client.get() + .uri("/spring5/baeldung") + .exchange() + .expectStatus() + .is2xxSuccessful() + .expectBody() + .equals("/baeldung"); } @Test diff --git a/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/jandexlib/JandexScannerService.java b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/jandexlib/JandexScannerService.java index fc10db223e..7ed41af65d 100644 --- a/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/jandexlib/JandexScannerService.java +++ b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/jandexlib/JandexScannerService.java @@ -27,7 +27,9 @@ public class JandexScannerService implements SampleAnnotationScanner { try { final IndexReader reader = new IndexReader(appFile.getInputStream()); Index jandexFile = reader.read(); - final List appAnnotationList = jandexFile.getAnnotations(DotName.createSimple("com.baeldung.annotation.scanner.SampleAnnotation")); + final List appAnnotationList = jandexFile + .getAnnotations(DotName + .createSimple("com.baeldung.annotation.scanner.SampleAnnotation")); List annotatedMethods = new ArrayList<>(); for (AnnotationInstance annotationInstance : appAnnotationList) { if (annotationInstance.target() @@ -48,7 +50,9 @@ public class JandexScannerService implements SampleAnnotationScanner { try { final IndexReader reader = new IndexReader(appFile.getInputStream()); Index jandexFile = reader.read(); - final List appAnnotationList = jandexFile.getAnnotations(DotName.createSimple("com.baeldung.annotation.scanner.SampleAnnotation")); + final List appAnnotationList = jandexFile + .getAnnotations(DotName + .createSimple("com.baeldung.annotation.scanner.SampleAnnotation")); List annotatedClasses = new ArrayList<>(); for (AnnotationInstance annotationInstance : appAnnotationList) { if (annotationInstance.target() diff --git a/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/javareflectionlib/JavaReflectionsScannerService.java b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/javareflectionlib/JavaReflectionsScannerService.java index 2833bb1326..76a2293965 100644 --- a/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/javareflectionlib/JavaReflectionsScannerService.java +++ b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/javareflectionlib/JavaReflectionsScannerService.java @@ -1,5 +1,6 @@ package com.baeldung.annotation.scanner.javareflectionlib; +import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; @@ -37,9 +38,14 @@ public class JavaReflectionsScannerService implements SampleAnnotationScanner { try { Class clazz = ClassLoader.getSystemClassLoader() .loadClass("com.baeldung.annotation.scanner.SampleAnnotatedClass"); - SampleAnnotation classAnnotation = clazz.getAnnotation(SampleAnnotation.class); List annotatedClasses = new ArrayList<>(); - annotatedClasses.add(classAnnotation.name()); + Annotation[] classAnnotations = clazz.getAnnotations(); + for (Annotation annotation : classAnnotations) { + if (annotation.annotationType() + .equals(SampleAnnotation.class)) { + annotatedClasses.add(((SampleAnnotation) annotation).name()); + } + } return Collections.unmodifiableList(annotatedClasses); } catch (ClassNotFoundException e) { throw new UnexpectedScanException(e); diff --git a/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/reflectionslib/ReflectionsScannerService.java b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/reflectionslib/ReflectionsScannerService.java index 82a10e21aa..9cee4f19e2 100644 --- a/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/reflectionslib/ReflectionsScannerService.java +++ b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/reflectionslib/ReflectionsScannerService.java @@ -16,7 +16,8 @@ public class ReflectionsScannerService implements SampleAnnotationScanner { @Override public List scanAnnotatedMethods() { Reflections reflections = new Reflections("com.baeldung.annotation.scanner"); - Set methods = reflections.getMethodsAnnotatedWith(SampleAnnotation.class); + Set methods = reflections + .getMethodsAnnotatedWith(SampleAnnotation.class); return methods.stream() .map(method -> method.getAnnotation(SampleAnnotation.class) .name()) @@ -26,7 +27,8 @@ public class ReflectionsScannerService implements SampleAnnotationScanner { @Override public List scanAnnotatedClasses() { Reflections reflections = new Reflections("com.baeldung.annotation.scanner"); - Set> types = reflections.getTypesAnnotatedWith(SampleAnnotation.class); + Set> types = reflections + .getTypesAnnotatedWith(SampleAnnotation.class); return types.stream() .map(clazz -> clazz.getAnnotation(SampleAnnotation.class) .name()) diff --git a/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/springcontextlib/SpringBeanAnnotationScannerService.java b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/springcontextlib/SpringContextAnnotationScannerService.java similarity index 80% rename from spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/springcontextlib/SpringBeanAnnotationScannerService.java rename to spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/springcontextlib/SpringContextAnnotationScannerService.java index cd31ae686e..8d52067ccc 100644 --- a/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/springcontextlib/SpringBeanAnnotationScannerService.java +++ b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/springcontextlib/SpringContextAnnotationScannerService.java @@ -17,7 +17,7 @@ import com.baeldung.annotation.scanner.SampleAnnotationScanner; import com.baeldung.annotation.scanner.ScanNotSupportedException; @Service -public class SpringBeanAnnotationScannerService implements SampleAnnotationScanner { +public class SpringContextAnnotationScannerService implements SampleAnnotationScanner { @Override public List scanAnnotatedMethods() { throw new ScanNotSupportedException(); @@ -25,13 +25,16 @@ public class SpringBeanAnnotationScannerService implements SampleAnnotationScann @Override public List scanAnnotatedClasses() { - ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false); + ClassPathScanningCandidateComponentProvider provider = + new ClassPathScanningCandidateComponentProvider(false); provider.addIncludeFilter(new AnnotationTypeFilter(SampleAnnotation.class)); - Set beanDefs = provider.findCandidateComponents("com.baeldung.annotation.scanner"); + Set beanDefs = provider + .findCandidateComponents("com.baeldung.annotation.scanner"); List annotatedBeans = new ArrayList<>(); for (BeanDefinition bd : beanDefs) { if (bd instanceof AnnotatedBeanDefinition) { - Map annotAttributeMap = ((AnnotatedBeanDefinition) bd).getMetadata() + Map annotAttributeMap = ((AnnotatedBeanDefinition) bd) + .getMetadata() .getAnnotationAttributes(SampleAnnotation.class.getCanonicalName()); annotatedBeans.add(annotAttributeMap.get("name") .toString()); diff --git a/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/springcorelib/SpringCoreAnnotationScannerService.java b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/springcorelib/SpringCoreAnnotationScannerService.java index f3421fe46d..14542a9104 100644 --- a/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/springcorelib/SpringCoreAnnotationScannerService.java +++ b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/springcorelib/SpringCoreAnnotationScannerService.java @@ -8,21 +8,24 @@ import org.springframework.core.annotation.AnnotationUtils; import org.springframework.stereotype.Service; import org.springframework.util.ClassUtils; -import com.baeldung.annotation.scanner.SampleAnnotationScanner; import com.baeldung.annotation.scanner.SampleAnnotatedClass; import com.baeldung.annotation.scanner.SampleAnnotation; +import com.baeldung.annotation.scanner.SampleAnnotationScanner; import com.baeldung.annotation.scanner.ScanNotSupportedException; @Service public class SpringCoreAnnotationScannerService implements SampleAnnotationScanner { @Override public List scanAnnotatedMethods() { - final Class userClass = ClassUtils.getUserClass(SampleAnnotatedClass.class); - return Arrays.stream(userClass.getMethods()) - .filter(method -> AnnotationUtils.getAnnotation(method, SampleAnnotation.class) != null) + Class userClass = ClassUtils.getUserClass(SampleAnnotatedClass.class); + List annotatedMethods = Arrays.stream(userClass.getMethods()) + .filter(method -> AnnotationUtils + .getAnnotation(method, SampleAnnotation.class) != null) .map(method -> method.getAnnotation(SampleAnnotation.class) .name()) .collect(Collectors.toList()); + + return annotatedMethods; } @Override diff --git a/spring-boot-modules/spring-boot-libraries-2/src/test/java/com/baeldung/annotation/scanner/SampleAnnotationScannerUnitTest.java b/spring-boot-modules/spring-boot-libraries-2/src/test/java/com/baeldung/annotation/scanner/SampleAnnotationScannerUnitTest.java index 80eca2b4c5..7c3d01b5e8 100644 --- a/spring-boot-modules/spring-boot-libraries-2/src/test/java/com/baeldung/annotation/scanner/SampleAnnotationScannerUnitTest.java +++ b/spring-boot-modules/spring-boot-libraries-2/src/test/java/com/baeldung/annotation/scanner/SampleAnnotationScannerUnitTest.java @@ -28,7 +28,8 @@ public class SampleAnnotationScannerUnitTest { assertNotNull(annotatedClasses); assertEquals(4, annotatedClasses.size()); - annotatedClasses.forEach(annotValue -> assertEquals("SampleAnnotatedClass", annotValue)); + annotatedClasses.forEach(annotValue -> assertEquals("SampleAnnotatedClass", + annotValue)); } @Test @@ -41,7 +42,7 @@ public class SampleAnnotationScannerUnitTest { assertNotNull(annotatedMethods); assertEquals(3, annotatedMethods.size()); - annotatedMethods.forEach(annotValue -> assertEquals("annotatedMethod", annotValue)); + annotatedMethods.forEach(annotValue -> assertEquals("annotatedMethod", + annotValue)); } - } diff --git a/spring-boot-modules/spring-boot-mvc-3/pom.xml b/spring-boot-modules/spring-boot-mvc-3/pom.xml index f2b6c129f8..6b0477cfc8 100644 --- a/spring-boot-modules/spring-boot-mvc-3/pom.xml +++ b/spring-boot-modules/spring-boot-mvc-3/pom.xml @@ -47,11 +47,4 @@ - - - - /src/main/resources - - - \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-mvc-3/src/test/java/com/baeldung/etag/EtagIntegrationTest.java b/spring-boot-modules/spring-boot-mvc-3/src/test/java/com/baeldung/etag/EtagIntegrationTest.java index 97de6d06f1..d7b50cb7fb 100644 --- a/spring-boot-modules/spring-boot-mvc-3/src/test/java/com/baeldung/etag/EtagIntegrationTest.java +++ b/spring-boot-modules/spring-boot-mvc-3/src/test/java/com/baeldung/etag/EtagIntegrationTest.java @@ -9,7 +9,6 @@ import org.assertj.core.util.Preconditions; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; import org.springframework.boot.web.server.LocalServerPort; @@ -26,7 +25,6 @@ import static org.junit.Assert.assertTrue; @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) @ComponentScan(basePackageClasses = WebConfig.class) -@EnableAutoConfiguration public class EtagIntegrationTest { @LocalServerPort diff --git a/spring-boot-modules/spring-boot-mvc-3/src/test/java/com/baeldung/produceimage/DataProducerControllerIntegrationTest.java b/spring-boot-modules/spring-boot-mvc-3/src/test/java/com/baeldung/produceimage/DataProducerControllerIntegrationTest.java index 29f794645a..eb459d88cc 100644 --- a/spring-boot-modules/spring-boot-mvc-3/src/test/java/com/baeldung/produceimage/DataProducerControllerIntegrationTest.java +++ b/spring-boot-modules/spring-boot-mvc-3/src/test/java/com/baeldung/produceimage/DataProducerControllerIntegrationTest.java @@ -1,32 +1,23 @@ package com.baeldung.produceimage; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; -import org.springframework.web.context.WebApplicationContext; - @SpringBootTest(classes = ImageApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@AutoConfigureMockMvc public class DataProducerControllerIntegrationTest { @Autowired - private WebApplicationContext webApplicationContext; - private MockMvc mockMvc; - @BeforeEach - public void setup() { - this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build(); - } - @Test void givenJpgTrue_whenGetImageDynamicType_ThenContentTypeIsJpg() throws Exception { mockMvc.perform(get("/get-image-dynamic-type?jpg=true")) diff --git a/spring-boot-modules/spring-boot-springdoc/README.md b/spring-boot-modules/spring-boot-springdoc/README.md index 733e31e698..3d0fd19ab1 100644 --- a/spring-boot-modules/spring-boot-springdoc/README.md +++ b/spring-boot-modules/spring-boot-springdoc/README.md @@ -6,3 +6,4 @@ - [Swagger @Api Description Is Deprecated](https://www.baeldung.com/java-swagger-api-description-deprecated) - [Set List of Objects in Swagger API Response](https://www.baeldung.com/java-swagger-set-list-response) - [Configure JWT Authentication for OpenAPI](https://www.baeldung.com/openapi-jwt-authentication) +- [Apply Default Global SecurityScheme in springdoc-openapi](https://www.baeldung.com/spring-openapi-global-securityscheme) diff --git a/spring-core-6/pom.xml b/spring-core-6/pom.xml index 92cd343234..af6fb50e1d 100644 --- a/spring-core-6/pom.xml +++ b/spring-core-6/pom.xml @@ -1,7 +1,7 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 com.baeldung @@ -10,23 +10,36 @@ spring-core-6 http://www.baeldung.com + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + + UTF-8 11 11 + 2.7.2 - junit - junit - 4.11 - test + org.springframework.boot + spring-boot-starter-web + ${spring.boot.version} org.springframework.boot - spring-boot-starter-web - 2.0.0.RELEASE + spring-boot-starter-test + ${spring.boot.version} + test + + + org.junit.jupiter + junit-jupiter-api + ${junit-jupiter.version} + test diff --git a/spring-core-6/src/main/java/com/baeldung/envvariables/BaeldungProperties.java b/spring-core-6/src/main/java/com/baeldung/envvariables/BaeldungProperties.java new file mode 100644 index 0000000000..a41ac7a509 --- /dev/null +++ b/spring-core-6/src/main/java/com/baeldung/envvariables/BaeldungProperties.java @@ -0,0 +1,20 @@ +package com.baeldung.envvariables.valueinjection; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Component +@ConfigurationProperties(prefix = "baeldung") +public class BaeldungProperties { + + private String presentation; + + public String getPresentation() { + return presentation; + } + + public void setPresentation(String presentation) { + this.presentation = presentation; + } + +} diff --git a/spring-core-6/src/main/java/com/baeldung/envvariables/MyController.java b/spring-core-6/src/main/java/com/baeldung/envvariables/MyController.java new file mode 100644 index 0000000000..503ee47157 --- /dev/null +++ b/spring-core-6/src/main/java/com/baeldung/envvariables/MyController.java @@ -0,0 +1,60 @@ +package com.baeldung.envvariables.valueinjection; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.env.Environment; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class MyController { + + @Value("${environment.name}") + private String environmentName; + + @Value("${java.home.and.environment}") + private String javaHomeAndEnvironmentName; + + @Value("${thispropertydoesnotexist}") + private String nonExistentProperty; + + @Value("${baeldung.presentation}") + private String baeldungPresentation; + + @Autowired + private Environment environment; + + @Autowired + private BaeldungProperties baeldungProperties; + + @GetMapping("/environment_name") + String getEnvironmentName_FromEnvironmentVariables() { + return environmentName; + } + + @GetMapping("/java_home_and_environment") + String getJavaHomeAndEnvironmentName_FromEnvironmentVariables() { + return javaHomeAndEnvironmentName; + } + + @GetMapping("non_existent_property") + String getNonexistentProperty_FromEnvironmentVariables() { + return nonExistentProperty; + } + + @GetMapping("baeldung_presentation_from_value") + String getBaeldungPresentation_FromValue() { + return baeldungPresentation; + } + + @GetMapping("baeldung_presentation_from_environment") + String getBaeldungPresentation_FromEnvironment() { + return environment.getProperty("baeldung.presentation"); + } + + @GetMapping("baeldung_configuration_properties") + String getBaeldungPresentation_FromConfigurationProperties() { + return baeldungProperties.getPresentation(); + } + +} diff --git a/spring-core-6/src/main/resources/application.properties b/spring-core-6/src/main/resources/application.properties new file mode 100644 index 0000000000..d0029f363c --- /dev/null +++ b/spring-core-6/src/main/resources/application.properties @@ -0,0 +1,4 @@ +environment.name=${OS} +java.home.and.environment=${JAVA_HOME}+${OS} +not.existing.system.property=${thispropertydoesnotexist} +baeldung.presentation=${HELLO_BAELDUNG}. Java is installed in the folder: ${JAVA_HOME} \ No newline at end of file diff --git a/spring-core-6/src/test/java/com/baeldung/envvariables/MyControllerIntegrationTest.java b/spring-core-6/src/test/java/com/baeldung/envvariables/MyControllerIntegrationTest.java new file mode 100644 index 0000000000..b3ee2c7c46 --- /dev/null +++ b/spring-core-6/src/test/java/com/baeldung/envvariables/MyControllerIntegrationTest.java @@ -0,0 +1,36 @@ +package com.baeldung.envvariables.valueinjection; + +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.web.servlet.MockMvc; + +@SpringBootTest(classes = MyController.class) +@AutoConfigureMockMvc +public class MyControllerIntegrationTest { + + @Autowired + private MockMvc mockMvc; + + /** NB : these tests are commented out because they are environment dependent + * If you want to run one of them on your machine, follow the instruction above it + * + * expects the value of your system environment property 'OS' (it is already defined at least in Windows_NT) + @Test void givenExistingSystemProperty_whenInjected_thenHasSystemPropertyValue() throws Exception { + mockMvc.perform(get("/environment_name")) + .andExpect(content().string(equalTo("Windows_NT"))); + } + + * expects the value of the JAVA_HOME environment variable (you need to define it if you haven't yet), with a + and the 'OS' environment property in the end + @Test void givenCombinationOfSystemPropertyAndEnvironmentVariable_whenInjected_thenHasExpectedValue() throws Exception { + mockMvc.perform(get("/java_home_and_environment")) + .andExpect(content().string(equalTo("C:\\Program Files\\Java\\jdk-11.0.14+Windows_NT"))); + } + + * expects the content to be ${thispropertydoesnotexist} ; if you have defined an environment property called thispropertydoesnotexist, it would fail + @Test void givenNonExistentProperty_whenInjected_thenKeepsTheStringValue() throws Exception { + mockMvc.perform(get("/non_existent_property")) + .andExpect(content().string(equalTo("${thispropertydoesnotexist}"))); + } + */ +} diff --git a/spring-jms/README.md b/spring-jms/README.md index fdeb64953a..666e32fa4b 100644 --- a/spring-jms/README.md +++ b/spring-jms/README.md @@ -4,3 +4,4 @@ This module contains articles about Spring with JMS ### Relevant Articles: - [Getting Started with Spring JMS](https://www.baeldung.com/spring-jms) +- [Testing Spring JMS](https://www.baeldung.com/spring-jms-testing) diff --git a/spring-kafka/src/main/java/com/baeldung/countingmessages/Application.java b/spring-kafka/src/main/java/com/baeldung/countingmessages/Application.java new file mode 100644 index 0000000000..7649494438 --- /dev/null +++ b/spring-kafka/src/main/java/com/baeldung/countingmessages/Application.java @@ -0,0 +1,11 @@ +package com.baeldung.countingmessages; + +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/spring-kafka/src/main/java/com/baeldung/countingmessages/KafkaCountingMessagesComponent.java b/spring-kafka/src/main/java/com/baeldung/countingmessages/KafkaCountingMessagesComponent.java new file mode 100644 index 0000000000..91ce1b0cbe --- /dev/null +++ b/spring-kafka/src/main/java/com/baeldung/countingmessages/KafkaCountingMessagesComponent.java @@ -0,0 +1,52 @@ +package com.baeldung.countingmessages; + +import org.apache.kafka.clients.consumer.ConsumerConfig; +import org.apache.kafka.common.TopicPartition; +import org.apache.kafka.common.serialization.StringDeserializer; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + + +@Component +public class KafkaCountingMessagesComponent { + @Value(value = "${kafka.bootstrapAddress}") + private String bootstrapAddress; + + public static Map props = new HashMap<>(); + + @PostConstruct + public void init(){ + System.out.println(getTotalNumberOfMessagesInATopic("baeldung")); + } + + public Long getTotalNumberOfMessagesInATopic(String topic){ + org.apache.kafka.clients.consumer.KafkaConsumer consumer = new org.apache.kafka.clients.consumer.KafkaConsumer<>(getProps()); + List partitions = consumer.partitionsFor(topic).stream() + .map(p -> new TopicPartition(topic, p.partition())) + .collect(Collectors.toList()); + consumer.assign(partitions); + consumer.seekToEnd(Collections.emptySet()); + Map endPartitions = partitions.stream() + .collect(Collectors.toMap(Function.identity(), consumer::position)); + return partitions.stream().mapToLong(p -> endPartitions.get(p)).sum(); + } + + public Map getProps() { + if (props.isEmpty()) { + props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapAddress); + props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); + props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); + props.put(ConsumerConfig.MAX_PARTITION_FETCH_BYTES_CONFIG, "20971520"); + props.put(ConsumerConfig.FETCH_MAX_BYTES_CONFIG, "20971520"); + } + return props; + } +} diff --git a/spring-security-modules/pom.xml b/spring-security-modules/pom.xml index 2bd6d23058..83412d2252 100644 --- a/spring-security-modules/pom.xml +++ b/spring-security-modules/pom.xml @@ -32,6 +32,7 @@ spring-security-web-boot-1 spring-security-web-boot-2 spring-security-web-boot-3 + spring-security-web-boot-4 spring-security-web-digest-auth spring-security-web-login spring-security-web-login-2 diff --git a/spring-security-modules/spring-security-web-boot-4/README.md b/spring-security-modules/spring-security-web-boot-4/README.md new file mode 100644 index 0000000000..0856315682 --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-4/README.md @@ -0,0 +1,10 @@ +## Spring Boot Security MVC + +This module contains articles about Spring Security with Spring MVC in Boot applications + +### The Course +The "REST With Spring" Classes: http://github.learnspringsecurity.com + +### Relevant Articles: + +- More articles: [[<-- prev]](/spring-security-modules/spring-security-web-boot-3) diff --git a/spring-security-modules/spring-security-web-boot-4/pom.xml b/spring-security-modules/spring-security-web-boot-4/pom.xml new file mode 100644 index 0000000000..8dd56e1de2 --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-4/pom.xml @@ -0,0 +1,39 @@ + + + 4.0.0 + spring-security-web-boot-4 + 0.0.1-SNAPSHOT + spring-security-web-boot-4 + jar + Spring Security MVC Boot - 4 + + + 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-security + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.security + spring-security-test + test + + + \ No newline at end of file diff --git a/spring-security-modules/spring-security-web-boot-4/src/main/java/com/baeldung/securityfilterchain/SecurityFilterChainApplication.java b/spring-security-modules/spring-security-web-boot-4/src/main/java/com/baeldung/securityfilterchain/SecurityFilterChainApplication.java new file mode 100644 index 0000000000..86f98b651b --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-4/src/main/java/com/baeldung/securityfilterchain/SecurityFilterChainApplication.java @@ -0,0 +1,14 @@ +package com.baeldung.securityfilterchain; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; + +@SpringBootApplication +@EnableWebMvc +public class SecurityFilterChainApplication { + + public static void main(String[] args) { + SpringApplication.run(SecurityFilterChainApplication.class, args); + } +} diff --git a/spring-security-modules/spring-security-web-boot-4/src/main/java/com/baeldung/securityfilterchain/configuration/SecurityConfig.java b/spring-security-modules/spring-security-web-boot-4/src/main/java/com/baeldung/securityfilterchain/configuration/SecurityConfig.java new file mode 100644 index 0000000000..4d3bec2ad2 --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-4/src/main/java/com/baeldung/securityfilterchain/configuration/SecurityConfig.java @@ -0,0 +1,50 @@ +package com.baeldung.securityfilterchain.configuration; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.http.HttpMethod; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.web.SecurityFilterChain; + +@EnableWebSecurity +@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true) +public class SecurityConfig { + + @Value("${spring.security.debug:false}") + boolean securityDebug; + + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + http.csrf() + .disable() + .authorizeRequests() + .antMatchers(HttpMethod.DELETE) + .hasRole("ADMIN") + .antMatchers("/admin/**") + .hasAnyRole("ADMIN") + .antMatchers("/user/**") + .hasAnyRole("USER", "ADMIN") + .antMatchers("/login/**") + .anonymous() + .anyRequest() + .authenticated() + .and() + .httpBasic() + .and() + .sessionManagement() + .sessionCreationPolicy(SessionCreationPolicy.STATELESS); + + return http.build(); + } + + @Bean + public WebSecurityCustomizer webSecurityCustomizer() { + return (web) -> web.debug(securityDebug) + .ignoring() + .antMatchers("/css/**", "/js/**", "/img/**", "/lib/**", "/favicon.ico"); + } +} diff --git a/spring-security-modules/spring-security-web-boot-4/src/main/java/com/baeldung/securityfilterchain/configuration/UserDetailServiceConfig.java b/spring-security-modules/spring-security-web-boot-4/src/main/java/com/baeldung/securityfilterchain/configuration/UserDetailServiceConfig.java new file mode 100644 index 0000000000..6a614e888b --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-4/src/main/java/com/baeldung/securityfilterchain/configuration/UserDetailServiceConfig.java @@ -0,0 +1,31 @@ +package com.baeldung.securityfilterchain.configuration; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.provisioning.InMemoryUserDetailsManager; + +@Configuration +public class UserDetailServiceConfig { + + @Bean + public UserDetailsService userDetailsService(BCryptPasswordEncoder bCryptPasswordEncoder) { + InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager(); + manager.createUser(User.withUsername("user") + .password(bCryptPasswordEncoder.encode("userPass")) + .roles("USER") + .build()); + manager.createUser(User.withUsername("admin") + .password(bCryptPasswordEncoder.encode("adminPass")) + .roles("ADMIN", "USER") + .build()); + return manager; + } + + @Bean + public BCryptPasswordEncoder bCryptPasswordEncoder() { + return new BCryptPasswordEncoder(); + } +} diff --git a/spring-security-modules/spring-security-web-boot-4/src/main/java/com/baeldung/securityfilterchain/controller/ResourceController.java b/spring-security-modules/spring-security-web-boot-4/src/main/java/com/baeldung/securityfilterchain/controller/ResourceController.java new file mode 100644 index 0000000000..e01d4ae9b3 --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-4/src/main/java/com/baeldung/securityfilterchain/controller/ResourceController.java @@ -0,0 +1,34 @@ +package com.baeldung.securityfilterchain.controller; + +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class ResourceController { + @GetMapping("/login") + public String loginEndpoint() { + return "Login!"; + } + + @GetMapping("/admin") + public String adminEndpoint() { + return "Admin!"; + } + + @GetMapping("/user") + public String userEndpoint() { + return "User!"; + } + + @GetMapping("/all") + public String allRolesEndpoint() { + return "All Roles!"; + } + + @DeleteMapping("/delete") + public String deleteEndpoint(@RequestBody String s) { + return "I am deleting " + s; + } +} diff --git a/spring-security-modules/spring-security-web-boot-4/src/test/java/com/baeldung/securityfilterchain/SecurityFilterChainIntegrationTest.java b/spring-security-modules/spring-security-web-boot-4/src/test/java/com/baeldung/securityfilterchain/SecurityFilterChainIntegrationTest.java new file mode 100644 index 0000000000..e94b1b2f12 --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-4/src/test/java/com/baeldung/securityfilterchain/SecurityFilterChainIntegrationTest.java @@ -0,0 +1,94 @@ +package com.baeldung.securityfilterchain; + +import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.security.test.context.support.WithAnonymousUser; +import org.springframework.security.test.context.support.WithUserDetails; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +@SpringBootTest(classes = SecurityFilterChainApplication.class) +public class SecurityFilterChainIntegrationTest { + @Autowired + private WebApplicationContext context; + + private MockMvc mvc; + + @BeforeEach + public void setup() { + mvc = MockMvcBuilders.webAppContextSetup(context) + .apply(springSecurity()) + .build(); + } + + @Test + @WithUserDetails(value = "admin") + public void whenAdminAccessUserEndpoint_thenOk() throws Exception { + mvc.perform(get("/user")) + .andExpect(status().isOk()); + } + + @Test + @WithUserDetails(value = "admin") + public void whenAdminAccessAdminSecuredEndpoint_thenIsOk() throws Exception { + mvc.perform(get("/admin")) + .andExpect(status().isOk()); + } + + @Test + @WithUserDetails(value = "admin") + public void whenAdminAccessDeleteSecuredEndpoint_thenIsOk() throws Exception { + mvc.perform(delete("/delete").content("{}")) + .andExpect(status().isOk()); + } + + @Test + @WithAnonymousUser + public void whenAnonymousAccessLogin_thenOk() throws Exception { + mvc.perform(get("/login")) + .andExpect(status().isOk()); + } + + @Test + @WithAnonymousUser + public void whenAnonymousAccessRestrictedEndpoint_thenIsUnauthorized() throws Exception { + mvc.perform(get("/all")) + .andExpect(status().isUnauthorized()); + } + + @Test + @WithUserDetails() + public void whenUserAccessUserSecuredEndpoint_thenOk() throws Exception { + mvc.perform(get("/user")) + .andExpect(status().isOk()); + } + + @Test + @WithUserDetails() + public void whenUserAccessRestrictedEndpoint_thenOk() throws Exception { + mvc.perform(get("/all")) + .andExpect(status().isOk()); + } + + @Test + @WithUserDetails() + public void whenUserAccessAdminSecuredEndpoint_thenIsForbidden() throws Exception { + mvc.perform(get("/admin")) + .andExpect(status().isForbidden()); + } + + @Test + @WithUserDetails() + public void whenUserAccessDeleteSecuredEndpoint_thenIsForbidden() throws Exception { + mvc.perform(delete("/delete")) + .andExpect(status().isForbidden()); + } +} diff --git a/spring-security-modules/spring-security-web-boot-4/src/test/resources/application.properties b/spring-security-modules/spring-security-web-boot-4/src/test/resources/application.properties new file mode 100644 index 0000000000..090ff54e92 --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-4/src/test/resources/application.properties @@ -0,0 +1 @@ +spring.security.debug=true \ No newline at end of file diff --git a/spring-security-modules/spring-security-web-boot-4/src/test/resources/logback-test.xml b/spring-security-modules/spring-security-web-boot-4/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..c5a4b0ab1c --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-4/src/test/resources/logback-test.xml @@ -0,0 +1,12 @@ + + + + + [%d{ISO8601}]-[%thread] %-5level %logger - %msg%n + + + + + + + \ No newline at end of file diff --git a/spring-security-modules/spring-security-web-thymeleaf/src/main/java/com/baeldung/customuserdetails/CustomUserDetails.java b/spring-security-modules/spring-security-web-thymeleaf/src/main/java/com/baeldung/customuserdetails/CustomUserDetails.java new file mode 100644 index 0000000000..380d9d1092 --- /dev/null +++ b/spring-security-modules/spring-security-web-thymeleaf/src/main/java/com/baeldung/customuserdetails/CustomUserDetails.java @@ -0,0 +1,94 @@ +package com.baeldung.customuserdetails; + +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.User; + +import java.util.Collection; +import java.util.Objects; + +public class CustomUserDetails extends User { + + private final String firstName; + private final String lastName; + private final String email; + + private CustomUserDetails(Builder builder) { + super(builder.username, builder.password, builder.authorities); + this.firstName = builder.firstName; + this.lastName = builder.lastName; + this.email = builder.email; + } + + public String getLastName() { + return this.lastName; + } + + public String getFirstName() { + return this.firstName; + } + + public String getEmail() { + return email; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + if (!super.equals(o)) + return false; + CustomUserDetails that = (CustomUserDetails) o; + return firstName.equals(that.firstName) && lastName.equals(that.lastName) && email.equals(that.email); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), firstName, lastName, email); + } + + public static class Builder { + + private String firstName; + private String lastName; + private String email; + private String username; + private String password; + private Collection authorities; + + public Builder withFirstName(String firstName) { + this.firstName = firstName; + return this; + } + + public Builder withLastName(String lastName) { + this.lastName = lastName; + return this; + } + + public Builder withEmail(String email) { + this.email = email; + return this; + } + + public Builder withUsername(String username) { + this.username = username; + return this; + } + + public Builder withPassword(String password) { + this.password = password; + return this; + } + + public Builder withAuthorities(Collection authorities) { + this.authorities = authorities; + return this; + } + + public CustomUserDetails build() { + return new CustomUserDetails(this); + } + } +} diff --git a/spring-security-modules/spring-security-web-thymeleaf/src/main/java/com/baeldung/customuserdetails/CustomUserDetailsService.java b/spring-security-modules/spring-security-web-thymeleaf/src/main/java/com/baeldung/customuserdetails/CustomUserDetailsService.java new file mode 100644 index 0000000000..e84f9eac55 --- /dev/null +++ b/spring-security-modules/spring-security-web-thymeleaf/src/main/java/com/baeldung/customuserdetails/CustomUserDetailsService.java @@ -0,0 +1,52 @@ +package com.baeldung.customuserdetails; + +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +@Service +public class CustomUserDetailsService implements UserDetailsService { + + private final PasswordEncoder passwordEncoder; + private final Map userRegistry = new HashMap<>(); + + public CustomUserDetailsService(PasswordEncoder passwordEncoder) { + this.passwordEncoder = passwordEncoder; + } + + @PostConstruct + public void init() { + userRegistry.put("user", new CustomUserDetails.Builder().withFirstName("Mark") + .withLastName("Johnson") + .withEmail("mark.johnson@email.com") + .withUsername("user") + .withPassword(passwordEncoder.encode("password")) + .withAuthorities(Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER"))) + .build()); + userRegistry.put("admin", new CustomUserDetails.Builder().withFirstName("James") + .withLastName("Davis") + .withEmail("james.davis@email.com") + .withUsername("admin") + .withPassword(passwordEncoder.encode("admin")) + .withAuthorities(Collections.singletonList(new SimpleGrantedAuthority("ROLE_ADMIN"))) + .build()); + } + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + final CustomUserDetails userDetails = userRegistry.get(username); + if (userDetails == null) { + throw new UsernameNotFoundException(username); + } + return userDetails; + } +} diff --git a/spring-security-modules/spring-security-web-thymeleaf/src/main/java/com/baeldung/customuserdetails/PasswordEncoderConfiguration.java b/spring-security-modules/spring-security-web-thymeleaf/src/main/java/com/baeldung/customuserdetails/PasswordEncoderConfiguration.java new file mode 100644 index 0000000000..fa19b62577 --- /dev/null +++ b/spring-security-modules/spring-security-web-thymeleaf/src/main/java/com/baeldung/customuserdetails/PasswordEncoderConfiguration.java @@ -0,0 +1,15 @@ +package com.baeldung.customuserdetails; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; + +@Configuration +public class PasswordEncoderConfiguration { + + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } +} diff --git a/spring-security-modules/spring-security-web-thymeleaf/src/main/java/com/baeldung/customuserdetails/SecurityConfiguration.java b/spring-security-modules/spring-security-web-thymeleaf/src/main/java/com/baeldung/customuserdetails/SecurityConfiguration.java new file mode 100644 index 0000000000..5d5863a564 --- /dev/null +++ b/spring-security-modules/spring-security-web-thymeleaf/src/main/java/com/baeldung/customuserdetails/SecurityConfiguration.java @@ -0,0 +1,38 @@ +package com.baeldung.customuserdetails; + +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; + +@Configuration +@EnableWebSecurity +public class SecurityConfiguration extends WebSecurityConfigurerAdapter { + + private final UserDetailsService userDetailsService; + + public SecurityConfiguration(UserDetailsService userDetailsService) { + this.userDetailsService = userDetailsService; + } + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.userDetailsService(userDetailsService) + .authorizeRequests() + .anyRequest() + .authenticated() + .and() + .formLogin() + .loginPage("/login") + .permitAll() + .successForwardUrl("/index") + .and() + .logout() + .permitAll() + .logoutRequestMatcher(new AntPathRequestMatcher("/logout")) + .logoutSuccessUrl("/login"); + } + +} diff --git a/spring-security-modules/spring-security-web-thymeleaf/src/main/java/com/baeldung/customuserdetails/SpringSecurityThymeleafApplication.java b/spring-security-modules/spring-security-web-thymeleaf/src/main/java/com/baeldung/customuserdetails/SpringSecurityThymeleafApplication.java new file mode 100644 index 0000000000..35cbc77552 --- /dev/null +++ b/spring-security-modules/spring-security-web-thymeleaf/src/main/java/com/baeldung/customuserdetails/SpringSecurityThymeleafApplication.java @@ -0,0 +1,12 @@ +package com.baeldung.customuserdetails; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SpringSecurityThymeleafApplication { + + public static void main(String[] args) { + SpringApplication.run(SpringSecurityThymeleafApplication.class, args); + } +} diff --git a/spring-security-modules/spring-security-web-thymeleaf/src/main/java/com/baeldung/customuserdetails/ViewController.java b/spring-security-modules/spring-security-web-thymeleaf/src/main/java/com/baeldung/customuserdetails/ViewController.java new file mode 100644 index 0000000000..bc4c41392d --- /dev/null +++ b/spring-security-modules/spring-security-web-thymeleaf/src/main/java/com/baeldung/customuserdetails/ViewController.java @@ -0,0 +1,21 @@ +package com.baeldung.customuserdetails; + +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +public class ViewController { + + @RequestMapping("/login") + public String login() { + return "login"; + } + + @RequestMapping({ "/index", "/" }) + public String index() { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + return "userdetails"; + } +} diff --git a/spring-security-modules/spring-security-web-thymeleaf/src/main/resources/templates/userdetails.html b/spring-security-modules/spring-security-web-thymeleaf/src/main/resources/templates/userdetails.html new file mode 100644 index 0000000000..5963fbc29e --- /dev/null +++ b/spring-security-modules/spring-security-web-thymeleaf/src/main/resources/templates/userdetails.html @@ -0,0 +1,25 @@ + + + +Welcome to Spring Security Thymeleaf tutorial + + +

Welcome

+

Spring Security Thymeleaf tutorial

+
Text visible to user.
+
Text visible to admin.
+
Text visible only to + authenticated users.
+ Authenticated username: +
+ Authenticated user's firstName: +
+ Authenticated user's lastName: +
+ Authenticated user's email: +
+ Authenticated user roles: +
+ + + \ No newline at end of file diff --git a/spring-security-modules/spring-security-web-thymeleaf/src/test/java/com/baeldung/customuserdetails/SpringSecurityThymeleafApplicationIntegrationTest.java b/spring-security-modules/spring-security-web-thymeleaf/src/test/java/com/baeldung/customuserdetails/SpringSecurityThymeleafApplicationIntegrationTest.java new file mode 100644 index 0000000000..c3b11e648a --- /dev/null +++ b/spring-security-modules/spring-security-web-thymeleaf/src/test/java/com/baeldung/customuserdetails/SpringSecurityThymeleafApplicationIntegrationTest.java @@ -0,0 +1,29 @@ +package com.baeldung.customuserdetails; + +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 org.springframework.web.context.WebApplicationContext; + +import static org.junit.Assert.assertNotNull; + +import com.baeldung.customuserdetails.ViewController; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class SpringSecurityThymeleafApplicationIntegrationTest { + + @Autowired + ViewController viewController; + @Autowired + WebApplicationContext wac; + + @Test + public void whenConfigured_thenLoadsContext() { + assertNotNull(viewController); + assertNotNull(wac); + } + +} diff --git a/spring-security-modules/spring-security-web-thymeleaf/src/test/java/com/baeldung/customuserdetails/ViewControllerIntegrationTest.java b/spring-security-modules/spring-security-web-thymeleaf/src/test/java/com/baeldung/customuserdetails/ViewControllerIntegrationTest.java new file mode 100644 index 0000000000..73d4bda112 --- /dev/null +++ b/spring-security-modules/spring-security-web-thymeleaf/src/test/java/com/baeldung/customuserdetails/ViewControllerIntegrationTest.java @@ -0,0 +1,42 @@ +package com.baeldung.customuserdetails; + +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.WebMvcTest; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; + +import com.baeldung.customuserdetails.PasswordEncoderConfiguration; + +@RunWith(SpringRunner.class) +@WebMvcTest +@Import(PasswordEncoderConfiguration.class) +public class ViewControllerIntegrationTest { + + @Autowired + private WebApplicationContext context; + MockMvc mvc; + + @Before + public void setup() { + mvc = MockMvcBuilders + .webAppContextSetup(context) + .build(); + } + + @Test + public void givenUser_whenPerformingGet_thenReturnsIndex() throws Exception { + mvc.perform(get("/index").with(user("user").password("password"))).andExpect(status().isOk()).andExpect(view().name("userdetails")); + } + +} diff --git a/spring-web-modules/spring-mvc-basics-3/src/main/java/com/baeldung/spring/headers/controller/ReadHeaderRestController.java b/spring-web-modules/spring-mvc-basics-3/src/main/java/com/baeldung/spring/headers/controller/ReadHeaderRestController.java index 6a0f3b6a0d..ff4d0eea58 100644 --- a/spring-web-modules/spring-mvc-basics-3/src/main/java/com/baeldung/spring/headers/controller/ReadHeaderRestController.java +++ b/spring-web-modules/spring-mvc-basics-3/src/main/java/com/baeldung/spring/headers/controller/ReadHeaderRestController.java @@ -1,6 +1,8 @@ package com.baeldung.spring.headers.controller; import java.net.InetSocketAddress; +import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.stream.Collectors; @@ -24,9 +26,10 @@ public class ReadHeaderRestController { } @GetMapping("/greeting") - public ResponseEntity greeting(@RequestHeader(value = "accept-language") String language) { + public ResponseEntity greeting(@RequestHeader(value = HttpHeaders.ACCEPT_LANGUAGE) String language) { String greeting = ""; - String firstLanguage = (language.length() > 1 ? language.substring(0, 2) : language); + List ranges = Locale.LanguageRange.parse(language); + String firstLanguage = ranges.get(0).getRange(); switch (firstLanguage) { case "es": greeting = "Hola!"; diff --git a/spring-web-modules/spring-mvc-basics-3/src/test/java/com/baeldung/headers/controller/ReadHeaderRestControllerIntegrationTest.java b/spring-web-modules/spring-mvc-basics-3/src/test/java/com/baeldung/headers/controller/ReadHeaderRestControllerIntegrationTest.java index 6f94004cc7..1641939b67 100644 --- a/spring-web-modules/spring-mvc-basics-3/src/test/java/com/baeldung/headers/controller/ReadHeaderRestControllerIntegrationTest.java +++ b/spring-web-modules/spring-mvc-basics-3/src/test/java/com/baeldung/headers/controller/ReadHeaderRestControllerIntegrationTest.java @@ -10,6 +10,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpHeaders; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig; import org.springframework.test.web.servlet.MockMvc; @@ -51,10 +52,24 @@ public class ReadHeaderRestControllerIntegrationTest { @Test public void whenGetRequestSentToGreeting_thenStatusOKAndGreetingReturned() throws Exception { - mockMvc.perform(get("/greeting").header("accept-language", "de")) + mockMvc.perform(get("/greeting").header(HttpHeaders.ACCEPT_LANGUAGE, "de")) .andExpect(status().isOk()) .andExpect(content().string("Hallo!")); } + + @Test + public void whenPrioritizedListGetRequestSentToGreeting_thenStatusOKAndGreetingReturned() throws Exception { + mockMvc.perform(get("/greeting").header(HttpHeaders.ACCEPT_LANGUAGE, "fr,en,de")) + .andExpect(status().isOk()) + .andExpect(content().string("Bonjour!")); + } + + @Test + public void whenWeightedListGetRequestSentToGreeting_thenStatusOKAndGreetingReturned() throws Exception { + mockMvc.perform(get("/greeting").header(HttpHeaders.ACCEPT_LANGUAGE, "Accept-Language: es; q=1.0, de; q=0.5")) + .andExpect(status().isOk()) + .andExpect(content().string("Hola!")); + } @Test public void whenGetRequestSentToDouble_thenStatusOKAndCorrectResultReturned() throws Exception { diff --git a/spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/imageupload/UploadController.java b/spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/imageupload/UploadController.java new file mode 100644 index 0000000000..d3ccc82323 --- /dev/null +++ b/spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/imageupload/UploadController.java @@ -0,0 +1,31 @@ +package com.baeldung.thymeleaf.imageupload; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +@Controller public class UploadController { + + public static String UPLOAD_DIRECTORY = System.getProperty("user.dir") + "/uploads"; + + @GetMapping("/uploadimage") public String displayUploadForm() { + return "imageupload/index"; + } + + @PostMapping("/upload") public String uploadImage(Model model, @RequestParam("image") MultipartFile file) throws IOException { + StringBuilder fileNames = new StringBuilder(); + Path fileNameAndPath = Paths.get(UPLOAD_DIRECTORY, file.getOriginalFilename()); + fileNames.append(file.getOriginalFilename()); + Files.write(fileNameAndPath, file.getBytes()); + model.addAttribute("msg", "Uploaded images: " + fileNames.toString()); + return "imageupload/index"; + } +} \ No newline at end of file diff --git a/spring-web-modules/spring-thymeleaf-5/src/main/resources/application.properties b/spring-web-modules/spring-thymeleaf-5/src/main/resources/application.properties index b09232bb1b..7a5b9c207d 100644 --- a/spring-web-modules/spring-thymeleaf-5/src/main/resources/application.properties +++ b/spring-web-modules/spring-thymeleaf-5/src/main/resources/application.properties @@ -1 +1,3 @@ -#spring.thymeleaf.prefix=classpath:/templates-2/ \ No newline at end of file +#spring.thymeleaf.prefix=classpath:/templates-2/ +spring.servlet.multipart.max-file-size = 5MB +spring.servlet.multipart.max-request-size = 5MB \ No newline at end of file diff --git a/spring-web-modules/spring-thymeleaf-5/src/main/resources/templates/imageupload/index.html b/spring-web-modules/spring-thymeleaf-5/src/main/resources/templates/imageupload/index.html new file mode 100644 index 0000000000..e129a123e9 --- /dev/null +++ b/spring-web-modules/spring-thymeleaf-5/src/main/resources/templates/imageupload/index.html @@ -0,0 +1,25 @@ + + + + + + +
+
+
+
+

Upload Image Example

+

+
+
+ +
+ +
+ +
+
+
+
+ + \ No newline at end of file diff --git a/testing-modules/mockito-simple/src/main/java/com/baeldung/app/api/MessageApi.java b/testing-modules/mockito-simple/src/main/java/com/baeldung/app/api/MessageDTO.java similarity index 94% rename from testing-modules/mockito-simple/src/main/java/com/baeldung/app/api/MessageApi.java rename to testing-modules/mockito-simple/src/main/java/com/baeldung/app/api/MessageDTO.java index edbe5a1d5a..1d9da244b0 100644 --- a/testing-modules/mockito-simple/src/main/java/com/baeldung/app/api/MessageApi.java +++ b/testing-modules/mockito-simple/src/main/java/com/baeldung/app/api/MessageDTO.java @@ -1,6 +1,6 @@ package com.baeldung.app.api; -public class MessageApi { +public class MessageDTO { private String from; private String to; private String text; diff --git a/testing-modules/mockito-simple/src/main/java/com/baeldung/app/rest/FlowerController.java b/testing-modules/mockito-simple/src/main/java/com/baeldung/app/rest/FlowerController.java index b3d8888cec..10f602088c 100644 --- a/testing-modules/mockito-simple/src/main/java/com/baeldung/app/rest/FlowerController.java +++ b/testing-modules/mockito-simple/src/main/java/com/baeldung/app/rest/FlowerController.java @@ -17,7 +17,7 @@ public class FlowerController { @PostMapping("/isAFlower") public String isAFlower (@RequestBody String flower) { - return flowerService.analize(flower); + return flowerService.analyze(flower); } @PostMapping("/isABigFlower") diff --git a/testing-modules/mockito-simple/src/main/java/com/baeldung/app/rest/MessageController.java b/testing-modules/mockito-simple/src/main/java/com/baeldung/app/rest/MessageController.java index e23c2e7607..6911197197 100644 --- a/testing-modules/mockito-simple/src/main/java/com/baeldung/app/rest/MessageController.java +++ b/testing-modules/mockito-simple/src/main/java/com/baeldung/app/rest/MessageController.java @@ -1,6 +1,6 @@ package com.baeldung.app.rest; -import com.baeldung.app.api.MessageApi; +import com.baeldung.app.api.MessageDTO; import com.baeldung.domain.model.Message; import com.baeldung.domain.service.MessageService; import org.springframework.beans.factory.annotation.Autowired; @@ -21,7 +21,7 @@ public class MessageController { private MessageService messageService; @PostMapping - public Message createMessage (@RequestBody MessageApi messageDTO) { + public Message createMessage (@RequestBody MessageDTO messageDTO) { Message message = new Message(); message.setText(messageDTO.getText()); message.setFrom(messageDTO.getFrom()); diff --git a/testing-modules/mockito-simple/src/main/java/com/baeldung/domain/service/FlowerService.java b/testing-modules/mockito-simple/src/main/java/com/baeldung/domain/service/FlowerService.java index 3c76cb5d76..74a9308890 100644 --- a/testing-modules/mockito-simple/src/main/java/com/baeldung/domain/service/FlowerService.java +++ b/testing-modules/mockito-simple/src/main/java/com/baeldung/domain/service/FlowerService.java @@ -10,7 +10,7 @@ public class FlowerService { private List flowers = Arrays.asList("Poppy", "Ageratum", "Carnation", "Diascia", "Lantana"); - public String analize(String name) { + public String analyze(String name) { if(flowers.contains(name)) { return "flower"; } diff --git a/testing-modules/mockito-simple/src/test/java/com/baeldung/app/rest/FlowerControllerUnitTest.java b/testing-modules/mockito-simple/src/test/java/com/baeldung/app/rest/FlowerControllerUnitTest.java index aeec57d136..df3561d646 100644 --- a/testing-modules/mockito-simple/src/test/java/com/baeldung/app/rest/FlowerControllerUnitTest.java +++ b/testing-modules/mockito-simple/src/test/java/com/baeldung/app/rest/FlowerControllerUnitTest.java @@ -1,14 +1,20 @@ package com.baeldung.app.rest; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.AdditionalMatchers.or; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.endsWith; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.exceptions.misusing.InvalidUseOfMatchersException; import org.mockito.junit.MockitoJUnitRunner; import com.baeldung.app.api.Flower; @@ -17,29 +23,67 @@ import com.baeldung.domain.service.FlowerService; @RunWith(MockitoJUnitRunner.class) public class FlowerControllerUnitTest { - @Mock - private FlowerService flowerService; + @InjectMocks + private FlowerController flowerController; - @InjectMocks - private FlowerController flowerController; + @Mock + private FlowerService flowerService; - @Test - public void isAFlower_withMockito_OK() { - when(flowerService.analize(eq("violetta"))).thenReturn("Flower"); + @Test + public void givenPoppyFlower_whenUsingDoReturn_thenCorrect() { + doReturn("Flower").when(flowerService).analyze("poppy"); - String response = flowerController.isAFlower("violetta"); + String response = flowerController.isAFlower("poppy"); + assertThat(response).isEqualTo("Flower"); + } - Assert.assertEquals("Flower", response); - } + @Test + public void givenAnyString_whenUsingArgumentMatcher_thenCorrect() { + when(flowerService.analyze(anyString())).thenReturn("Flower"); - @Test - public void isABigFlower_withMockito_OK() { - when(flowerService.isABigFlower(eq("violetta"), anyInt())).thenReturn(true); + String response = flowerController.isAFlower("violetta"); + assertThat(response).isEqualTo("Flower"); + } - Flower flower = new Flower("violetta", 15); + @Test(expected = InvalidUseOfMatchersException.class) + public void whenIncorrectMatchers_thenThrowsError() { + when(flowerService.isABigFlower("poppy", anyInt())).thenReturn(true); - Boolean response = flowerController.isABigFlower(flower); + Flower flower = new Flower("poppy", 15); - Assert.assertTrue(response); - } + Boolean response = flowerController.isABigFlower(flower); + assertThat(response).isTrue(); + } + + @Test + public void whenCorrectMatchers_thenCorrect() { + when(flowerService.isABigFlower(eq("poppy"), anyInt())).thenReturn(true); + + Flower flower = new Flower("poppy", 15); + + Boolean response = flowerController.isABigFlower(flower); + assertThat(response).isTrue(); + } + + @Test(expected = InvalidUseOfMatchersException.class) + public void whenUsingMatchersAsReturnValue_thenThrowsError() { + flowerController.isAFlower("poppy"); + + String orMatcher = or(eq("poppy"), endsWith("y")); + verify(flowerService).analyze(orMatcher); + } + + @Test + public void whenUsingMatchersAsOngoingStubbing_thenCorrect1() { + flowerController.isAFlower("poppy"); + + verify(flowerService).analyze(or(eq("poppy"), endsWith("y"))); + } + + @Test + public void whenUsingMatchersAsOngoingStubbing_thenCorrect2() { + flowerController.isAFlower("lily"); + + verify(flowerService).analyze(or(eq("poppy"), endsWith("y"))); + } } diff --git a/testing-modules/mockito-simple/src/test/java/com/baeldung/app/rest/MessageControllerUnitTest.java b/testing-modules/mockito-simple/src/test/java/com/baeldung/app/rest/MessageControllerUnitTest.java index 15e91d86b5..1bfbeecfec 100644 --- a/testing-modules/mockito-simple/src/test/java/com/baeldung/app/rest/MessageControllerUnitTest.java +++ b/testing-modules/mockito-simple/src/test/java/com/baeldung/app/rest/MessageControllerUnitTest.java @@ -1,16 +1,17 @@ package com.baeldung.app.rest; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.ArgumentMatchers; import org.mockito.InjectMocks; import org.mockito.Mock; -import org.mockito.Mockito; import org.mockito.junit.MockitoJUnitRunner; -import com.baeldung.app.api.MessageApi; +import com.baeldung.app.api.MessageDTO; import com.baeldung.domain.model.Message; import com.baeldung.domain.service.MessageService; import com.baeldung.domain.util.MessageMatcher; @@ -18,26 +19,38 @@ import com.baeldung.domain.util.MessageMatcher; @RunWith(MockitoJUnitRunner.class) public class MessageControllerUnitTest { - @Mock - private MessageService messageService; + @InjectMocks + private MessageController messageController; + + @Mock + private MessageService messageService; - @InjectMocks - private MessageController messageController; + @Test + public void givenMsg_whenVerifyUsingAnyMatcher_thenOk() { + MessageDTO messageDTO = new MessageDTO(); + messageDTO.setFrom("me"); + messageDTO.setTo("you"); + messageDTO.setText("Hello, you!"); - @Test - public void createMessage_NewMessage_OK() { - MessageApi messageApi = new MessageApi(); - messageApi.setFrom("me"); - messageApi.setTo("you"); - messageApi.setText("Hello, you!"); + messageController.createMessage(messageDTO); - messageController.createMessage(messageApi); + verify(messageService, times(1)).deliverMessage(any(Message.class)); + } - Message message = new Message(); - message.setFrom("me"); - message.setTo("you"); - message.setText("Hello, you!"); + @Test + public void givenMsg_whenVerifyUsingMessageMatcher_thenOk() { + MessageDTO messageDTO = new MessageDTO(); + messageDTO.setFrom("me"); + messageDTO.setTo("you"); + messageDTO.setText("Hello, you!"); - Mockito.verify(messageService, times(1)).deliverMessage(ArgumentMatchers.argThat(new MessageMatcher(message))); - } + messageController.createMessage(messageDTO); + + Message message = new Message(); + message.setFrom("me"); + message.setTo("you"); + message.setText("Hello, you!"); + + verify(messageService, times(1)).deliverMessage(argThat(new MessageMatcher(message))); + } } diff --git a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoMockUnitTest.java b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoMockUnitTest.java index 80f01338e6..6b2bae16c3 100644 --- a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoMockUnitTest.java +++ b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoMockUnitTest.java @@ -2,7 +2,7 @@ package com.baeldung.mockito; import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -33,11 +33,10 @@ public class MockitoMockUnitTest { MyList listMock = mock(MyList.class, "myMock"); when(listMock.add(anyString())).thenReturn(false); listMock.add(randomAlphabetic(6)); - - Throwable exceptionThrown = assertThrows(TooFewActualInvocations.class, - () -> verify(listMock, times(2)).add(anyString())); - - assertThat(exceptionThrown.getMessage()).contains("myMock.add"); + + assertThatThrownBy(() -> verify(listMock, times(2)).add(anyString())) + .isInstanceOf(TooFewActualInvocations.class) + .hasMessageContaining("myMock.add"); } private static class CustomAnswer implements Answer { diff --git a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoVerifyExamplesUnitTest.java b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoVerifyExamplesUnitTest.java index f138256e72..c3c5758950 100644 --- a/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoVerifyExamplesUnitTest.java +++ b/testing-modules/mockito-simple/src/test/java/com/baeldung/mockito/MockitoVerifyExamplesUnitTest.java @@ -1,6 +1,17 @@ package com.baeldung.mockito; -import com.google.common.collect.Lists; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.atLeast; +import static org.mockito.Mockito.atMost; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +import java.util.List; import org.junit.Test; import org.mockito.ArgumentCaptor; @@ -8,11 +19,7 @@ import org.mockito.InOrder; import org.mockito.Mockito; import org.mockito.exceptions.verification.NoInteractionsWanted; -import java.util.List; - -import static org.hamcrest.Matchers.hasItem; -import static org.junit.Assert.assertThat; -import static org.mockito.Mockito.*; +import com.google.common.collect.Lists; public class MockitoVerifyExamplesUnitTest { @@ -108,10 +115,12 @@ public class MockitoVerifyExamplesUnitTest { public final void whenVerifyingAnInteractionWithArgumentCapture_thenCorrect() { final List mockedList = mock(MyList.class); mockedList.addAll(Lists.newArrayList("someElement")); - final ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(List.class); + + final ArgumentCaptor> argumentCaptor = ArgumentCaptor.forClass(List.class); verify(mockedList).addAll(argumentCaptor.capture()); - final List capturedArgument = argumentCaptor.>getValue(); - assertThat(capturedArgument, hasItem("someElement")); + + final List capturedArgument = argumentCaptor.getValue(); + assertThat(capturedArgument).contains("someElement"); } } diff --git a/testing-modules/mockito/README.md b/testing-modules/mockito/README.md index 2870d1afcf..46795d2fe4 100644 --- a/testing-modules/mockito/README.md +++ b/testing-modules/mockito/README.md @@ -1,7 +1,7 @@ ### Relevant articles - [Mockito’s Java 8 Features](https://www.baeldung.com/mockito-2-java-8) -- [Lazy Verification with Mockito 2](https://www.baeldung.com/mockito-2-lazy-verification) +- [Lazy Verification with Mockito](https://www.baeldung.com/mockito-2-lazy-verification) - [Mockito Strict Stubbing and The UnnecessaryStubbingException](https://www.baeldung.com/mockito-unnecessary-stubbing-exception) - [Mockito and Fluent APIs](https://www.baeldung.com/mockito-fluent-apis) - [Mocking the ObjectMapper readValue() Method](https://www.baeldung.com/mockito-mock-jackson-read-value)