Merge branch 'eugenp:master' into master
This commit is contained in:
+4
-1
@@ -99,4 +99,7 @@ spring-boot-modules/spring-boot-react/frontend/yarn.lock
|
||||
spring-boot-modules/spring-boot-properties-3/*.log
|
||||
|
||||
# SDKMan
|
||||
.sdkmanrc
|
||||
.sdkmanrc
|
||||
|
||||
# Localstack
|
||||
**/.localstack
|
||||
@@ -13,18 +13,32 @@
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>${guava.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>${lombok.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<properties>
|
||||
<combinatoricslib3.version>3.3.3</combinatoricslib3.version>
|
||||
<commons-collections4.version>4.4</commons-collections4.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>${guava.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>${lombok.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.dpaukov</groupId>
|
||||
<artifactId>combinatoricslib3</artifactId>
|
||||
<version>${combinatoricslib3.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-collections4</artifactId>
|
||||
<version>${commons-collections4.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package com.baeldung.algorithms.stringpermutation;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ArrayHelper {
|
||||
|
||||
private ArrayHelper() {
|
||||
}
|
||||
|
||||
static List<Character> toCharacterList(final String string) {
|
||||
return string.chars().mapToObj(s -> ((char) s)).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package com.baeldung.algorithms.stringpermutation;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.collections4.iterators.PermutationIterator;
|
||||
|
||||
public class StringPermutationsApache {
|
||||
|
||||
public Collection<List<Character>> eagerPermutationWithRepetitions(final String string) {
|
||||
final List<Character> characters = ArrayHelper.toCharacterList(string);
|
||||
return CollectionUtils.permutations(characters);
|
||||
}
|
||||
|
||||
public PermutationIterator<Character> lazyPermutationWithoutRepetitions(final String string) {
|
||||
final List<Character> characters = ArrayHelper.toCharacterList(string);
|
||||
return new PermutationIterator<>(characters);
|
||||
}
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.baeldung.algorithms.stringpermutation;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import org.paukov.combinatorics3.Generator;
|
||||
import org.paukov.combinatorics3.PermutationGenerator.TreatDuplicatesAs;
|
||||
|
||||
public class StringPermutationsCombinatoricsLib {
|
||||
|
||||
public List<List<Character>> permutationWithoutRepetitions(final String string) {
|
||||
List<Character> chars = ArrayHelper.toCharacterList(string);
|
||||
return Generator.permutation(chars)
|
||||
.simple()
|
||||
.stream()
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<List<Character>> permutationWithRepetitions(final String string) {
|
||||
List<Character> chars = ArrayHelper.toCharacterList(string);
|
||||
return Generator.permutation(chars)
|
||||
.simple(TreatDuplicatesAs.IDENTICAL)
|
||||
.stream()
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package com.baeldung.algorithms.stringpermutation;
|
||||
|
||||
import com.google.common.collect.Collections2;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class StringPermutationsGuava {
|
||||
|
||||
public Collection<List<Character>> permutationWithRepetitions(final String string) {
|
||||
final List<Character> characters = ArrayHelper.toCharacterList(string);
|
||||
return Collections2.permutations(characters);
|
||||
}
|
||||
public Collection<List<Character>> permutationWithoutRepetitions(final String string) {
|
||||
final List<Character> characters = ArrayHelper.toCharacterList(string);
|
||||
return Collections2.orderedPermutations(characters);
|
||||
}
|
||||
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
package com.baeldung.algorithms.stringpermutation;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import org.apache.commons.collections4.iterators.PermutationIterator;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.CsvSource;
|
||||
|
||||
class StringPermutationsApacheUnitTest {
|
||||
|
||||
@CsvSource({"abc, 6",
|
||||
"hello, 120",
|
||||
"aaaaaa, 720"})
|
||||
@DisplayName("Apache permutation for ")
|
||||
void testPermutationsWithRepetitions(String string, int numberOfPermutations) {
|
||||
StringPermutationsApache permutationGenerator = new StringPermutationsApache();
|
||||
final Collection<List<Character>> permutations = permutationGenerator.eagerPermutationWithRepetitions(string);
|
||||
final int size = permutations.size();
|
||||
assertThat(permutations)
|
||||
.as("\"%s\" should have %d permutation, but had %d", string, numberOfPermutations, size)
|
||||
.hasSize(numberOfPermutations);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource({"abc, 6",
|
||||
"hello, 120",
|
||||
"aaaaaa, 720"})
|
||||
void testPermutationsWithoutRepetitions(String string, int numberOfPermutations) {
|
||||
StringPermutationsApache permutationGenerator = new StringPermutationsApache();
|
||||
final PermutationIterator<Character> permutations = permutationGenerator.lazyPermutationWithoutRepetitions(string);
|
||||
int size = 0;
|
||||
while (permutations.hasNext()) {
|
||||
permutations.next();
|
||||
++size;
|
||||
}
|
||||
assertThat(size)
|
||||
.as("\"%s\" should have %d permutation, but had %d", string, numberOfPermutations, size)
|
||||
.isEqualTo(numberOfPermutations);
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package com.baeldung.algorithms.stringpermutation;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.List;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.CsvSource;
|
||||
|
||||
class StringPermutationsCombinatoricsLibUnitTest {
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource({"abc, 6",
|
||||
"hello, 120",
|
||||
"aaaaaa, 720"})
|
||||
void testPermutationsWithRepetitions(String string, int numberOfPermutations) {
|
||||
StringPermutationsCombinatoricsLib permutationGenerator = new StringPermutationsCombinatoricsLib();
|
||||
final List<List<Character>> permutations = permutationGenerator.permutationWithRepetitions(string);
|
||||
final int size = permutations.size();
|
||||
assertThat(permutations)
|
||||
.as("\"%s\" should have %d permutation, but had %d", string, numberOfPermutations, size)
|
||||
.hasSize(numberOfPermutations);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource({"abc, 6",
|
||||
"hello, 60",
|
||||
"aaaaaa, 1"})
|
||||
void testPermutationsWithoutRepetitions(String string, int numberOfPermutations) {
|
||||
StringPermutationsCombinatoricsLib permutationGenerator = new StringPermutationsCombinatoricsLib();
|
||||
final List<List<Character>> permutations = permutationGenerator.permutationWithoutRepetitions(string);
|
||||
final int size = permutations.size();
|
||||
assertThat(permutations)
|
||||
.as("\"%s\" should have %d permutation, but had %d", string, numberOfPermutations, size)
|
||||
.hasSize(numberOfPermutations);
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package com.baeldung.algorithms.stringpermutation;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.CsvSource;
|
||||
|
||||
class StringPermutationsGuavaUnitTest {
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource({"abc, 6",
|
||||
"hello, 120",
|
||||
"aaaaaa, 720"})
|
||||
void testPermutationsWithRepetitions(String string, int numberOfPermutations) {
|
||||
StringPermutationsGuava permutationGenerator = new StringPermutationsGuava();
|
||||
final Collection<List<Character>> permutations = permutationGenerator.permutationWithRepetitions(string);
|
||||
final int size = permutations.size();
|
||||
assertThat(permutations)
|
||||
.as("\"%s\" should have %d permutation, but had %d", string, numberOfPermutations, size)
|
||||
.hasSize(numberOfPermutations);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource({"abc, 6",
|
||||
"hello, 60",
|
||||
"aaaaaa, 1"})
|
||||
void testPermutationsWithoutRepetitions(String string, int numberOfPermutations) {
|
||||
StringPermutationsGuava permutationGenerator = new StringPermutationsGuava();
|
||||
final Collection<List<Character>> permutations = permutationGenerator.permutationWithoutRepetitions(string);
|
||||
final int size = permutations.size();
|
||||
assertThat(permutations)
|
||||
.as("\"%s\" should have %d permutation, but had %d", string, numberOfPermutations, size)
|
||||
.hasSize(numberOfPermutations);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,4 +6,6 @@ This module contains articles about the Java List collection
|
||||
- [Working With a List of Lists in Java](https://www.baeldung.com/java-list-of-lists)
|
||||
- [Reverse an ArrayList in Java](https://www.baeldung.com/java-reverse-arraylist)
|
||||
- [Sort a List Alphabetically in Java](https://www.baeldung.com/java-sort-list-alphabetically)
|
||||
- [Arrays.asList() vs Collections.singletonList()](https://www.baeldung.com/java-aslist-vs-singletonlist)
|
||||
- [Replace Element at a Specific Index in a Java ArrayList](https://www.baeldung.com/java-arraylist-replace-at-index)
|
||||
- [[<-- Prev]](/core-java-modules/core-java-collections-list-3)
|
||||
|
||||
@@ -8,4 +8,5 @@
|
||||
- [Java Map – keySet() vs. entrySet() vs. values() Methods](https://www.baeldung.com/java-map-entries-methods)
|
||||
- [Java IdentityHashMap Class and Its Use Cases](https://www.baeldung.com/java-identityhashmap)
|
||||
- [How to Invert a Map in Java](https://www.baeldung.com/java-invert-map)
|
||||
- [Implementing a Map with Multiple Keys in Java](https://www.baeldung.com/java-multiple-keys-map)
|
||||
- More articles: [[<-- prev]](../core-java-collections-maps-4)
|
||||
|
||||
@@ -7,3 +7,4 @@
|
||||
- [Producer-Consumer Problem With Example in Java](https://www.baeldung.com/java-producer-consumer-problem)
|
||||
- [Acquire a Lock by a Key in Java](https://www.baeldung.com/java-acquire-lock-by-key)
|
||||
- [Differences Between set() and lazySet() in Java Atomic Variables](https://www.baeldung.com/java-atomic-set-vs-lazyset)
|
||||
- [Volatile vs. Atomic Variables in Java](https://www.baeldung.com/java-volatile-vs-atomic)
|
||||
|
||||
@@ -7,4 +7,5 @@ This module contains articles about core java exceptions
|
||||
- [Java Missing Return Statement](https://www.baeldung.com/java-missing-return-statement)
|
||||
- [Convert long to int Type in Java](https://www.baeldung.com/java-convert-long-to-int)
|
||||
- [“Sneaky Throws” in Java](https://www.baeldung.com/java-sneaky-throws)
|
||||
- [[<-- Prev]](../core-java-exceptions-3)
|
||||
- [Get the Current Stack Trace in Java](https://www.baeldung.com/java-get-current-stack-trace)
|
||||
- [[<-- Prev]](../core-java-exceptions-3)
|
||||
|
||||
@@ -11,3 +11,4 @@ This module contains article about constructors in Java
|
||||
- [Constructors in Java Abstract Classes](https://www.baeldung.com/java-abstract-classes-constructors)
|
||||
- [Java Implicit Super Constructor is Undefined Error](https://www.baeldung.com/java-implicit-super-constructor-is-undefined-error)
|
||||
- [Constructor Specification in Java](https://www.baeldung.com/java-constructor-specification)
|
||||
- [Static vs. Instance Initializer Block in Java](https://www.baeldung.com/java-static-instance-initializer-blocks)
|
||||
|
||||
+2
-2
@@ -17,9 +17,9 @@ import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class FileDownloadIntegrationTest {
|
||||
|
||||
static String FILE_URL = "https://s3.amazonaws.com/baeldung.com/Do+JSON+with+Jackson+by+Baeldung.pdf";
|
||||
static String FILE_URL = "https://s3.amazonaws.com/baeldung.com/Do+JSON+with+Jackson.pdf?__s=vatuzcrazsqopnn7finb";
|
||||
static String FILE_NAME = "file.dat";
|
||||
static String FILE_MD5_HASH = "753197aa27f162faa3e3c2e48ee5eb07";
|
||||
static String FILE_MD5_HASH = "CE20E17B1E1FBF65A85E74AC00FA1FD8";
|
||||
|
||||
@Test
|
||||
public void givenJavaIO_whenDownloadingFile_thenDownloadShouldBeCorrect() throws NoSuchAlgorithmException, IOException {
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
### Relevant Articles:
|
||||
- [Check if a Number Is Odd or Even](https://www.baeldung.com/java-check-number-parity)
|
||||
- [How to Check Whether an Integer Exists in a Range with Java](https://www.baeldung.com/java-interval-contains-integer)
|
||||
|
||||
@@ -2,3 +2,4 @@
|
||||
|
||||
- [Count Occurrences Using Java groupingBy Collector](https://www.baeldung.com/java-groupingby-count)
|
||||
- [How to Split a Stream into Multiple Streams](https://www.baeldung.com/java-split-stream)
|
||||
- [Filter Java Stream to 1 and Only 1 Element](https://www.baeldung.com/java-filter-stream-unique-element)
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package com.baeldung.chararraytostring;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class IntToStringUnitTest {
|
||||
|
||||
@Test
|
||||
public void whenValidIntIsPassed_thenShouldConvertToString() {
|
||||
assertEquals("11", Integer.toString(11));
|
||||
assertEquals("11", Integer.toString(+11));
|
||||
assertEquals("-11", Integer.toString(-11));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenValidIntIsPassed_thenShouldConvertToValidString() {
|
||||
assertEquals("11", String.valueOf(11));
|
||||
assertEquals("11", String.valueOf(+11));
|
||||
assertEquals("-11", String.valueOf(-11));
|
||||
}
|
||||
|
||||
@Test(expected = NullPointerException.class)
|
||||
public void whenNullIntegerObjectIsPassed_thenShouldThrowException() {
|
||||
Integer i = null;
|
||||
System.out.println(String.valueOf(i)); // it prints "null"
|
||||
System.out.println(i.toString());
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package com.baeldung.namedformatting;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class NamedFormatter {
|
||||
private NamedFormatter() {}
|
||||
|
||||
public static String format(String template, Map<String, Object> parameters) {
|
||||
StringBuilder newTemplate = new StringBuilder(template);
|
||||
List<Object> valueList = new ArrayList<>();
|
||||
|
||||
Matcher matcher = Pattern.compile("[$][{](\\w+)}").matcher(template);
|
||||
|
||||
while (matcher.find()) {
|
||||
String key = matcher.group(1);
|
||||
|
||||
String paramName = "${" + key + "}";
|
||||
int index = newTemplate.indexOf(paramName);
|
||||
if (index != -1) {
|
||||
newTemplate.replace(index, index + paramName.length(), "%s");
|
||||
valueList.add(parameters.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
return String.format(newTemplate.toString(), valueList.toArray());
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
package com.baeldung.namedformatting;
|
||||
|
||||
import org.apache.commons.text.StrSubstitutor;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class NamedFormatterUnitTest {
|
||||
private static final String TEMPLATE = "Text: [${text}] Number: [${number}] Text again: [${text}]";
|
||||
|
||||
@Test
|
||||
void givenTemplateWithNamedParam_whenCallingCommonsTextStrSubstitutor_shouldGetExpectedResult() {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("text", "It's awesome!");
|
||||
params.put("number", 42);
|
||||
String result = StrSubstitutor.replace(TEMPLATE, params, "${", "}");
|
||||
assertThat(result).isEqualTo("Text: [It's awesome!] Number: [42] Text again: [It's awesome!]");
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenTemplateWithNamedParam_whenCallingCommonsTextStrSubstitutorWithParameterNames_shouldNotWorkAsExpected() {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("text", "'${number}' is a placeholder.");
|
||||
params.put("number", 42);
|
||||
String result = StrSubstitutor.replace(TEMPLATE, params, "${", "}");
|
||||
|
||||
assertThat(result).isNotEqualTo("Text: ['${number}' is a placeholder.] Number: [42] Text again: ['${number}' is a placeholder.]");
|
||||
|
||||
assertThat(result).isEqualTo("Text: ['42' is a placeholder.] Number: [42] Text again: ['42' is a placeholder.]");
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenTemplateWithNamedParam_whenCallingNamedFormatter_shouldGetExpectedResult() {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("text", "It's awesome!");
|
||||
params.put("number", 42);
|
||||
String result = NamedFormatter.format(TEMPLATE, params);
|
||||
assertThat(result).isEqualTo("Text: [It's awesome!] Number: [42] Text again: [It's awesome!]");
|
||||
|
||||
params.put("text", "'${number}' is a placeholder.");
|
||||
result = NamedFormatter.format(TEMPLATE, params);
|
||||
assertThat(result).isEqualTo("Text: ['${number}' is a placeholder.] Number: [42] Text again: ['${number}' is a placeholder.]");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
services:
|
||||
mysql-db:
|
||||
image: mysql:latest
|
||||
environment:
|
||||
- MYSQL_ROOT_PASSWORD=password
|
||||
- MYSQL_ROOT_HOST=localhost
|
||||
ports:
|
||||
- '3306:3306'
|
||||
volumes:
|
||||
- first-volume-data:/var/lib/mysql
|
||||
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
|
||||
|
||||
volumes:
|
||||
first-volume-data:
|
||||
external: true
|
||||
@@ -0,0 +1,9 @@
|
||||
CREATE DATABASE IF NOT EXISTS test;
|
||||
|
||||
use test;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS test_table (id int, description varchar(255));
|
||||
|
||||
INSERT INTO test_table VALUES (1, 'TEST_1');
|
||||
INSERT INTO test_table VALUES (2, 'TEST_2');
|
||||
INSERT INTO test_table VALUES (3, 'TEST_3');
|
||||
@@ -0,0 +1,15 @@
|
||||
services:
|
||||
localstack:
|
||||
privileged: true
|
||||
image: localstack/localstack:latest
|
||||
container_name: localstack
|
||||
ports:
|
||||
- '4563-4599:4563-4599'
|
||||
- '8055:8080'
|
||||
environment:
|
||||
- SERVICES=s3
|
||||
- DEBUG=1
|
||||
- DATA_DIR=/tmp/localstack/data
|
||||
volumes:
|
||||
- './.localstack:/var/lib/localstack'
|
||||
- '/var/run/docker.sock:/var/run/docker.sock'
|
||||
@@ -0,0 +1,15 @@
|
||||
services:
|
||||
my_app:
|
||||
image: web-app:latest
|
||||
container_name: web-app
|
||||
ports:
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- first-volume-data:/container-path-1
|
||||
- second-volume-data:/container-path-2:ro
|
||||
|
||||
volumes:
|
||||
first-volume-data:
|
||||
driver: local
|
||||
second-volume-data:
|
||||
driver: local
|
||||
@@ -0,0 +1,4 @@
|
||||
|
||||
### Relevant Articles:
|
||||
|
||||
- [Dockerizing a Java Application](https://www.baeldung.com/java-dockerize-app)
|
||||
@@ -150,9 +150,9 @@
|
||||
|
||||
<properties>
|
||||
<orika.version>1.5.4</orika.version>
|
||||
<dozer.version>6.5.0</dozer.version>
|
||||
<mapstruct.version>1.3.1.Final</mapstruct.version>
|
||||
<modelmapper.version>2.3.8</modelmapper.version>
|
||||
<dozer.version>6.5.2</dozer.version>
|
||||
<mapstruct.version>1.5.2.Final</mapstruct.version>
|
||||
<modelmapper.version>3.1.0</modelmapper.version>
|
||||
<jmapper.version>1.6.1.CR2</jmapper.version>
|
||||
<!-- Java source/target to use for compilation. -->
|
||||
<javac.target>1.8</javac.target>
|
||||
|
||||
+5
@@ -29,6 +29,11 @@ public class WebClientController {
|
||||
return bodyString.map(body -> "processed-" + body);
|
||||
}
|
||||
|
||||
@PostMapping("/resource-override")
|
||||
public Mono<String> postStringResourceOverride(@RequestBody Mono<String> bodyString) {
|
||||
return bodyString.map(body -> "override-processed-" + body);
|
||||
}
|
||||
|
||||
@PostMapping("/resource-foo")
|
||||
public Mono<String> postFooResource(@RequestBody Mono<Foo> bodyFoo) {
|
||||
return bodyFoo.map(foo -> "processedFoo-" + foo.getName());
|
||||
|
||||
+52
-59
@@ -54,58 +54,44 @@ class WebClientIntegrationTest {
|
||||
|
||||
@Test
|
||||
void givenDifferentWebClientCreationMethods_whenUsed_thenObtainExpectedResponse() {
|
||||
// WebClient creation
|
||||
WebClient client1 = WebClient.create();
|
||||
WebClient client2 = WebClient.create("http://localhost:" + port);
|
||||
WebClient client3 = WebClient.builder()
|
||||
.baseUrl("http://localhost:" + port)
|
||||
.defaultCookie("cookieKey", "cookieValue")
|
||||
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
|
||||
.defaultUriVariables(Collections.singletonMap("url", "http://localhost:8080"))
|
||||
.build();
|
||||
|
||||
// response assertions
|
||||
WebClient client1 = WebClient.builder().clientConnector(httpConnector()).build();
|
||||
StepVerifier.create(retrieveResponse(client1.post()
|
||||
.uri("http://localhost:" + port + "/resource")))
|
||||
.expectNext("processed-bodyValue")
|
||||
.verifyComplete();
|
||||
|
||||
WebClient client2 = WebClient.builder().baseUrl("http://localhost:" + port)
|
||||
.clientConnector(httpConnector()).build();
|
||||
StepVerifier.create(retrieveResponse(client2))
|
||||
.expectNext("processed-bodyValue")
|
||||
.verifyComplete();
|
||||
|
||||
WebClient client3 = WebClient.builder()
|
||||
.baseUrl("http://localhost:" + port)
|
||||
.clientConnector(httpConnector())
|
||||
.defaultCookie("cookieKey", "cookieValue")
|
||||
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
|
||||
.defaultUriVariables(Collections.singletonMap("url", "http://localhost:8080"))
|
||||
.build();
|
||||
StepVerifier.create(retrieveResponse(client3))
|
||||
.expectNext("processed-bodyValue")
|
||||
.verifyComplete();
|
||||
// assert response without specifying URI
|
||||
StepVerifier.create(retrieveResponse(client1))
|
||||
.expectErrorMatches(ex -> WebClientRequestException.class.isAssignableFrom(ex.getClass()) && ex.getMessage()
|
||||
.contains("Connection refused"))
|
||||
.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenWebClientCreationWithoutUri_whenUsed_thenObtainExpectedResponse() {
|
||||
WebClient client = WebClient.create();
|
||||
|
||||
StepVerifier.create(retrieveResponse(client))
|
||||
.expectErrorMatches(ex -> WebClientRequestException.class.isAssignableFrom(ex.getClass()) && ex.getMessage()
|
||||
.contains("Connection refused"))
|
||||
.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenDifferentMethodSpecifications_whenUsed_thenObtainExpectedResponse() {
|
||||
// request specification
|
||||
RequestBodyUriSpec uriSpecPost1 = createDefaultClient().method(HttpMethod.POST);
|
||||
RequestBodyUriSpec uriSpecPost2 = createDefaultClient().post();
|
||||
RequestHeadersUriSpec<?> requestGet = createDefaultClient().get();
|
||||
|
||||
// response assertions
|
||||
RequestBodyUriSpec uriSpecPost1 = createDefaultClient().method(HttpMethod.POST);
|
||||
StepVerifier.create(retrieveResponse(uriSpecPost1))
|
||||
.expectNext("processed-bodyValue")
|
||||
.verifyComplete();
|
||||
|
||||
RequestBodyUriSpec uriSpecPost2 = createDefaultClient().post();
|
||||
StepVerifier.create(retrieveResponse(uriSpecPost2))
|
||||
.expectNext("processed-bodyValue")
|
||||
.verifyComplete();
|
||||
|
||||
RequestHeadersUriSpec<?> requestGet = createDefaultClient().get();
|
||||
StepVerifier.create(retrieveGetResponse(requestGet))
|
||||
.expectNextMatches(nextMap -> nextMap.get("field")
|
||||
.equals("value"))
|
||||
@@ -114,21 +100,21 @@ class WebClientIntegrationTest {
|
||||
|
||||
@Test
|
||||
void givenDifferentUriSpecifications_whenUsed_thenObtainExpectedResponse() {
|
||||
// uri specification
|
||||
RequestBodySpec bodySpecUsingString = createDefaultPostRequest().uri("/resource");
|
||||
RequestBodySpec bodySpecUsingUriBuilder = createDefaultPostRequest().uri(
|
||||
uriBuilder -> uriBuilder.pathSegment("resource")
|
||||
.build());
|
||||
RequestBodySpec bodySpecusingURI = createDefaultPostRequest().uri(
|
||||
URI.create("http://localhost:" + port + "/resource"));
|
||||
|
||||
// response assertions
|
||||
RequestBodySpec bodySpecUsingString = createDefaultPostRequest().uri("/resource");
|
||||
StepVerifier.create(retrieveResponse(bodySpecUsingString))
|
||||
.expectNext("processed-bodyValue")
|
||||
.verifyComplete();
|
||||
|
||||
RequestBodySpec bodySpecUsingUriBuilder = createDefaultPostRequest().uri(
|
||||
uriBuilder -> uriBuilder.pathSegment("resource")
|
||||
.build());
|
||||
StepVerifier.create(retrieveResponse(bodySpecUsingUriBuilder))
|
||||
.expectNext("processed-bodyValue")
|
||||
.verifyComplete();
|
||||
|
||||
RequestBodySpec bodySpecusingURI = createDefaultPostRequest().uri(
|
||||
URI.create("http://localhost:" + port + "/resource"));
|
||||
StepVerifier.create(retrieveResponse(bodySpecusingURI))
|
||||
.expectNext("processed-bodyValue")
|
||||
.verifyComplete();
|
||||
@@ -136,21 +122,23 @@ class WebClientIntegrationTest {
|
||||
|
||||
@Test
|
||||
void givenOverriddenUriSpecifications_whenUsed_thenObtainExpectedResponse() {
|
||||
RequestBodySpec bodySpecOverriddenBaseUri = createDefaultPostRequest().uri(URI.create("/resource"));
|
||||
RequestBodySpec bodySpecOverriddenBaseUri = createDefaultPostRequest()
|
||||
.uri(URI.create("http://localhost:" + port + "/resource-override"));
|
||||
|
||||
StepVerifier.create(retrieveResponse(bodySpecOverriddenBaseUri))
|
||||
.expectErrorMatches(ex -> WebClientRequestException.class.isAssignableFrom(ex.getClass()) && ex.getMessage()
|
||||
.contains("Connection refused"))
|
||||
.verify();
|
||||
.expectNext("override-processed-bodyValue")
|
||||
.verifyComplete();
|
||||
|
||||
RequestBodySpec bodySpecOverriddenBaseUri2 = WebClient.builder()
|
||||
.clientConnector(httpConnector())
|
||||
.baseUrl("http://localhost:" + port)
|
||||
.build()
|
||||
.post()
|
||||
.uri(URI.create("/resource"));
|
||||
.uri(URI.create("http://localhost:" + port + "/resource-override"));
|
||||
|
||||
StepVerifier.create(retrieveResponse(bodySpecOverriddenBaseUri2))
|
||||
.expectErrorMatches(ex -> WebClientRequestException.class.isAssignableFrom(ex.getClass()) && ex.getMessage()
|
||||
.contains("Connection refused"))
|
||||
.verify();
|
||||
.expectNext("override-processed-bodyValue")
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -195,7 +183,7 @@ class WebClientIntegrationTest {
|
||||
StepVerifier.create(retrieveResponse(headersSpecPlainObject))
|
||||
.expectError(CodecException.class)
|
||||
.verify();
|
||||
// assert response for request with no body
|
||||
// assert response for request without body
|
||||
Mono<Map<String, String>> responsePostWithNoBody = createDefaultPostResourceRequest().exchangeToMono(
|
||||
responseHandler -> {
|
||||
assertThat(responseHandler.statusCode()).isEqualTo(HttpStatus.BAD_REQUEST);
|
||||
@@ -294,7 +282,17 @@ class WebClientIntegrationTest {
|
||||
|
||||
// helper methods to create default instances
|
||||
private WebClient createDefaultClient() {
|
||||
return WebClient.create("http://localhost:" + port);
|
||||
return WebClient.builder()
|
||||
.baseUrl("http://localhost:" + port)
|
||||
.clientConnector(httpConnector())
|
||||
.build();
|
||||
}
|
||||
|
||||
private static ReactorClientHttpConnector httpConnector() {
|
||||
HttpClient httpClient = HttpClient
|
||||
.create()
|
||||
.wiretap(true);
|
||||
return new ReactorClientHttpConnector(httpClient);
|
||||
}
|
||||
|
||||
private RequestBodyUriSpec createDefaultPostRequest() {
|
||||
@@ -315,35 +313,30 @@ class WebClientIntegrationTest {
|
||||
.uri("/resource")
|
||||
.bodyValue(BODY_VALUE)
|
||||
.retrieve()
|
||||
.bodyToMono(String.class)
|
||||
.log();
|
||||
.bodyToMono(String.class);
|
||||
}
|
||||
|
||||
private Mono<String> retrieveResponse(RequestBodyUriSpec spec) {
|
||||
return spec.uri("/resource")
|
||||
.bodyValue(BODY_VALUE)
|
||||
.retrieve()
|
||||
.bodyToMono(String.class)
|
||||
.log();
|
||||
.bodyToMono(String.class);
|
||||
}
|
||||
|
||||
private Mono<Map<String, String>> retrieveGetResponse(RequestHeadersUriSpec<?> spec) {
|
||||
return spec.uri("/resource")
|
||||
.retrieve()
|
||||
.bodyToMono(MAP_RESPONSE_REF)
|
||||
.log();
|
||||
.bodyToMono(MAP_RESPONSE_REF);
|
||||
}
|
||||
|
||||
private Mono<String> retrieveResponse(RequestBodySpec spec) {
|
||||
return spec.bodyValue(BODY_VALUE)
|
||||
.retrieve()
|
||||
.bodyToMono(String.class)
|
||||
.log();
|
||||
.bodyToMono(String.class);
|
||||
}
|
||||
|
||||
private Mono<String> retrieveResponse(RequestHeadersSpec<?> spec) {
|
||||
return spec.retrieve()
|
||||
.bodyToMono(String.class)
|
||||
.log();
|
||||
.bodyToMono(String.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
name="com.baeldung.reactive.debugging.consumer.service.FooService">
|
||||
<appender-ref ref="LISTAPPENDER" />
|
||||
</logger>
|
||||
|
||||
<logger name="reactor.netty.http.client" level="INFO"/>
|
||||
|
||||
<root level="info">
|
||||
<appender-ref ref="CONSOLE" />
|
||||
<appender-ref ref="LISTAPPENDER" />
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
|
||||
### Relevant Articles:
|
||||
|
||||
- [Spring Boot 3 and Spring Framework 6.0 – What's New](https://www.baeldung.com/spring-boot-3-spring-6-new)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user