commit
223a507172
@ -0,0 +1,8 @@
|
|||||||
|
package com.baeldung.annotations;
|
||||||
|
|
||||||
|
import javax.annotation.Generated;
|
||||||
|
|
||||||
|
@RetentionAnnotation
|
||||||
|
@Generated("Available only on source code")
|
||||||
|
public class AnnotatedClass {
|
||||||
|
}
|
@ -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 {
|
||||||
|
}
|
@ -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));
|
||||||
|
}
|
||||||
|
}
|
@ -25,7 +25,7 @@
|
|||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<assertj.version>3.18.0</assertj.version>
|
<assertj.version>3.19.0</assertj.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
@ -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<E> implements LifoStack<E> {
|
||||||
|
private final Deque<E> 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<E> iterator() {
|
||||||
|
return deque.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object[] toArray() {
|
||||||
|
return deque.toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> 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();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package com.baeldung.collections.dequestack;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
public interface LifoStack<E> extends Collection<E> {
|
||||||
|
|
||||||
|
E peek();
|
||||||
|
|
||||||
|
E pop();
|
||||||
|
|
||||||
|
void push(E item);
|
||||||
|
}
|
@ -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<String> 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<String> 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<String> 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<String> 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<String> 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<String> 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<String> it = myStack.iterator();
|
||||||
|
|
||||||
|
assertThat(it).toIterable().containsExactly(
|
||||||
|
"I am at the top.",
|
||||||
|
"I am in the middle.",
|
||||||
|
"I am at the bottom.");
|
||||||
|
}
|
||||||
|
}
|
@ -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)
|
- [Comparing Two HashMaps in Java](https://www.baeldung.com/java-compare-hashmaps)
|
||||||
- [The Map.computeIfAbsent() Method](https://www.baeldung.com/java-map-computeifabsent)
|
- [The Map.computeIfAbsent() Method](https://www.baeldung.com/java-map-computeifabsent)
|
||||||
- [Collections.synchronizedMap vs. ConcurrentHashMap](https://www.baeldung.com/java-synchronizedmap-vs-concurrenthashmap)
|
- [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)
|
- More articles: [[<-- prev]](/core-java-modules/core-java-collections-maps-2)
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.baeldung.servicemodule</groupId>
|
<groupId>com.baeldung.servicemodule</groupId>
|
||||||
<artifactId>servicemodule</artifactId>
|
<artifactId>servicemodule2</artifactId>
|
||||||
<version>${servicemodule.version}</version>
|
<version>${servicemodule.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -8,3 +8,4 @@ This module contains articles about generics in Java
|
|||||||
- [Raw Types in Java](https://www.baeldung.com/raw-types-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)
|
- [Super Type Tokens in Java Generics](https://www.baeldung.com/java-super-type-tokens)
|
||||||
- [Java Warning “unchecked conversion”](https://www.baeldung.com/java-unchecked-conversion)
|
- [Java Warning “unchecked conversion”](https://www.baeldung.com/java-unchecked-conversion)
|
||||||
|
- [Java Warning “Unchecked Cast”](https://www.baeldung.com/java-warning-unchecked-cast)
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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<String, LocalDate> castFromRawMap = (Map<String, LocalDate>) 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<String, LocalDate> castFromRawMap = (Map<String, LocalDate>) UncheckedCast.getRawMapWithMixedTypes();
|
||||||
|
Assert.assertEquals(4, castFromRawMap.size());
|
||||||
|
Assert.assertTrue(castFromRawMap.get("date 4").isAfter(castFromRawMap.get("date 3")));
|
||||||
|
}
|
||||||
|
}
|
@ -14,5 +14,12 @@
|
|||||||
<version>0.0.1-SNAPSHOT</version>
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
<relativePath>../</relativePath>
|
<relativePath>../</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.assertj</groupId>
|
||||||
|
<artifactId>assertj-core</artifactId>
|
||||||
|
<version>3.6.1</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
</project>
|
</project>
|
@ -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<String> 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"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -3,3 +3,4 @@
|
|||||||
- [Introduction to Docker Compose](https://www.baeldung.com/docker-compose)
|
- [Introduction to Docker Compose](https://www.baeldung.com/docker-compose)
|
||||||
- [Reusing Docker Layers with Spring Boot](https://www.baeldung.com/docker-layers-spring-boot)
|
- [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)
|
- [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)
|
||||||
|
4
docker/heap-sizing/Dockerfile
Normal file
4
docker/heap-sizing/Dockerfile
Normal file
@ -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
|
61
docker/heap-sizing/pom.xml
Normal file
61
docker/heap-sizing/pom.xml
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
|
<version>2.4.2</version>
|
||||||
|
<relativePath/> <!-- lookup parent from repository -->
|
||||||
|
</parent>
|
||||||
|
<groupId>com.baeldung.docker</groupId>
|
||||||
|
<artifactId>heap-sizing</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<name>heap-sizing</name>
|
||||||
|
<description>Demo project for Spring Boot</description>
|
||||||
|
<properties>
|
||||||
|
<java.version>11</java.version>
|
||||||
|
</properties>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.projectreactor</groupId>
|
||||||
|
<artifactId>reactor-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<image>
|
||||||
|
<name>heapsizing-demo</name>
|
||||||
|
</image>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>com.google.cloud.tools</groupId>
|
||||||
|
<artifactId>jib-maven-plugin</artifactId>
|
||||||
|
<version>2.7.1</version>
|
||||||
|
|
||||||
|
<configuration>
|
||||||
|
<to>
|
||||||
|
<image>heapsizing-demo-jib</image>
|
||||||
|
</to>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
package com.baeldung.map.hashing;
|
||||||
|
|
||||||
|
class Member {
|
||||||
|
Integer id;
|
||||||
|
String name;
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
package com.baeldung.map.hashing;
|
||||||
|
|
||||||
|
public class MemberWithBadHashing extends Member {
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return name.hashCode();
|
||||||
|
}
|
||||||
|
}
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -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 <T extends Member> Duration[] testDuration(Supplier<T> factory) {
|
||||||
|
HashMap<T, String> 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};
|
||||||
|
}
|
||||||
|
}
|
@ -7,7 +7,7 @@ It contains the code of a simple API for some CRUD operations built using Spring
|
|||||||
|
|
||||||
- Maven
|
- Maven
|
||||||
- JDK 8
|
- JDK 8
|
||||||
- MongoDB
|
- MongoDB (Note: for the Write Extracted Data to a File Using JMeter example MongoDB is not required)
|
||||||
|
|
||||||
### Running
|
### 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
|
$ 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)
|
Now with default configurations it will be available at: [http://localhost:8080](http://localhost:8080)
|
||||||
|
|
||||||
Enjoy it :)
|
Enjoy it :)
|
||||||
|
@ -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()));
|
||||||
|
}
|
||||||
|
}
|
40
jmeter/src/main/java/com/baeldung/model/Response.java
Normal file
40
jmeter/src/main/java/com/baeldung/model/Response.java
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
124
jmeter/src/main/resources/FileExtractionExample.jmx
Normal file
124
jmeter/src/main/resources/FileExtractionExample.jmx
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<jmeterTestPlan version="1.2" properties="5.0" jmeter="5.4.1">
|
||||||
|
<hashTree>
|
||||||
|
<TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Test Plan" enabled="true">
|
||||||
|
<stringProp name="TestPlan.comments">To run this test plan you must also be running the Spring application "JmeterApplication" That can be found in this directory</stringProp>
|
||||||
|
<boolProp name="TestPlan.functional_mode">false</boolProp>
|
||||||
|
<boolProp name="TestPlan.tearDown_on_shutdown">true</boolProp>
|
||||||
|
<boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
|
||||||
|
<elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
|
||||||
|
<collectionProp name="Arguments.arguments"/>
|
||||||
|
</elementProp>
|
||||||
|
<stringProp name="TestPlan.user_define_classpath"></stringProp>
|
||||||
|
</TestPlan>
|
||||||
|
<hashTree>
|
||||||
|
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Thread Group" enabled="true">
|
||||||
|
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
|
||||||
|
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
|
||||||
|
<boolProp name="LoopController.continue_forever">false</boolProp>
|
||||||
|
<stringProp name="LoopController.loops">1</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
<stringProp name="ThreadGroup.num_threads">1</stringProp>
|
||||||
|
<stringProp name="ThreadGroup.ramp_time">1</stringProp>
|
||||||
|
<boolProp name="ThreadGroup.scheduler">false</boolProp>
|
||||||
|
<stringProp name="ThreadGroup.duration"></stringProp>
|
||||||
|
<stringProp name="ThreadGroup.delay"></stringProp>
|
||||||
|
<boolProp name="ThreadGroup.same_user_on_next_iteration">true</boolProp>
|
||||||
|
</ThreadGroup>
|
||||||
|
<hashTree>
|
||||||
|
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Call GET Test endpoint " enabled="true">
|
||||||
|
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
|
||||||
|
<collectionProp name="Arguments.arguments"/>
|
||||||
|
</elementProp>
|
||||||
|
<stringProp name="HTTPSampler.domain">localhost</stringProp>
|
||||||
|
<stringProp name="HTTPSampler.port">8080</stringProp>
|
||||||
|
<stringProp name="HTTPSampler.protocol">http</stringProp>
|
||||||
|
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
|
||||||
|
<stringProp name="HTTPSampler.path">/api/test</stringProp>
|
||||||
|
<stringProp name="HTTPSampler.method">GET</stringProp>
|
||||||
|
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
|
||||||
|
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
|
||||||
|
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
|
||||||
|
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
|
||||||
|
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
|
||||||
|
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
|
||||||
|
<stringProp name="HTTPSampler.response_timeout"></stringProp>
|
||||||
|
</HTTPSamplerProxy>
|
||||||
|
<hashTree>
|
||||||
|
<JSONPostProcessor guiclass="JSONPostProcessorGui" testclass="JSONPostProcessor" testname="JSON Extractor" enabled="true">
|
||||||
|
<stringProp name="JSONPostProcessor.referenceNames">message</stringProp>
|
||||||
|
<stringProp name="JSONPostProcessor.jsonPathExprs">$.message</stringProp>
|
||||||
|
<stringProp name="JSONPostProcessor.match_numbers">1</stringProp>
|
||||||
|
<boolProp name="JSONPostProcessor.compute_concat">true</boolProp>
|
||||||
|
<stringProp name="JSONPostProcessor.defaultValues">NOT_FOUND</stringProp>
|
||||||
|
</JSONPostProcessor>
|
||||||
|
<hashTree/>
|
||||||
|
<BeanShellPostProcessor guiclass="TestBeanGUI" testclass="BeanShellPostProcessor" testname="Response to file using BeanShell PostProcessor" enabled="true">
|
||||||
|
<stringProp name="filename"></stringProp>
|
||||||
|
<stringProp name="parameters"></stringProp>
|
||||||
|
<boolProp name="resetInterpreter">false</boolProp>
|
||||||
|
<stringProp name="script">FileWriter fWriter = new FileWriter("<path>/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();</stringProp>
|
||||||
|
</BeanShellPostProcessor>
|
||||||
|
<hashTree/>
|
||||||
|
<ResultSaver guiclass="ResultSaverGui" testclass="ResultSaver" testname="Response to file using file write Listener" enabled="true">
|
||||||
|
<stringProp name="FileSaver.filename">response</stringProp>
|
||||||
|
<boolProp name="FileSaver.errorsonly">false</boolProp>
|
||||||
|
<boolProp name="FileSaver.successonly">false</boolProp>
|
||||||
|
<boolProp name="FileSaver.skipsuffix">false</boolProp>
|
||||||
|
<boolProp name="FileSaver.skipautonumber">false</boolProp>
|
||||||
|
</ResultSaver>
|
||||||
|
<hashTree/>
|
||||||
|
</hashTree>
|
||||||
|
<ResultCollector guiclass="ViewResultsFullVisualizer" testclass="ResultCollector" testname="View Results Tree" enabled="true">
|
||||||
|
<boolProp name="ResultCollector.error_logging">false</boolProp>
|
||||||
|
<objProp>
|
||||||
|
<name>saveConfig</name>
|
||||||
|
<value class="SampleSaveConfiguration">
|
||||||
|
<time>true</time>
|
||||||
|
<latency>true</latency>
|
||||||
|
<timestamp>true</timestamp>
|
||||||
|
<success>true</success>
|
||||||
|
<label>true</label>
|
||||||
|
<code>true</code>
|
||||||
|
<message>true</message>
|
||||||
|
<threadName>true</threadName>
|
||||||
|
<dataType>true</dataType>
|
||||||
|
<encoding>false</encoding>
|
||||||
|
<assertions>true</assertions>
|
||||||
|
<subresults>true</subresults>
|
||||||
|
<responseData>false</responseData>
|
||||||
|
<samplerData>false</samplerData>
|
||||||
|
<xml>false</xml>
|
||||||
|
<fieldNames>true</fieldNames>
|
||||||
|
<responseHeaders>false</responseHeaders>
|
||||||
|
<requestHeaders>false</requestHeaders>
|
||||||
|
<responseDataOnError>false</responseDataOnError>
|
||||||
|
<saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
|
||||||
|
<assertionsResultsToSave>0</assertionsResultsToSave>
|
||||||
|
<bytes>true</bytes>
|
||||||
|
<sentBytes>true</sentBytes>
|
||||||
|
<url>true</url>
|
||||||
|
<threadCounts>true</threadCounts>
|
||||||
|
<idleTime>true</idleTime>
|
||||||
|
<connectTime>true</connectTime>
|
||||||
|
</value>
|
||||||
|
</objProp>
|
||||||
|
<stringProp name="filename"></stringProp>
|
||||||
|
</ResultCollector>
|
||||||
|
<hashTree/>
|
||||||
|
</hashTree>
|
||||||
|
</hashTree>
|
||||||
|
</hashTree>
|
||||||
|
</jmeterTestPlan>
|
35
jmeter/src/test/java/com/baeldung/JmeterIntegrationTest.java
Normal file
35
jmeter/src/test/java/com/baeldung/JmeterIntegrationTest.java
Normal file
@ -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...");
|
||||||
|
}
|
||||||
|
}
|
@ -27,6 +27,7 @@
|
|||||||
<module>versions-maven-plugin</module>
|
<module>versions-maven-plugin</module>
|
||||||
<module>version-collision</module>
|
<module>version-collision</module>
|
||||||
<module>optional-dependencies</module>
|
<module>optional-dependencies</module>
|
||||||
|
<module>version-overriding-plugins</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
5
maven-modules/version-overriding-plugins/README.md
Normal file
5
maven-modules/version-overriding-plugins/README.md
Normal file
@ -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)
|
36
maven-modules/version-overriding-plugins/child-a/pom.xml
Normal file
36
maven-modules/version-overriding-plugins/child-a/pom.xml
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<artifactId>version-overriding-plugins</artifactId>
|
||||||
|
<groupId>com.baeldung</groupId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
|
<artifactId>child-a</artifactId>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-resources-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<resources combine.self="override">
|
||||||
|
<resource>
|
||||||
|
<directory>child-a-resources</directory>
|
||||||
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<source>1.8</source>
|
||||||
|
<target>1.8</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
15
maven-modules/version-overriding-plugins/child-b/pom.xml
Normal file
15
maven-modules/version-overriding-plugins/child-b/pom.xml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<artifactId>version-overriding-plugins</artifactId>
|
||||||
|
<groupId>com.baeldung</groupId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>child-b</artifactId>
|
||||||
|
|
||||||
|
|
||||||
|
</project>
|
55
maven-modules/version-overriding-plugins/pom.xml
Normal file
55
maven-modules/version-overriding-plugins/pom.xml
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<artifactId>maven-modules</artifactId>
|
||||||
|
<groupId>com.baeldung</groupId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.plugin>3.8.0</maven.compiler.plugin>
|
||||||
|
</properties>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>version-overriding-plugins</artifactId>
|
||||||
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
|
<modules>
|
||||||
|
<module>child-a</module>
|
||||||
|
<module>child-b</module>
|
||||||
|
</modules>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<pluginManagement>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>${maven.compiler.plugin}</version>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</pluginManagement>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-resources-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<resources combine.children="append">
|
||||||
|
<resource>
|
||||||
|
<directory>parent-resources</directory>
|
||||||
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<source>11</source>
|
||||||
|
<target>11</target>
|
||||||
|
<maxmem>512m</maxmem>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
@ -8,7 +8,6 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring
|
|||||||
### Relevant Articles
|
### Relevant Articles
|
||||||
- [Logging Spring WebClient Calls](https://www.baeldung.com/spring-log-webclient-calls)
|
- [Logging Spring WebClient Calls](https://www.baeldung.com/spring-log-webclient-calls)
|
||||||
- [Simultaneous Spring WebClient Calls](https://www.baeldung.com/spring-webclient-simultaneous-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)
|
- [Mocking a WebClient in Spring](https://www.baeldung.com/spring-mocking-webclient)
|
||||||
- [Spring WebClient Filters](https://www.baeldung.com/spring-webclient-filters)
|
- [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)
|
- [Get List of JSON Objects with WebClient](https://www.baeldung.com/spring-webclient-json-list)
|
||||||
|
@ -176,7 +176,6 @@
|
|||||||
<commons-collections4.version>4.1</commons-collections4.version>
|
<commons-collections4.version>4.1</commons-collections4.version>
|
||||||
<jetty-reactive-httpclient.version>1.0.3</jetty-reactive-httpclient.version>
|
<jetty-reactive-httpclient.version>1.0.3</jetty-reactive-httpclient.version>
|
||||||
<okhttp.version>4.0.1</okhttp.version>
|
<okhttp.version>4.0.1</okhttp.version>
|
||||||
<spring-boot.version>2.3.3.RELEASE</spring-boot.version>
|
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
logging.level.root=INFO
|
logging.level.root=INFO
|
||||||
|
|
||||||
server.port=8081
|
server.port=8081
|
||||||
|
|
||||||
|
logging.level.reactor.netty.http.client.HttpClient=DEBUG
|
@ -1,13 +1,13 @@
|
|||||||
package com.baeldung.reactive.logging;
|
package com.baeldung.reactive.logging;
|
||||||
|
|
||||||
import ch.qos.logback.classic.spi.LoggingEvent;
|
import static com.baeldung.reactive.logging.jetty.RequestLogEnhancer.enhance;
|
||||||
import ch.qos.logback.core.Appender;
|
import static org.mockito.ArgumentMatchers.argThat;
|
||||||
import com.baeldung.reactive.logging.filters.LogFilters;
|
import static org.mockito.Mockito.mock;
|
||||||
import com.baeldung.reactive.logging.netty.CustomLogger;
|
import static org.mockito.Mockito.verify;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Data;
|
|
||||||
import org.eclipse.jetty.client.api.Request;
|
import org.eclipse.jetty.client.api.Request;
|
||||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
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.http.client.reactive.ReactorClientHttpConnector;
|
||||||
import org.springframework.web.reactive.function.BodyInserters;
|
import org.springframework.web.reactive.function.BodyInserters;
|
||||||
import org.springframework.web.reactive.function.client.WebClient;
|
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 com.baeldung.reactive.logging.filters.LogFilters;
|
||||||
import static org.mockito.ArgumentMatchers.argThat;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
import static org.mockito.Mockito.verify;
|
import ch.qos.logback.classic.spi.LoggingEvent;
|
||||||
import static org.mockito.Mockito.when;
|
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 {
|
public class WebClientLoggingIntegrationTest {
|
||||||
@ -114,14 +117,10 @@ public class WebClientLoggingIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void givenNettyHttpClientWithCustomLogger_whenEndpointIsConsumed_thenRequestAndResponseBodyLogged() {
|
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
|
WebClient.builder()
|
||||||
.create()
|
|
||||||
.tcpConfiguration(
|
|
||||||
tc -> tc.bootstrap(
|
|
||||||
b -> BootstrapHandlers.updateLogSupport(b, new CustomLogger(HttpClient.class))));
|
|
||||||
WebClient
|
|
||||||
.builder()
|
|
||||||
.clientConnector(new ReactorClientHttpConnector(httpClient))
|
.clientConnector(new ReactorClientHttpConnector(httpClient))
|
||||||
.build()
|
.build()
|
||||||
.post()
|
.post()
|
||||||
|
@ -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 "";
|
|
||||||
}
|
|
||||||
}
|
|
@ -54,6 +54,7 @@
|
|||||||
<module>spring-boot-mvc-2</module>
|
<module>spring-boot-mvc-2</module>
|
||||||
<module>spring-boot-mvc-3</module>
|
<module>spring-boot-mvc-3</module>
|
||||||
<module>spring-boot-mvc-birt</module>
|
<module>spring-boot-mvc-birt</module>
|
||||||
|
<module>spring-boot-mvc-jersey</module>
|
||||||
<module>spring-boot-nashorn</module>
|
<module>spring-boot-nashorn</module>
|
||||||
<module>spring-boot-parent</module>
|
<module>spring-boot-parent</module>
|
||||||
<module>spring-boot-performance</module>
|
<module>spring-boot-performance</module>
|
||||||
|
@ -61,7 +61,7 @@
|
|||||||
</build>
|
</build>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<spring-boot-admin-starter-client.version>2.2.2</spring-boot-admin-starter-client.version>
|
<spring-boot-admin-starter-client.version>2.4.0</spring-boot-admin-starter-client.version>
|
||||||
<spring-boot-maven-plugin.version>2.0.4.RELEASE</spring-boot-maven-plugin.version>
|
<spring-boot-maven-plugin.version>2.0.4.RELEASE</spring-boot-maven-plugin.version>
|
||||||
</properties>
|
</properties>
|
||||||
</project>
|
</project>
|
||||||
|
@ -82,10 +82,9 @@
|
|||||||
</build>
|
</build>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<spring-boot-admin-server.version>2.2.2</spring-boot-admin-server.version>
|
<spring-boot-admin-server.version>2.4.0</spring-boot-admin-server.version>
|
||||||
<spring-boot-admin-starter-client.version>2.2.2</spring-boot-admin-starter-client.version>
|
<spring-boot-admin-starter-client.version>2.4.0</spring-boot-admin-starter-client.version>
|
||||||
<spring-boot-admin-server-ui-login.version>1.5.7</spring-boot-admin-server-ui-login.version>
|
<spring-boot-admin-server-ui-login.version>1.5.7</spring-boot-admin-server-ui-login.version>
|
||||||
<spring-boot-maven-plugin.version>2.0.4.RELEASE</spring-boot-maven-plugin.version>
|
<spring-boot-maven-plugin.version>2.0.4.RELEASE</spring-boot-maven-plugin.version>
|
||||||
<spring-boot.version>2.3.3.RELEASE</spring-boot.version>
|
|
||||||
</properties>
|
</properties>
|
||||||
</project>
|
</project>
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
package com.baeldung.springbootadminserver;
|
package com.baeldung.springbootadminserver;
|
||||||
|
|
||||||
|
import de.codecentric.boot.admin.server.config.AdminServerHazelcastAutoConfiguration;
|
||||||
import de.codecentric.boot.admin.server.config.EnableAdminServer;
|
import de.codecentric.boot.admin.server.config.EnableAdminServer;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
@EnableAdminServer
|
@EnableAdminServer
|
||||||
@SpringBootApplication
|
@SpringBootApplication(exclude = AdminServerHazelcastAutoConfiguration.class)
|
||||||
public class SpringBootAdminServerApplication {
|
public class SpringBootAdminServerApplication {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
package com.baeldung.springbootadminserver.configs;
|
package com.baeldung.springbootadminserver.configs;
|
||||||
|
|
||||||
import com.hazelcast.config.Config;
|
import com.hazelcast.config.Config;
|
||||||
|
import com.hazelcast.config.EvictionConfig;
|
||||||
import com.hazelcast.config.EvictionPolicy;
|
import com.hazelcast.config.EvictionPolicy;
|
||||||
import com.hazelcast.config.InMemoryFormat;
|
import com.hazelcast.config.InMemoryFormat;
|
||||||
import com.hazelcast.config.MapConfig;
|
import com.hazelcast.config.MapConfig;
|
||||||
import com.hazelcast.config.MergePolicyConfig;
|
import com.hazelcast.config.MergePolicyConfig;
|
||||||
import com.hazelcast.config.TcpIpConfig;
|
import com.hazelcast.config.TcpIpConfig;
|
||||||
import com.hazelcast.map.merge.PutIfAbsentMapMergePolicy;
|
import com.hazelcast.spi.merge.PutIfAbsentMergePolicy;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
@ -18,28 +19,23 @@ public class HazelcastConfig {
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public Config hazelcast() {
|
public Config hazelcast() {
|
||||||
MapConfig eventStoreMap = new MapConfig("spring-boot-admin-event-store").setInMemoryFormat(InMemoryFormat.OBJECT)
|
MapConfig eventStoreMap = new MapConfig("spring-boot-admin-event-store")
|
||||||
.setBackupCount(1)
|
.setInMemoryFormat(InMemoryFormat.OBJECT).setBackupCount(1)
|
||||||
.setEvictionPolicy(EvictionPolicy.NONE)
|
.setEvictionConfig(new EvictionConfig().setEvictionPolicy(EvictionPolicy.NONE))
|
||||||
.setMergePolicyConfig(new MergePolicyConfig(PutIfAbsentMapMergePolicy.class.getName(), 100));
|
.setMergePolicyConfig(new MergePolicyConfig(PutIfAbsentMergePolicy.class.getName(), 100));
|
||||||
|
|
||||||
MapConfig sentNotificationsMap = new MapConfig("spring-boot-admin-application-store").setInMemoryFormat(InMemoryFormat.OBJECT)
|
MapConfig sentNotificationsMap = new MapConfig("spring-boot-admin-application-store")
|
||||||
.setBackupCount(1)
|
.setInMemoryFormat(InMemoryFormat.OBJECT).setBackupCount(1)
|
||||||
.setEvictionPolicy(EvictionPolicy.LRU)
|
.setEvictionConfig(new EvictionConfig().setEvictionPolicy(EvictionPolicy.LRU))
|
||||||
.setMergePolicyConfig(new MergePolicyConfig(PutIfAbsentMapMergePolicy.class.getName(), 100));
|
.setMergePolicyConfig(new MergePolicyConfig(PutIfAbsentMergePolicy.class.getName(), 100));
|
||||||
|
|
||||||
Config config = new Config();
|
Config config = new Config();
|
||||||
config.addMapConfig(eventStoreMap);
|
config.addMapConfig(eventStoreMap);
|
||||||
config.addMapConfig(sentNotificationsMap);
|
config.addMapConfig(sentNotificationsMap);
|
||||||
config.setProperty("hazelcast.jmx", "true");
|
config.setProperty("hazelcast.jmx", "true");
|
||||||
|
|
||||||
config.getNetworkConfig()
|
config.getNetworkConfig().getJoin().getMulticastConfig().setEnabled(false);
|
||||||
.getJoin()
|
TcpIpConfig tcpIpConfig = config.getNetworkConfig().getJoin().getTcpIpConfig();
|
||||||
.getMulticastConfig()
|
|
||||||
.setEnabled(false);
|
|
||||||
TcpIpConfig tcpIpConfig = config.getNetworkConfig()
|
|
||||||
.getJoin()
|
|
||||||
.getTcpIpConfig();
|
|
||||||
tcpIpConfig.setEnabled(true);
|
tcpIpConfig.setEnabled(true);
|
||||||
tcpIpConfig.setMembers(Collections.singletonList("127.0.0.1"));
|
tcpIpConfig.setMembers(Collections.singletonList("127.0.0.1"));
|
||||||
return config;
|
return config;
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
### Relevant Articles:
|
### Relevant Articles:
|
||||||
|
|
||||||
- [Spring Boot: Customize the Jackson ObjectMapper](https://www.baeldung.com/spring-boot-customize-jackson-objectmapper)
|
- [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)
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -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<Student> get(@PathVariable("id") int id) {
|
||||||
|
// Custom logic
|
||||||
|
return ResponseEntity.ok(new Student(id, "John", "Wiliams", "AA"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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"));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
8
spring-boot-modules/spring-boot-mvc-jersey/README.md
Normal file
8
spring-boot-modules/spring-boot-mvc-jersey/README.md
Normal file
@ -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)
|
23
spring-boot-modules/spring-boot-mvc-jersey/pom.xml
Normal file
23
spring-boot-modules/spring-boot-mvc-jersey/pom.xml
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>com.baeldung.spring-boot-modules</groupId>
|
||||||
|
<artifactId>spring-boot-modules</artifactId>
|
||||||
|
<version>1.0.0-SNAPSHOT</version>
|
||||||
|
<relativePath>../</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>spring-boot-mvc-jersey</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
|
<name>spring-boot-mvc-jersey</name>
|
||||||
|
|
||||||
|
<modules>
|
||||||
|
<module>spring-boot-jersey</module>
|
||||||
|
<module>spring-boot-mvc</module>
|
||||||
|
</modules>
|
||||||
|
</project>
|
@ -0,0 +1,38 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
|
<version>2.4.2</version>
|
||||||
|
<relativePath/> <!-- lookup parent from repository -->
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<groupId>com.baeldung.boot</groupId>
|
||||||
|
<artifactId>spring-boot-jersey</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-jersey</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
|
@ -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() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
|
<version>2.4.2</version>
|
||||||
|
<relativePath/> <!-- lookup parent from repository -->
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<groupId>com.baeldung.boot</groupId>
|
||||||
|
<artifactId>spring-boot-mvc</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
|
@ -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() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -3,4 +3,4 @@
|
|||||||
This module contains articles about administering a Spring Boot runtime
|
This module contains articles about administering a Spring Boot runtime
|
||||||
|
|
||||||
### Relevant Articles:
|
### Relevant Articles:
|
||||||
-
|
- [Configure the Heap Size When Starting a Spring Boot Application](https://www.baeldung.com/spring-boot-heap-size)
|
||||||
|
@ -2,6 +2,7 @@ package com.baeldung.web.config;
|
|||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.springframework.boot.web.error.ErrorAttributeOptions;
|
||||||
import org.springframework.boot.web.servlet.error.DefaultErrorAttributes;
|
import org.springframework.boot.web.servlet.error.DefaultErrorAttributes;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.web.context.request.WebRequest;
|
import org.springframework.web.context.request.WebRequest;
|
||||||
@ -10,8 +11,8 @@ import org.springframework.web.context.request.WebRequest;
|
|||||||
public class MyCustomErrorAttributes extends DefaultErrorAttributes {
|
public class MyCustomErrorAttributes extends DefaultErrorAttributes {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
|
public Map<String, Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {
|
||||||
Map<String, Object> errorAttributes = super.getErrorAttributes(webRequest, includeStackTrace);
|
Map<String, Object> errorAttributes = super.getErrorAttributes(webRequest, options);
|
||||||
errorAttributes.put("locale", webRequest.getLocale()
|
errorAttributes.put("locale", webRequest.getLocale()
|
||||||
.toString());
|
.toString());
|
||||||
errorAttributes.remove("error");
|
errorAttributes.remove("error");
|
||||||
|
@ -4,7 +4,7 @@ import java.util.Map;
|
|||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
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.autoconfigure.web.servlet.error.BasicErrorController;
|
||||||
import org.springframework.boot.web.servlet.error.ErrorAttributes;
|
import org.springframework.boot.web.servlet.error.ErrorAttributes;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
@ -16,13 +16,13 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
|||||||
@Component
|
@Component
|
||||||
public class MyErrorController extends BasicErrorController {
|
public class MyErrorController extends BasicErrorController {
|
||||||
|
|
||||||
public MyErrorController(ErrorAttributes errorAttributes) {
|
public MyErrorController(ErrorAttributes errorAttributes, ServerProperties serverProperties) {
|
||||||
super(errorAttributes, new ErrorProperties());
|
super(errorAttributes, serverProperties.getError());
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(produces = MediaType.APPLICATION_XML_VALUE)
|
@RequestMapping(produces = MediaType.APPLICATION_XML_VALUE)
|
||||||
public ResponseEntity<Map<String, Object>> xmlError(HttpServletRequest request) {
|
public ResponseEntity<Map<String, Object>> xmlError(HttpServletRequest request) {
|
||||||
Map<String, Object> body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.APPLICATION_XML));
|
Map<String, Object> body = getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.APPLICATION_XML));
|
||||||
body.put("xmlkey", "the XML response is different!");
|
body.put("xmlkey", "the XML response is different!");
|
||||||
HttpStatus status = getStatus(request);
|
HttpStatus status = getStatus(request);
|
||||||
return new ResponseEntity<>(body, status);
|
return new ResponseEntity<>(body, status);
|
||||||
|
@ -50,7 +50,7 @@ public class CustomerController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Link link = linkTo(methodOn(CustomerController.class).getOrdersForCustomer(customerId)).withSelfRel();
|
Link link = linkTo(methodOn(CustomerController.class).getOrdersForCustomer(customerId)).withSelfRel();
|
||||||
CollectionModel<Order> result = new CollectionModel<>(orders, link);
|
CollectionModel<Order> result = CollectionModel.of(orders, link);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,7 +72,7 @@ public class CustomerController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Link link = linkTo(CustomerController.class).withSelfRel();
|
Link link = linkTo(CustomerController.class).withSelfRel();
|
||||||
CollectionModel<Customer> result = new CollectionModel<>(allCustomers, link);
|
CollectionModel<Customer> result = CollectionModel.of(allCustomers, link);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,3 +3,4 @@ server.servlet.context-path=/spring-boot-rest
|
|||||||
### Spring Boot default error handling configurations
|
### Spring Boot default error handling configurations
|
||||||
#server.error.whitelabel.enabled=false
|
#server.error.whitelabel.enabled=false
|
||||||
#server.error.include-stacktrace=always
|
#server.error.include-stacktrace=always
|
||||||
|
server.error.include-message=always
|
||||||
|
@ -33,7 +33,7 @@ public class ExamplePostControllerRequestIntegrationTest {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void preTest() {
|
public void preTest() {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.openMocks(this);
|
||||||
mockMvc = MockMvcBuilders
|
mockMvc = MockMvcBuilders
|
||||||
.standaloneSetup(exampleController)
|
.standaloneSetup(exampleController)
|
||||||
.build();
|
.build();
|
||||||
|
@ -34,7 +34,7 @@ public class ExamplePostControllerResponseIntegrationTest {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void preTest() {
|
public void preTest() {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.openMocks(this);
|
||||||
mockMvc = MockMvcBuilders
|
mockMvc = MockMvcBuilders
|
||||||
.standaloneSetup(exampleController)
|
.standaloneSetup(exampleController)
|
||||||
.build();
|
.build();
|
||||||
|
@ -8,12 +8,10 @@ import org.springframework.boot.test.context.SpringBootTest;
|
|||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.test.context.junit4.SpringRunner;
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
import org.springframework.test.web.servlet.MockMvc;
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
import org.springframework.web.server.MediaTypeNotSupportedStatusException;
|
|
||||||
|
|
||||||
import com.baeldung.web.controller.students.Student;
|
import com.baeldung.web.controller.students.Student;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
||||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
|
@ -2,3 +2,4 @@
|
|||||||
|
|
||||||
- [Introduction to Spring Cloud OpenFeign](https://www.baeldung.com/spring-cloud-openfeign)
|
- [Introduction to Spring Cloud OpenFeign](https://www.baeldung.com/spring-cloud-openfeign)
|
||||||
- [Differences Between Netflix Feign and OpenFeign](https://www.baeldung.com/netflix-feign-vs-openfeign)
|
- [Differences Between Netflix Feign and OpenFeign](https://www.baeldung.com/netflix-feign-vs-openfeign)
|
||||||
|
- [File Upload With Open Feign](https://www.baeldung.com/java-feign-file-upload)
|
||||||
|
@ -43,6 +43,18 @@
|
|||||||
<artifactId>spring-boot-starter-web</artifactId>
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.github.openfeign.form</groupId>
|
||||||
|
<artifactId>feign-form</artifactId>
|
||||||
|
<version>3.8.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.github.openfeign.form</groupId>
|
||||||
|
<artifactId>feign-form-spring</artifactId>
|
||||||
|
<version>3.8.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-test</artifactId>
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
@ -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<HttpMessageConverters>() {
|
||||||
|
@Override
|
||||||
|
public HttpMessageConverters getObject() {
|
||||||
|
return new HttpMessageConverters(new RestTemplate().getMessageConverters());
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
@ -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);
|
||||||
|
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -4,4 +4,5 @@ This module contains articles about core Spring functionality
|
|||||||
|
|
||||||
## Relevant Articles:
|
## Relevant Articles:
|
||||||
|
|
||||||
|
- [Spring @Component Annotation](https://www.baeldung.com/spring-component-annotation)
|
||||||
- More articles: [[<-- prev]](/spring-core-4)
|
- More articles: [[<-- prev]](/spring-core-4)
|
@ -35,7 +35,7 @@
|
|||||||
<!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-rest-hal-browser -->
|
<!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-rest-hal-browser -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.data</groupId>
|
<groupId>org.springframework.data</groupId>
|
||||||
<artifactId>spring-data-rest-hal-browser</artifactId>
|
<artifactId>spring-data-rest-hal-explorer</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
@ -99,7 +99,6 @@
|
|||||||
<properties>
|
<properties>
|
||||||
<start-class>com.baeldung.books.SpringDataRestApplication</start-class>
|
<start-class>com.baeldung.books.SpringDataRestApplication</start-class>
|
||||||
<maven.version>1.0</maven.version>
|
<maven.version>1.0</maven.version>
|
||||||
<spring-boot.version>2.3.3.RELEASE</spring-boot.version>
|
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
</project>
|
</project>
|
@ -4,11 +4,11 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.data.rest.core.event.ValidatingRepositoryEventListener;
|
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;
|
import org.springframework.validation.Validator;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
public class RestConfig extends RepositoryRestConfigurerAdapter {
|
public class RestConfig implements RepositoryRestConfigurer {
|
||||||
|
|
||||||
//access to global validator
|
//access to global validator
|
||||||
@Autowired
|
@Autowired
|
||||||
|
@ -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)
|
- [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)
|
- [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)
|
- [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)
|
||||||
|
@ -1,17 +1,13 @@
|
|||||||
package com.baeldung.web.controller;
|
package com.baeldung.web.controller;
|
||||||
|
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
|
import com.baeldung.spring.web.config.WebConfig;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import javax.servlet.ServletContext;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.mock.web.MockServletContext;
|
import org.springframework.mock.web.MockServletContext;
|
||||||
import org.springframework.test.context.ContextConfiguration;
|
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.context.web.WebAppConfiguration;
|
||||||
import org.springframework.test.web.servlet.MockMvc;
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
import org.springframework.test.web.servlet.MvcResult;
|
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.test.web.servlet.setup.MockMvcBuilders;
|
||||||
import org.springframework.web.context.WebApplicationContext;
|
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
|
@WebAppConfiguration
|
||||||
@ContextConfiguration(classes = { WebConfig.class, WebConfig.class })
|
|
||||||
public class GreetControllerIntegrationTest {
|
public class GreetControllerIntegrationTest {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private WebApplicationContext wac;
|
private WebApplicationContext webApplicationContext;
|
||||||
|
|
||||||
private MockMvc mockMvc;
|
private MockMvc mockMvc;
|
||||||
|
|
||||||
private static final String CONTENT_TYPE = "application/json";
|
private static final String CONTENT_TYPE = "application/json";
|
||||||
|
|
||||||
@Before
|
@BeforeEach
|
||||||
public void setup() throws Exception {
|
public void setup() {
|
||||||
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
|
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void givenWac_whenServletContext_thenItProvidesGreetController() {
|
public void givenWac_whenServletContext_thenItProvidesGreetController() {
|
||||||
final ServletContext servletContext = wac.getServletContext();
|
final ServletContext servletContext = webApplicationContext.getServletContext();
|
||||||
Assert.assertNotNull(servletContext);
|
assertNotNull(servletContext);
|
||||||
Assert.assertTrue(servletContext instanceof MockServletContext);
|
assertTrue(servletContext instanceof MockServletContext);
|
||||||
Assert.assertNotNull(wac.getBean("greetController"));
|
assertNotNull(webApplicationContext.getBean("greetController"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -54,8 +53,12 @@ public class GreetControllerIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void givenGreetURI_whenMockMVC_thenVerifyResponse() throws Exception {
|
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();
|
final MvcResult mvcResult = this.mockMvc.perform(MockMvcRequestBuilders.get("/greet"))
|
||||||
Assert.assertEquals(CONTENT_TYPE, mvcResult.getResponse().getContentType());
|
.andDo(print())
|
||||||
|
.andExpect(MockMvcResultMatchers.status().isOk())
|
||||||
|
.andExpect(MockMvcResultMatchers.jsonPath("$.message").value("Hello World!!!"))
|
||||||
|
.andReturn();
|
||||||
|
assertEquals(CONTENT_TYPE, mvcResult.getResponse().getContentType());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -1,18 +1,15 @@
|
|||||||
package com.baeldung.web.controller;
|
package com.baeldung.web.controller;
|
||||||
|
|
||||||
import io.restassured.RestAssured;
|
import io.restassured.RestAssured;
|
||||||
import org.junit.Before;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
import org.springframework.boot.web.server.LocalServerPort;
|
import org.springframework.boot.web.server.LocalServerPort;
|
||||||
import org.springframework.test.context.TestPropertySource;
|
import org.springframework.test.context.TestPropertySource;
|
||||||
import org.springframework.test.context.junit4.SpringRunner;
|
|
||||||
|
|
||||||
import static io.restassured.RestAssured.given;
|
import static io.restassured.RestAssured.given;
|
||||||
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
|
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
|
||||||
|
|
||||||
@RunWith(SpringRunner.class)
|
|
||||||
@SpringBootTest(webEnvironment = RANDOM_PORT)
|
@SpringBootTest(webEnvironment = RANDOM_PORT)
|
||||||
@TestPropertySource(properties = {"spring.main.allow-bean-definition-overriding=true", "server.servlet.context-path=/"})
|
@TestPropertySource(properties = {"spring.main.allow-bean-definition-overriding=true", "server.servlet.context-path=/"})
|
||||||
public class GreetControllerRealIntegrationTest {
|
public class GreetControllerRealIntegrationTest {
|
||||||
@ -20,7 +17,7 @@ public class GreetControllerRealIntegrationTest {
|
|||||||
@LocalServerPort
|
@LocalServerPort
|
||||||
private int port;
|
private int port;
|
||||||
|
|
||||||
@Before
|
@BeforeEach
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
RestAssured.port = port;
|
RestAssured.port = port;
|
||||||
}
|
}
|
||||||
|
@ -1,25 +1,22 @@
|
|||||||
package com.baeldung.web.controller;
|
package com.baeldung.web.controller;
|
||||||
|
|
||||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
|
import org.junit.jupiter.api.Test;
|
||||||
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.springframework.test.web.servlet.MockMvc;
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
|
||||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
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 {
|
public class GreetControllerUnitTest {
|
||||||
|
|
||||||
private MockMvc mockMvc;
|
private MockMvc mockMvc;
|
||||||
private static final String CONTENT_TYPE = "application/json";
|
private static final String CONTENT_TYPE = "application/json";
|
||||||
|
|
||||||
@Before
|
@BeforeEach
|
||||||
public void setup() {
|
void setUp() {
|
||||||
this.mockMvc = MockMvcBuilders.standaloneSetup(new GreetController()).build();
|
this.mockMvc = MockMvcBuilders.standaloneSetup(new GreetController()).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,12 +47,12 @@ public class GreetControllerUnitTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void givenGreetURIWithPost_whenMockMVC_thenVerifyResponse() throws Exception {
|
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
|
@Test
|
||||||
public void givenGreetURIWithPostAndFormData_whenMockMVC_thenVerifyResponse() throws Exception {
|
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));
|
.andExpect(jsonPath("$.message").value("Hello World John Doe!!!")).andExpect(jsonPath("$.id").value(1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,4 +65,10 @@ public class RedirectController {
|
|||||||
return new ModelAndView("redirection");
|
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");
|
||||||
|
}
|
||||||
}
|
}
|
@ -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");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +0,0 @@
|
|||||||
## Testing Modules
|
|
||||||
|
|
||||||
This is an aggregator module containing multiple modules focused on testing libraries.
|
|
@ -44,6 +44,7 @@
|
|||||||
<module>testing-libraries</module>
|
<module>testing-libraries</module>
|
||||||
<module>testing-libraries-2</module>
|
<module>testing-libraries-2</module>
|
||||||
<module>powermock</module>
|
<module>powermock</module>
|
||||||
|
<module>zerocode</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
102
testing-modules/zerocode/pom.xml
Normal file
102
testing-modules/zerocode/pom.xml
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<artifactId>testing-modules</artifactId>
|
||||||
|
<groupId>com.baeldung</groupId>
|
||||||
|
<version>1.0.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>zerocode</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
<version>${spring.boot.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<version>${spring.boot.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jsmart</groupId>
|
||||||
|
<artifactId>zerocode-tdd</artifactId>
|
||||||
|
<version>1.3.27</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<profiles>
|
||||||
|
<profile>it</profile>
|
||||||
|
</profiles>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>pre-integration-test</id>
|
||||||
|
<goals>
|
||||||
|
<goal>start</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<skip>${skip.it}</skip>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>post-integration-test</id>
|
||||||
|
<goals>
|
||||||
|
<goal>stop</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<skip>${skip.it}</skip>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-failsafe-plugin</artifactId>
|
||||||
|
<version>3.0.0-M5</version>
|
||||||
|
<configuration>
|
||||||
|
<skip>${skip.it}</skip>
|
||||||
|
</configuration>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.maven.surefire</groupId>
|
||||||
|
<artifactId>surefire-junit47</artifactId>
|
||||||
|
<version>3.0.0-M5</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>integration-test</goal>
|
||||||
|
<goal>verify</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<maven.compiler.source>8</maven.compiler.source>
|
||||||
|
<maven.compiler.target>8</maven.compiler.target>
|
||||||
|
<spring.boot.version>2.4.2</spring.boot.version>
|
||||||
|
<skip.it>true</skip.it>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
</project>
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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<User> 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
web.application.endpoint.host=http://localhost
|
||||||
|
web.application.endpoint.port=8080
|
||||||
|
web.application.endpoint.context=
|
Loading…
x
Reference in New Issue
Block a user