Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
4bc5986a42
|
@ -26,7 +26,7 @@ public class Product {
|
|||
return tags;
|
||||
}
|
||||
|
||||
public Product addTagsOfOtherProdcut(Product product) {
|
||||
public Product addTagsOfOtherProduct(Product product) {
|
||||
this.tags.addAll(product.getTags());
|
||||
return this;
|
||||
}
|
||||
|
@ -100,11 +100,11 @@ public class Product {
|
|||
HashMap<String, Product> productsByName = new HashMap<>();
|
||||
Product eBike2 = new Product("E-Bike", "A bike with a battery");
|
||||
eBike2.getTags().add("sport");
|
||||
productsByName.merge("E-Bike", eBike2, Product::addTagsOfOtherProdcut);
|
||||
productsByName.merge("E-Bike", eBike2, Product::addTagsOfOtherProduct);
|
||||
|
||||
//Prior to Java 8:
|
||||
if(productsByName.containsKey("E-Bike")) {
|
||||
productsByName.get("E-Bike").addTagsOfOtherProdcut(eBike2);
|
||||
productsByName.get("E-Bike").addTagsOfOtherProduct(eBike2);
|
||||
} else {
|
||||
productsByName.put("E-Bike", eBike2);
|
||||
}
|
||||
|
@ -117,7 +117,7 @@ public class Product {
|
|||
|
||||
productsByName.compute("E-Bike", (k,v) -> {
|
||||
if(v != null) {
|
||||
return v.addTagsOfOtherProdcut(eBike2);
|
||||
return v.addTagsOfOtherProduct(eBike2);
|
||||
} else {
|
||||
return eBike2;
|
||||
}
|
||||
|
@ -125,7 +125,7 @@ public class Product {
|
|||
|
||||
//Prior to Java 8:
|
||||
if(productsByName.containsKey("E-Bike")) {
|
||||
productsByName.get("E-Bike").addTagsOfOtherProdcut(eBike2);
|
||||
productsByName.get("E-Bike").addTagsOfOtherProduct(eBike2);
|
||||
} else {
|
||||
productsByName.put("E-Bike", eBike2);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
### Relevant Articles:
|
||||
|
||||
- [Binary Semaphore vs Reentrant Lock](https://www.baeldung.com/java-binary-semaphore-vs-reentrant-lock)
|
||||
- [Bad Practices With Synchronization](https://www.baeldung.com/java-synchronization-bad-practices)
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
package com.baeldung.synchronizationbadpractices;
|
||||
|
||||
public class AnimalBadPractice {
|
||||
|
||||
private String name;
|
||||
private String owner;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public synchronized void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setOwner(String owner) {
|
||||
synchronized(this) {
|
||||
this.owner = owner;
|
||||
}
|
||||
}
|
||||
|
||||
public AnimalBadPractice() {
|
||||
|
||||
}
|
||||
|
||||
public AnimalBadPractice(String name, String owner) {
|
||||
this.name = name;
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package com.baeldung.synchronizationbadpractices;
|
||||
|
||||
public class AnimalSolution {
|
||||
|
||||
private final Object objLock1 = new Object();
|
||||
private final Object objLock2 = new Object();
|
||||
|
||||
private String name;
|
||||
private String owner;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
|
||||
public void setName(String name) {
|
||||
synchronized(objLock1) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
public void setOwner(String owner) {
|
||||
synchronized(objLock2) {
|
||||
this.owner = owner;
|
||||
}
|
||||
}
|
||||
|
||||
public AnimalSolution() {
|
||||
|
||||
}
|
||||
|
||||
public AnimalSolution(String name, String owner) {
|
||||
this.name = name;
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package com.baeldung.synchronizationbadpractices;
|
||||
|
||||
public class SynchronizationBadPracticeExample {
|
||||
|
||||
public void stringBadPractice1() {
|
||||
String stringLock = "LOCK_STRING";
|
||||
synchronized (stringLock) {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
private final String stringLock = "LOCK_STRING";
|
||||
public void stringBadPractice2() {
|
||||
synchronized (stringLock) {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
private final String internedStringLock = new String("LOCK_STRING").intern();
|
||||
public void stringBadPractice3() {
|
||||
synchronized (internedStringLock) {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
private final Boolean booleanLock = Boolean.FALSE;
|
||||
public void booleanBadPractice() {
|
||||
synchronized (booleanLock) {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
private int count = 0;
|
||||
private final Integer intLock = count;
|
||||
public void boxedPrimitiveBadPractice() {
|
||||
synchronized (intLock) {
|
||||
count++;
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
public void classBadPractice() throws InterruptedException {
|
||||
AnimalBadPractice animalObj = new AnimalBadPractice("Tommy", "John");
|
||||
synchronized(animalObj) {
|
||||
while (true) {
|
||||
Thread.sleep(Integer.MAX_VALUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package com.baeldung.synchronizationbadpractices;
|
||||
|
||||
public class SynchronizationSolutionExample {
|
||||
|
||||
private final String stringLock = new String("LOCK_STRING");
|
||||
public void stringSolution() {
|
||||
synchronized (stringLock) {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
private int count = 0;
|
||||
private final Integer intLock = new Integer(count);
|
||||
public void boxedPrimitiveSolution() {
|
||||
synchronized(intLock) {
|
||||
count++;
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
private static int staticCount = 0;
|
||||
private static final Object staticObjLock = new Object();
|
||||
public void staticVariableSolution() {
|
||||
synchronized(staticObjLock) {
|
||||
staticCount++;
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -11,4 +11,5 @@ This module contains articles about working with the Java Virtual Machine (JVM).
|
|||
- [Where Is the Array Length Stored in JVM?](https://www.baeldung.com/java-jvm-array-length)
|
||||
- [Memory Address of Objects in Java](https://www.baeldung.com/java-object-memory-address)
|
||||
- [List All Classes Loaded in a Specific Class Loader](https://www.baeldung.com/java-list-classes-class-loader)
|
||||
- [An Introduction to the Constant Pool in the JVM](https://www.baeldung.com/jvm-constant-pool)
|
||||
- More articles: [[<-- prev]](/core-java-modules/core-java-jvm)
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
package com.baeldung.compareto;
|
||||
|
||||
public class BankAccount implements Comparable<BankAccount> {
|
||||
|
||||
private final int balance;
|
||||
|
||||
public BankAccount(int balance) {
|
||||
this.balance = balance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(BankAccount anotherAccount) {
|
||||
return this.balance - anotherAccount.balance;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package com.baeldung.compareto;
|
||||
|
||||
public class BankAccountFix implements Comparable<BankAccountFix> {
|
||||
|
||||
private final int balance;
|
||||
|
||||
public BankAccountFix(int balance) {
|
||||
this.balance = balance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(BankAccountFix anotherAccount) {
|
||||
return Integer.compare(this.balance, anotherAccount.balance);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package com.baeldung.compareto;
|
||||
|
||||
public class FootballPlayer implements Comparable<FootballPlayer> {
|
||||
|
||||
private final String name;
|
||||
private final int goalsScored;
|
||||
|
||||
public FootballPlayer(String name, int goalsScored) {
|
||||
this.name = name;
|
||||
this.goalsScored = goalsScored;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(FootballPlayer anotherPlayer) {
|
||||
return Integer.compare(this.goalsScored, anotherPlayer.goalsScored);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
if (this == object)
|
||||
return true;
|
||||
if (object == null || getClass() != object.getClass())
|
||||
return false;
|
||||
FootballPlayer player = (FootballPlayer) object;
|
||||
return name.equals(player.name);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package com.baeldung.compareto;
|
||||
|
||||
public class HandballPlayer {
|
||||
|
||||
private final String name;
|
||||
private final int height;
|
||||
|
||||
public HandballPlayer(String name, int height) {
|
||||
this.name = name;
|
||||
this.height = height;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package com.baeldung.compareto;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class ArraysSortingUnitTest {
|
||||
|
||||
@Test
|
||||
public void givenArrayOfNumbers_whenSortingArray_thenNumbersAreSortedAscending() {
|
||||
int[] numbers = new int[] {5, 3, 9, 11, 1, 7};
|
||||
Arrays.sort(numbers);
|
||||
assertThat(numbers).containsExactly(1, 3, 5, 7, 9, 11);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenArrayOfStrings_whenSortingArray_thenStringsAreSortedAlphabetically() {
|
||||
String[] players = new String[] {"ronaldo", "modric", "ramos", "messi"};
|
||||
Arrays.sort(players);
|
||||
assertThat(players).containsExactly("messi", "modric", "ramos", "ronaldo");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package com.baeldung.compareto;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class BankAccountFixUnitTest {
|
||||
|
||||
@Test
|
||||
public void givenComparisonBasedImpl_whenUsingSmallIntegers_thenComparisonWorks() {
|
||||
BankAccountFix accountOne = new BankAccountFix(5000);
|
||||
BankAccountFix accountTwo = new BankAccountFix(1000);
|
||||
int comparison = accountOne.compareTo(accountTwo);
|
||||
assertThat(comparison).isPositive();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenComparisonBasedImpl_whenUsingLargeIntegers_thenComparisonWorks() {
|
||||
BankAccountFix accountOne = new BankAccountFix(1900000000);
|
||||
BankAccountFix accountTwo = new BankAccountFix(-2000000000);
|
||||
int comparison = accountOne.compareTo(accountTwo);
|
||||
assertThat(comparison).isPositive();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package com.baeldung.compareto;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
public class BankAccountUnitTest {
|
||||
|
||||
@Test
|
||||
public void givenSubtractionBasedImpl_whenUsingSmallIntegers_thenComparisonWorks() {
|
||||
BankAccount accountOne = new BankAccount(5000);
|
||||
BankAccount accountTwo = new BankAccount(1000);
|
||||
int comparison = accountOne.compareTo(accountTwo);
|
||||
assertThat(comparison).isPositive();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenSubtractionBasedImpl_whenUsingLargeIntegers_thenComparisonBreaks() {
|
||||
BankAccount accountOne = new BankAccount(1900000000);
|
||||
BankAccount accountTwo = new BankAccount(-2000000000);
|
||||
int comparison = accountOne.compareTo(accountTwo);
|
||||
assertThat(comparison).isNegative();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package com.baeldung.compareto;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class FootballPlayerUnitTest {
|
||||
|
||||
@Test
|
||||
public void givenInconsistentCompareToAndEqualsImpl_whenUsingSortedSet_thenSomeElementsAreNotAdded() {
|
||||
FootballPlayer messi = new FootballPlayer("Messi", 800);
|
||||
FootballPlayer ronaldo = new FootballPlayer("Ronaldo", 800);
|
||||
|
||||
TreeSet<FootballPlayer> set = new TreeSet<>();
|
||||
set.add(messi);
|
||||
set.add(ronaldo);
|
||||
|
||||
assertThat(set).hasSize(1);
|
||||
assertThat(set).doesNotContain(ronaldo);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenCompareToImpl_whenUsingCustomComparator_thenComparatorLogicIsApplied() {
|
||||
FootballPlayer ronaldo = new FootballPlayer("Ronaldo", 900);
|
||||
FootballPlayer messi = new FootballPlayer("Messi", 800);
|
||||
FootballPlayer modric = new FootballPlayer("Modric", 100);
|
||||
|
||||
List<FootballPlayer> players = Arrays.asList(ronaldo, messi, modric);
|
||||
Comparator<FootballPlayer> nameComparator = Comparator.comparing(FootballPlayer::getName);
|
||||
Collections.sort(players, nameComparator);
|
||||
|
||||
assertThat(players).containsExactly(messi, modric, ronaldo);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenCompareToImpl_whenSavingElementsInTreeMap_thenKeysAreSortedUsingCompareTo() {
|
||||
FootballPlayer ronaldo = new FootballPlayer("Ronaldo", 900);
|
||||
FootballPlayer messi = new FootballPlayer("Messi", 800);
|
||||
FootballPlayer modric = new FootballPlayer("Modric", 100);
|
||||
|
||||
Map<FootballPlayer, String> players = new TreeMap<>();
|
||||
players.put(ronaldo, "forward");
|
||||
players.put(messi, "forward");
|
||||
players.put(modric, "midfielder");
|
||||
|
||||
assertThat(players.keySet()).containsExactly(modric, messi, ronaldo);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package com.baeldung.compareto;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
|
||||
public class HandballPlayerUnitTest {
|
||||
|
||||
@Test
|
||||
public void givenComparableIsNotImplemented_whenSortingArray_thenExceptionIsThrown() {
|
||||
HandballPlayer duvnjak = new HandballPlayer("Duvnjak", 197);
|
||||
HandballPlayer hansen = new HandballPlayer("Hansen", 196);
|
||||
|
||||
HandballPlayer[] players = new HandballPlayer[] {duvnjak, hansen};
|
||||
|
||||
assertThatExceptionOfType(ClassCastException.class).isThrownBy(() -> Arrays.sort(players));
|
||||
}
|
||||
|
||||
}
|
|
@ -7,3 +7,4 @@ This module contains articles about generics in Java
|
|||
- [Type Erasure in Java Explained](https://www.baeldung.com/java-type-erasure)
|
||||
- [Raw Types in Java](https://www.baeldung.com/raw-types-java)
|
||||
- [Super Type Tokens in Java Generics](https://www.baeldung.com/java-super-type-tokens)
|
||||
- [Java Warning “unchecked conversion”](https://www.baeldung.com/java-unchecked-conversion)
|
||||
|
|
|
@ -13,4 +13,32 @@
|
|||
<name>core-java-lang-oop-generics</name>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>${maven-compiler-plugin.version}</version>
|
||||
<configuration>
|
||||
<source>${maven.compiler.source}</source>
|
||||
<target>${maven.compiler.target}</target>
|
||||
<compilerArguments>
|
||||
<Xlint:unchecked/>
|
||||
</compilerArguments>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<properties>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,45 @@
|
|||
package com.baeldung.uncheckedconversion;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
public class UncheckedConversion {
|
||||
public static List getRawList() {
|
||||
List result = new ArrayList();
|
||||
result.add("I am the 1st String.");
|
||||
result.add("I am the 2nd String.");
|
||||
result.add("I am the 3rd String.");
|
||||
return result;
|
||||
}
|
||||
|
||||
public static List getRawListWithMixedTypes() {
|
||||
List result = new ArrayList();
|
||||
result.add("I am the 1st String.");
|
||||
result.add("I am the 2nd String.");
|
||||
result.add("I am the 3rd String.");
|
||||
result.add(new Date());
|
||||
return result;
|
||||
}
|
||||
|
||||
public static <T> List<T> castList(Class<? extends T> clazz, Collection<?> rawCollection) {
|
||||
List<T> result = new ArrayList<>(rawCollection.size());
|
||||
for (Object o : rawCollection) {
|
||||
try {
|
||||
result.add(clazz.cast(o));
|
||||
} catch (ClassCastException e) {
|
||||
// log the exception or other error handling
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static <T> List<T> castList2(Class<? extends T> clazz, Collection<?> rawCollection) throws ClassCastException {
|
||||
List<T> result = new ArrayList<>(rawCollection.size());
|
||||
for (Object o : rawCollection) {
|
||||
result.add(clazz.cast(o));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package com.baeldung.uncheckedconversion;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class UncheckedConversionUnitTest {
|
||||
|
||||
@Test
|
||||
public void givenRawList_whenAssignToTypedList_shouldHaveCompilerWarning() {
|
||||
List<String> fromRawList = UncheckedConversion.getRawList();
|
||||
Assert.assertEquals(3, fromRawList.size());
|
||||
Assert.assertEquals("I am the 1st String.", fromRawList.get(0));
|
||||
}
|
||||
|
||||
@Test(expected = ClassCastException.class)
|
||||
public void givenRawList_whenListHasMixedType_shouldThrowClassCastException() {
|
||||
List<String> fromRawList = UncheckedConversion.getRawListWithMixedTypes();
|
||||
Assert.assertEquals(4, fromRawList.size());
|
||||
Assert.assertFalse(fromRawList.get(3).endsWith("String."));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenRawList_whenAssignToTypedListAfterCallingCastList_shouldOnlyHaveElementsWithExpectedType() {
|
||||
List rawList = UncheckedConversion.getRawListWithMixedTypes();
|
||||
List<String> strList = UncheckedConversion.castList(String.class, rawList);
|
||||
Assert.assertEquals(4, rawList.size());
|
||||
Assert.assertEquals("One element with the wrong type has been filtered out.", 3, strList.size());
|
||||
Assert.assertTrue(strList.stream().allMatch(el -> el.endsWith("String.")));
|
||||
}
|
||||
|
||||
@Test(expected = ClassCastException.class)
|
||||
public void givenRawListWithWrongType_whenAssignToTypedListAfterCallingCastList2_shouldThrowException() {
|
||||
List rawList = UncheckedConversion.getRawListWithMixedTypes();
|
||||
UncheckedConversion.castList2(String.class, rawList);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
package com.baeldung.reflection.check.abstractclass;
|
||||
|
||||
public interface InterfaceExample {
|
||||
}
|
|
@ -1,16 +1,36 @@
|
|||
package com.baeldung.reflection.check.abstractclass;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Date;
|
||||
|
||||
class AbstractExampleUnitTest {
|
||||
|
||||
@Test
|
||||
void givenAbstractClass_whenCheckModifierIsAbstract_thenTrue() throws Exception {
|
||||
void givenAbstractClass_whenCheckModifierIsAbstract_thenTrue() {
|
||||
Class<AbstractExample> clazz = AbstractExample.class;
|
||||
Assertions.assertTrue(Modifier.isAbstract(clazz.getModifiers()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenInterface_whenCheckModifierIsAbstract_thenTrue() {
|
||||
Class<InterfaceExample> clazz = InterfaceExample.class;
|
||||
Assertions.assertTrue(Modifier.isAbstract(clazz.getModifiers()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenAbstractClass_whenCheckIsAbstractClass_thenTrue() {
|
||||
Class<AbstractExample> clazz = AbstractExample.class;
|
||||
int mod = clazz.getModifiers();
|
||||
Assertions.assertTrue(Modifier.isAbstract(mod) && !Modifier.isInterface(mod));
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenConcreteClass_whenCheckIsAbstractClass_thenFalse() {
|
||||
Class<Date> clazz = Date.class;
|
||||
int mod = clazz.getModifiers();
|
||||
Assertions.assertFalse(Modifier.isAbstract(mod) && !Modifier.isInterface(mod));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
package com.baeldung.egd;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
|
||||
/**
|
||||
* JavaSecurityEgdTester - run this with JVM parameter java.security.egd, e.g.:
|
||||
* java -Djava.security.egd=file:/dev/urandom -cp . com.baeldung.egd.JavaSecurityEgdTester
|
||||
*/
|
||||
public class JavaSecurityEgdTester {
|
||||
public static final double NANOSECS = 1000000000.0;
|
||||
public static final String JAVA_SECURITY_EGD = "java.security.egd";
|
||||
|
||||
public static void main(String[] args) {
|
||||
SecureRandom secureRandom = new SecureRandom();
|
||||
long start = System.nanoTime();
|
||||
byte[] randomBytes = new byte[256];
|
||||
secureRandom.nextBytes(randomBytes);
|
||||
double duration = (System.nanoTime() - start) / NANOSECS;
|
||||
|
||||
String message = String.format("java.security.egd=%s took %.3f seconds and used the %s algorithm", System.getProperty(JAVA_SECURITY_EGD), duration, secureRandom.getAlgorithm());
|
||||
System.out.println(message);
|
||||
}
|
||||
}
|
|
@ -2,3 +2,4 @@
|
|||
|
||||
- [Java Map With Case-Insensitive Keys](https://www.baeldung.com/java-map-with-case-insensitive-keys)
|
||||
- [Using a Byte Array as Map Key in Java](https://www.baeldung.com/java-map-key-byte-array)
|
||||
- [Using the Map.Entry Java Class](https://www.baeldung.com/java-map-entry)
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
package com.baeldung.map.entry;
|
||||
|
||||
public class Book {
|
||||
private String title;
|
||||
private String author;
|
||||
|
||||
public Book(String title, String author) {
|
||||
this.title = title;
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
public void setAuthor(String author) {
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Book{" +
|
||||
"title='" + title + '\'' +
|
||||
", author='" + author + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package com.baeldung.map.entry;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class MapEntryEfficiencyExample {
|
||||
|
||||
public static void main(String[] args) {
|
||||
MapEntryEfficiencyExample mapEntryEfficiencyExample = new MapEntryEfficiencyExample();
|
||||
Map<String, String> map = new HashMap<>();
|
||||
|
||||
map.put("Robert C. Martin", "Clean Code");
|
||||
map.put("Joshua Bloch", "Effective Java");
|
||||
|
||||
System.out.println("Iterating Using Map.KeySet - 2 operations");
|
||||
mapEntryEfficiencyExample.usingKeySet(map);
|
||||
|
||||
System.out.println("Iterating Using Map.Entry - 1 operation");
|
||||
mapEntryEfficiencyExample.usingEntrySet(map);
|
||||
|
||||
}
|
||||
|
||||
public void usingKeySet(Map<String, String> bookMap) {
|
||||
for (String key : bookMap.keySet()) {
|
||||
System.out.println("key: " + key + " value: " + bookMap.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
public void usingEntrySet(Map<String, String> bookMap) {
|
||||
for (Map.Entry<String, String> book: bookMap.entrySet()) {
|
||||
System.out.println("key: " + book.getKey() + " value: " + book.getValue());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package com.baeldung.map.entry;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class MapEntryTupleExample {
|
||||
|
||||
public static void main(String[] args) {
|
||||
Map.Entry<String, Book> tuple1;
|
||||
Map.Entry<String, Book> tuple2;
|
||||
Map.Entry<String, Book> tuple3;
|
||||
|
||||
tuple1 = new AbstractMap.SimpleEntry<>("9780134685991", new Book("Effective Java 3d Edition", "Joshua Bloch"));
|
||||
tuple2 = new AbstractMap.SimpleEntry<>("9780132350884", new Book("Clean Code", "Robert C Martin"));
|
||||
tuple3 = new AbstractMap.SimpleEntry<>("9780132350884", new Book("Clean Code", "Robert C Martin"));
|
||||
|
||||
List<Map.Entry<String, Book>> orderedTuples = new ArrayList<>();
|
||||
orderedTuples.add(tuple1);
|
||||
orderedTuples.add(tuple2);
|
||||
orderedTuples.add(tuple3);
|
||||
|
||||
for (Map.Entry<String, Book> tuple : orderedTuples) {
|
||||
System.out.println("key: " + tuple.getKey() + " value: " + tuple.getValue());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package com.baeldung.map.entry;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class MapEntryUnitTest {
|
||||
|
||||
@Test
|
||||
public void givenSimpleEntryList_whenAddDuplicateKey_thenDoesNotOverwriteExistingKey() {
|
||||
List<Map.Entry<String, Book>> orderedTuples = new ArrayList<>();
|
||||
orderedTuples.add(new AbstractMap.SimpleEntry<>("9780134685991", new Book("Effective Java 3d Edition", "Joshua Bloch")));
|
||||
orderedTuples.add(new AbstractMap.SimpleEntry<>("9780132350884", new Book("Clean Code", "Robert C Martin")));
|
||||
orderedTuples.add(new AbstractMap.SimpleEntry<>("9780132350884", new Book("Clean Code", "Robert C Martin")));
|
||||
|
||||
assertEquals(3, orderedTuples.size());
|
||||
assertEquals("9780134685991", orderedTuples.get(0).getKey());
|
||||
assertEquals("9780132350884", orderedTuples.get(1).getKey());
|
||||
assertEquals("9780132350884", orderedTuples.get(2).getKey());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenRegularMap_whenAddDuplicateKey_thenOverwritesExistingKey() {
|
||||
Map<String, Book> entries = new HashMap<>();
|
||||
entries.put("9780134685991", new Book("Effective Java 3d Edition", "Joshua Bloch"));
|
||||
entries.put("9780132350884", new Book("Clean Code", "Robert C Martin"));
|
||||
entries.put("9780132350884", new Book("Clean Code", "Robert C Martin"));
|
||||
|
||||
assertEquals(2, entries.size());
|
||||
}
|
||||
}
|
|
@ -120,7 +120,7 @@
|
|||
<httpclient.version>4.5.3</httpclient.version>
|
||||
<!-- <jackson.version>2.9.8</jackson.version>-->
|
||||
<assertj.version>3.6.2</assertj.version>
|
||||
<com.squareup.okhttp3.version>3.14.2</com.squareup.okhttp3.version>
|
||||
<com.squareup.okhttp3.version>4.9.1</com.squareup.okhttp3.version>
|
||||
<googleclient.version>1.23.0</googleclient.version>
|
||||
<async.http.client.version>2.2.0</async.http.client.version>
|
||||
<retrofit.version>2.3.0</retrofit.version>
|
||||
|
|
|
@ -6,6 +6,7 @@ This module contains articles about performance testing.
|
|||
|
||||
- [Performance of Java Mapping Frameworks](https://www.baeldung.com/java-performance-mapping-frameworks)
|
||||
- [Performance Effects of Exceptions in Java](https://www.baeldung.com/java-exceptions-performance)
|
||||
- [Is Java a Compiled or Interpreted Language?](https://www.baeldung.com/java-compiled-interpreted)
|
||||
|
||||
### Running
|
||||
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
package com.baeldung.zoneddatetime.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.data.mongodb.config.AbstractMongoClientConfiguration;
|
||||
import org.springframework.data.mongodb.core.convert.MongoCustomConversions;
|
||||
|
@ -13,12 +10,7 @@ import org.springframework.data.mongodb.repository.config.EnableMongoRepositorie
|
|||
|
||||
import com.baeldung.zoneddatetime.converter.ZonedDateTimeReadConverter;
|
||||
import com.baeldung.zoneddatetime.converter.ZonedDateTimeWriteConverter;
|
||||
import com.mongodb.ConnectionString;
|
||||
import com.mongodb.MongoClientSettings;
|
||||
import com.mongodb.client.MongoClient;
|
||||
import com.mongodb.client.MongoClients;
|
||||
|
||||
@Configuration
|
||||
@EnableMongoRepositories(basePackages = { "com.baeldung" })
|
||||
public class MongoConfig extends AbstractMongoClientConfiguration {
|
||||
|
||||
|
@ -29,20 +21,6 @@ public class MongoConfig extends AbstractMongoClientConfiguration {
|
|||
return "test";
|
||||
}
|
||||
|
||||
@Override
|
||||
public MongoClient mongoClient() {
|
||||
final ConnectionString connectionString = new ConnectionString("mongodb://localhost:27017/test");
|
||||
final MongoClientSettings mongoClientSettings = MongoClientSettings.builder()
|
||||
.applyConnectionString(connectionString)
|
||||
.build();
|
||||
return MongoClients.create(mongoClientSettings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getMappingBasePackages() {
|
||||
return Collections.singleton("com.baeldung");
|
||||
}
|
||||
|
||||
@Override
|
||||
public MongoCustomConversions customConversions() {
|
||||
converters.add(new ZonedDateTimeReadConverter());
|
||||
|
|
|
@ -24,8 +24,8 @@
|
|||
<constructor-arg ref="mongoConverter" />
|
||||
</bean>
|
||||
|
||||
<mongo:mapping-converter id="mongoConverter" base-package="com.baeldung.converter">
|
||||
<mongo:custom-converters base-package="com.baeldung.converter" />
|
||||
<mongo:mapping-converter id="mongoConverter" base-package="com.baeldung.zoneddatetime.converter">
|
||||
<mongo:custom-converters base-package="com.baeldung.zoneddatetime.converter" />
|
||||
</mongo:mapping-converter>
|
||||
|
||||
</beans>
|
|
@ -11,3 +11,4 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring
|
|||
- [Logging Spring WebClient Calls](https://www.baeldung.com/spring-log-webclient-calls)
|
||||
- [Mocking a WebClient in Spring](https://www.baeldung.com/spring-mocking-webclient)
|
||||
- [Spring WebClient Filters](https://www.baeldung.com/spring-webclient-filters)
|
||||
- [Get List of JSON Objects with WebClient](https://www.baeldung.com/spring-webclient-json-list)
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
package com.baeldung.webclient.json;
|
||||
|
||||
import com.baeldung.webclient.json.model.Book;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ReaderConsumerService {
|
||||
|
||||
List<Book> processReaderDataFromObjectArray();
|
||||
|
||||
List<Book> processReaderDataFromReaderArray();
|
||||
|
||||
List<Book> processReaderDataFromReaderList();
|
||||
|
||||
List<String> processNestedReaderDataFromReaderArray();
|
||||
|
||||
List<String> processNestedReaderDataFromReaderList();
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
package com.baeldung.webclient.json;
|
||||
|
||||
import com.baeldung.webclient.json.model.Book;
|
||||
import com.baeldung.webclient.json.model.Reader;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ReaderConsumerServiceImpl implements ReaderConsumerService {
|
||||
|
||||
private final WebClient webClient;
|
||||
private static final ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
public ReaderConsumerServiceImpl(WebClient webClient) {
|
||||
this.webClient = webClient;
|
||||
}
|
||||
@Override
|
||||
public List<Book> processReaderDataFromObjectArray() {
|
||||
Mono<Object[]> response = webClient.get()
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.retrieve()
|
||||
.bodyToMono(Object[].class).log();
|
||||
Object[] objects = response.block();
|
||||
return Arrays.stream(objects)
|
||||
.map(object -> mapper.convertValue(object, Reader.class))
|
||||
.map(Reader::getFavouriteBook)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Book> processReaderDataFromReaderArray() {
|
||||
Mono<Reader[]> response =
|
||||
webClient.get()
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.retrieve()
|
||||
.bodyToMono(Reader[].class).log();
|
||||
|
||||
Reader[] readers = response.block();
|
||||
return Arrays.stream(readers)
|
||||
.map(Reader::getFavouriteBook)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Book> processReaderDataFromReaderList() {
|
||||
Mono<List<Reader>> response = webClient.get()
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.retrieve()
|
||||
.bodyToMono(new ParameterizedTypeReference<List<Reader>>() {});
|
||||
List<Reader> readers = response.block();
|
||||
|
||||
return readers.stream()
|
||||
.map(Reader::getFavouriteBook)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> processNestedReaderDataFromReaderArray() {
|
||||
Mono<Reader[]> response = webClient.get()
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.retrieve()
|
||||
.bodyToMono(Reader[].class).log();
|
||||
Reader[] readers = response.block();
|
||||
|
||||
return Arrays.stream(readers)
|
||||
.flatMap(reader -> reader.getBooksRead().stream())
|
||||
.map(Book::getAuthor)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> processNestedReaderDataFromReaderList() {
|
||||
Mono<List<Reader>> response = webClient.get()
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.retrieve()
|
||||
.bodyToMono(new ParameterizedTypeReference<List<Reader>>() {});
|
||||
|
||||
List<Reader> readers = response.block();
|
||||
return readers.stream()
|
||||
.flatMap(reader -> reader.getBooksRead().stream())
|
||||
.map(Book::getAuthor)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package com.baeldung.webclient.json.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class Book {
|
||||
private final String author;
|
||||
private final String title;
|
||||
|
||||
@JsonCreator
|
||||
public Book(
|
||||
@JsonProperty("author") String author,
|
||||
@JsonProperty("title") String title) {
|
||||
this.author = author;
|
||||
this.title = title;
|
||||
}
|
||||
public String getAuthor() {
|
||||
return this.author;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package com.baeldung.webclient.json.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class Reader {
|
||||
private final int id;
|
||||
private final String name;
|
||||
private final Book favouriteBook;
|
||||
private final List<Book> booksRead;
|
||||
|
||||
@JsonCreator
|
||||
public Reader(
|
||||
@JsonProperty("id") int id,
|
||||
@JsonProperty("name") String name,
|
||||
@JsonProperty("favouriteBook") Book favouriteBook,
|
||||
@JsonProperty("booksRead") List<Book> booksRead) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.favouriteBook = favouriteBook;
|
||||
this.booksRead =booksRead;
|
||||
}
|
||||
|
||||
public Book getFavouriteBook() {
|
||||
return favouriteBook;
|
||||
}
|
||||
|
||||
public List<Book> getBooksRead() { return booksRead; }
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
package com.baeldung.webclient.json;
|
||||
|
||||
import com.baeldung.webclient.json.model.Book;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.reactive.function.client.ClientResponse;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.CoreMatchers.hasItems;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.Matchers.hasProperty;
|
||||
|
||||
public class ReaderConsumerServiceImplUnitTest {
|
||||
|
||||
private static String READER_JSON = "[{\"id\":1,\"name\":\"reader1\",\"favouriteBook\":{\"author\":\"Milan Kundera\",\"title\":\"The Unbearable Lightness of Being\"}," +
|
||||
"\"booksRead\":[{\"author\":\"Charles Dickens\",\"title\":\"Oliver Twist\"},{\"author\":\"Milan Kundera\",\"title\":\"The Unbearable Lightness of Being\"}]}," +
|
||||
"{\"id\":2,\"name\":\"reader2\",\"favouriteBook\":{\"author\":\"Douglas Adams\",\"title\":\"The Hitchhiker\'s Guide to the Galaxy\"}," +
|
||||
"\"booksRead\":[{\"author\":\"J.R.R. Tolkien\",\"title\":\"Lord of the Rings\"}, " +
|
||||
"{\"author\":\"Douglas Adams\",\"title\":\"The Hitchhiker\'s Guide to the Galaxy\"}]}]";
|
||||
|
||||
private static String BASE_URL = "http://localhost:8080/readers";
|
||||
|
||||
WebClient webClientMock = WebClient.builder().baseUrl(BASE_URL)
|
||||
.exchangeFunction(clientRequest -> Mono.just(ClientResponse.create(HttpStatus.OK)
|
||||
.header("content-type", "application/json")
|
||||
.body(READER_JSON)
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
private final ReaderConsumerService tested = new ReaderConsumerServiceImpl(webClientMock);
|
||||
|
||||
@Test
|
||||
void when_processReaderDataFromObjectArray_then_OK() {
|
||||
String expectedAuthor1 = "Milan Kundera";
|
||||
String expectedAuthor2 = "Douglas Adams";
|
||||
List<Book> actual = tested.processReaderDataFromObjectArray();
|
||||
assertThat(actual, hasItems(hasProperty("author", is(expectedAuthor1)),
|
||||
hasProperty("author", is(expectedAuthor2))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void when_processReaderDataFromReaderArray_then_OK() {
|
||||
String expectedAuthor1 = "Milan Kundera";
|
||||
String expectedAuthor2 = "Douglas Adams";
|
||||
List<Book> actual = tested.processReaderDataFromReaderArray();
|
||||
assertThat(actual, hasItems(hasProperty("author", is(expectedAuthor1)),
|
||||
hasProperty("author", is(expectedAuthor2))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void when_processReaderDataFromReaderList_then_OK() {
|
||||
String expectedAuthor1 = "Milan Kundera";
|
||||
String expectedAuthor2 = "Douglas Adams";
|
||||
List<Book> actual = tested.processReaderDataFromReaderList();
|
||||
assertThat(actual, hasItems(hasProperty("author", is(expectedAuthor1)),
|
||||
hasProperty("author", is(expectedAuthor2))));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void when_processNestedReaderDataFromReaderArray_then_OK() {
|
||||
List<String> expected = Arrays.asList(
|
||||
"Milan Kundera",
|
||||
"Charles Dickens",
|
||||
"J.R.R. Tolkien",
|
||||
"Douglas Adams");
|
||||
|
||||
List<String> actual = tested.processNestedReaderDataFromReaderArray();
|
||||
assertThat(actual, hasItems(expected.get(0), expected.get(1), expected.get(2), expected.get(3)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void when_processNestedReaderDataFromReaderList_then_OK() {
|
||||
List<String> expected = Arrays.asList(
|
||||
"Milan Kundera",
|
||||
"Charles Dickens",
|
||||
"J.R.R. Tolkien",
|
||||
"Douglas Adams");
|
||||
|
||||
List<String> actual = tested.processNestedReaderDataFromReaderList();
|
||||
assertThat(actual, hasItems(expected.get(0), expected.get(1), expected.get(2), expected.get(3)));
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
<?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">
|
||||
<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>
|
||||
<artifactId>spring-5-reactive</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
|
@ -73,6 +74,12 @@
|
|||
<artifactId>spring-security-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.projectreactor</groupId>
|
||||
<artifactId>reactor-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Spring WebFlux WebSession -->
|
||||
<dependency>
|
||||
|
|
|
@ -11,7 +11,7 @@ import java.util.concurrent.atomic.AtomicLong;
|
|||
|
||||
import static org.springframework.web.reactive.function.BodyExtractors.toDataBuffers;
|
||||
import static org.springframework.web.reactive.function.BodyExtractors.toFormData;
|
||||
import static org.springframework.web.reactive.function.BodyInserters.fromObject;
|
||||
import static org.springframework.web.reactive.function.BodyInserters.fromValue;
|
||||
import static org.springframework.web.reactive.function.server.ServerResponse.ok;
|
||||
|
||||
public class FormHandler {
|
||||
|
@ -29,7 +29,7 @@ public class FormHandler {
|
|||
Mono<ServerResponse> handleUpload(ServerRequest request) {
|
||||
return request.body(toDataBuffers())
|
||||
.collectList()
|
||||
.flatMap(dataBuffers -> ok().body(fromObject(extractData(dataBuffers).toString())));
|
||||
.flatMap(dataBuffers -> ok().body(fromValue(extractData(dataBuffers).toString())));
|
||||
}
|
||||
|
||||
private AtomicLong extractData(List<DataBuffer> dataBuffers) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package com.baeldung.functional;
|
||||
|
||||
import static org.springframework.web.reactive.function.BodyInserters.fromObject;
|
||||
import static org.springframework.web.reactive.function.BodyInserters.fromValue;
|
||||
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
|
||||
import static org.springframework.web.reactive.function.server.RequestPredicates.POST;
|
||||
import static org.springframework.web.reactive.function.server.RequestPredicates.path;
|
||||
|
@ -44,7 +44,7 @@ public class FunctionalSpringBootApplication {
|
|||
.doOnNext(actors::add)
|
||||
.then(ok().build()));
|
||||
|
||||
return route(GET("/test"), serverRequest -> ok().body(fromObject("helloworld")))
|
||||
return route(GET("/test"), serverRequest -> ok().body(fromValue("helloworld")))
|
||||
.andRoute(POST("/login"), formHandler::handleLogin)
|
||||
.andRoute(POST("/upload"), formHandler::handleUpload)
|
||||
.and(RouterFunctions.resources("/files/**", new ClassPathResource("files/")))
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package com.baeldung.functional;
|
||||
|
||||
import static org.springframework.web.reactive.function.BodyInserters.fromObject;
|
||||
import static org.springframework.web.reactive.function.BodyInserters.fromValue;
|
||||
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
|
||||
import static org.springframework.web.reactive.function.server.RequestPredicates.POST;
|
||||
import static org.springframework.web.reactive.function.server.RequestPredicates.accept;
|
||||
|
@ -42,7 +42,7 @@ public class FunctionalWebApplication {
|
|||
.doOnNext(actors::add)
|
||||
.then(ok().build()));
|
||||
|
||||
return route(GET("/test"), serverRequest -> ok().body(fromObject("helloworld"))).andRoute(POST("/login"), formHandler::handleLogin)
|
||||
return route(GET("/test"), serverRequest -> ok().body(fromValue("helloworld"))).andRoute(POST("/login"), formHandler::handleLogin)
|
||||
.andRoute(POST("/upload"), formHandler::handleUpload)
|
||||
.and(RouterFunctions.resources("/files/**", new ClassPathResource("files/")))
|
||||
.andNest(accept(MediaType.APPLICATION_JSON), restfulRouter)
|
||||
|
|
|
@ -2,7 +2,7 @@ package com.baeldung.functional;
|
|||
|
||||
import static org.springframework.web.reactive.function.BodyExtractors.toDataBuffers;
|
||||
import static org.springframework.web.reactive.function.BodyExtractors.toFormData;
|
||||
import static org.springframework.web.reactive.function.BodyInserters.fromObject;
|
||||
import static org.springframework.web.reactive.function.BodyInserters.fromValue;
|
||||
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
|
||||
import static org.springframework.web.reactive.function.server.RequestPredicates.POST;
|
||||
import static org.springframework.web.reactive.function.server.RequestPredicates.path;
|
||||
|
@ -46,7 +46,7 @@ public class RootServlet extends ServletHttpHandlerAdapter {
|
|||
|
||||
private static RouterFunction<?> routingFunction() {
|
||||
|
||||
return route(GET("/test"), serverRequest -> ok().body(fromObject("helloworld"))).andRoute(POST("/login"), serverRequest -> serverRequest.body(toFormData())
|
||||
return route(GET("/test"), serverRequest -> ok().body(fromValue("helloworld"))).andRoute(POST("/login"), serverRequest -> serverRequest.body(toFormData())
|
||||
.map(MultiValueMap::toSingleValueMap)
|
||||
.map(formData -> {
|
||||
System.out.println("form data: " + formData.toString());
|
||||
|
@ -65,7 +65,7 @@ public class RootServlet extends ServletHttpHandlerAdapter {
|
|||
dataBuffers.forEach(d -> atomicLong.addAndGet(d.asByteBuffer()
|
||||
.array().length));
|
||||
System.out.println("data length:" + atomicLong.get());
|
||||
return ok().body(fromObject(atomicLong.toString()))
|
||||
return ok().body(fromValue(atomicLong.toString()))
|
||||
.block();
|
||||
}))
|
||||
.and(RouterFunctions.resources("/files/**", new ClassPathResource("files/")))
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
package com.baeldung.reactive.errorhandling;
|
||||
|
||||
import java.util.Map;
|
||||
import org.springframework.boot.autoconfigure.web.ResourceProperties;
|
||||
|
||||
import org.springframework.boot.autoconfigure.web.WebProperties;
|
||||
import org.springframework.boot.autoconfigure.web.reactive.error.AbstractErrorWebExceptionHandler;
|
||||
import org.springframework.boot.web.error.ErrorAttributeOptions;
|
||||
import org.springframework.boot.web.reactive.error.ErrorAttributes;
|
||||
|
@ -18,6 +19,7 @@ import org.springframework.web.reactive.function.server.RouterFunction;
|
|||
import org.springframework.web.reactive.function.server.RouterFunctions;
|
||||
import org.springframework.web.reactive.function.server.ServerRequest;
|
||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@Component
|
||||
|
@ -26,7 +28,7 @@ public class GlobalErrorWebExceptionHandler extends AbstractErrorWebExceptionHan
|
|||
|
||||
public GlobalErrorWebExceptionHandler(GlobalErrorAttributes g, ApplicationContext applicationContext,
|
||||
ServerCodecConfigurer serverCodecConfigurer) {
|
||||
super(g, new ResourceProperties(), applicationContext);
|
||||
super(g, new WebProperties.Resources(), applicationContext);
|
||||
super.setMessageWriters(serverCodecConfigurer.getWriters());
|
||||
super.setMessageReaders(serverCodecConfigurer.getReaders());
|
||||
}
|
||||
|
@ -41,8 +43,8 @@ public class GlobalErrorWebExceptionHandler extends AbstractErrorWebExceptionHan
|
|||
final Map<String, Object> errorPropertiesMap = getErrorAttributes(request, ErrorAttributeOptions.defaults());
|
||||
|
||||
return ServerResponse.status(HttpStatus.BAD_REQUEST)
|
||||
.contentType(MediaType.APPLICATION_JSON_UTF8)
|
||||
.body(BodyInserters.fromObject(errorPropertiesMap));
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.body(BodyInserters.fromValue(errorPropertiesMap));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ public class Handler1 {
|
|||
return sayHello(request).onErrorReturn("Hello, Stranger")
|
||||
.flatMap(s -> ServerResponse.ok()
|
||||
.contentType(MediaType.TEXT_PLAIN)
|
||||
.syncBody(s));
|
||||
.bodyValue(s));
|
||||
}
|
||||
|
||||
private Mono<String> sayHello(ServerRequest request) {
|
||||
|
|
|
@ -15,11 +15,11 @@ public Mono<ServerResponse> handleRequest2(ServerRequest request) {
|
|||
sayHello(request)
|
||||
.flatMap(s -> ServerResponse.ok()
|
||||
.contentType(MediaType.TEXT_PLAIN)
|
||||
.syncBody(s))
|
||||
.bodyValue(s))
|
||||
.onErrorResume(e -> sayHelloFallback()
|
||||
.flatMap(s -> ServerResponse.ok()
|
||||
.contentType(MediaType.TEXT_PLAIN)
|
||||
.syncBody(s)));
|
||||
.bodyValue(s)));
|
||||
}
|
||||
|
||||
private Mono<String> sayHello(ServerRequest request) {
|
||||
|
|
|
@ -15,11 +15,11 @@ public class Handler3 {
|
|||
sayHello(request)
|
||||
.flatMap(s -> ServerResponse.ok()
|
||||
.contentType(MediaType.TEXT_PLAIN)
|
||||
.syncBody(s))
|
||||
.bodyValue(s))
|
||||
.onErrorResume(e -> (Mono.just("Hi, I looked around for your name but found: " +
|
||||
e.getMessage())).flatMap(s -> ServerResponse.ok()
|
||||
.contentType(MediaType.TEXT_PLAIN)
|
||||
.syncBody(s)));
|
||||
.bodyValue(s)));
|
||||
}
|
||||
|
||||
private Mono<String> sayHello(ServerRequest request) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package com.baeldung.reactive.urlmatch;
|
||||
|
||||
import static org.springframework.web.reactive.function.BodyInserters.fromObject;
|
||||
import static org.springframework.web.reactive.function.BodyInserters.fromValue;
|
||||
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
|
||||
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
|
||||
import static org.springframework.web.reactive.function.server.RouterFunctions.toHttpHandler;
|
||||
|
@ -24,10 +24,10 @@ public class ExploreSpring5URLPatternUsingRouterFunctions {
|
|||
|
||||
private RouterFunction<ServerResponse> routingFunction() {
|
||||
|
||||
return route(GET("/p?ths"), serverRequest -> ok().body(fromObject("/p?ths"))).andRoute(GET("/test/{*id}"), serverRequest -> ok().body(fromObject(serverRequest.pathVariable("id"))))
|
||||
.andRoute(GET("/*card"), serverRequest -> ok().body(fromObject("/*card path was accessed")))
|
||||
.andRoute(GET("/{var1}_{var2}"), serverRequest -> ok().body(fromObject(serverRequest.pathVariable("var1") + " , " + serverRequest.pathVariable("var2"))))
|
||||
.andRoute(GET("/{baeldung:[a-z]+}"), serverRequest -> ok().body(fromObject("/{baeldung:[a-z]+} was accessed and baeldung=" + serverRequest.pathVariable("baeldung"))))
|
||||
return route(GET("/p?ths"), serverRequest -> ok().body(fromValue("/p?ths"))).andRoute(GET("/test/{*id}"), serverRequest -> ok().body(fromValue(serverRequest.pathVariable("id"))))
|
||||
.andRoute(GET("/*card"), serverRequest -> ok().body(fromValue("/*card path was accessed")))
|
||||
.andRoute(GET("/{var1}_{var2}"), serverRequest -> ok().body(fromValue(serverRequest.pathVariable("var1") + " , " + serverRequest.pathVariable("var2"))))
|
||||
.andRoute(GET("/{baeldung:[a-z]+}"), serverRequest -> ok().body(fromValue("/{baeldung:[a-z]+} was accessed and baeldung=" + serverRequest.pathVariable("baeldung"))))
|
||||
.and(RouterFunctions.resources("/files/{*filepaths}", new ClassPathResource("files/")));
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ import java.util.concurrent.atomic.AtomicLong;
|
|||
|
||||
import static org.springframework.web.reactive.function.BodyExtractors.toDataBuffers;
|
||||
import static org.springframework.web.reactive.function.BodyExtractors.toFormData;
|
||||
import static org.springframework.web.reactive.function.BodyInserters.fromObject;
|
||||
import static org.springframework.web.reactive.function.BodyInserters.fromValue;
|
||||
import static org.springframework.web.reactive.function.server.ServerResponse.ok;
|
||||
|
||||
public class FormHandler {
|
||||
|
@ -29,7 +29,7 @@ public class FormHandler {
|
|||
Mono<ServerResponse> handleUpload(ServerRequest request) {
|
||||
return request.body(toDataBuffers())
|
||||
.collectList()
|
||||
.flatMap(dataBuffers -> ok().body(fromObject(extractData(dataBuffers).toString())));
|
||||
.flatMap(dataBuffers -> ok().body(fromValue(extractData(dataBuffers).toString())));
|
||||
}
|
||||
|
||||
private AtomicLong extractData(List<DataBuffer> dataBuffers) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package com.baeldung.reactive.urlmatch;
|
||||
|
||||
import static org.springframework.web.reactive.function.BodyInserters.fromObject;
|
||||
import static org.springframework.web.reactive.function.BodyInserters.fromValue;
|
||||
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
|
||||
import static org.springframework.web.reactive.function.server.RequestPredicates.POST;
|
||||
import static org.springframework.web.reactive.function.server.RequestPredicates.path;
|
||||
|
@ -40,7 +40,7 @@ public class FunctionalWebApplication {
|
|||
.doOnNext(actors::add)
|
||||
.then(ok().build()));
|
||||
|
||||
return route(GET("/test"), serverRequest -> ok().body(fromObject("helloworld"))).andRoute(POST("/login"), formHandler::handleLogin)
|
||||
return route(GET("/test"), serverRequest -> ok().body(fromValue("helloworld"))).andRoute(POST("/login"), formHandler::handleLogin)
|
||||
.andRoute(POST("/upload"), formHandler::handleUpload)
|
||||
.and(RouterFunctions.resources("/files/**", new ClassPathResource("files/")))
|
||||
.andNest(path("/actor"), restfulRouter)
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
package com.baeldung.web.reactive.client;
|
||||
|
||||
public class Foo {
|
||||
|
||||
private String name;
|
||||
|
||||
public Foo() {
|
||||
super();
|
||||
}
|
||||
|
||||
public Foo(String name) {
|
||||
super();
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
}
|
|
@ -2,9 +2,10 @@ package com.baeldung.web.reactive.client;
|
|||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration;
|
||||
|
||||
@SpringBootApplication
|
||||
public class WebClientApplication{
|
||||
@SpringBootApplication(exclude = { ReactiveSecurityAutoConfiguration.class })
|
||||
public class WebClientApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(WebClientApplication.class, args);
|
||||
|
|
|
@ -1,36 +1,18 @@
|
|||
package com.baeldung.web.reactive.client;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.charset.Charset;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.reactivestreams.Publisher;
|
||||
import org.reactivestreams.Subscriber;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ReactiveHttpOutputMessage;
|
||||
import org.springframework.http.client.reactive.ClientHttpRequest;
|
||||
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestPart;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.reactive.function.BodyInserter;
|
||||
import org.springframework.web.reactive.function.BodyInserters;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.handler.timeout.ReadTimeoutHandler;
|
||||
import io.netty.handler.timeout.WriteTimeoutHandler;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.netty.http.client.HttpClient;
|
||||
|
||||
@RestController
|
||||
public class WebClientController {
|
||||
|
@ -43,74 +25,18 @@ public class WebClientController {
|
|||
return response;
|
||||
}
|
||||
|
||||
public void demonstrateWebClient() {
|
||||
// request
|
||||
WebClient.UriSpec<WebClient.RequestBodySpec> request1 = createWebClientWithServerURLAndDefaultValues().method(HttpMethod.POST);
|
||||
WebClient.UriSpec<WebClient.RequestBodySpec> request2 = createWebClientWithServerURLAndDefaultValues().post();
|
||||
|
||||
// request body specifications
|
||||
WebClient.RequestBodySpec uri1 = createWebClientWithServerURLAndDefaultValues().method(HttpMethod.POST)
|
||||
.uri("/resource");
|
||||
WebClient.RequestBodySpec uri2 = createWebClientWithServerURLAndDefaultValues().post()
|
||||
.uri(URI.create("/resource"));
|
||||
|
||||
// request header specification
|
||||
WebClient.RequestHeadersSpec<?> requestSpec1 = uri1.body(BodyInserters.fromPublisher(Mono.just("data"), String.class));
|
||||
WebClient.RequestHeadersSpec<?> requestSpec2 = uri2.body(BodyInserters.fromValue("data"));
|
||||
|
||||
// inserters
|
||||
BodyInserter<Publisher<String>, ReactiveHttpOutputMessage> inserter1 = BodyInserters.fromPublisher(Subscriber::onComplete, String.class);
|
||||
|
||||
LinkedMultiValueMap<String, String> map = new LinkedMultiValueMap<>();
|
||||
map.add("key1", "value1");
|
||||
map.add("key2", "value2");
|
||||
|
||||
BodyInserter<MultiValueMap<String, Object>, ClientHttpRequest> inserter2 = BodyInserters.fromMultipartData(map);
|
||||
BodyInserter<Object, ReactiveHttpOutputMessage> inserter3 = BodyInserters.fromValue(new Object());
|
||||
BodyInserter<String, ReactiveHttpOutputMessage> inserter4 = BodyInserters.fromValue("body");
|
||||
|
||||
// responses
|
||||
WebClient.ResponseSpec response1 = uri1.body(inserter3)
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
|
||||
.accept(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML)
|
||||
.acceptCharset(Charset.forName("UTF-8"))
|
||||
.ifNoneMatch("*")
|
||||
.ifModifiedSince(ZonedDateTime.now())
|
||||
.retrieve();
|
||||
String response2 = uri1.exchangeToMono(response -> response.bodyToMono(String.class))
|
||||
.block();
|
||||
String response3 = uri2.retrieve()
|
||||
.bodyToMono(String.class)
|
||||
.block();
|
||||
WebClient.ResponseSpec response4 = requestSpec2.retrieve();
|
||||
@PostMapping("/resource")
|
||||
public Mono<String> postStringResource(@RequestBody Mono<String> bodyString) {
|
||||
return bodyString.map(body -> "processed-" + body);
|
||||
}
|
||||
|
||||
private WebClient createWebClient() {
|
||||
return WebClient.create();
|
||||
@PostMapping("/resource-foo")
|
||||
public Mono<String> postFooResource(@RequestBody Mono<Foo> bodyFoo) {
|
||||
return bodyFoo.map(foo -> "processedFoo-" + foo.getName());
|
||||
}
|
||||
|
||||
private WebClient createWebClientWithServerURL() {
|
||||
return WebClient.create("http://localhost:8081");
|
||||
@PostMapping(value = "/resource-multipart", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||
public String handleFormUpload(@RequestPart("key1") String value1, @RequestPart("key2") String value2) {
|
||||
return "processed-" + value1 + "-" + value2;
|
||||
}
|
||||
|
||||
private WebClient createWebClientConfiguringTimeout() {
|
||||
HttpClient httpClient = HttpClient.create()
|
||||
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
|
||||
.doOnConnected(conn -> conn.addHandlerLast(new ReadTimeoutHandler(5000, TimeUnit.MILLISECONDS))
|
||||
.addHandlerLast(new WriteTimeoutHandler(5000, TimeUnit.MILLISECONDS)));
|
||||
|
||||
return WebClient.builder()
|
||||
.clientConnector(new ReactorClientHttpConnector(httpClient))
|
||||
.build();
|
||||
}
|
||||
|
||||
private WebClient createWebClientWithServerURLAndDefaultValues() {
|
||||
return WebClient.builder()
|
||||
.baseUrl("http://localhost:8081")
|
||||
.defaultCookie("cookieKey", "cookieValue")
|
||||
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
|
||||
.defaultUriVariables(Collections.singletonMap("url", "http://localhost:8080"))
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,17 +1,15 @@
|
|||
package com.baeldung.functional;
|
||||
|
||||
import static org.springframework.web.reactive.function.BodyInserters.fromObject;
|
||||
import static org.springframework.web.reactive.function.BodyInserters.fromValue;
|
||||
import static org.springframework.web.reactive.function.BodyInserters.fromResource;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.springframework.boot.web.server.WebServer;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.test.context.support.WithMockUser;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
@ -115,7 +113,7 @@ public class FunctionalWebApplicationIntegrationTest {
|
|||
|
||||
client.post()
|
||||
.uri("/actor")
|
||||
.body(fromObject(new Actor("Clint", "Eastwood")))
|
||||
.body(fromValue(new Actor("Clint", "Eastwood")))
|
||||
.exchange()
|
||||
.expectStatus()
|
||||
.isOk();
|
||||
|
|
|
@ -133,7 +133,7 @@ public class ErrorHandlingIntegrationTest {
|
|||
.expectStatus()
|
||||
.isBadRequest()
|
||||
.expectHeader()
|
||||
.contentType(MediaType.APPLICATION_JSON_UTF8)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.expectBody()
|
||||
.jsonPath("$.message")
|
||||
.isNotEmpty()
|
||||
|
@ -164,7 +164,7 @@ public class ErrorHandlingIntegrationTest {
|
|||
.expectStatus()
|
||||
.isBadRequest()
|
||||
.expectHeader()
|
||||
.contentType(MediaType.APPLICATION_JSON_UTF8)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.expectBody()
|
||||
.jsonPath("$.message")
|
||||
.isNotEmpty()
|
||||
|
|
|
@ -0,0 +1,331 @@
|
|||
package com.baeldung.web.client;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Duration;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.reactivestreams.Publisher;
|
||||
import org.reactivestreams.Subscriber;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.core.codec.CodecException;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ReactiveHttpOutputMessage;
|
||||
import org.springframework.http.client.reactive.ClientHttpRequest;
|
||||
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.reactive.function.BodyInserter;
|
||||
import org.springframework.web.reactive.function.BodyInserters;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
import org.springframework.web.reactive.function.client.WebClient.RequestBodySpec;
|
||||
import org.springframework.web.reactive.function.client.WebClient.RequestBodyUriSpec;
|
||||
import org.springframework.web.reactive.function.client.WebClient.RequestHeadersSpec;
|
||||
import org.springframework.web.reactive.function.client.WebClient.RequestHeadersUriSpec;
|
||||
import org.springframework.web.reactive.function.client.WebClient.ResponseSpec;
|
||||
import org.springframework.web.reactive.function.client.WebClientRequestException;
|
||||
|
||||
import com.baeldung.web.reactive.client.Foo;
|
||||
import com.baeldung.web.reactive.client.WebClientApplication;
|
||||
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.handler.timeout.ReadTimeoutHandler;
|
||||
import io.netty.handler.timeout.WriteTimeoutHandler;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.netty.http.client.HttpClient;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
@SpringBootTest(classes = WebClientApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
public class WebClientIntegrationTest {
|
||||
|
||||
@LocalServerPort
|
||||
private int port;
|
||||
|
||||
private static final String BODY_VALUE = "bodyValue";
|
||||
private static final ParameterizedTypeReference<Map<String, String>> MAP_RESPONSE_REF = new ParameterizedTypeReference<Map<String, String>>() {
|
||||
};
|
||||
|
||||
@Test
|
||||
public 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
|
||||
StepVerifier.create(retrieveResponse(client1.post()
|
||||
.uri("http://localhost:" + port + "/resource")))
|
||||
.expectNext("processed-bodyValue")
|
||||
.verifyComplete();
|
||||
StepVerifier.create(retrieveResponse(client2))
|
||||
.expectNext("processed-bodyValue")
|
||||
.verifyComplete();
|
||||
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
|
||||
public void givenDifferentMethodSpecifications_whenUsed_thenObtainExpectedResponse() {
|
||||
// request specification
|
||||
RequestBodyUriSpec uriSpecPost1 = createDefaultClient().method(HttpMethod.POST);
|
||||
RequestBodyUriSpec uriSpecPost2 = createDefaultClient().post();
|
||||
RequestHeadersUriSpec<?> requestGet = createDefaultClient().get();
|
||||
|
||||
// response assertions
|
||||
StepVerifier.create(retrieveResponse(uriSpecPost1))
|
||||
.expectNext("processed-bodyValue")
|
||||
.verifyComplete();
|
||||
StepVerifier.create(retrieveResponse(uriSpecPost2))
|
||||
.expectNext("processed-bodyValue")
|
||||
.verifyComplete();
|
||||
StepVerifier.create(retrieveGetResponse(requestGet))
|
||||
.expectNextMatches(nextMap -> nextMap.get("field")
|
||||
.equals("value"))
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
public 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"));
|
||||
RequestBodySpec bodySpecOverridenBaseUri = createDefaultPostRequest().uri(URI.create("/resource"));
|
||||
RequestBodySpec bodySpecOverridenBaseUri2 = WebClient.builder()
|
||||
.baseUrl("http://localhost:" + port)
|
||||
.build()
|
||||
.post()
|
||||
.uri(URI.create("/resource"));
|
||||
|
||||
// response assertions
|
||||
StepVerifier.create(retrieveResponse(bodySpecUsingString))
|
||||
.expectNext("processed-bodyValue")
|
||||
.verifyComplete();
|
||||
StepVerifier.create(retrieveResponse(bodySpecUsingUriBuilder))
|
||||
.expectNext("processed-bodyValue")
|
||||
.verifyComplete();
|
||||
StepVerifier.create(retrieveResponse(bodySpecusingURI))
|
||||
.expectNext("processed-bodyValue")
|
||||
.verifyComplete();
|
||||
// assert sending request overriding base URI
|
||||
StepVerifier.create(retrieveResponse(bodySpecOverridenBaseUri))
|
||||
.expectErrorMatches(ex -> WebClientRequestException.class.isAssignableFrom(ex.getClass()) && ex.getMessage()
|
||||
.contains("Connection refused"))
|
||||
.verify();
|
||||
StepVerifier.create(retrieveResponse(bodySpecOverridenBaseUri2))
|
||||
.expectErrorMatches(ex -> WebClientRequestException.class.isAssignableFrom(ex.getClass()) && ex.getMessage()
|
||||
.contains("Connection refused"))
|
||||
.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenDifferentBodySpecifications_whenUsed_thenObtainExpectedResponse() {
|
||||
// request body specifications
|
||||
RequestHeadersSpec<?> headersSpecPost1 = createDefaultPostResourceRequest().body(BodyInserters.fromPublisher(Mono.just(BODY_VALUE), String.class));
|
||||
RequestHeadersSpec<?> headersSpecPost2 = createDefaultPostResourceRequest().body(BodyInserters.fromValue(BODY_VALUE));
|
||||
RequestHeadersSpec<?> headersSpecPost3 = createDefaultPostResourceRequest().bodyValue(BODY_VALUE);
|
||||
RequestHeadersSpec<?> headersSpecFooPost = createDefaultPostRequest().uri("/resource-foo")
|
||||
.body(Mono.just(new Foo("fooName")), Foo.class);
|
||||
BodyInserter<Object, ReactiveHttpOutputMessage> inserterPlainObject = BodyInserters.fromValue(new Object());
|
||||
RequestHeadersSpec<?> headersSpecPlainObject = createDefaultPostResourceRequest().body(inserterPlainObject);
|
||||
|
||||
// request body specifications - using other inserter method (multipart request)
|
||||
LinkedMultiValueMap<String, String> map = new LinkedMultiValueMap<>();
|
||||
map.add("key1", "multipartValue1");
|
||||
map.add("key2", "multipartValue2");
|
||||
BodyInserter<MultiValueMap<String, Object>, ClientHttpRequest> inserterMultipart = BodyInserters.fromMultipartData(map);
|
||||
RequestHeadersSpec<?> headersSpecInserterMultipart = createDefaultPostRequest().uri("/resource-multipart")
|
||||
.body(inserterMultipart);
|
||||
|
||||
// response assertions
|
||||
StepVerifier.create(retrieveResponse(headersSpecPost1))
|
||||
.expectNext("processed-bodyValue")
|
||||
.verifyComplete();
|
||||
StepVerifier.create(retrieveResponse(headersSpecPost2))
|
||||
.expectNext("processed-bodyValue")
|
||||
.verifyComplete();
|
||||
StepVerifier.create(retrieveResponse(headersSpecPost3))
|
||||
.expectNext("processed-bodyValue")
|
||||
.verifyComplete();
|
||||
StepVerifier.create(retrieveResponse(headersSpecFooPost))
|
||||
.expectNext("processedFoo-fooName")
|
||||
.verifyComplete();
|
||||
StepVerifier.create(retrieveResponse(headersSpecInserterMultipart))
|
||||
.expectNext("processed-multipartValue1-multipartValue2")
|
||||
.verifyComplete();
|
||||
// assert error plain `new Object()` as request body
|
||||
StepVerifier.create(retrieveResponse(headersSpecPlainObject))
|
||||
.expectError(CodecException.class)
|
||||
.verify();
|
||||
// assert response for request with no body
|
||||
Mono<Map<String, String>> responsePostWithNoBody = createDefaultPostResourceRequest().exchangeToMono(responseHandler -> {
|
||||
assertThat(responseHandler.statusCode()).isEqualTo(HttpStatus.BAD_REQUEST);
|
||||
return responseHandler.bodyToMono(MAP_RESPONSE_REF);
|
||||
});
|
||||
StepVerifier.create(responsePostWithNoBody)
|
||||
.expectNextMatches(nextMap -> nextMap.get("error")
|
||||
.equals("Bad Request"))
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenPostSpecifications_whenHeadersAdded_thenObtainExpectedResponse() {
|
||||
// request header specification
|
||||
RequestHeadersSpec<?> headersSpecInserterStringWithHeaders = createDefaultPostResourceRequestResponse().header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
|
||||
.accept(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML)
|
||||
.acceptCharset(StandardCharsets.UTF_8)
|
||||
.ifNoneMatch("*")
|
||||
.ifModifiedSince(ZonedDateTime.now());
|
||||
|
||||
// response assertions
|
||||
StepVerifier.create(retrieveResponse(headersSpecInserterStringWithHeaders))
|
||||
.expectNext("processed-bodyValue")
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenDifferentResponseSpecifications_whenUsed_thenObtainExpectedResponse() {
|
||||
ResponseSpec responseSpecPostString = createDefaultPostResourceRequestResponse().retrieve();
|
||||
Mono<String> responsePostString = responseSpecPostString.bodyToMono(String.class);
|
||||
Mono<String> responsePostString2 = createDefaultPostResourceRequestResponse().exchangeToMono(response -> {
|
||||
if (response.statusCode()
|
||||
.equals(HttpStatus.OK)) {
|
||||
return response.bodyToMono(String.class);
|
||||
} else if (response.statusCode()
|
||||
.is4xxClientError()) {
|
||||
return Mono.just("Error response");
|
||||
} else {
|
||||
return response.createException()
|
||||
.flatMap(Mono::error);
|
||||
}
|
||||
});
|
||||
Mono<String> responsePostNoBody = createDefaultPostResourceRequest().exchangeToMono(response -> {
|
||||
if (response.statusCode()
|
||||
.equals(HttpStatus.OK)) {
|
||||
return response.bodyToMono(String.class);
|
||||
} else if (response.statusCode()
|
||||
.is4xxClientError()) {
|
||||
return Mono.just("Error response");
|
||||
} else {
|
||||
return response.createException()
|
||||
.flatMap(Mono::error);
|
||||
}
|
||||
});
|
||||
Mono<Map<String, String>> responseGet = createDefaultClient().get()
|
||||
.uri("/resource")
|
||||
.retrieve()
|
||||
.bodyToMono(MAP_RESPONSE_REF);
|
||||
|
||||
// response assertions
|
||||
StepVerifier.create(responsePostString)
|
||||
.expectNext("processed-bodyValue")
|
||||
.verifyComplete();
|
||||
StepVerifier.create(responsePostString2)
|
||||
.expectNext("processed-bodyValue")
|
||||
.verifyComplete();
|
||||
StepVerifier.create(responsePostNoBody)
|
||||
.expectNext("Error response")
|
||||
.verifyComplete();
|
||||
StepVerifier.create(responseGet)
|
||||
.expectNextMatches(nextMap -> nextMap.get("field")
|
||||
.equals("value"))
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenWebClientWithTimeoutConfigurations_whenRequestUsingWronglyConfiguredPublisher_thenObtainTimeout() {
|
||||
HttpClient httpClient = HttpClient.create()
|
||||
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 1000)
|
||||
.responseTimeout(Duration.ofMillis(1000))
|
||||
.doOnConnected(conn -> conn.addHandlerLast(new ReadTimeoutHandler(1000, TimeUnit.MILLISECONDS))
|
||||
.addHandlerLast(new WriteTimeoutHandler(1000, TimeUnit.MILLISECONDS)));
|
||||
|
||||
WebClient timeoutClient = WebClient.builder()
|
||||
.clientConnector(new ReactorClientHttpConnector(httpClient))
|
||||
.build();
|
||||
|
||||
BodyInserter<Publisher<String>, ReactiveHttpOutputMessage> inserterCompleteSuscriber = BodyInserters.fromPublisher(Subscriber::onComplete, String.class);
|
||||
RequestHeadersSpec<?> headersSpecInserterCompleteSuscriber = timeoutClient.post()
|
||||
.uri("/resource")
|
||||
.body(inserterCompleteSuscriber);
|
||||
|
||||
StepVerifier.create(headersSpecInserterCompleteSuscriber.retrieve()
|
||||
.bodyToMono(String.class))
|
||||
.expectTimeout(Duration.ofMillis(2000))
|
||||
.verify();
|
||||
}
|
||||
|
||||
// helper methods to create default instances
|
||||
private WebClient createDefaultClient() {
|
||||
return WebClient.create("http://localhost:" + port);
|
||||
}
|
||||
|
||||
private RequestBodyUriSpec createDefaultPostRequest() {
|
||||
return createDefaultClient().post();
|
||||
}
|
||||
|
||||
private RequestBodySpec createDefaultPostResourceRequest() {
|
||||
return createDefaultPostRequest().uri("/resource");
|
||||
}
|
||||
|
||||
private RequestHeadersSpec<?> createDefaultPostResourceRequestResponse() {
|
||||
return createDefaultPostResourceRequest().bodyValue(BODY_VALUE);
|
||||
}
|
||||
|
||||
// helper methods to retrieve a response based on different steps of the process (specs)
|
||||
private Mono<String> retrieveResponse(WebClient client) {
|
||||
return client.post()
|
||||
.uri("/resource")
|
||||
.bodyValue(BODY_VALUE)
|
||||
.retrieve()
|
||||
.bodyToMono(String.class);
|
||||
}
|
||||
|
||||
private Mono<String> retrieveResponse(RequestBodyUriSpec spec) {
|
||||
return spec.uri("/resource")
|
||||
.bodyValue(BODY_VALUE)
|
||||
.retrieve()
|
||||
.bodyToMono(String.class);
|
||||
}
|
||||
|
||||
private Mono<Map<String, String>> retrieveGetResponse(RequestHeadersUriSpec<?> spec) {
|
||||
return spec.uri("/resource")
|
||||
.retrieve()
|
||||
.bodyToMono(MAP_RESPONSE_REF);
|
||||
}
|
||||
|
||||
private Mono<String> retrieveResponse(RequestBodySpec spec) {
|
||||
return spec.bodyValue(BODY_VALUE)
|
||||
.retrieve()
|
||||
.bodyToMono(String.class);
|
||||
}
|
||||
|
||||
private Mono<String> retrieveResponse(RequestHeadersSpec<?> spec) {
|
||||
return spec.retrieve()
|
||||
.bodyToMono(String.class);
|
||||
}
|
||||
}
|
|
@ -11,3 +11,4 @@ This module contains articles about Spring aspect oriented programming (AOP)
|
|||
- [Introduction to Pointcut Expressions in Spring](https://www.baeldung.com/spring-aop-pointcut-tutorial)
|
||||
- [Introduction to Advice Types in Spring](https://www.baeldung.com/spring-aop-advice-tutorial)
|
||||
- [When Does Java Throw UndeclaredThrowableException?](https://www.baeldung.com/java-undeclaredthrowableexception)
|
||||
- [Get Advised Method Info in Spring AOP](https://www.baeldung.com/spring-aop-get-advised-method-info)
|
||||
|
|
|
@ -62,6 +62,7 @@
|
|||
<module>spring-boot-properties-3</module>
|
||||
<module>spring-boot-property-exp</module>
|
||||
<module>spring-boot-runtime</module>
|
||||
<module>spring-boot-runtime-2</module>
|
||||
<module>spring-boot-security</module>
|
||||
<module>spring-boot-springdoc</module>
|
||||
<module>spring-boot-swagger</module>
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.3.0.RELEASE</version>
|
||||
<version>2.3.2.RELEASE</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
management.health.probes.enabled=true
|
||||
management.endpoint.health.probes.enabled=true
|
||||
management.health.livenessState.enabled=true
|
||||
management.health.readinessState.enabled=true
|
||||
management.endpoint.health.show-details=always
|
||||
management.endpoint.health.status.http-mapping.down=500
|
||||
management.endpoint.health.status.http-mapping.out_of_service=503
|
||||
|
@ -8,4 +10,4 @@ management.endpoint.health.status.http-mapping.warning=500
|
|||
info.app.name=Spring Sample Application
|
||||
info.app.description=This is my first spring boot application G1
|
||||
info.app.version=1.0.0
|
||||
info.java-vendor = ${java.specification.vendor}
|
||||
info.java-vendor = ${java.specification.vendor}
|
||||
|
|
|
@ -10,3 +10,4 @@ This module contains articles about Spring Boot annotations
|
|||
- [Spring Core Annotations](https://www.baeldung.com/spring-core-annotations)
|
||||
- [Spring Bean Annotations](https://www.baeldung.com/spring-bean-annotations)
|
||||
- [Difference Between @ComponentScan and @EnableAutoConfiguration in Spring Boot](https://www.baeldung.com/spring-componentscan-vs-enableautoconfiguration)
|
||||
- [Where Should the Spring @Service Annotation Be Kept?](https://www.baeldung.com/spring-service-annotation-placement)
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
package com.baeldung.annotations.service;
|
||||
|
||||
import com.baeldung.annotations.service.abstracts.AbstractAuthenticationService;
|
||||
import com.baeldung.annotations.service.interfaces.AuthenticationService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class AuthApplication {
|
||||
|
||||
@Autowired
|
||||
private AuthenticationService inMemoryAuthService;
|
||||
|
||||
@Autowired
|
||||
private AbstractAuthenticationService ldapAuthService;
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(AuthApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package com.baeldung.annotations.service.abstracts;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public abstract class AbstractAuthenticationService {
|
||||
|
||||
public boolean authenticate(String username, String password) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.baeldung.annotations.service.concretes;
|
||||
|
||||
import com.baeldung.annotations.service.interfaces.AuthenticationService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class InMemoryAuthenticationService implements AuthenticationService {
|
||||
|
||||
@Override
|
||||
public boolean authenticate(String username, String password) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.baeldung.annotations.service.concretes;
|
||||
|
||||
import com.baeldung.annotations.service.abstracts.AbstractAuthenticationService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class LdapAuthenticationService extends AbstractAuthenticationService {
|
||||
|
||||
@Override
|
||||
public boolean authenticate(String username, String password) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package com.baeldung.annotations.service.interfaces;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public interface AuthenticationService {
|
||||
|
||||
boolean authenticate(String username, String password);
|
||||
|
||||
}
|
|
@ -6,7 +6,7 @@ import static org.junit.Assert.assertFalse;
|
|||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.assertAll;
|
||||
|
||||
public class EmployeeApplicationTest {
|
||||
public class EmployeeApplicationUnitTest {
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withUserConfiguration(EmployeeApplication.class);
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
package com.baeldung.annotations.service;
|
||||
|
||||
import com.baeldung.annotations.service.abstracts.AbstractAuthenticationService;
|
||||
import com.baeldung.annotations.service.config.AbstractsAnnotatedTestConfiguration;
|
||||
import com.baeldung.annotations.service.config.ConcreteClassesAnnotatedTestConfiguration;
|
||||
import com.baeldung.annotations.service.config.InterfacesAnnotatedTestConfiguration;
|
||||
import com.baeldung.annotations.service.interfaces.AuthenticationService;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
|
||||
public class AuthApplicationUnitTest {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner();
|
||||
|
||||
@Test
|
||||
void whenOnlyInterfacesAnnotated_noSuchBeanDefinitionExceptionThrown() {
|
||||
contextRunner
|
||||
.withUserConfiguration(InterfacesAnnotatedTestConfiguration.class)
|
||||
.run(context -> {
|
||||
Assertions.assertThrows(NoSuchBeanDefinitionException.class, () -> {
|
||||
context.getBean(AuthenticationService.class);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenOnlyAbstractClassesAnnotated_noSuchBeanDefinitionExceptionThrown() {
|
||||
contextRunner
|
||||
.withUserConfiguration(AbstractsAnnotatedTestConfiguration.class)
|
||||
.run(context -> {
|
||||
Assertions.assertThrows(NoSuchBeanDefinitionException.class, () -> {
|
||||
context.getBean(AbstractAuthenticationService.class);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenConcreteClassesAnnotated_noExceptionThrown() {
|
||||
contextRunner
|
||||
.withUserConfiguration(ConcreteClassesAnnotatedTestConfiguration.class)
|
||||
.run(context -> {
|
||||
AuthenticationService inMemoryAuthService = context.getBean(AuthenticationService.class);
|
||||
AbstractAuthenticationService ldapAuthService = context.getBean(AbstractAuthenticationService.class);
|
||||
|
||||
Assertions.assertNotNull(inMemoryAuthService);
|
||||
Assertions.assertNotNull(ldapAuthService);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package com.baeldung.annotations.service.config;
|
||||
|
||||
import org.springframework.boot.test.context.TestConfiguration;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
|
||||
@TestConfiguration
|
||||
@ComponentScan("com.baeldung.annotations.service.abstracts")
|
||||
public class AbstractsAnnotatedTestConfiguration {
|
||||
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package com.baeldung.annotations.service.config;
|
||||
|
||||
import org.springframework.boot.test.context.TestConfiguration;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
|
||||
@TestConfiguration
|
||||
@ComponentScan("com.baeldung.annotations.service.concretes")
|
||||
public class ConcreteClassesAnnotatedTestConfiguration {
|
||||
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package com.baeldung.annotations.service.config;
|
||||
|
||||
import org.springframework.boot.test.context.TestConfiguration;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
|
||||
@TestConfiguration
|
||||
@ComponentScan("com.baeldung.annotations.service.interfaces")
|
||||
public class InterfacesAnnotatedTestConfiguration {
|
||||
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
## Spring Boot Runtime 2
|
||||
|
||||
This module contains articles about administering a Spring Boot runtime
|
||||
|
||||
### Relevant Articles:
|
||||
-
|
|
@ -0,0 +1,66 @@
|
|||
<?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-runtime-2</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>spring-boot-runtime-2</name>
|
||||
<description>Demo project for Spring Boot</description>
|
||||
|
||||
<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>
|
||||
<finalName>${project.artifactId}</finalName>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources/heap</directory>
|
||||
<targetPath>${project.build.directory}</targetPath>
|
||||
<filtering>true</filtering>
|
||||
<includes>
|
||||
<include>${project.name}.conf</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<configuration>
|
||||
<mainClass>com.baeldung.heap.HeapSizeDemoApplication</mainClass>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<executable>true</executable>
|
||||
<jvmArguments>
|
||||
-Xms256m
|
||||
-Xmx1g
|
||||
</jvmArguments>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
|
@ -0,0 +1,12 @@
|
|||
package com.baeldung.heap;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class HeapSizeDemoApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(HeapSizeDemoApplication.class, args);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package com.baeldung.heap;
|
||||
|
||||
public class MemoryStats {
|
||||
private long heapSize;
|
||||
private long heapMaxSize;
|
||||
private long heapFreeSize;
|
||||
|
||||
public long getHeapSize() {
|
||||
return heapSize;
|
||||
}
|
||||
|
||||
public void setHeapSize(long heapSize) {
|
||||
this.heapSize = heapSize;
|
||||
}
|
||||
|
||||
public long getHeapMaxSize() {
|
||||
return heapMaxSize;
|
||||
}
|
||||
|
||||
public void setHeapMaxSize(long heapMaxSize) {
|
||||
this.heapMaxSize = heapMaxSize;
|
||||
}
|
||||
|
||||
public long getHeapFreeSize() {
|
||||
return heapFreeSize;
|
||||
}
|
||||
|
||||
public void setHeapFreeSize(long heapFreeSize) {
|
||||
this.heapFreeSize = heapFreeSize;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package com.baeldung.heap;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
public class MemoryStatusController {
|
||||
|
||||
@GetMapping("memory-status")
|
||||
public MemoryStats getMemoryStatistics() {
|
||||
MemoryStats stats = new MemoryStats();
|
||||
stats.setHeapSize(Runtime.getRuntime()
|
||||
.totalMemory());
|
||||
stats.setHeapMaxSize(Runtime.getRuntime()
|
||||
.maxMemory());
|
||||
stats.setHeapFreeSize(Runtime.getRuntime()
|
||||
.freeMemory());
|
||||
return stats;
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
JAVA_OPTS="-Xms512m -Xmx1024m"
|
|
@ -0,0 +1,32 @@
|
|||
package com.baeldung.heap;
|
||||
|
||||
import static org.hamcrest.Matchers.notANumber;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
|
||||
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.MediaType;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@WebMvcTest(MemoryStatusController.class)
|
||||
public class MemoryStatusControllerIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
private MockMvc mvc;
|
||||
|
||||
@Test
|
||||
public void whenGetMemoryStatistics_thenReturnJsonArray() throws Exception {
|
||||
mvc.perform(get("/memory-status").contentType(MediaType.APPLICATION_JSON))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("heapSize", not(notANumber())))
|
||||
.andExpect(jsonPath("heapMaxSize", not(notANumber())))
|
||||
.andExpect(jsonPath("heapFreeSize", not(notANumber())));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package com.baeldung.springdoc.controller;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
|
||||
@Hidden
|
||||
@RestController
|
||||
public class RegularRestController {
|
||||
|
||||
@Hidden
|
||||
@GetMapping("/getAuthor")
|
||||
public String getAuthor() {
|
||||
return "Umang Budhwar";
|
||||
}
|
||||
|
||||
@GetMapping("/getDate")
|
||||
public LocalDate getDate() {
|
||||
return LocalDate.now();
|
||||
}
|
||||
|
||||
@GetMapping("/getTime")
|
||||
public LocalTime getTime() {
|
||||
return LocalTime.now();
|
||||
}
|
||||
|
||||
}
|
|
@ -7,3 +7,4 @@ This module contains articles about Spring MVC Forms using JSP
|
|||
- [Getting Started with Forms in Spring MVC](https://www.baeldung.com/spring-mvc-form-tutorial)
|
||||
- [Form Validation with AngularJS and Spring MVC](https://www.baeldung.com/validation-angularjs-spring-mvc)
|
||||
- [A Guide to the JSTL Library](https://www.baeldung.com/jstl)
|
||||
- [Multiple Submit Buttons on a Form](https://www.baeldung.com/spring-form-multiple-submit-buttons)
|
||||
|
|
|
@ -26,7 +26,7 @@ public class EmployeeController {
|
|||
return employeeMap.get(Id);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/addEmployee", method = RequestMethod.POST)
|
||||
@RequestMapping(value = "/addEmployee", method = RequestMethod.POST, params = "submit")
|
||||
public String submit(@Valid @ModelAttribute("employee") final Employee employee, final BindingResult result, final ModelMap model) {
|
||||
if (result.hasErrors()) {
|
||||
return "error";
|
||||
|
@ -37,5 +37,11 @@ public class EmployeeController {
|
|||
employeeMap.put(employee.getId(), employee);
|
||||
return "employeeView";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/addEmployee", method = RequestMethod.POST, params = "cancel")
|
||||
public String cancel(@Valid @ModelAttribute("employee") final Employee employee, final BindingResult result, final ModelMap model) {
|
||||
model.addAttribute("message", "You clicked cancel, please re-enter employee details:");
|
||||
return "employeeHome";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
</head>
|
||||
<body>
|
||||
<h3>Welcome, Enter The Employee Details</h3>
|
||||
<h4>${message}</h4>
|
||||
|
||||
<form:form method="POST" action="${pageContext.request.contextPath}/addEmployee" modelAttribute="employee">
|
||||
<table>
|
||||
|
@ -23,7 +24,8 @@
|
|||
<td><form:input path="contactNumber" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="submit" value="Submit" /></td>
|
||||
<td><input type="submit" name="submit" value="Submit" /></td>
|
||||
<td><input type="submit" name="cancel" value="Cancel" /></td>
|
||||
</tr>
|
||||
</table>
|
||||
</form:form>
|
||||
|
|
|
@ -8,3 +8,4 @@ The "REST With Spring 2" Classes: http://bit.ly/restwithspring
|
|||
### Relevant Articles:
|
||||
|
||||
- [How to Turn Off Swagger-ui in Production](https://www.baeldung.com/swagger-ui-turn-off-in-production)
|
||||
- [Setting a Request Timeout for a Spring REST API](https://www.baeldung.com/spring-rest-timeout)
|
||||
|
|
|
@ -10,3 +10,5 @@ This module contains articles about Spring RestTemplate
|
|||
- [RestTemplate Post Request with JSON](https://www.baeldung.com/spring-resttemplate-post-json)
|
||||
- [How to Compress Requests Using the Spring RestTemplate](https://www.baeldung.com/spring-resttemplate-compressing-requests)
|
||||
- [Get list of JSON objects with Spring RestTemplate](https://www.baeldung.com/spring-resttemplate-json-list)
|
||||
- [A Guide To Spring Redirects](https://www.baeldung.com/spring-redirect-and-forward)
|
||||
- [Spring RestTemplate Exception: “Not enough variables available to expand”](https://www.baeldung.com/spring-not-enough-variables-available)
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-boot-2</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<relativePath>parent-boot-2/pom.xml</relativePath>
|
||||
<relativePath>../../parent-boot-2/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
package com.baeldung.resttemplateexception;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class RestTemplateExceptionApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(RestTemplateExceptionApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package com.baeldung.resttemplateexception.controller;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.baeldung.resttemplateexception.model.Criterion;
|
||||
import com.baeldung.resttemplateexception.model.Product;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonMappingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api")
|
||||
public class ProductApi {
|
||||
|
||||
private List<Product> productList = new ArrayList<>(Arrays.asList(new Product(1, "Acer Aspire 5", 437), new Product(2, "ASUS VivoBook", 650), new Product(3, "Lenovo Legion", 990)));
|
||||
|
||||
@GetMapping("/get")
|
||||
public Product get(@RequestParam String criterion) throws JsonMappingException, JsonProcessingException {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
Criterion crt = objectMapper.readValue(criterion, Criterion.class);
|
||||
if (crt.getProp().equals("name"))
|
||||
return findByName(crt.getValue());
|
||||
|
||||
// Search by other properties (id,price)
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private Product findByName(String name) {
|
||||
for (Product product : this.productList) {
|
||||
if (product.getName().equals(name)) {
|
||||
return product;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Other methods
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package com.baeldung.resttemplateexception.model;
|
||||
|
||||
public class Criterion {
|
||||
|
||||
private String prop;
|
||||
private String value;
|
||||
|
||||
public Criterion() {
|
||||
|
||||
}
|
||||
|
||||
public String getProp() {
|
||||
return prop;
|
||||
}
|
||||
|
||||
public void setProp(String prop) {
|
||||
this.prop = prop;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package com.baeldung.resttemplateexception.model;
|
||||
|
||||
public class Product {
|
||||
|
||||
private int id;
|
||||
private String name;
|
||||
private double price;
|
||||
|
||||
public Product() {
|
||||
|
||||
}
|
||||
|
||||
public Product(int id, String name, double price) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.price = price;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public double getPrice() {
|
||||
return price;
|
||||
}
|
||||
|
||||
public void setPrice(double price) {
|
||||
this.price = price;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
|
||||
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd"
|
||||
>
|
||||
|
||||
<context:component-scan base-package="com.baeldung.sampleapp.web" />
|
||||
|
||||
<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager" >
|
||||
<mvc:message-converters register-defaults="true">
|
||||
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
|
||||
<!-- <bean class="org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter"/> -->
|
||||
</mvc:message-converters>
|
||||
</mvc:annotation-driven>
|
||||
|
||||
|
||||
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" />
|
||||
<bean class="org.springframework.web.servlet.view.XmlViewResolver">
|
||||
<property name="location">
|
||||
<value>/WEB-INF/spring-views.xml</value>
|
||||
</property>
|
||||
<property name="order" value="0" />
|
||||
</bean>
|
||||
|
||||
|
||||
<bean id="contentNegotiationManager"
|
||||
class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
|
||||
<property name="defaultContentType" value="application/json" />
|
||||
</bean>
|
||||
|
||||
|
||||
</beans>
|
||||
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"
|
||||
>
|
||||
|
||||
<bean id="RedirectedUrl" class="org.springframework.web.servlet.view.RedirectView">
|
||||
<property name="url" value="redirectedUrl" />
|
||||
</bean>
|
||||
|
||||
</beans>
|
|
@ -0,0 +1,47 @@
|
|||
package com.baeldung.resttemplateexception;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import com.baeldung.resttemplateexception.model.Product;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = { RestTemplate.class, RestTemplateExceptionApplication.class })
|
||||
public class RestTemplateExceptionLiveTest {
|
||||
|
||||
@Autowired
|
||||
RestTemplate restTemplate;
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void givenGetUrl_whenJsonIsPassed_thenThrowException() {
|
||||
String url = "http://localhost:8080/spring-rest/api/get?criterion={\"prop\":\"name\",\"value\":\"ASUS VivoBook\"}";
|
||||
Product product = restTemplate.getForObject(url, Product.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenGetUrl_whenJsonIsPassed_thenGetProduct() {
|
||||
String criterion = "{\"prop\":\"name\",\"value\":\"ASUS VivoBook\"}";
|
||||
String url = "http://localhost:8080/spring-rest/api/get?criterion={criterion}";
|
||||
Product product = restTemplate.getForObject(url, Product.class, criterion);
|
||||
|
||||
assertEquals(product.getPrice(), 650, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenGetUrl_whenJsonIsPassed_thenReturnProduct() {
|
||||
String criterion = "{\"prop\":\"name\",\"value\":\"Acer Aspire 5\"}";
|
||||
String url = "http://localhost:8080/spring-rest/api/get";
|
||||
|
||||
UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(url).queryParam("criterion", criterion);
|
||||
Product product = restTemplate.getForObject(builder.build().toUri(), Product.class);
|
||||
|
||||
assertEquals(product.getId(), 1, 0);
|
||||
}
|
||||
}
|
|
@ -188,7 +188,7 @@
|
|||
<artifactId>cargo-maven2-plugin</artifactId>
|
||||
<version>${cargo-maven2-plugin.version}</version>
|
||||
<configuration>
|
||||
<!--<wait>true</wait> caused errors on commit -->
|
||||
<wait>true</wait>
|
||||
<container>
|
||||
<containerId>tomcat8x</containerId>
|
||||
<type>embedded</type>
|
||||
|
@ -297,7 +297,7 @@
|
|||
<guava.version>20.0</guava.version>
|
||||
|
||||
<!-- Maven plugins -->
|
||||
<cargo-maven2-plugin.version>1.6.0</cargo-maven2-plugin.version>
|
||||
<cargo-maven2-plugin.version>1.6.1</cargo-maven2-plugin.version>
|
||||
<findbugs-maven-plugin.version>3.0.4</findbugs-maven-plugin.version>
|
||||
|
||||
<!-- okhttp -->
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package com.baeldung.resttemplate.web.service;
|
||||
package com.baeldung.mock;
|
||||
|
||||
import com.baeldung.resttemplate.web.model.Employee;
|
||||
import org.slf4j.Logger;
|
|
@ -18,6 +18,7 @@ import org.springframework.web.client.RestTemplate;
|
|||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
|
||||
// This test needs RestTemplateConfigurationApplication to be up and running
|
||||
public class TestRestTemplateBasicLiveTest {
|
||||
|
||||
private RestTemplate restTemplate;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package com.baeldung.web.service;
|
||||
package com.baeldung.mock;
|
||||
|
||||
import static org.springframework.test.web.client.match.MockRestRequestMatchers.method;
|
||||
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
|
||||
|
@ -7,8 +7,9 @@ import static org.springframework.test.web.client.response.MockRestResponseCreat
|
|||
import java.net.URI;
|
||||
|
||||
import com.baeldung.SpringTestConfig;
|
||||
import com.baeldung.mock.EmployeeService;
|
||||
import com.baeldung.resttemplate.web.model.Employee;
|
||||
import com.baeldung.resttemplate.web.service.EmployeeService;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
|
@ -1,7 +1,8 @@
|
|||
package com.baeldung.web.service;
|
||||
package com.baeldung.mock;
|
||||
|
||||
import com.baeldung.mock.EmployeeService;
|
||||
import com.baeldung.resttemplate.web.model.Employee;
|
||||
import com.baeldung.resttemplate.web.service.EmployeeService;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
|
@ -38,6 +38,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
|||
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
|
||||
import com.google.common.base.Charsets;
|
||||
|
||||
// This test needs RestTemplateConfigurationApplication to be up and running
|
||||
public class RestTemplateBasicLiveTest {
|
||||
|
||||
private RestTemplate restTemplate;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue