diff --git a/core-java-modules/core-java-annotations/src/main/java/com/baeldung/annotations/AnnotatedClass.java b/core-java-modules/core-java-annotations/src/main/java/com/baeldung/annotations/AnnotatedClass.java
new file mode 100644
index 0000000000..d5d9c88388
--- /dev/null
+++ b/core-java-modules/core-java-annotations/src/main/java/com/baeldung/annotations/AnnotatedClass.java
@@ -0,0 +1,8 @@
+package com.baeldung.annotations;
+
+import javax.annotation.Generated;
+
+@RetentionAnnotation
+@Generated("Available only on source code")
+public class AnnotatedClass {
+}
diff --git a/core-java-modules/core-java-annotations/src/main/java/com/baeldung/annotations/RetentionAnnotation.java b/core-java-modules/core-java-annotations/src/main/java/com/baeldung/annotations/RetentionAnnotation.java
new file mode 100644
index 0000000000..4591334dde
--- /dev/null
+++ b/core-java-modules/core-java-annotations/src/main/java/com/baeldung/annotations/RetentionAnnotation.java
@@ -0,0 +1,12 @@
+package com.baeldung.annotations;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.TYPE;
+
+@Target(TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface RetentionAnnotation {
+}
\ No newline at end of file
diff --git a/core-java-modules/core-java-annotations/src/test/java/com/baeldung/annotations/AnnotatedClassUnitTest.java b/core-java-modules/core-java-annotations/src/test/java/com/baeldung/annotations/AnnotatedClassUnitTest.java
new file mode 100644
index 0000000000..9bf0b78cbb
--- /dev/null
+++ b/core-java-modules/core-java-annotations/src/test/java/com/baeldung/annotations/AnnotatedClassUnitTest.java
@@ -0,0 +1,18 @@
+package com.baeldung.annotations;
+
+import org.junit.Test;
+
+import java.lang.annotation.Annotation;
+
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertThat;
+
+public class AnnotatedClassUnitTest {
+
+ @Test
+ public void whenAnnotationRetentionPolicyRuntime_shouldAccess() {
+ AnnotatedClass anAnnotatedClass = new AnnotatedClass();
+ Annotation[] annotations = anAnnotatedClass.getClass().getAnnotations();
+ assertThat(annotations.length, is(1));
+ }
+}
diff --git a/core-java-modules/core-java-collections-4/pom.xml b/core-java-modules/core-java-collections-4/pom.xml
index 0e3cabf40e..b4f8aa6320 100644
--- a/core-java-modules/core-java-collections-4/pom.xml
+++ b/core-java-modules/core-java-collections-4/pom.xml
@@ -25,7 +25,7 @@
- 3.18.0
+ 3.19.0
diff --git a/core-java-modules/core-java-collections-4/src/main/java/com/baeldung/collections/dequestack/ArrayLifoStack.java b/core-java-modules/core-java-collections-4/src/main/java/com/baeldung/collections/dequestack/ArrayLifoStack.java
new file mode 100644
index 0000000000..16fdec5b77
--- /dev/null
+++ b/core-java-modules/core-java-collections-4/src/main/java/com/baeldung/collections/dequestack/ArrayLifoStack.java
@@ -0,0 +1,91 @@
+package com.baeldung.collections.dequestack;
+
+import java.util.ArrayDeque;
+import java.util.Collection;
+import java.util.Deque;
+import java.util.Iterator;
+
+public class ArrayLifoStack implements LifoStack {
+ private final Deque deque = new ArrayDeque<>();
+
+ @Override
+ public void push(E item) {
+ deque.addFirst(item);
+ }
+
+ @Override
+ public E pop() {
+ return deque.removeFirst();
+ }
+
+ @Override
+ public E peek() {
+ return deque.peekFirst();
+ }
+
+ // implementing methods from the Collection interface
+ @Override
+ public int size() {
+ return deque.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return deque.isEmpty();
+ }
+
+ @Override
+ public boolean contains(Object o) {
+ return deque.contains(o);
+ }
+
+ @Override
+ public Iterator iterator() {
+ return deque.iterator();
+ }
+
+ @Override
+ public Object[] toArray() {
+ return deque.toArray();
+ }
+
+ @Override
+ public T[] toArray(T[] a) {
+ return deque.toArray(a);
+ }
+
+ @Override
+ public boolean add(E e) {
+ return deque.add(e);
+ }
+
+ @Override
+ public boolean remove(Object o) {
+ return deque.remove(o);
+ }
+
+ @Override
+ public boolean containsAll(Collection> c) {
+ return deque.containsAll(c);
+ }
+
+ @Override
+ public boolean addAll(Collection extends E> c) {
+ return deque.addAll(c);
+ }
+
+ @Override
+ public boolean removeAll(Collection> c) {
+ return deque.removeAll(c);
+ }
+
+ @Override
+ public boolean retainAll(Collection> c) {
+ return deque.retainAll(c);
+ }
+
+ @Override
+ public void clear() {
+ deque.clear();
+ }
+}
diff --git a/core-java-modules/core-java-collections-4/src/main/java/com/baeldung/collections/dequestack/LifoStack.java b/core-java-modules/core-java-collections-4/src/main/java/com/baeldung/collections/dequestack/LifoStack.java
new file mode 100644
index 0000000000..11e07e3555
--- /dev/null
+++ b/core-java-modules/core-java-collections-4/src/main/java/com/baeldung/collections/dequestack/LifoStack.java
@@ -0,0 +1,12 @@
+package com.baeldung.collections.dequestack;
+
+import java.util.Collection;
+
+public interface LifoStack extends Collection {
+
+ E peek();
+
+ E pop();
+
+ void push(E item);
+}
\ No newline at end of file
diff --git a/core-java-modules/core-java-collections-4/src/test/java/com/baeldung/collections/dequestack/StackVsDequeUnitTest.java b/core-java-modules/core-java-collections-4/src/test/java/com/baeldung/collections/dequestack/StackVsDequeUnitTest.java
new file mode 100644
index 0000000000..ca3b0e8d54
--- /dev/null
+++ b/core-java-modules/core-java-collections-4/src/test/java/com/baeldung/collections/dequestack/StackVsDequeUnitTest.java
@@ -0,0 +1,90 @@
+package com.baeldung.collections.dequestack;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.Stack;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class StackVsDequeUnitTest {
+
+ @Test
+ void givenAStack_whenAccessByIndex_thenElementCanBeRead() {
+ Stack myStack = new Stack<>();
+ myStack.push("I am the 1st element."); //index 0
+ myStack.push("I am the 2nd element."); //index 1
+ myStack.push("I am the 3rd element."); //index 2
+ //access by index
+ assertThat(myStack.get(0)).isEqualTo("I am the 1st element.");
+ }
+
+ @Test
+ void givenAStack_whenIterate_thenFromBottomToTop() {
+ Stack myStack = new Stack<>();
+ myStack.push("I am at the bottom.");
+ myStack.push("I am in the middle.");
+ myStack.push("I am at the top.");
+
+ Iterator it = myStack.iterator();
+
+ assertThat(it).toIterable().containsExactly(
+ "I am at the bottom.",
+ "I am in the middle.",
+ "I am at the top.");
+ }
+
+ @Test
+ void givenAStack_whenAddOrRemoveByIndex_thenElementCanBeAddedOrRemoved() {
+ Stack myStack = new Stack<>();
+ myStack.push("I am the 1st element.");
+ myStack.push("I am the 3rd element.");
+
+ assertThat(myStack.size()).isEqualTo(2);
+
+ //insert by index
+ myStack.add(1, "I am the 2nd element.");
+ assertThat(myStack.size()).isEqualTo(3);
+ assertThat(myStack.get(1)).isEqualTo("I am the 2nd element.");
+ //remove by index
+ myStack.remove(1);
+ assertThat(myStack.size()).isEqualTo(2);
+ }
+
+ @Test
+ void givenADeque_whenAddOrRemoveLastElement_thenTheLastElementCanBeAddedOrRemoved() {
+ Deque myStack = new ArrayDeque<>();
+ myStack.push("I am the 1st element.");
+ myStack.push("I am the 2nd element.");
+ myStack.push("I am the 3rd element.");
+
+ assertThat(myStack.size()).isEqualTo(3);
+
+ //insert element to the bottom of the stack
+ myStack.addLast("I am the NEW element.");
+ assertThat(myStack.size()).isEqualTo(4);
+ assertThat(myStack.peek()).isEqualTo("I am the 3rd element.");
+
+ //remove element from the bottom of the stack
+ String removedStr = myStack.removeLast();
+ assertThat(myStack.size()).isEqualTo(3);
+ assertThat(removedStr).isEqualTo("I am the NEW element.");
+ }
+
+ @Test
+ void givenADeque_whenIterate_thenFromTopToBottom() {
+ Deque myStack = new ArrayDeque<>();
+ myStack.push("I am at the bottom.");
+ myStack.push("I am in the middle.");
+ myStack.push("I am at the top.");
+
+ Iterator it = myStack.iterator();
+
+ assertThat(it).toIterable().containsExactly(
+ "I am at the top.",
+ "I am in the middle.",
+ "I am at the bottom.");
+ }
+}
\ No newline at end of file
diff --git a/core-java-modules/core-java-collections-maps-3/README.md b/core-java-modules/core-java-collections-maps-3/README.md
index 918c81fe4b..8b84ecbf81 100644
--- a/core-java-modules/core-java-collections-maps-3/README.md
+++ b/core-java-modules/core-java-collections-maps-3/README.md
@@ -7,4 +7,5 @@ This module contains articles about Map data structures in Java.
- [Comparing Two HashMaps in Java](https://www.baeldung.com/java-compare-hashmaps)
- [The Map.computeIfAbsent() Method](https://www.baeldung.com/java-map-computeifabsent)
- [Collections.synchronizedMap vs. ConcurrentHashMap](https://www.baeldung.com/java-synchronizedmap-vs-concurrenthashmap)
+- [Java HashMap Load Factor](https://www.baeldung.com/java-hashmap-load-factor)
- More articles: [[<-- prev]](/core-java-modules/core-java-collections-maps-2)
diff --git a/core-java-modules/core-java-jpms/decoupling-pattern2/consumermodule/pom.xml b/core-java-modules/core-java-jpms/decoupling-pattern2/consumermodule/pom.xml
index e6b351b1b9..816f5cf9e8 100644
--- a/core-java-modules/core-java-jpms/decoupling-pattern2/consumermodule/pom.xml
+++ b/core-java-modules/core-java-jpms/decoupling-pattern2/consumermodule/pom.xml
@@ -17,7 +17,7 @@
com.baeldung.servicemodule
- servicemodule
+ servicemodule2
${servicemodule.version}
@@ -41,4 +41,4 @@
1.0
-
\ No newline at end of file
+
diff --git a/core-java-modules/core-java-lang-oop-generics/README.md b/core-java-modules/core-java-lang-oop-generics/README.md
index 9c9080ece3..720ba9dcfd 100644
--- a/core-java-modules/core-java-lang-oop-generics/README.md
+++ b/core-java-modules/core-java-lang-oop-generics/README.md
@@ -8,3 +8,4 @@ This module contains articles about generics in Java
- [Raw Types in Java](https://www.baeldung.com/raw-types-java)
- [Super Type Tokens in Java Generics](https://www.baeldung.com/java-super-type-tokens)
- [Java Warning “unchecked conversion”](https://www.baeldung.com/java-unchecked-conversion)
+- [Java Warning “Unchecked Cast”](https://www.baeldung.com/java-warning-unchecked-cast)
diff --git a/core-java-modules/core-java-lang-oop-generics/src/main/java/com/baeldung/uncheckedcast/UncheckedCast.java b/core-java-modules/core-java-lang-oop-generics/src/main/java/com/baeldung/uncheckedcast/UncheckedCast.java
new file mode 100644
index 0000000000..fe79488d11
--- /dev/null
+++ b/core-java-modules/core-java-lang-oop-generics/src/main/java/com/baeldung/uncheckedcast/UncheckedCast.java
@@ -0,0 +1,26 @@
+package com.baeldung.uncheckedcast;
+
+import java.time.LocalDate;
+import java.time.Month;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+public class UncheckedCast {
+ public static Map getRawMap() {
+ Map rawMap = new HashMap();
+ rawMap.put("date 1", LocalDate.of(2021, Month.FEBRUARY, 10));
+ rawMap.put("date 2", LocalDate.of(1992, Month.AUGUST, 8));
+ rawMap.put("date 3", LocalDate.of(1976, Month.NOVEMBER, 18));
+ return rawMap;
+ }
+
+ public static Map getRawMapWithMixedTypes() {
+ Map rawMap = new HashMap();
+ rawMap.put("date 1", LocalDate.of(2021, Month.FEBRUARY, 10));
+ rawMap.put("date 2", LocalDate.of(1992, Month.AUGUST, 8));
+ rawMap.put("date 3", LocalDate.of(1976, Month.NOVEMBER, 18));
+ rawMap.put("date 4", new Date());
+ return rawMap;
+ }
+}
diff --git a/core-java-modules/core-java-lang-oop-generics/src/test/java/com/baeldung/uncheckedcast/UncheckedCastUnitTest.java b/core-java-modules/core-java-lang-oop-generics/src/test/java/com/baeldung/uncheckedcast/UncheckedCastUnitTest.java
new file mode 100644
index 0000000000..b1bd46555e
--- /dev/null
+++ b/core-java-modules/core-java-lang-oop-generics/src/test/java/com/baeldung/uncheckedcast/UncheckedCastUnitTest.java
@@ -0,0 +1,25 @@
+package com.baeldung.uncheckedcast;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.time.LocalDate;
+import java.time.Month;
+import java.util.Map;
+
+public class UncheckedCastUnitTest {
+
+ @Test
+ public void givenRawMap_whenCastToTypedMap_shouldHaveCompilerWarning() {
+ Map castFromRawMap = (Map) UncheckedCast.getRawMap();
+ Assert.assertEquals(3, castFromRawMap.size());
+ Assert.assertEquals(castFromRawMap.get("date 2"), LocalDate.of(1992, Month.AUGUST, 8));
+ }
+
+ @Test(expected = ClassCastException.class)
+ public void givenMixTypedRawMap_whenCastToTypedMap_shouldThrowClassCastException() {
+ Map castFromRawMap = (Map) UncheckedCast.getRawMapWithMixedTypes();
+ Assert.assertEquals(4, castFromRawMap.size());
+ Assert.assertTrue(castFromRawMap.get("date 4").isAfter(castFromRawMap.get("date 3")));
+ }
+}
diff --git a/core-java-modules/core-java-nio-2/pom.xml b/core-java-modules/core-java-nio-2/pom.xml
index 0c7c079406..7c4583476d 100644
--- a/core-java-modules/core-java-nio-2/pom.xml
+++ b/core-java-modules/core-java-nio-2/pom.xml
@@ -14,5 +14,12 @@
0.0.1-SNAPSHOT
../
-
+
+
+ org.assertj
+ assertj-core
+ 3.6.1
+ test
+
+
\ No newline at end of file
diff --git a/core-java-modules/core-java-nio-2/src/test/java/com/baeldung/selector/SelectorManualTest.java b/core-java-modules/core-java-nio-2/src/test/java/com/baeldung/selector/SelectorManualTest.java
new file mode 100644
index 0000000000..7a6c9e6eab
--- /dev/null
+++ b/core-java-modules/core-java-nio-2/src/test/java/com/baeldung/selector/SelectorManualTest.java
@@ -0,0 +1,64 @@
+package com.baeldung.selector;
+
+import org.junit.Test;
+import java.io.IOException;
+import java.nio.channels.Pipe;
+import java.nio.channels.SelectableChannel;
+import java.nio.channels.Selector;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import static java.nio.channels.SelectionKey.OP_READ;
+
+public class SelectorManualTest {
+
+ @Test
+ public void whenWakeUpCalledOnSelector_thenBlockedThreadReturns() throws IOException, InterruptedException {
+ Pipe pipe = Pipe.open();
+
+ Selector selector = Selector.open();
+ SelectableChannel channel = pipe.source();
+ channel.configureBlocking(false);
+ channel.register(selector, OP_READ);
+
+ List invocationStepsTracker = Collections.synchronizedList(new ArrayList<>());
+
+ CountDownLatch latch = new CountDownLatch(1);
+
+ Thread thread = new Thread(() -> {
+ invocationStepsTracker.add(">> Count down");
+ latch.countDown();
+ try {
+ invocationStepsTracker.add(">> Start select");
+ selector.select();
+ invocationStepsTracker.add(">> End select");
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ });
+
+ invocationStepsTracker.add(">> Start await");
+ thread.start();
+ latch.await();
+ invocationStepsTracker.add(">> End await");
+
+ invocationStepsTracker.add(">> Wakeup thread");
+
+ selector.wakeup();
+ channel.close();
+
+ assertThat(invocationStepsTracker)
+ .containsExactly(
+ ">> Start await",
+ ">> Count down",
+ ">> Start select",
+ ">> End await",
+ ">> Wakeup thread",
+ ">> End select"
+ );
+ }
+}
diff --git a/docker/README.md b/docker/README.md
index ce7fe261c2..f1b4181e64 100644
--- a/docker/README.md
+++ b/docker/README.md
@@ -3,3 +3,4 @@
- [Introduction to Docker Compose](https://www.baeldung.com/docker-compose)
- [Reusing Docker Layers with Spring Boot](https://www.baeldung.com/docker-layers-spring-boot)
- [Running Spring Boot with PostgreSQL in Docker Compose](https://www.baeldung.com/spring-boot-postgresql-docker)
+- [How To Configure Java Heap Size Inside a Docker Container](https://www.baeldung.com/ops/docker-jvm-heap-size)
diff --git a/docker/heap-sizing/Dockerfile b/docker/heap-sizing/Dockerfile
new file mode 100644
index 0000000000..c455e45c70
--- /dev/null
+++ b/docker/heap-sizing/Dockerfile
@@ -0,0 +1,4 @@
+FROM openjdk:8u92-jdk-alpine
+COPY /src /src/
+RUN mkdir /app && ls /src && javac /src/main/java/com/baeldung/docker/heapsizing/PrintXmxXms.java -d /app
+CMD java -version && java $JAVA_OPTS -cp /app com.baeldung.docker.heapsizing.PrintXmxXms
\ No newline at end of file
diff --git a/docker/heap-sizing/pom.xml b/docker/heap-sizing/pom.xml
new file mode 100644
index 0000000000..a86a67fdcd
--- /dev/null
+++ b/docker/heap-sizing/pom.xml
@@ -0,0 +1,61 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.4.2
+
+
+ com.baeldung.docker
+ heap-sizing
+ 0.0.1-SNAPSHOT
+ heap-sizing
+ Demo project for Spring Boot
+
+ 11
+
+
+
+ org.springframework.boot
+ spring-boot-starter-webflux
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ io.projectreactor
+ reactor-test
+ test
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+ heapsizing-demo
+
+
+
+
+ com.google.cloud.tools
+ jib-maven-plugin
+ 2.7.1
+
+
+
+ heapsizing-demo-jib
+
+
+
+
+
+
+
diff --git a/docker/heap-sizing/src/main/java/com/baeldung/docker/heapsizing/HeapSizingApplication.java b/docker/heap-sizing/src/main/java/com/baeldung/docker/heapsizing/HeapSizingApplication.java
new file mode 100644
index 0000000000..00bee376c5
--- /dev/null
+++ b/docker/heap-sizing/src/main/java/com/baeldung/docker/heapsizing/HeapSizingApplication.java
@@ -0,0 +1,19 @@
+package com.baeldung.docker.heapsizing;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+import java.util.logging.Logger;
+
+import static com.baeldung.docker.heapsizing.PrintXmxXms.logMemory;
+
+@SpringBootApplication
+public class HeapSizingApplication {
+ private static final Logger logger = Logger.getLogger(HeapSizingApplication.class.getName());
+
+ public static void main(String[] args) {
+ SpringApplication.run(HeapSizingApplication.class, args);
+ logMemory(logger);
+ }
+
+}
diff --git a/docker/heap-sizing/src/main/java/com/baeldung/docker/heapsizing/PrintXmxXms.java b/docker/heap-sizing/src/main/java/com/baeldung/docker/heapsizing/PrintXmxXms.java
new file mode 100644
index 0000000000..98f2f6455f
--- /dev/null
+++ b/docker/heap-sizing/src/main/java/com/baeldung/docker/heapsizing/PrintXmxXms.java
@@ -0,0 +1,36 @@
+package com.baeldung.docker.heapsizing;
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryMXBean;
+import java.lang.management.MemoryPoolMXBean;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class PrintXmxXms {
+
+ private static final Logger logger = Logger.getLogger(PrintXmxXms.class.getName());
+
+ public static void main(String[] args) {
+ logMemory(logger);
+ }
+
+ /**
+ * We're reusing this method in HeapSizingApplication, therefore this method was extracted
+ * to avoid repetition.
+ */
+ static void logMemory(Logger logger) {
+ float mb = 1024f * 1024f;
+ MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
+
+ // xmx controls the maximum size of the memory allocation pool,
+ // which includes the heap, the garbage collector's survivor space, and other pools.
+ float xmx = memoryBean.getHeapMemoryUsage().getMax() / mb;
+ float xms = memoryBean.getHeapMemoryUsage().getInit() / mb;
+ logger.log(Level.INFO, "Initial Memory (xms) : {0}mb", xms);
+ logger.log(Level.INFO, "Max Memory (xmx) : {0}mb", xmx);
+
+ for (MemoryPoolMXBean mp : ManagementFactory.getMemoryPoolMXBeans()) {
+ logger.log(Level.INFO, "Pool: {0} (type {1}) = {2}", new Object[]{ mp.getName(), mp.getType(), mp.getUsage().getMax() / mb });
+ }
+ }
+}
diff --git a/java-collections-maps-3/src/main/java/com/baeldung/map/hashing/Member.java b/java-collections-maps-3/src/main/java/com/baeldung/map/hashing/Member.java
new file mode 100644
index 0000000000..22b6a61d4d
--- /dev/null
+++ b/java-collections-maps-3/src/main/java/com/baeldung/map/hashing/Member.java
@@ -0,0 +1,6 @@
+package com.baeldung.map.hashing;
+
+class Member {
+ Integer id;
+ String name;
+}
diff --git a/java-collections-maps-3/src/main/java/com/baeldung/map/hashing/MemberWithBadHashing.java b/java-collections-maps-3/src/main/java/com/baeldung/map/hashing/MemberWithBadHashing.java
new file mode 100644
index 0000000000..2a69291742
--- /dev/null
+++ b/java-collections-maps-3/src/main/java/com/baeldung/map/hashing/MemberWithBadHashing.java
@@ -0,0 +1,8 @@
+package com.baeldung.map.hashing;
+
+public class MemberWithBadHashing extends Member {
+ @Override
+ public int hashCode() {
+ return name.hashCode();
+ }
+}
diff --git a/java-collections-maps-3/src/main/java/com/baeldung/map/hashing/MemberWithGuavaHashing.java b/java-collections-maps-3/src/main/java/com/baeldung/map/hashing/MemberWithGuavaHashing.java
new file mode 100644
index 0000000000..bb33ace0b7
--- /dev/null
+++ b/java-collections-maps-3/src/main/java/com/baeldung/map/hashing/MemberWithGuavaHashing.java
@@ -0,0 +1,18 @@
+package com.baeldung.map.hashing;
+
+import com.google.common.base.Charsets;
+import com.google.common.hash.HashFunction;
+import com.google.common.hash.Hashing;
+
+public class MemberWithGuavaHashing extends Member {
+ @Override
+ public int hashCode() {
+ HashFunction hashFunction = Hashing.murmur3_32();
+ return hashFunction.newHasher()
+ .putInt(id)
+ .putString(name, Charsets.UTF_8)
+ .hash().hashCode();
+ }
+
+
+}
diff --git a/java-collections-maps-3/src/main/java/com/baeldung/map/hashing/MemberWithId.java b/java-collections-maps-3/src/main/java/com/baeldung/map/hashing/MemberWithId.java
new file mode 100644
index 0000000000..5d82eb0cb7
--- /dev/null
+++ b/java-collections-maps-3/src/main/java/com/baeldung/map/hashing/MemberWithId.java
@@ -0,0 +1,18 @@
+package com.baeldung.map.hashing;
+
+public class MemberWithId extends Member {
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ MemberWithId that = (MemberWithId) o;
+
+ return id.equals(that.id);
+ }
+
+ @Override
+ public int hashCode() {
+ return id;
+ }
+}
diff --git a/java-collections-maps-3/src/main/java/com/baeldung/map/hashing/MemberWithIdAndName.java b/java-collections-maps-3/src/main/java/com/baeldung/map/hashing/MemberWithIdAndName.java
new file mode 100644
index 0000000000..81ae48cf55
--- /dev/null
+++ b/java-collections-maps-3/src/main/java/com/baeldung/map/hashing/MemberWithIdAndName.java
@@ -0,0 +1,23 @@
+package com.baeldung.map.hashing;
+
+import java.util.Objects;
+
+public class MemberWithIdAndName extends Member {
+ public static final int PRIME = 31;
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ MemberWithObjects that = (MemberWithObjects) o;
+ return Objects.equals(id, that.id) &&
+ Objects.equals(name, that.name);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = id.hashCode();
+ result = PRIME * result + (name == null ? 0 : name.hashCode());
+ return result;
+ }
+}
diff --git a/java-collections-maps-3/src/main/java/com/baeldung/map/hashing/MemberWithObjects.java b/java-collections-maps-3/src/main/java/com/baeldung/map/hashing/MemberWithObjects.java
new file mode 100644
index 0000000000..b641035e4f
--- /dev/null
+++ b/java-collections-maps-3/src/main/java/com/baeldung/map/hashing/MemberWithObjects.java
@@ -0,0 +1,19 @@
+package com.baeldung.map.hashing;
+
+import java.util.Objects;
+
+public class MemberWithObjects extends Member {
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ MemberWithObjects that = (MemberWithObjects) o;
+ return Objects.equals(id, that.id) &&
+ Objects.equals(name, that.name);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, name);
+ }
+}
diff --git a/java-collections-maps-3/src/test/java/com/baeldung/map/hashing/HashingUnitTest.java b/java-collections-maps-3/src/test/java/com/baeldung/map/hashing/HashingUnitTest.java
new file mode 100644
index 0000000000..d28a3b50b5
--- /dev/null
+++ b/java-collections-maps-3/src/test/java/com/baeldung/map/hashing/HashingUnitTest.java
@@ -0,0 +1,76 @@
+package com.baeldung.map.hashing;
+
+import com.google.common.base.Stopwatch;
+import org.junit.jupiter.api.Test;
+
+import java.time.Duration;
+import java.util.HashMap;
+import java.util.SplittableRandom;
+import java.util.function.Supplier;
+
+public class HashingUnitTest {
+
+ public static final int SAMPLES = 1000000;
+ private SplittableRandom random = new SplittableRandom();
+
+ private String[] names = {"John", "Adam", "Suzie"};
+
+ @Test
+ void givenPrimitiveByteArrayKey_whenRetrievingFromMap_shouldRetrieveDifferentObjects() {
+ // bad hashing example is prohibitively slow for bigger samples
+// Duration[] badHashing = testDuration(MemberWithBadHashing::new);
+ Duration[] withId = testDuration(MemberWithId::new);
+ Duration[] withObjects = testDuration(MemberWithObjects::new);
+ Duration[] withIdAndName = testDuration(MemberWithIdAndName::new);
+
+// System.out.println("Inserting with bad hashing:");
+// System.out.println(badHashing[0]);
+// System.out.println("Getting with bad hashing:");
+// System.out.println(badHashing[1]);
+
+ System.out.println("Inserting with id hashing:");
+ System.out.println(withId[0]);
+ System.out.println("Getting with id hashing:");
+ System.out.println(withId[1]);
+
+ System.out.println("Inserting with id and name hashing:");
+ System.out.println(withIdAndName[0]);
+ System.out.println("Getting with id and name hashing:");
+ System.out.println(withIdAndName[1]);
+
+ System.out.println("Inserting with Objects hashing:");
+ System.out.println(withObjects[0]);
+ System.out.println("Getting with Objects hashing:");
+ System.out.println(withObjects[1]);
+ }
+
+ private String randomName() {
+ return names[random.nextInt(2)];
+ }
+
+ private Duration[] testDuration(Supplier factory) {
+ HashMap map = new HashMap<>();
+ Stopwatch stopwatch = Stopwatch.createUnstarted();
+
+ stopwatch.start();
+ for(int i = 0; i < SAMPLES; i++) {
+ T member = factory.get();
+ member.id = i;
+ member.name = randomName();
+ map.put(member, member.name);
+ }
+ stopwatch.stop();
+ Duration elapsedInserting = stopwatch.elapsed();
+ stopwatch.reset();
+
+ stopwatch.start();
+ for (T key : map.keySet()) {
+ map.get(key);
+ }
+ stopwatch.stop();
+ Duration elapsedGetting = stopwatch.elapsed();
+ stopwatch.reset();
+
+ return new Duration[]{elapsedInserting, elapsedGetting};
+ }
+}
diff --git a/jmeter/README.md b/jmeter/README.md
index 81300afe7c..11351ffdda 100644
--- a/jmeter/README.md
+++ b/jmeter/README.md
@@ -7,7 +7,7 @@ It contains the code of a simple API for some CRUD operations built using Spring
- Maven
- JDK 8
-- MongoDB
+- MongoDB (Note: for the Write Extracted Data to a File Using JMeter example MongoDB is not required)
### Running
@@ -36,6 +36,14 @@ Or create a new one via a POST:
$ curl -X POST -H "Content-Type:application/json" -d '{ "firstName" : "Dassi", "lastName" : "Orleando", "phoneNumber": "+237 545454545", "email": "mymail@yahoo.fr" }' localhost:8080/students
```
+### Available UUID API
+
+You can view the test response using curl:
+
+```bash
+$ curl localhost:8080/api/uuid
+```
+
Now with default configurations it will be available at: [http://localhost:8080](http://localhost:8080)
Enjoy it :)
diff --git a/jmeter/src/main/java/com/baeldung/controller/RetrieveUuidController.java b/jmeter/src/main/java/com/baeldung/controller/RetrieveUuidController.java
new file mode 100644
index 0000000000..32265c0170
--- /dev/null
+++ b/jmeter/src/main/java/com/baeldung/controller/RetrieveUuidController.java
@@ -0,0 +1,18 @@
+package com.baeldung.controller;
+
+import com.baeldung.model.Response;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.UUID;
+
+import static java.lang.String.format;
+
+@RestController
+public class RetrieveUuidController {
+
+ @GetMapping("/api/uuid")
+ public Response uuid() {
+ return new Response(format("Test message... %s.", UUID.randomUUID()));
+ }
+}
diff --git a/jmeter/src/main/java/com/baeldung/model/Response.java b/jmeter/src/main/java/com/baeldung/model/Response.java
new file mode 100644
index 0000000000..547e5b536e
--- /dev/null
+++ b/jmeter/src/main/java/com/baeldung/model/Response.java
@@ -0,0 +1,40 @@
+package com.baeldung.model;
+
+import java.time.Instant;
+import java.util.UUID;
+
+public class Response {
+ private Instant timestamp;
+ private UUID uuid;
+ private String message;
+
+ public Response(String message) {
+ this.timestamp = Instant.now();
+ this.uuid = UUID.randomUUID();
+ this.message = message;
+ }
+
+ public Instant getTimestamp() {
+ return timestamp;
+ }
+
+ public void setTimestamp(Instant timestamp) {
+ this.timestamp = timestamp;
+ }
+
+ public UUID getUuid() {
+ return uuid;
+ }
+
+ public void setUuid(UUID uuid) {
+ this.uuid = uuid;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+}
diff --git a/jmeter/src/main/resources/FileExtractionExample.jmx b/jmeter/src/main/resources/FileExtractionExample.jmx
new file mode 100644
index 0000000000..961b6f143f
--- /dev/null
+++ b/jmeter/src/main/resources/FileExtractionExample.jmx
@@ -0,0 +1,124 @@
+
+
+
+
+ To run this test plan you must also be running the Spring application "JmeterApplication" That can be found in this directory
+ false
+ true
+ false
+
+
+
+
+
+
+
+ continue
+
+ false
+ 1
+
+ 1
+ 1
+ false
+
+
+ true
+
+
+
+
+
+
+ localhost
+ 8080
+ http
+
+ /api/test
+ GET
+ true
+ false
+ true
+ false
+
+
+
+
+
+
+ message
+ $.message
+ 1
+ true
+ NOT_FOUND
+
+
+
+
+
+ false
+ FileWriter fWriter = new FileWriter("/result.txt", true);
+BufferedWriter buff = new BufferedWriter(fWriter);
+
+buff.write("Response Code : " + ctx.getPreviousResult().getResponseCode());
+buff.write(System.getProperty("line.separator"));
+buff.write("Response Headers : " + ctx.getPreviousResult().getResponseHeaders());
+buff.write(System.getProperty("line.separator"));
+buff.write("Response Body : " + new String(ctx.getPreviousResult().getResponseData()));
+
+buff.write("More complex extraction : " + vars.get("message"));
+
+buff.close();
+fWriter.close();
+
+
+
+ response
+ false
+ false
+ false
+ false
+
+
+
+
+ false
+
+ saveConfig
+
+
+ true
+ true
+ true
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ false
+ true
+ false
+ false
+ false
+ true
+ 0
+ true
+ true
+ true
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
diff --git a/jmeter/src/test/java/com/baeldung/JmeterIntegrationTest.java b/jmeter/src/test/java/com/baeldung/JmeterIntegrationTest.java
new file mode 100644
index 0000000000..a1494416ef
--- /dev/null
+++ b/jmeter/src/test/java/com/baeldung/JmeterIntegrationTest.java
@@ -0,0 +1,35 @@
+package com.baeldung;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.mock.web.MockHttpServletResponse;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@SpringBootTest
+class JmeterIntegrationTest {
+
+ MockMvc mvc;
+
+ public JmeterIntegrationTest(WebApplicationContext wac) {
+ this.mvc = MockMvcBuilders.webAppContextSetup(wac).build();
+ }
+
+ @Test
+ void whenCallingUUIDController_thenWeShouldRecieveRandomizedResponse() throws Exception {
+ MockHttpServletResponse response = mvc.perform(get("/api/uuid"))
+ .andDo(print())
+ .andExpect(status().isOk())
+ .andReturn()
+ .getResponse();
+
+ assertThat(response.getContentAsString())
+ .contains("Test message...");
+ }
+}
diff --git a/maven-modules/pom.xml b/maven-modules/pom.xml
index 86a7d5756c..c9a2b67a6c 100644
--- a/maven-modules/pom.xml
+++ b/maven-modules/pom.xml
@@ -27,6 +27,7 @@
versions-maven-plugin
version-collision
optional-dependencies
+ version-overriding-plugins
diff --git a/maven-modules/version-overriding-plugins/README.md b/maven-modules/version-overriding-plugins/README.md
new file mode 100644
index 0000000000..1542692ca0
--- /dev/null
+++ b/maven-modules/version-overriding-plugins/README.md
@@ -0,0 +1,5 @@
+Use `` mvn help:effective-pom`` to see the final generated pom.
+
+### Relevant Articles:
+
+- [Override Maven Plugin Configuration from Parent](https://www.baeldung.com/maven-plugin-override-parent)
diff --git a/maven-modules/version-overriding-plugins/child-a/pom.xml b/maven-modules/version-overriding-plugins/child-a/pom.xml
new file mode 100644
index 0000000000..780e1c4125
--- /dev/null
+++ b/maven-modules/version-overriding-plugins/child-a/pom.xml
@@ -0,0 +1,36 @@
+
+
+
+ version-overriding-plugins
+ com.baeldung
+ 0.0.1-SNAPSHOT
+
+ 4.0.0
+ pom
+
+ child-a
+
+
+
+ maven-resources-plugin
+
+
+
+ child-a-resources
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 1.8
+ 1.8
+
+
+
+
+
\ No newline at end of file
diff --git a/maven-modules/version-overriding-plugins/child-b/pom.xml b/maven-modules/version-overriding-plugins/child-b/pom.xml
new file mode 100644
index 0000000000..05f127bc5c
--- /dev/null
+++ b/maven-modules/version-overriding-plugins/child-b/pom.xml
@@ -0,0 +1,15 @@
+
+
+
+ version-overriding-plugins
+ com.baeldung
+ 0.0.1-SNAPSHOT
+
+ 4.0.0
+
+ child-b
+
+
+
\ No newline at end of file
diff --git a/maven-modules/version-overriding-plugins/pom.xml b/maven-modules/version-overriding-plugins/pom.xml
new file mode 100644
index 0000000000..8d703ab568
--- /dev/null
+++ b/maven-modules/version-overriding-plugins/pom.xml
@@ -0,0 +1,55 @@
+
+
+
+ maven-modules
+ com.baeldung
+ 0.0.1-SNAPSHOT
+
+
+ 3.8.0
+
+ 4.0.0
+
+ version-overriding-plugins
+ pom
+
+
+ child-a
+ child-b
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ ${maven.compiler.plugin}
+
+
+
+
+
+ maven-resources-plugin
+
+
+
+ parent-resources
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 11
+ 11
+ 512m
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-5-reactive-client/README.md b/spring-5-reactive-client/README.md
index b247a1669b..154a3cab0b 100644
--- a/spring-5-reactive-client/README.md
+++ b/spring-5-reactive-client/README.md
@@ -8,7 +8,6 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring
### Relevant Articles
- [Logging Spring WebClient Calls](https://www.baeldung.com/spring-log-webclient-calls)
- [Simultaneous Spring WebClient Calls](https://www.baeldung.com/spring-webclient-simultaneous-calls)
-- [Logging Spring WebClient Calls](https://www.baeldung.com/spring-log-webclient-calls)
- [Mocking a WebClient in Spring](https://www.baeldung.com/spring-mocking-webclient)
- [Spring WebClient Filters](https://www.baeldung.com/spring-webclient-filters)
- [Get List of JSON Objects with WebClient](https://www.baeldung.com/spring-webclient-json-list)
diff --git a/spring-5-reactive-client/pom.xml b/spring-5-reactive-client/pom.xml
index 5b773cc63f..7ae7ba6edd 100644
--- a/spring-5-reactive-client/pom.xml
+++ b/spring-5-reactive-client/pom.xml
@@ -176,7 +176,6 @@
4.1
1.0.3
4.0.1
- 2.3.3.RELEASE
diff --git a/spring-5-reactive-client/src/main/resources/application.properties b/spring-5-reactive-client/src/main/resources/application.properties
index 2d93456aeb..05033054b1 100644
--- a/spring-5-reactive-client/src/main/resources/application.properties
+++ b/spring-5-reactive-client/src/main/resources/application.properties
@@ -1,3 +1,5 @@
logging.level.root=INFO
-server.port=8081
\ No newline at end of file
+server.port=8081
+
+logging.level.reactor.netty.http.client.HttpClient=DEBUG
\ No newline at end of file
diff --git a/spring-5-reactive-client/src/test/java/com/baeldung/reactive/logging/WebClientLoggingIntegrationTest.java b/spring-5-reactive-client/src/test/java/com/baeldung/reactive/logging/WebClientLoggingIntegrationTest.java
index 95c63f267f..bb4e682481 100644
--- a/spring-5-reactive-client/src/test/java/com/baeldung/reactive/logging/WebClientLoggingIntegrationTest.java
+++ b/spring-5-reactive-client/src/test/java/com/baeldung/reactive/logging/WebClientLoggingIntegrationTest.java
@@ -1,13 +1,13 @@
package com.baeldung.reactive.logging;
-import ch.qos.logback.classic.spi.LoggingEvent;
-import ch.qos.logback.core.Appender;
-import com.baeldung.reactive.logging.filters.LogFilters;
-import com.baeldung.reactive.logging.netty.CustomLogger;
-import com.fasterxml.jackson.databind.ObjectMapper;
+import static com.baeldung.reactive.logging.jetty.RequestLogEnhancer.enhance;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
import java.net.URI;
-import lombok.AllArgsConstructor;
-import lombok.Data;
+
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.junit.jupiter.api.BeforeEach;
@@ -17,14 +17,17 @@ import org.springframework.http.client.reactive.JettyClientHttpConnector;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;
-import reactor.netty.channel.BootstrapHandlers;
-import reactor.netty.http.client.HttpClient;
-import static com.baeldung.reactive.logging.jetty.RequestLogEnhancer.enhance;
-import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
+import com.baeldung.reactive.logging.filters.LogFilters;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import ch.qos.logback.classic.spi.LoggingEvent;
+import ch.qos.logback.core.Appender;
+import io.netty.handler.logging.LogLevel;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import reactor.netty.http.client.HttpClient;
+import reactor.netty.transport.logging.AdvancedByteBufFormat;
public class WebClientLoggingIntegrationTest {
@@ -114,21 +117,17 @@ public class WebClientLoggingIntegrationTest {
@Test
public void givenNettyHttpClientWithCustomLogger_whenEndpointIsConsumed_thenRequestAndResponseBodyLogged() {
+ reactor.netty.http.client.HttpClient httpClient = HttpClient.create()
+ .wiretap("reactor.netty.http.client.HttpClient", LogLevel.DEBUG, AdvancedByteBufFormat.TEXTUAL);
- reactor.netty.http.client.HttpClient httpClient = HttpClient
- .create()
- .tcpConfiguration(
- tc -> tc.bootstrap(
- b -> BootstrapHandlers.updateLogSupport(b, new CustomLogger(HttpClient.class))));
- WebClient
- .builder()
- .clientConnector(new ReactorClientHttpConnector(httpClient))
- .build()
- .post()
- .uri(sampleUrl)
- .body(BodyInserters.fromObject(post))
- .exchange()
- .block();
+ WebClient.builder()
+ .clientConnector(new ReactorClientHttpConnector(httpClient))
+ .build()
+ .post()
+ .uri(sampleUrl)
+ .body(BodyInserters.fromObject(post))
+ .exchange()
+ .block();
verify(nettyAppender).doAppend(argThat(argument -> (((LoggingEvent) argument).getFormattedMessage()).contains(sampleResponseBody)));
}
diff --git a/spring-5-reactive-client/src/test/java/com/baeldung/reactive/logging/netty/CustomLogger.java b/spring-5-reactive-client/src/test/java/com/baeldung/reactive/logging/netty/CustomLogger.java
deleted file mode 100644
index 9f2a4d127f..0000000000
--- a/spring-5-reactive-client/src/test/java/com/baeldung/reactive/logging/netty/CustomLogger.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.baeldung.reactive.logging.netty;
-
-import io.netty.buffer.ByteBuf;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.handler.logging.LoggingHandler;
-import java.nio.charset.Charset;
-
-import static io.netty.util.internal.PlatformDependent.allocateUninitializedArray;
-import static java.lang.Math.max;
-import static java.nio.charset.Charset.defaultCharset;
-
-public class CustomLogger extends LoggingHandler {
- public CustomLogger(Class> clazz) {
- super(clazz);
- }
-
- @Override
- protected String format(ChannelHandlerContext ctx, String event, Object arg) {
- if (arg instanceof ByteBuf) {
- ByteBuf msg = (ByteBuf) arg;
- return decode(msg, msg.readerIndex(), msg.readableBytes(), defaultCharset());
- }
- return super.format(ctx, event, arg);
- }
-
- private String decode(ByteBuf src, int readerIndex, int len, Charset charset) {
- if (len != 0) {
- byte[] array;
- int offset;
- if (src.hasArray()) {
- array = src.array();
- offset = src.arrayOffset() + readerIndex;
- } else {
- array = allocateUninitializedArray(max(len, 1024));
- offset = 0;
- src.getBytes(readerIndex, array, 0, len);
- }
- return new String(array, offset, len, charset);
- }
- return "";
- }
-}
diff --git a/spring-boot-modules/pom.xml b/spring-boot-modules/pom.xml
index 263d2af089..4902368d7e 100644
--- a/spring-boot-modules/pom.xml
+++ b/spring-boot-modules/pom.xml
@@ -54,6 +54,7 @@
spring-boot-mvc-2
spring-boot-mvc-3
spring-boot-mvc-birt
+ spring-boot-mvc-jersey
spring-boot-nashorn
spring-boot-parent
spring-boot-performance
diff --git a/spring-boot-modules/spring-boot-admin/spring-boot-admin-client/pom.xml b/spring-boot-modules/spring-boot-admin/spring-boot-admin-client/pom.xml
index eb40bfe8ea..f7a4b157e7 100644
--- a/spring-boot-modules/spring-boot-admin/spring-boot-admin-client/pom.xml
+++ b/spring-boot-modules/spring-boot-admin/spring-boot-admin-client/pom.xml
@@ -61,7 +61,7 @@
- 2.2.2
+ 2.4.0
2.0.4.RELEASE
diff --git a/spring-boot-modules/spring-boot-admin/spring-boot-admin-server/pom.xml b/spring-boot-modules/spring-boot-admin/spring-boot-admin-server/pom.xml
index 558aed8b26..bcec12a14c 100644
--- a/spring-boot-modules/spring-boot-admin/spring-boot-admin-server/pom.xml
+++ b/spring-boot-modules/spring-boot-admin/spring-boot-admin-server/pom.xml
@@ -82,10 +82,9 @@
- 2.2.2
- 2.2.2
+ 2.4.0
+ 2.4.0
1.5.7
2.0.4.RELEASE
- 2.3.3.RELEASE
diff --git a/spring-boot-modules/spring-boot-admin/spring-boot-admin-server/src/main/java/com/baeldung/springbootadminserver/SpringBootAdminServerApplication.java b/spring-boot-modules/spring-boot-admin/spring-boot-admin-server/src/main/java/com/baeldung/springbootadminserver/SpringBootAdminServerApplication.java
index e934086cf4..5a713c7e8f 100644
--- a/spring-boot-modules/spring-boot-admin/spring-boot-admin-server/src/main/java/com/baeldung/springbootadminserver/SpringBootAdminServerApplication.java
+++ b/spring-boot-modules/spring-boot-admin/spring-boot-admin-server/src/main/java/com/baeldung/springbootadminserver/SpringBootAdminServerApplication.java
@@ -1,11 +1,12 @@
package com.baeldung.springbootadminserver;
+import de.codecentric.boot.admin.server.config.AdminServerHazelcastAutoConfiguration;
import de.codecentric.boot.admin.server.config.EnableAdminServer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@EnableAdminServer
-@SpringBootApplication
+@SpringBootApplication(exclude = AdminServerHazelcastAutoConfiguration.class)
public class SpringBootAdminServerApplication {
public static void main(String[] args) {
diff --git a/spring-boot-modules/spring-boot-admin/spring-boot-admin-server/src/main/java/com/baeldung/springbootadminserver/configs/HazelcastConfig.java b/spring-boot-modules/spring-boot-admin/spring-boot-admin-server/src/main/java/com/baeldung/springbootadminserver/configs/HazelcastConfig.java
index d38b0e933c..d53707c19a 100644
--- a/spring-boot-modules/spring-boot-admin/spring-boot-admin-server/src/main/java/com/baeldung/springbootadminserver/configs/HazelcastConfig.java
+++ b/spring-boot-modules/spring-boot-admin/spring-boot-admin-server/src/main/java/com/baeldung/springbootadminserver/configs/HazelcastConfig.java
@@ -1,12 +1,13 @@
package com.baeldung.springbootadminserver.configs;
import com.hazelcast.config.Config;
+import com.hazelcast.config.EvictionConfig;
import com.hazelcast.config.EvictionPolicy;
import com.hazelcast.config.InMemoryFormat;
import com.hazelcast.config.MapConfig;
import com.hazelcast.config.MergePolicyConfig;
import com.hazelcast.config.TcpIpConfig;
-import com.hazelcast.map.merge.PutIfAbsentMapMergePolicy;
+import com.hazelcast.spi.merge.PutIfAbsentMergePolicy;
import java.util.Collections;
@@ -16,32 +17,27 @@ import org.springframework.context.annotation.Configuration;
@Configuration
public class HazelcastConfig {
- @Bean
- public Config hazelcast() {
- MapConfig eventStoreMap = new MapConfig("spring-boot-admin-event-store").setInMemoryFormat(InMemoryFormat.OBJECT)
- .setBackupCount(1)
- .setEvictionPolicy(EvictionPolicy.NONE)
- .setMergePolicyConfig(new MergePolicyConfig(PutIfAbsentMapMergePolicy.class.getName(), 100));
+ @Bean
+ public Config hazelcast() {
+ MapConfig eventStoreMap = new MapConfig("spring-boot-admin-event-store")
+ .setInMemoryFormat(InMemoryFormat.OBJECT).setBackupCount(1)
+ .setEvictionConfig(new EvictionConfig().setEvictionPolicy(EvictionPolicy.NONE))
+ .setMergePolicyConfig(new MergePolicyConfig(PutIfAbsentMergePolicy.class.getName(), 100));
- MapConfig sentNotificationsMap = new MapConfig("spring-boot-admin-application-store").setInMemoryFormat(InMemoryFormat.OBJECT)
- .setBackupCount(1)
- .setEvictionPolicy(EvictionPolicy.LRU)
- .setMergePolicyConfig(new MergePolicyConfig(PutIfAbsentMapMergePolicy.class.getName(), 100));
+ MapConfig sentNotificationsMap = new MapConfig("spring-boot-admin-application-store")
+ .setInMemoryFormat(InMemoryFormat.OBJECT).setBackupCount(1)
+ .setEvictionConfig(new EvictionConfig().setEvictionPolicy(EvictionPolicy.LRU))
+ .setMergePolicyConfig(new MergePolicyConfig(PutIfAbsentMergePolicy.class.getName(), 100));
- Config config = new Config();
- config.addMapConfig(eventStoreMap);
- config.addMapConfig(sentNotificationsMap);
- config.setProperty("hazelcast.jmx", "true");
+ Config config = new Config();
+ config.addMapConfig(eventStoreMap);
+ config.addMapConfig(sentNotificationsMap);
+ config.setProperty("hazelcast.jmx", "true");
- config.getNetworkConfig()
- .getJoin()
- .getMulticastConfig()
- .setEnabled(false);
- TcpIpConfig tcpIpConfig = config.getNetworkConfig()
- .getJoin()
- .getTcpIpConfig();
- tcpIpConfig.setEnabled(true);
- tcpIpConfig.setMembers(Collections.singletonList("127.0.0.1"));
- return config;
- }
+ config.getNetworkConfig().getJoin().getMulticastConfig().setEnabled(false);
+ TcpIpConfig tcpIpConfig = config.getNetworkConfig().getJoin().getTcpIpConfig();
+ tcpIpConfig.setEnabled(true);
+ tcpIpConfig.setMembers(Collections.singletonList("127.0.0.1"));
+ return config;
+ }
}
diff --git a/spring-boot-modules/spring-boot-data-2/README.md b/spring-boot-modules/spring-boot-data-2/README.md
index d5020ce354..29d9dafe66 100644
--- a/spring-boot-modules/spring-boot-data-2/README.md
+++ b/spring-boot-modules/spring-boot-data-2/README.md
@@ -1,3 +1,4 @@
### Relevant Articles:
- [Spring Boot: Customize the Jackson ObjectMapper](https://www.baeldung.com/spring-boot-customize-jackson-objectmapper)
+- [“HttpMessageNotWritableException: No converter found for return value of type”](https://www.baeldung.com/spring-no-converter-found)
diff --git a/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/noconverterfound/NoConverterFoundApplication.java b/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/noconverterfound/NoConverterFoundApplication.java
new file mode 100644
index 0000000000..7abfa29bf2
--- /dev/null
+++ b/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/noconverterfound/NoConverterFoundApplication.java
@@ -0,0 +1,12 @@
+package com.baeldung.boot.noconverterfound;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class NoConverterFoundApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(NoConverterFoundApplication.class, args);
+ }
+}
diff --git a/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/noconverterfound/controller/StudentRestController.java b/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/noconverterfound/controller/StudentRestController.java
new file mode 100644
index 0000000000..21cb98710d
--- /dev/null
+++ b/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/noconverterfound/controller/StudentRestController.java
@@ -0,0 +1,21 @@
+package com.baeldung.boot.noconverterfound.controller;
+
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.baeldung.boot.noconverterfound.model.Student;
+
+@RestController
+@RequestMapping(value = "/api")
+public class StudentRestController {
+
+ @GetMapping("/student/{id}")
+ public ResponseEntity get(@PathVariable("id") int id) {
+ // Custom logic
+ return ResponseEntity.ok(new Student(id, "John", "Wiliams", "AA"));
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/noconverterfound/model/Student.java b/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/noconverterfound/model/Student.java
new file mode 100644
index 0000000000..94ece02f8f
--- /dev/null
+++ b/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/noconverterfound/model/Student.java
@@ -0,0 +1,53 @@
+package com.baeldung.boot.noconverterfound.model;
+
+public class Student {
+
+ private int id;
+ private String firstName;
+ private String lastName;
+ private String grade;
+
+ public Student() {
+
+ }
+
+ public Student(int id, String firstName, String lastName, String grade) {
+ this.id = id;
+ this.firstName = firstName;
+ this.lastName = lastName;
+ this.grade = grade;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public String getFirstName() {
+ return firstName;
+ }
+
+ public void setFirstName(String firstName) {
+ this.firstName = firstName;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public void setLastName(String lastName) {
+ this.lastName = lastName;
+ }
+
+ public String getGrade() {
+ return grade;
+ }
+
+ public void setGrade(String grade) {
+ this.grade = grade;
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/noconverterfound/NoConverterFoundIntegrationTest.java b/spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/noconverterfound/NoConverterFoundIntegrationTest.java
new file mode 100644
index 0000000000..f8ded91e65
--- /dev/null
+++ b/spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/noconverterfound/NoConverterFoundIntegrationTest.java
@@ -0,0 +1,52 @@
+package com.baeldung.boot.noconverterfound;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
+import org.springframework.http.converter.HttpMessageNotWritableException;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.web.servlet.MockMvc;
+
+import com.baeldung.boot.noconverterfound.controller.StudentRestController;
+
+@RunWith(SpringRunner.class)
+@WebMvcTest(StudentRestController.class)
+public class NoConverterFoundIntegrationTest {
+
+ @Autowired
+ private MockMvc mockMvc;
+
+ /* Remove Getters from Student class to successfully run this test case
+ * @Test
+ public void whenGettersNotDefined_thenThrowException() throws Exception {
+
+ String url = "/api/student/1";
+
+ this.mockMvc.perform(get(url))
+ .andExpect(status().isInternalServerError())
+ .andExpect(result -> assertThat(result.getResolvedException())
+ .isInstanceOf(HttpMessageNotWritableException.class))
+ .andExpect(result -> assertThat(result.getResolvedException().getMessage())
+ .contains("No converter found for return value of type"));
+
+ }
+ */
+
+ @Test
+ public void whenGettersAreDefined_thenReturnObject() throws Exception {
+
+ String url = "/api/student/2";
+
+ this.mockMvc.perform(get(url))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.firstName").value("John"));
+
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-mvc-jersey/README.md b/spring-boot-modules/spring-boot-mvc-jersey/README.md
new file mode 100644
index 0000000000..07f9e78ea6
--- /dev/null
+++ b/spring-boot-modules/spring-boot-mvc-jersey/README.md
@@ -0,0 +1,8 @@
+## Spring Boot Admin
+
+This module contains articles about Spring Boot: JAX-RS vs Spring
+
+
+### Relevant Articles:
+
+- [REST API: JAX-RS vs Spring](https://www.baeldung.com/TBD)
diff --git a/spring-boot-modules/spring-boot-mvc-jersey/pom.xml b/spring-boot-modules/spring-boot-mvc-jersey/pom.xml
new file mode 100644
index 0000000000..ab117c4d2e
--- /dev/null
+++ b/spring-boot-modules/spring-boot-mvc-jersey/pom.xml
@@ -0,0 +1,23 @@
+
+
+ 4.0.0
+
+
+ com.baeldung.spring-boot-modules
+ spring-boot-modules
+ 1.0.0-SNAPSHOT
+ ../
+
+
+ spring-boot-mvc-jersey
+ 0.0.1-SNAPSHOT
+ pom
+
+ spring-boot-mvc-jersey
+
+
+ spring-boot-jersey
+ spring-boot-mvc
+
+
diff --git a/spring-boot-modules/spring-boot-mvc-jersey/spring-boot-jersey/pom.xml b/spring-boot-modules/spring-boot-mvc-jersey/spring-boot-jersey/pom.xml
new file mode 100644
index 0000000000..5756a27eca
--- /dev/null
+++ b/spring-boot-modules/spring-boot-mvc-jersey/spring-boot-jersey/pom.xml
@@ -0,0 +1,38 @@
+
+
+ 4.0.0
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.4.2
+
+
+
+ com.baeldung.boot
+ spring-boot-jersey
+ 0.0.1-SNAPSHOT
+
+
+
+ org.springframework.boot
+ spring-boot-starter-jersey
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
diff --git a/spring-boot-modules/spring-boot-mvc-jersey/spring-boot-jersey/src/main/java/com/baeldung/boot/jersey/JerseyApplication.java b/spring-boot-modules/spring-boot-mvc-jersey/spring-boot-jersey/src/main/java/com/baeldung/boot/jersey/JerseyApplication.java
new file mode 100644
index 0000000000..b8ee0d0115
--- /dev/null
+++ b/spring-boot-modules/spring-boot-mvc-jersey/spring-boot-jersey/src/main/java/com/baeldung/boot/jersey/JerseyApplication.java
@@ -0,0 +1,13 @@
+package com.baeldung.boot.jersey;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class JerseyApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(JerseyApplication.class, args);
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-mvc-jersey/spring-boot-jersey/src/main/java/com/baeldung/boot/jersey/controllers/HelloController.java b/spring-boot-modules/spring-boot-mvc-jersey/spring-boot-jersey/src/main/java/com/baeldung/boot/jersey/controllers/HelloController.java
new file mode 100644
index 0000000000..2774e458de
--- /dev/null
+++ b/spring-boot-modules/spring-boot-mvc-jersey/spring-boot-jersey/src/main/java/com/baeldung/boot/jersey/controllers/HelloController.java
@@ -0,0 +1,20 @@
+package com.baeldung.boot.jersey.controllers;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+@Path("/hello")
+public class HelloController {
+
+ @GET
+ @Path("/{name}")
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response hello(@PathParam("name") String name) {
+ return Response.ok("Hello, " + name).build();
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-mvc-jersey/spring-boot-jersey/src/main/resources/application.properties b/spring-boot-modules/spring-boot-mvc-jersey/spring-boot-jersey/src/main/resources/application.properties
new file mode 100644
index 0000000000..8b13789179
--- /dev/null
+++ b/spring-boot-modules/spring-boot-mvc-jersey/spring-boot-jersey/src/main/resources/application.properties
@@ -0,0 +1 @@
+
diff --git a/spring-boot-modules/spring-boot-mvc-jersey/spring-boot-jersey/src/test/java/com/baeldung/boot/jersey/JerseyApplicationIntegrationTests.java b/spring-boot-modules/spring-boot-mvc-jersey/spring-boot-jersey/src/test/java/com/baeldung/boot/jersey/JerseyApplicationIntegrationTests.java
new file mode 100644
index 0000000000..9bd6bbf029
--- /dev/null
+++ b/spring-boot-modules/spring-boot-mvc-jersey/spring-boot-jersey/src/test/java/com/baeldung/boot/jersey/JerseyApplicationIntegrationTests.java
@@ -0,0 +1,13 @@
+package com.baeldung.boot.jersey;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class JerseyApplicationIntegrationTests {
+
+ @Test
+ void contextLoads() {
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-mvc-jersey/spring-boot-jersey/src/test/java/com/baeldung/boot/jersey/controllers/HelloControllerUnitTest.java b/spring-boot-modules/spring-boot-mvc-jersey/spring-boot-jersey/src/test/java/com/baeldung/boot/jersey/controllers/HelloControllerUnitTest.java
new file mode 100644
index 0000000000..e0c48da5bd
--- /dev/null
+++ b/spring-boot-modules/spring-boot-mvc-jersey/spring-boot-jersey/src/test/java/com/baeldung/boot/jersey/controllers/HelloControllerUnitTest.java
@@ -0,0 +1,27 @@
+package com.baeldung.boot.jersey.controllers;
+
+import javax.ws.rs.core.Response;
+
+import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Import;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+@Import(HelloController.class)
+@ExtendWith(SpringExtension.class)
+public class HelloControllerUnitTest {
+
+ @Autowired
+ private HelloController helloController;
+
+ @Test
+ public void whenHelloIsInvokedWithCaio_thenReturn200AsStatusAndHelloCaioAsBody() {
+ Response response = this.helloController.hello("Caio");
+ assertThat(response.getStatus()).isEqualTo(200);
+ assertThat(response.getEntity()).isEqualTo("Hello, Caio");
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-mvc-jersey/spring-boot-mvc/pom.xml b/spring-boot-modules/spring-boot-mvc-jersey/spring-boot-mvc/pom.xml
new file mode 100644
index 0000000000..69d355e574
--- /dev/null
+++ b/spring-boot-modules/spring-boot-mvc-jersey/spring-boot-mvc/pom.xml
@@ -0,0 +1,38 @@
+
+
+ 4.0.0
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.4.2
+
+
+
+ com.baeldung.boot
+ spring-boot-mvc
+ 0.0.1-SNAPSHOT
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
diff --git a/spring-boot-modules/spring-boot-mvc-jersey/spring-boot-mvc/src/main/java/com/baeldung/boot/mvc/MvcApplication.java b/spring-boot-modules/spring-boot-mvc-jersey/spring-boot-mvc/src/main/java/com/baeldung/boot/mvc/MvcApplication.java
new file mode 100644
index 0000000000..9c42c72fd7
--- /dev/null
+++ b/spring-boot-modules/spring-boot-mvc-jersey/spring-boot-mvc/src/main/java/com/baeldung/boot/mvc/MvcApplication.java
@@ -0,0 +1,13 @@
+package com.baeldung.boot.mvc;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class MvcApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(MvcApplication.class, args);
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-mvc-jersey/spring-boot-mvc/src/main/java/com/baeldung/boot/mvc/controllers/HelloController.java b/spring-boot-modules/spring-boot-mvc-jersey/spring-boot-mvc/src/main/java/com/baeldung/boot/mvc/controllers/HelloController.java
new file mode 100644
index 0000000000..0b4c569ba9
--- /dev/null
+++ b/spring-boot-modules/spring-boot-mvc-jersey/spring-boot-mvc/src/main/java/com/baeldung/boot/mvc/controllers/HelloController.java
@@ -0,0 +1,21 @@
+package com.baeldung.boot.mvc.controllers;
+
+
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/hello")
+public class HelloController {
+
+ @GetMapping(value = "/{name}", produces = MediaType.TEXT_PLAIN_VALUE)
+ public ResponseEntity> hello(@PathVariable String name) {
+ return new ResponseEntity<>("Hello, " + name, HttpStatus.OK);
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-mvc-jersey/spring-boot-mvc/src/main/resources/application.properties b/spring-boot-modules/spring-boot-mvc-jersey/spring-boot-mvc/src/main/resources/application.properties
new file mode 100644
index 0000000000..8b13789179
--- /dev/null
+++ b/spring-boot-modules/spring-boot-mvc-jersey/spring-boot-mvc/src/main/resources/application.properties
@@ -0,0 +1 @@
+
diff --git a/spring-boot-modules/spring-boot-mvc-jersey/spring-boot-mvc/src/test/java/com/baeldung/boot/mvc/MvcApplicationIntegrationTests.java b/spring-boot-modules/spring-boot-mvc-jersey/spring-boot-mvc/src/test/java/com/baeldung/boot/mvc/MvcApplicationIntegrationTests.java
new file mode 100644
index 0000000000..d05cb97e47
--- /dev/null
+++ b/spring-boot-modules/spring-boot-mvc-jersey/spring-boot-mvc/src/test/java/com/baeldung/boot/mvc/MvcApplicationIntegrationTests.java
@@ -0,0 +1,13 @@
+package com.baeldung.boot.mvc;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class MvcApplicationIntegrationTests {
+
+ @Test
+ void contextLoads() {
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-mvc-jersey/spring-boot-mvc/src/test/java/com/baeldung/boot/mvc/controllers/HelloControllerUnitTest.java b/spring-boot-modules/spring-boot-mvc-jersey/spring-boot-mvc/src/test/java/com/baeldung/boot/mvc/controllers/HelloControllerUnitTest.java
new file mode 100644
index 0000000000..3bef9df4fd
--- /dev/null
+++ b/spring-boot-modules/spring-boot-mvc-jersey/spring-boot-mvc/src/test/java/com/baeldung/boot/mvc/controllers/HelloControllerUnitTest.java
@@ -0,0 +1,27 @@
+package com.baeldung.boot.mvc.controllers;
+
+import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Import;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+@Import(HelloController.class)
+@ExtendWith(SpringExtension.class)
+public class HelloControllerUnitTest {
+
+ @Autowired
+ private HelloController helloController;
+
+ @Test
+ public void whenHelloIsInvokedWithCaio_thenReturn200AsStatusAndHelloCaioAsBody() {
+ ResponseEntity response = this.helloController.hello("Caio");
+ assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
+ assertThat(response.getBody()).isEqualTo("Hello, Caio");
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-runtime-2/README.md b/spring-boot-modules/spring-boot-runtime-2/README.md
index f997f2473d..9f0d814d8d 100644
--- a/spring-boot-modules/spring-boot-runtime-2/README.md
+++ b/spring-boot-modules/spring-boot-runtime-2/README.md
@@ -3,4 +3,4 @@
This module contains articles about administering a Spring Boot runtime
### Relevant Articles:
- -
+ - [Configure the Heap Size When Starting a Spring Boot Application](https://www.baeldung.com/spring-boot-heap-size)
diff --git a/spring-boot-rest/src/main/java/com/baeldung/web/config/MyCustomErrorAttributes.java b/spring-boot-rest/src/main/java/com/baeldung/web/config/MyCustomErrorAttributes.java
index 1948d5552f..5e776c0e29 100644
--- a/spring-boot-rest/src/main/java/com/baeldung/web/config/MyCustomErrorAttributes.java
+++ b/spring-boot-rest/src/main/java/com/baeldung/web/config/MyCustomErrorAttributes.java
@@ -2,6 +2,7 @@ package com.baeldung.web.config;
import java.util.Map;
+import org.springframework.boot.web.error.ErrorAttributeOptions;
import org.springframework.boot.web.servlet.error.DefaultErrorAttributes;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.WebRequest;
@@ -10,8 +11,8 @@ import org.springframework.web.context.request.WebRequest;
public class MyCustomErrorAttributes extends DefaultErrorAttributes {
@Override
- public Map getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
- Map errorAttributes = super.getErrorAttributes(webRequest, includeStackTrace);
+ public Map getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {
+ Map errorAttributes = super.getErrorAttributes(webRequest, options);
errorAttributes.put("locale", webRequest.getLocale()
.toString());
errorAttributes.remove("error");
diff --git a/spring-boot-rest/src/main/java/com/baeldung/web/config/MyErrorController.java b/spring-boot-rest/src/main/java/com/baeldung/web/config/MyErrorController.java
index cf3f9c4dbd..05150716f6 100644
--- a/spring-boot-rest/src/main/java/com/baeldung/web/config/MyErrorController.java
+++ b/spring-boot-rest/src/main/java/com/baeldung/web/config/MyErrorController.java
@@ -4,7 +4,7 @@ import java.util.Map;
import javax.servlet.http.HttpServletRequest;
-import org.springframework.boot.autoconfigure.web.ErrorProperties;
+import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController;
import org.springframework.boot.web.servlet.error.ErrorAttributes;
import org.springframework.http.HttpStatus;
@@ -16,13 +16,13 @@ import org.springframework.web.bind.annotation.RequestMapping;
@Component
public class MyErrorController extends BasicErrorController {
- public MyErrorController(ErrorAttributes errorAttributes) {
- super(errorAttributes, new ErrorProperties());
+ public MyErrorController(ErrorAttributes errorAttributes, ServerProperties serverProperties) {
+ super(errorAttributes, serverProperties.getError());
}
@RequestMapping(produces = MediaType.APPLICATION_XML_VALUE)
public ResponseEntity
-
+
org.springframework.boot
spring-boot-starter-web
+
+
+ io.github.openfeign.form
+ feign-form
+ 3.8.0
+
+
+ io.github.openfeign.form
+ feign-form-spring
+ 3.8.0
+
+
org.springframework.boot
spring-boot-starter-test
diff --git a/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/config/FeignSupportConfig.java b/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/config/FeignSupportConfig.java
new file mode 100644
index 0000000000..943134213a
--- /dev/null
+++ b/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/config/FeignSupportConfig.java
@@ -0,0 +1,22 @@
+package com.baeldung.cloud.openfeign.fileupload.config;
+
+import org.springframework.beans.factory.ObjectFactory;
+import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
+import org.springframework.cloud.openfeign.support.SpringEncoder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.web.client.RestTemplate;
+
+import feign.codec.Encoder;
+import feign.form.spring.SpringFormEncoder;
+
+public class FeignSupportConfig {
+ @Bean
+ public Encoder multipartFormEncoder() {
+ return new SpringFormEncoder(new SpringEncoder(new ObjectFactory() {
+ @Override
+ public HttpMessageConverters getObject() {
+ return new HttpMessageConverters(new RestTemplate().getMessageConverters());
+ }
+ }));
+ }
+}
diff --git a/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/controller/FileController.java b/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/controller/FileController.java
new file mode 100644
index 0000000000..ebdf7ff6c8
--- /dev/null
+++ b/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/controller/FileController.java
@@ -0,0 +1,28 @@
+package com.baeldung.cloud.openfeign.fileupload.controller;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestPart;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+
+import com.baeldung.cloud.openfeign.fileupload.service.UploadService;
+
+@RestController
+public class FileController {
+
+ @Autowired
+ private UploadService service;
+
+ @PostMapping(value = "/upload")
+ public String handleFileUpload(@RequestPart(value = "file") MultipartFile file) {
+ return service.uploadFile(file);
+ }
+
+ @PostMapping(value = "/upload-mannual-client")
+ public boolean handleFileUploadWithManualClient(
+ @RequestPart(value = "file") MultipartFile file) {
+ return service.uploadFileWithManualClient(file);
+ }
+
+}
\ No newline at end of file
diff --git a/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/UploadClient.java b/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/UploadClient.java
new file mode 100644
index 0000000000..63d17130e9
--- /dev/null
+++ b/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/UploadClient.java
@@ -0,0 +1,15 @@
+package com.baeldung.cloud.openfeign.fileupload.service;
+
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestPart;
+import org.springframework.web.multipart.MultipartFile;
+
+import com.baeldung.cloud.openfeign.fileupload.config.FeignSupportConfig;
+
+@FeignClient(name = "file", url = "http://localhost:8081", configuration = FeignSupportConfig.class)
+public interface UploadClient {
+ @PostMapping(value = "/upload-file", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+ String fileUpload(@RequestPart(value = "file") MultipartFile file);
+}
diff --git a/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/UploadResource.java b/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/UploadResource.java
new file mode 100644
index 0000000000..26e658a7f0
--- /dev/null
+++ b/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/UploadResource.java
@@ -0,0 +1,16 @@
+package com.baeldung.cloud.openfeign.fileupload.service;
+
+import org.springframework.web.multipart.MultipartFile;
+
+import feign.Headers;
+import feign.Param;
+import feign.RequestLine;
+import feign.Response;
+
+public interface UploadResource {
+
+ @RequestLine("POST /upload-file")
+ @Headers("Content-Type: multipart/form-data")
+ Response uploadFile(@Param("file") MultipartFile file);
+
+}
\ No newline at end of file
diff --git a/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/UploadService.java b/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/UploadService.java
new file mode 100644
index 0000000000..7dd7f5a89c
--- /dev/null
+++ b/spring-cloud/spring-cloud-openfeign/src/main/java/com/baeldung/cloud/openfeign/fileupload/service/UploadService.java
@@ -0,0 +1,29 @@
+package com.baeldung.cloud.openfeign.fileupload.service;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+import feign.Feign;
+import feign.Response;
+import feign.form.spring.SpringFormEncoder;
+
+@Service
+public class UploadService {
+ private static final String HTTP_FILE_UPLOAD_URL = "http://localhost:8081";
+
+ @Autowired
+ private UploadClient client;
+
+ public boolean uploadFileWithManualClient(MultipartFile file) {
+ UploadResource fileUploadResource = Feign.builder().encoder(new SpringFormEncoder())
+ .target(UploadResource.class, HTTP_FILE_UPLOAD_URL);
+ Response response = fileUploadResource.uploadFile(file);
+ return response.status() == 200;
+ }
+
+ public String uploadFile(MultipartFile file) {
+ return client.fileUpload(file);
+ }
+
+}
\ No newline at end of file
diff --git a/spring-cloud/spring-cloud-openfeign/src/main/resources/fileupload.txt b/spring-cloud/spring-cloud-openfeign/src/main/resources/fileupload.txt
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/spring-cloud/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/OpenFeignFileUploadLiveTest.java b/spring-cloud/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/OpenFeignFileUploadLiveTest.java
new file mode 100644
index 0000000000..f558e07491
--- /dev/null
+++ b/spring-cloud/spring-cloud-openfeign/src/test/java/com/baeldung/cloud/openfeign/OpenFeignFileUploadLiveTest.java
@@ -0,0 +1,50 @@
+package com.baeldung.cloud.openfeign;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+
+import org.apache.commons.io.IOUtils;
+import org.junit.Assert;
+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.mock.web.MockMultipartFile;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.web.multipart.MultipartFile;
+
+import com.baeldung.cloud.openfeign.fileupload.service.UploadService;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest
+public class OpenFeignFileUploadLiveTest {
+
+ @Autowired
+ private UploadService uploadService;
+
+ private static String FILE_NAME = "fileupload.txt";
+
+ @Test
+ public void whenFeignBuilder_thenFileUploadSuccess() throws IOException {
+ ClassLoader classloader = Thread.currentThread().getContextClassLoader();
+ File file = new File(classloader.getResource(FILE_NAME).getFile());
+ Assert.assertTrue(file.exists());
+ FileInputStream input = new FileInputStream(file);
+ MultipartFile multipartFile = new MockMultipartFile("file", file.getName(), "text/plain",
+ IOUtils.toByteArray(input));
+ Assert.assertTrue(uploadService.uploadFileWithManualClient(multipartFile));
+ }
+
+ @Test
+ public void whenAnnotatedFeignClient_thenFileUploadSuccess() throws IOException {
+ ClassLoader classloader = Thread.currentThread().getContextClassLoader();
+ File file = new File(classloader.getResource(FILE_NAME).getFile());
+ Assert.assertTrue(file.exists());
+ FileInputStream input = new FileInputStream(file);
+ MultipartFile multipartFile = new MockMultipartFile("file", file.getName(), "text/plain",
+ IOUtils.toByteArray(input));
+ String uploadFile = uploadService.uploadFile(multipartFile);
+ Assert.assertNotNull(uploadFile);
+ }
+}
diff --git a/spring-core-5/README.md b/spring-core-5/README.md
index 81669e46a7..4109faca67 100644
--- a/spring-core-5/README.md
+++ b/spring-core-5/README.md
@@ -4,4 +4,5 @@ This module contains articles about core Spring functionality
## Relevant Articles:
-- More articles: [[<-- prev]](/spring-core-4)
\ No newline at end of file
+- [Spring @Component Annotation](https://www.baeldung.com/spring-component-annotation)
+- More articles: [[<-- prev]](/spring-core-4)
diff --git a/spring-data-rest/pom.xml b/spring-data-rest/pom.xml
index dd96182264..bfbd66a280 100644
--- a/spring-data-rest/pom.xml
+++ b/spring-data-rest/pom.xml
@@ -35,7 +35,7 @@
org.springframework.data
- spring-data-rest-hal-browser
+ spring-data-rest-hal-explorer
org.springframework.boot
@@ -99,7 +99,6 @@
com.baeldung.books.SpringDataRestApplication
1.0
- 2.3.3.RELEASE
\ No newline at end of file
diff --git a/spring-data-rest/src/main/java/com/baeldung/halbrowser/config/RestConfig.java b/spring-data-rest/src/main/java/com/baeldung/halbrowser/config/RestConfig.java
index 73f7e0f26a..a322bf0027 100644
--- a/spring-data-rest/src/main/java/com/baeldung/halbrowser/config/RestConfig.java
+++ b/spring-data-rest/src/main/java/com/baeldung/halbrowser/config/RestConfig.java
@@ -4,11 +4,11 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.rest.core.event.ValidatingRepositoryEventListener;
-import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurerAdapter;
+import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurer;
import org.springframework.validation.Validator;
@Configuration
-public class RestConfig extends RepositoryRestConfigurerAdapter {
+public class RestConfig implements RepositoryRestConfigurer {
//access to global validator
@Autowired
diff --git a/spring-security-modules/spring-5-security/README.md b/spring-security-modules/spring-5-security/README.md
index 1917d347fb..bad99c22d4 100644
--- a/spring-security-modules/spring-5-security/README.md
+++ b/spring-security-modules/spring-5-security/README.md
@@ -11,3 +11,4 @@ This module contains articles about Spring Security 5
- [Guide to the AuthenticationManagerResolver in Spring Security](https://www.baeldung.com/spring-security-authenticationmanagerresolver)
- [Manual Logout With Spring Security](https://www.baeldung.com/spring-security-manual-logout)
- [How to Disable Spring Security Logout Redirects](https://www.baeldung.com/spring-security-disable-logout-redirects)
+- [Prevent Cross-Site Scripting (XSS) in a Spring Application](https://www.baeldung.com/spring-prevent-xss)
diff --git a/spring-web-modules/spring-mvc-java/src/test/java/com/baeldung/web/controller/GreetControllerIntegrationTest.java b/spring-web-modules/spring-mvc-java/src/test/java/com/baeldung/web/controller/GreetControllerIntegrationTest.java
index 3d34a46791..7b9da5707d 100644
--- a/spring-web-modules/spring-mvc-java/src/test/java/com/baeldung/web/controller/GreetControllerIntegrationTest.java
+++ b/spring-web-modules/spring-mvc-java/src/test/java/com/baeldung/web/controller/GreetControllerIntegrationTest.java
@@ -1,17 +1,13 @@
package com.baeldung.web.controller;
-import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
-
-import javax.servlet.ServletContext;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+import com.baeldung.spring.web.config.WebConfig;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.MockServletContext;
import org.springframework.test.context.ContextConfiguration;
-import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
@@ -20,31 +16,34 @@ import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
-import com.baeldung.spring.web.config.WebConfig;
+import javax.servlet.ServletContext;
-@RunWith(SpringJUnit4ClassRunner.class)
+import static org.junit.jupiter.api.Assertions.*;
+import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
+
+@ExtendWith(SpringExtension.class)
+@ContextConfiguration(classes = {WebConfig.class})
@WebAppConfiguration
-@ContextConfiguration(classes = { WebConfig.class, WebConfig.class })
public class GreetControllerIntegrationTest {
@Autowired
- private WebApplicationContext wac;
+ private WebApplicationContext webApplicationContext;
private MockMvc mockMvc;
private static final String CONTENT_TYPE = "application/json";
- @Before
- public void setup() throws Exception {
- this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
+ @BeforeEach
+ public void setup() {
+ this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext).build();
}
@Test
public void givenWac_whenServletContext_thenItProvidesGreetController() {
- final ServletContext servletContext = wac.getServletContext();
- Assert.assertNotNull(servletContext);
- Assert.assertTrue(servletContext instanceof MockServletContext);
- Assert.assertNotNull(wac.getBean("greetController"));
+ final ServletContext servletContext = webApplicationContext.getServletContext();
+ assertNotNull(servletContext);
+ assertTrue(servletContext instanceof MockServletContext);
+ assertNotNull(webApplicationContext.getBean("greetController"));
}
@Test
@@ -54,8 +53,12 @@ public class GreetControllerIntegrationTest {
@Test
public void givenGreetURI_whenMockMVC_thenVerifyResponse() throws Exception {
- final MvcResult mvcResult = this.mockMvc.perform(MockMvcRequestBuilders.get("/greet")).andDo(print()).andExpect(MockMvcResultMatchers.status().isOk()).andExpect(MockMvcResultMatchers.jsonPath("$.message").value("Hello World!!!")).andReturn();
- Assert.assertEquals(CONTENT_TYPE, mvcResult.getResponse().getContentType());
+ final MvcResult mvcResult = this.mockMvc.perform(MockMvcRequestBuilders.get("/greet"))
+ .andDo(print())
+ .andExpect(MockMvcResultMatchers.status().isOk())
+ .andExpect(MockMvcResultMatchers.jsonPath("$.message").value("Hello World!!!"))
+ .andReturn();
+ assertEquals(CONTENT_TYPE, mvcResult.getResponse().getContentType());
}
@Test
diff --git a/spring-web-modules/spring-mvc-java/src/test/java/com/baeldung/web/controller/GreetControllerRealIntegrationTest.java b/spring-web-modules/spring-mvc-java/src/test/java/com/baeldung/web/controller/GreetControllerRealIntegrationTest.java
index 05c6313e76..825520526e 100644
--- a/spring-web-modules/spring-mvc-java/src/test/java/com/baeldung/web/controller/GreetControllerRealIntegrationTest.java
+++ b/spring-web-modules/spring-mvc-java/src/test/java/com/baeldung/web/controller/GreetControllerRealIntegrationTest.java
@@ -1,18 +1,15 @@
package com.baeldung.web.controller;
import io.restassured.RestAssured;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.test.context.TestPropertySource;
-import org.springframework.test.context.junit4.SpringRunner;
import static io.restassured.RestAssured.given;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
-@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = RANDOM_PORT)
@TestPropertySource(properties = {"spring.main.allow-bean-definition-overriding=true", "server.servlet.context-path=/"})
public class GreetControllerRealIntegrationTest {
@@ -20,7 +17,7 @@ public class GreetControllerRealIntegrationTest {
@LocalServerPort
private int port;
- @Before
+ @BeforeEach
public void setUp() {
RestAssured.port = port;
}
@@ -28,7 +25,7 @@ public class GreetControllerRealIntegrationTest {
@Test
public void givenGreetURI_whenSendingReq_thenVerifyResponse() {
given().get("/greet")
- .then()
- .statusCode(200);
+ .then()
+ .statusCode(200);
}
}
diff --git a/spring-web-modules/spring-mvc-java/src/test/java/com/baeldung/web/controller/GreetControllerUnitTest.java b/spring-web-modules/spring-mvc-java/src/test/java/com/baeldung/web/controller/GreetControllerUnitTest.java
index eacd256438..ecc55e8da2 100644
--- a/spring-web-modules/spring-mvc-java/src/test/java/com/baeldung/web/controller/GreetControllerUnitTest.java
+++ b/spring-web-modules/spring-mvc-java/src/test/java/com/baeldung/web/controller/GreetControllerUnitTest.java
@@ -1,25 +1,22 @@
package com.baeldung.web.controller;
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
-import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
-
-import org.junit.Before;
-import org.junit.Test;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
import org.springframework.test.web.servlet.MockMvc;
-import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
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.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+
public class GreetControllerUnitTest {
private MockMvc mockMvc;
private static final String CONTENT_TYPE = "application/json";
- @Before
- public void setup() {
+ @BeforeEach
+ void setUp() {
this.mockMvc = MockMvcBuilders.standaloneSetup(new GreetController()).build();
}
@@ -50,12 +47,12 @@ public class GreetControllerUnitTest {
@Test
public void givenGreetURIWithPost_whenMockMVC_thenVerifyResponse() throws Exception {
- this.mockMvc.perform(MockMvcRequestBuilders.post("/greetWithPost")).andDo(print()).andExpect(status().isOk()).andExpect(content().contentType(CONTENT_TYPE)).andExpect(jsonPath("$.message").value("Hello World!!!"));
+ this.mockMvc.perform(post("/greetWithPost")).andDo(print()).andExpect(status().isOk()).andExpect(content().contentType(CONTENT_TYPE)).andExpect(jsonPath("$.message").value("Hello World!!!"));
}
@Test
public void givenGreetURIWithPostAndFormData_whenMockMVC_thenVerifyResponse() throws Exception {
- this.mockMvc.perform(MockMvcRequestBuilders.post("/greetWithPostAndFormData").param("id", "1").param("name", "John Doe")).andDo(print()).andExpect(status().isOk()).andExpect(content().contentType(CONTENT_TYPE))
+ this.mockMvc.perform(post("/greetWithPostAndFormData").param("id", "1").param("name", "John Doe")).andDo(print()).andExpect(status().isOk()).andExpect(content().contentType(CONTENT_TYPE))
.andExpect(jsonPath("$.message").value("Hello World John Doe!!!")).andExpect(jsonPath("$.id").value(1));
}
}
diff --git a/spring-web-modules/spring-resttemplate-2/src/main/java/com/baeldung/sampleapp/web/controller/redirect/RedirectController.java b/spring-web-modules/spring-resttemplate-2/src/main/java/com/baeldung/sampleapp/web/controller/redirect/RedirectController.java
index 321f3be3ef..1d77a07bea 100644
--- a/spring-web-modules/spring-resttemplate-2/src/main/java/com/baeldung/sampleapp/web/controller/redirect/RedirectController.java
+++ b/spring-web-modules/spring-resttemplate-2/src/main/java/com/baeldung/sampleapp/web/controller/redirect/RedirectController.java
@@ -64,5 +64,11 @@ public class RedirectController {
public ModelAndView redirectedPostToPost() {
return new ModelAndView("redirection");
}
-
+
+ @RequestMapping(value="/forwardWithParams", method = RequestMethod.GET)
+ public ModelAndView forwardWithParams(HttpServletRequest request) {
+ request.setAttribute("param1", "one");
+ request.setAttribute("param2", "two");
+ return new ModelAndView("forward:/forwardedWithParams");
+ }
}
\ No newline at end of file
diff --git a/spring-web-modules/spring-resttemplate-2/src/main/java/com/baeldung/sampleapp/web/controller/redirect/RedirectParamController.java b/spring-web-modules/spring-resttemplate-2/src/main/java/com/baeldung/sampleapp/web/controller/redirect/RedirectParamController.java
new file mode 100644
index 0000000000..abe268b435
--- /dev/null
+++ b/spring-web-modules/spring-resttemplate-2/src/main/java/com/baeldung/sampleapp/web/controller/redirect/RedirectParamController.java
@@ -0,0 +1,25 @@
+package com.baeldung.sampleapp.web.controller.redirect;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.servlet.mvc.support.RedirectAttributes;
+import org.springframework.web.servlet.view.RedirectView;
+
+@Controller
+@RequestMapping("/")
+public class RedirectParamController {
+
+ @RequestMapping(value = "/forwardedWithParams", method = RequestMethod.GET)
+ public RedirectView forwardedWithParams(final RedirectAttributes redirectAttributes, HttpServletRequest request) {
+
+ redirectAttributes.addAttribute("param1", request.getAttribute("param1"));
+ redirectAttributes.addAttribute("param2", request.getAttribute("param2"));
+
+ redirectAttributes.addAttribute("attribute", "forwardedWithParams");
+ return new RedirectView("redirectedUrl");
+
+ }
+}
\ No newline at end of file
diff --git a/testing-modules/README.md b/testing-modules/README.md
deleted file mode 100644
index c6098d1210..0000000000
--- a/testing-modules/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## Testing Modules
-
-This is an aggregator module containing multiple modules focused on testing libraries.
diff --git a/testing-modules/pom.xml b/testing-modules/pom.xml
index 0416423239..fd4a13d026 100644
--- a/testing-modules/pom.xml
+++ b/testing-modules/pom.xml
@@ -31,7 +31,7 @@
rest-assured
rest-testing
selenium-junit-testng
- spring-testing
+ spring-testing
spring-testing-2
test-containers
testing-assertions
@@ -41,9 +41,10 @@
junit-5-advanced
xmlunit-2
junit-4
- testing-libraries
- testing-libraries-2
+ testing-libraries
+ testing-libraries-2
powermock
+ zerocode
diff --git a/testing-modules/zerocode/pom.xml b/testing-modules/zerocode/pom.xml
new file mode 100644
index 0000000000..9d765e6cb4
--- /dev/null
+++ b/testing-modules/zerocode/pom.xml
@@ -0,0 +1,102 @@
+
+
+ 4.0.0
+
+ testing-modules
+ com.baeldung
+ 1.0.0-SNAPSHOT
+
+
+ zerocode
+ 1.0-SNAPSHOT
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ ${spring.boot.version}
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ ${spring.boot.version}
+ test
+
+
+
+
+ org.jsmart
+ zerocode-tdd
+ 1.3.27
+ test
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+ it
+
+
+
+
+ pre-integration-test
+
+ start
+
+
+ ${skip.it}
+
+
+
+ post-integration-test
+
+ stop
+
+
+ ${skip.it}
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-failsafe-plugin
+ 3.0.0-M5
+
+ ${skip.it}
+
+
+
+ org.apache.maven.surefire
+ surefire-junit47
+ 3.0.0-M5
+
+
+
+
+
+ integration-test
+ verify
+
+
+
+
+
+
+
+
+ UTF-8
+ 8
+ 8
+ 2.4.2
+ true
+
+
+
diff --git a/testing-modules/zerocode/src/main/java/com/baeldung/zerocode/User.java b/testing-modules/zerocode/src/main/java/com/baeldung/zerocode/User.java
new file mode 100644
index 0000000000..3a2a853220
--- /dev/null
+++ b/testing-modules/zerocode/src/main/java/com/baeldung/zerocode/User.java
@@ -0,0 +1,31 @@
+package com.baeldung.zerocode;
+
+public class User {
+ private String id;
+ private String firstName;
+ private String lastName;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getFirstName() {
+ return firstName;
+ }
+
+ public void setFirstName(String firstName) {
+ this.firstName = firstName;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public void setLastName(String lastName) {
+ this.lastName = lastName;
+ }
+}
diff --git a/testing-modules/zerocode/src/main/java/com/baeldung/zerocode/ZerocodeApplication.java b/testing-modules/zerocode/src/main/java/com/baeldung/zerocode/ZerocodeApplication.java
new file mode 100644
index 0000000000..3218e97400
--- /dev/null
+++ b/testing-modules/zerocode/src/main/java/com/baeldung/zerocode/ZerocodeApplication.java
@@ -0,0 +1,38 @@
+package com.baeldung.zerocode;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.*;
+
+@SpringBootApplication
+@RestController
+@RequestMapping("/api/users")
+public class ZerocodeApplication {
+ private List users = new ArrayList<>();
+
+ public static void main(String[] args) {
+ SpringApplication.run(ZerocodeApplication.class, args);
+ }
+
+ @PostMapping
+ public ResponseEntity create(@RequestBody User user) {
+ if (!StringUtils.hasText(user.getFirstName())) {
+ return new ResponseEntity("firstName can't be empty!", HttpStatus.BAD_REQUEST);
+ }
+ if (!StringUtils.hasText(user.getLastName())) {
+ return new ResponseEntity("lastName can't be empty!", HttpStatus.BAD_REQUEST);
+ }
+ user.setId(UUID.randomUUID()
+ .toString());
+ users.add(user);
+ return new ResponseEntity(user, HttpStatus.CREATED);
+ }
+
+}
diff --git a/testing-modules/zerocode/src/test/java/com/baeldung/zerocode/rest/UserEndpointIT.java b/testing-modules/zerocode/src/test/java/com/baeldung/zerocode/rest/UserEndpointIT.java
new file mode 100644
index 0000000000..cc461fd0fc
--- /dev/null
+++ b/testing-modules/zerocode/src/test/java/com/baeldung/zerocode/rest/UserEndpointIT.java
@@ -0,0 +1,18 @@
+package com.baeldung.zerocode.rest;
+
+import org.jsmart.zerocode.core.domain.Scenario;
+import org.jsmart.zerocode.core.domain.TargetEnv;
+import org.jsmart.zerocode.core.runner.ZeroCodeUnitRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(ZeroCodeUnitRunner.class)
+@TargetEnv("rest_api.properties")
+public class UserEndpointIT {
+
+ @Test
+ @Scenario("rest/user_create_test.json")
+ public void test_user_creation_endpoint() {
+ }
+
+}
diff --git a/testing-modules/zerocode/src/test/resources/rest/user_create_test.json b/testing-modules/zerocode/src/test/resources/rest/user_create_test.json
new file mode 100644
index 0000000000..0e8ee66196
--- /dev/null
+++ b/testing-modules/zerocode/src/test/resources/rest/user_create_test.json
@@ -0,0 +1,39 @@
+{
+ "scenarioName": "test user creation endpoint",
+ "steps": [
+ {
+ "name": "test_successful_creation",
+ "url": "/api/users",
+ "method": "POST",
+ "request": {
+ "body": {
+ "firstName": "John",
+ "lastName": "Doe"
+ }
+ },
+ "verify": {
+ "status": 201,
+ "body": {
+ "id": "$NOT.NULL",
+ "firstName": "John",
+ "lastName": "Doe"
+ }
+ }
+ },
+ {
+ "name": "test_firstname_validation",
+ "url": "/api/users",
+ "method": "POST",
+ "request": {
+ "body": {
+ "firstName": "",
+ "lastName": "Doe"
+ }
+ },
+ "assertions": {
+ "status": 400,
+ "rawBody": "firstName can't be empty!"
+ }
+ }
+ ]
+}
diff --git a/testing-modules/zerocode/src/test/resources/rest_api.properties b/testing-modules/zerocode/src/test/resources/rest_api.properties
new file mode 100644
index 0000000000..724042ade7
--- /dev/null
+++ b/testing-modules/zerocode/src/test/resources/rest_api.properties
@@ -0,0 +1,3 @@
+web.application.endpoint.host=http://localhost
+web.application.endpoint.port=8080
+web.application.endpoint.context=
\ No newline at end of file