commit
03d74d627f
|
@ -1,7 +1,6 @@
|
|||
## Atomikos
|
||||
|
||||
This module contains articles about Atomikos
|
||||
|
||||
### Relevant Articles:
|
||||
|
||||
- [Guide Transactions Using Atomikos]()
|
||||
- [A Guide to Atomikos](https://www.baeldung.com/java-atomikos)
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
### Relevant Articles:
|
||||
|
||||
- [Building Java Applications with Bazel](https://www.baeldung.com/bazel-build-tool)
|
|
@ -12,4 +12,5 @@ This module contains articles about core Groovy concepts
|
|||
- [Closures in Groovy](https://www.baeldung.com/groovy-closures)
|
||||
- [Converting a String to a Date in Groovy](https://www.baeldung.com/groovy-string-to-date)
|
||||
- [Guide to I/O in Groovy](https://www.baeldung.com/groovy-io)
|
||||
- [[More -->]](/core-groovy-2)
|
||||
- [Convert String to Integer in Groovy](https://www.baeldung.com/groovy-convert-string-to-integer)
|
||||
- [[More -->]](/core-groovy-2)
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
package com.baeldung.java14.foreign.api;
|
||||
|
||||
import jdk.incubator.foreign.*;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.core.Is.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.lang.invoke.VarHandle;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
public class ForeignMemoryUnitTest {
|
||||
|
||||
@Test
|
||||
public void whenAValueIsSet_thenAccessTheValue() {
|
||||
long value = 10;
|
||||
MemoryAddress memoryAddress =
|
||||
MemorySegment.allocateNative(8).baseAddress();
|
||||
VarHandle varHandle = MemoryHandles.varHandle(long.class,
|
||||
ByteOrder.nativeOrder());
|
||||
varHandle.set(memoryAddress, value);
|
||||
assertThat(varHandle.get(memoryAddress), is(value));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenMultipleValuesAreSet_thenAccessAll() {
|
||||
VarHandle varHandle = MemoryHandles.varHandle(int.class,
|
||||
ByteOrder.nativeOrder());
|
||||
|
||||
try(MemorySegment memorySegment =
|
||||
MemorySegment.allocateNative(100)) {
|
||||
MemoryAddress base = memorySegment.baseAddress();
|
||||
for(int i=0; i<25; i++) {
|
||||
varHandle.set(base.addOffset((i*4)), i);
|
||||
}
|
||||
for(int i=0; i<25; i++) {
|
||||
assertThat(varHandle.get(base.addOffset((i*4))), is(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenSetValuesWithMemoryLayout_thenTheyCanBeRetrieved() {
|
||||
SequenceLayout sequenceLayout =
|
||||
MemoryLayout.ofSequence(25,
|
||||
MemoryLayout.ofValueBits(64, ByteOrder.nativeOrder()));
|
||||
VarHandle varHandle =
|
||||
sequenceLayout.varHandle(long.class,
|
||||
MemoryLayout.PathElement.sequenceElement());
|
||||
|
||||
try(MemorySegment memorySegment =
|
||||
MemorySegment.allocateNative(sequenceLayout)) {
|
||||
MemoryAddress base = memorySegment.baseAddress();
|
||||
for(long i=0; i<sequenceLayout.elementCount().getAsLong(); i++) {
|
||||
varHandle.set(base, i, i);
|
||||
}
|
||||
for(long i=0; i<sequenceLayout.elementCount().getAsLong(); i++) {
|
||||
assertThat(varHandle.get(base, i), is(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenSlicingMemorySegment_thenTheyCanBeAccessedIndividually() {
|
||||
MemoryAddress memoryAddress =
|
||||
MemorySegment.allocateNative(12).baseAddress();
|
||||
MemoryAddress memoryAddress1 =
|
||||
memoryAddress.segment().asSlice(0,4).baseAddress();
|
||||
MemoryAddress memoryAddress2 =
|
||||
memoryAddress.segment().asSlice(4,4).baseAddress();
|
||||
MemoryAddress memoryAddress3 =
|
||||
memoryAddress.segment().asSlice(8,4).baseAddress();
|
||||
|
||||
VarHandle intHandle =
|
||||
MemoryHandles.varHandle(int.class, ByteOrder.nativeOrder());
|
||||
intHandle.set(memoryAddress1, Integer.MIN_VALUE);
|
||||
intHandle.set(memoryAddress2, 0);
|
||||
intHandle.set(memoryAddress3, Integer.MAX_VALUE);
|
||||
|
||||
assertThat(intHandle.get(memoryAddress1), is(Integer.MIN_VALUE));
|
||||
assertThat(intHandle.get(memoryAddress2), is(0));
|
||||
assertThat(intHandle.get(memoryAddress3), is(Integer.MAX_VALUE));
|
||||
}
|
||||
}
|
|
@ -5,4 +5,5 @@ This module contains articles about Map data structures in Java.
|
|||
### Relevant Articles:
|
||||
- [Java TreeMap vs HashMap](https://www.baeldung.com/java-treemap-vs-hashmap)
|
||||
- [Comparing Two HashMaps in Java](https://www.baeldung.com/java-compare-hashmaps)
|
||||
- [The Map.computeIfAbsent() Method](https://www.baeldung.com/java-map-computeifabsent)
|
||||
- More articles: [[<-- prev]](/core-java-modules/core-java-collections-maps-2)
|
||||
|
|
|
@ -4,5 +4,5 @@
|
|||
|
||||
### Relevant Articles:
|
||||
- [Using a Mutex Object in Java](https://www.baeldung.com/java-mutex)
|
||||
- [Testing Multi-Threaded Code in Java] (https://www.baeldung.com/java-testing-multithreaded)
|
||||
- [Testing Multi-Threaded Code in Java](https://www.baeldung.com/java-testing-multithreaded)
|
||||
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
package com.baeldung.lockfree;
|
||||
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class NonBlockingQueue<T> {
|
||||
|
||||
private final AtomicReference<Node<T>> head, tail;
|
||||
private final AtomicInteger size;
|
||||
|
||||
public NonBlockingQueue() {
|
||||
head = new AtomicReference<>(null);
|
||||
tail = new AtomicReference<>(null);
|
||||
size = new AtomicInteger();
|
||||
size.set(0);
|
||||
}
|
||||
|
||||
public void add(T element) {
|
||||
if (element == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
Node<T> node = new Node<>(element);
|
||||
Node<T> currentTail;
|
||||
do {
|
||||
currentTail = tail.get();
|
||||
node.setPrevious(currentTail);
|
||||
} while(!tail.compareAndSet(currentTail, node));
|
||||
|
||||
if(node.previous != null) {
|
||||
node.previous.next = node;
|
||||
}
|
||||
|
||||
head.compareAndSet(null, node); //if we are inserting the first element
|
||||
size.incrementAndGet();
|
||||
}
|
||||
|
||||
public T get() {
|
||||
if(head.get() == null) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
Node<T> currentHead;
|
||||
Node<T> nextNode;
|
||||
do {
|
||||
currentHead = head.get();
|
||||
nextNode = currentHead.getNext();
|
||||
} while(!head.compareAndSet(currentHead, nextNode));
|
||||
|
||||
size.decrementAndGet();
|
||||
return currentHead.getValue();
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return this.size.get();
|
||||
}
|
||||
|
||||
private class Node<T> {
|
||||
private final T value;
|
||||
private volatile Node<T> next;
|
||||
private volatile Node<T> previous;
|
||||
|
||||
public Node(T value) {
|
||||
this.value = value;
|
||||
this.next = null;
|
||||
}
|
||||
|
||||
public T getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public Node<T> getNext() {
|
||||
return next;
|
||||
}
|
||||
|
||||
public void setPrevious(Node<T> previous) {
|
||||
this.previous = previous;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,4 +11,5 @@ This module contains articles about networking in Java
|
|||
- [Sending Emails with Java](https://www.baeldung.com/java-email)
|
||||
- [Authentication with HttpUrlConnection](https://www.baeldung.com/java-http-url-connection)
|
||||
- [Download a File from an URL in Java](https://www.baeldung.com/java-download-file)
|
||||
- [Handling java.net.ConnectException](https://www.baeldung.com/java-net-connectexception)
|
||||
- [[<-- Prev]](/core-java-modules/core-java-networking)
|
||||
|
|
|
@ -26,7 +26,6 @@ public class RegexUnitTest {
|
|||
while (matcher.find())
|
||||
matches++;
|
||||
assertEquals(matches, 2);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -452,7 +451,6 @@ public class RegexUnitTest {
|
|||
Matcher matcher = pattern.matcher("dogs are friendly");
|
||||
assertTrue(matcher.lookingAt());
|
||||
assertFalse(matcher.matches());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -460,7 +458,6 @@ public class RegexUnitTest {
|
|||
Pattern pattern = Pattern.compile("dog");
|
||||
Matcher matcher = pattern.matcher("dog");
|
||||
assertTrue(matcher.matches());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -469,7 +466,6 @@ public class RegexUnitTest {
|
|||
Matcher matcher = pattern.matcher("dogs are domestic animals, dogs are friendly");
|
||||
String newStr = matcher.replaceFirst("cat");
|
||||
assertEquals("cats are domestic animals, dogs are friendly", newStr);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -478,7 +474,6 @@ public class RegexUnitTest {
|
|||
Matcher matcher = pattern.matcher("dogs are domestic animals, dogs are friendly");
|
||||
String newStr = matcher.replaceAll("cat");
|
||||
assertEquals("cats are domestic animals, cats are friendly", newStr);
|
||||
|
||||
}
|
||||
|
||||
public synchronized static int runTest(String regex, String text) {
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
package com.baeldung.regex.phonenumbers;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class PhoneNumbersRegexUnitTest {
|
||||
|
||||
@Test
|
||||
public void whenMatchesTenDigitsNumber_thenCorrect() {
|
||||
Pattern pattern = Pattern.compile("^\\d{10}$");
|
||||
Matcher matcher = pattern.matcher("2055550125");
|
||||
assertTrue(matcher.matches());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenMOreThanTenDigits_thenNotCorrect() {
|
||||
Pattern pattern = Pattern.compile("^\\d{10}$");
|
||||
Matcher matcher = pattern.matcher("20555501251");
|
||||
assertFalse(matcher.matches());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenMatchesTenDigitsNumberWhitespacesDotHyphen_thenCorrect() {
|
||||
Pattern pattern = Pattern.compile("^(\\d{3}[- .]?){2}\\d{4}$");
|
||||
Matcher matcher = pattern.matcher("202 555 0125");
|
||||
assertTrue(matcher.matches());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenIncludesBracket_thenNotCorrect() {
|
||||
Pattern pattern = Pattern.compile("^(\\d{3}[- .]?){2}\\d{4}$");
|
||||
Matcher matcher = pattern.matcher("202]555 0125");
|
||||
assertFalse(matcher.matches());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenNotStartsWithBatchesOfThreeDigits_thenNotCorrect() {
|
||||
Pattern pattern = Pattern.compile("^(\\d{3}[- .]?){2}\\d{4}$");
|
||||
Matcher matcher = pattern.matcher("2021 555 0125");
|
||||
assertFalse(matcher.matches());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenLastPartWithNoFourDigits_thenNotCorrect() {
|
||||
Pattern pattern = Pattern.compile("^(\\d{3}[- .]?){2}\\d{4}$");
|
||||
Matcher matcher = pattern.matcher("202 555 012");
|
||||
assertFalse(matcher.matches());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenMatchesTenDigitsNumberParenthesis_thenCorrect() {
|
||||
Pattern pattern = Pattern.compile("^((\\(\\d{3}\\))|\\d{3})[- .]?\\d{3}[- .]?\\d{4}$");
|
||||
Matcher matcher = pattern.matcher("(202) 555-0125");
|
||||
assertTrue(matcher.matches());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenJustOpeningParenthesis_thenNotCorrect() {
|
||||
Pattern pattern = Pattern.compile("^((\\(\\d{3}\\))|\\d{3})[- .]?\\d{3}[- .]?\\d{4}$");
|
||||
Matcher matcher = pattern.matcher("(202 555-0125");
|
||||
assertFalse(matcher.matches());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenJustClosingParenthesis_thenNotCorrect() {
|
||||
Pattern pattern = Pattern.compile("^((\\(\\d{3}\\))|\\d{3})[- .]?\\d{3}[- .]?\\d{4}$");
|
||||
Matcher matcher = pattern.matcher("202) 555-0125");
|
||||
assertFalse(matcher.matches());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenMatchesTenDigitsNumberPrefix_thenCorrect() {
|
||||
Pattern pattern = Pattern.compile("^(\\+\\d{1,3}( )?)?((\\(\\d{3}\\))|\\d{3})[- .]?\\d{3}[- .]?\\d{4}$");
|
||||
Matcher matcher = pattern.matcher("+111 (202) 555-0125");
|
||||
assertTrue(matcher.matches());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenIncorrectPrefix_thenNotCorrect() {
|
||||
Pattern pattern = Pattern.compile("^(\\+\\d{1,3}( )?)?((\\(\\d{3}\\))|\\d{3})[- .]?\\d{3}[- .]?\\d{4}$");
|
||||
Matcher matcher = pattern.matcher("-111 (202) 555-0125");
|
||||
assertFalse(matcher.matches());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenTooLongPrefix_thenNotCorrect() {
|
||||
Pattern pattern = Pattern.compile("^(\\+\\d{1,3}( )?)?((\\(\\d{3}\\))|\\d{3})[- .]?\\d{3}[- .]?\\d{4}$");
|
||||
Matcher matcher = pattern.matcher("+1111 (202) 555-0125");
|
||||
assertFalse(matcher.matches());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenMatchesPhoneNumber_thenCorrect() {
|
||||
String patterns
|
||||
= "^(\\+\\d{1,3}( )?)?((\\(\\d{3}\\))|\\d{3})[- .]?\\d{3}[- .]?\\d{4}$"
|
||||
+ "|^(\\+\\d{1,3}( )?)?(\\d{3}[ ]?){2}\\d{3}$"
|
||||
+ "|^(\\+\\d{1,3}( )?)?(\\d{3}[ ]?)(\\d{2}[ ]?){2}\\d{2}$";
|
||||
|
||||
String[] validPhoneNumbers
|
||||
= {"2055550125","202 555 0125", "(202) 555-0125", "+111 (202) 555-0125", "636 856 789", "+111 636 856 789", "636 85 67 89", "+111 636 85 67 89"};
|
||||
|
||||
Pattern pattern = Pattern.compile(patterns);
|
||||
for(String phoneNumber : validPhoneNumbers) {
|
||||
Matcher matcher = pattern.matcher(phoneNumber);
|
||||
assertTrue(matcher.matches());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenNotMatchesPhoneNumber_thenNotCorrect() {
|
||||
String patterns
|
||||
= "^(\\+\\d{1,3}( )?)?((\\(\\d{3}\\))|\\d{3})[- .]?\\d{3}[- .]?\\d{4}$"
|
||||
+ "|^(\\+\\d{1,3}( )?)?(\\d{3}[ ]?){2}\\d{3}$"
|
||||
+ "|^(\\+\\d{1,3}( )?)?(\\d{3}[ ]?)(\\d{2}[ ]?){2}\\d{2}$";
|
||||
|
||||
String[] invalidPhoneNumbers
|
||||
= {"20555501251","202]555 0125", "2021 555 012", "(202 555-0125", "202) 555-0125", "-111 (202) 555-0125", "+1111 (202) 555-0125", "636 85 789", "636 85 67 893"};
|
||||
|
||||
Pattern pattern = Pattern.compile(patterns);
|
||||
for(String phoneNumber : invalidPhoneNumbers) {
|
||||
Matcher matcher = pattern.matcher(phoneNumber);
|
||||
assertFalse(matcher.matches());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,4 +10,5 @@ This module contains articles about the Stream API in Java.
|
|||
- [Primitive Type Streams in Java 8](https://www.baeldung.com/java-8-primitive-streams)
|
||||
- [Debugging Java 8 Streams with IntelliJ](https://www.baeldung.com/intellij-debugging-java-streams)
|
||||
- [Add BigDecimals using the Stream API](https://www.baeldung.com/java-stream-add-bigdecimals)
|
||||
- [Should We Close a Java Stream?](https://www.baeldung.com/java-stream-close)
|
||||
- More articles: [[<-- prev>]](/../core-java-streams-2)
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
package com.baeldung.late
|
||||
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class LateInitUnitTest {
|
||||
|
||||
private lateinit var answer: String
|
||||
|
||||
@Test(expected = UninitializedPropertyAccessException::class)
|
||||
fun givenLateInit_WhenNotInitialized_ShouldThrowAnException() {
|
||||
answer.length
|
||||
}
|
||||
|
||||
@Test
|
||||
fun givenLateInit_TheIsInitialized_ReturnsTheInitializationStatus() {
|
||||
assertFalse { this::answer.isInitialized }
|
||||
answer = "42"
|
||||
assertTrue { this::answer.isInitialized }
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ import org.apache.commons.collections4.MapUtils;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ConvertListToMapService {
|
||||
|
@ -21,7 +22,7 @@ public class ConvertListToMapService {
|
|||
}
|
||||
|
||||
public Map<Integer, Animal> convertListAfterJava8(List<Animal> list) {
|
||||
Map<Integer, Animal> map = list.stream().collect(Collectors.toMap(Animal::getId, animal -> animal));
|
||||
Map<Integer, Animal> map = list.stream().collect(Collectors.toMap(Animal::getId, Function.identity()));
|
||||
return map;
|
||||
}
|
||||
|
||||
|
|
|
@ -53,14 +53,14 @@ public class CollectionToArrayListUnitTest {
|
|||
|
||||
verifyShallowCopy(srcCollection, newList);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Section 5. Deep Copy
|
||||
*/
|
||||
@Test
|
||||
public void whenUsingDeepCopy_thenVerifyDeepCopy() {
|
||||
ArrayList<Foo> newList = srcCollection.stream()
|
||||
.map(foo -> foo.deepCopy())
|
||||
.map(Foo::deepCopy)
|
||||
.collect(toCollection(ArrayList::new));
|
||||
|
||||
verifyDeepCopy(srcCollection, newList);
|
||||
|
@ -83,13 +83,13 @@ public class CollectionToArrayListUnitTest {
|
|||
* @param a
|
||||
* @param b
|
||||
*/
|
||||
private void verifyShallowCopy(Collection a, Collection b) {
|
||||
private void verifyShallowCopy(Collection<Foo> a, Collection<Foo> b) {
|
||||
assertEquals("Collections have different lengths", a.size(), b.size());
|
||||
Iterator<Foo> iterA = a.iterator();
|
||||
Iterator<Foo> iterB = b.iterator();
|
||||
while (iterA.hasNext()) {
|
||||
// use '==' to test instance identity
|
||||
assertTrue("Foo instances differ!", iterA.next() == iterB.next());
|
||||
assertSame("Foo instances differ!", iterA.next(), iterB.next());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -98,7 +98,7 @@ public class CollectionToArrayListUnitTest {
|
|||
* @param a
|
||||
* @param b
|
||||
*/
|
||||
private void verifyDeepCopy(Collection a, Collection b) {
|
||||
private void verifyDeepCopy(Collection<Foo> a, Collection<Foo> b) {
|
||||
assertEquals("Collections have different lengths", a.size(), b.size());
|
||||
Iterator<Foo> iterA = a.iterator();
|
||||
Iterator<Foo> iterB = b.iterator();
|
||||
|
@ -106,7 +106,7 @@ public class CollectionToArrayListUnitTest {
|
|||
Foo nextA = iterA.next();
|
||||
Foo nextB = iterB.next();
|
||||
// should not be same instance
|
||||
assertFalse("Foo instances are the same!", nextA == nextB);
|
||||
assertNotSame("Foo instances are the same!", nextA, nextB);
|
||||
// but should have same content
|
||||
assertFalse("Foo instances have different content!", fooDiff(nextA, nextB));
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ public class ConvertIteratorToListServiceUnitTest {
|
|||
Iterator<Integer> iterator;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
public void setUp() {
|
||||
iterator = Arrays.asList(1, 2, 3)
|
||||
.iterator();
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ public class ConvertIteratorToListServiceUnitTest {
|
|||
@Test
|
||||
public void givenAnIterator_whenConvertIteratorToListUsingWhileLoop_thenReturnAList() {
|
||||
|
||||
List<Integer> actualList = new ArrayList<Integer>();
|
||||
List<Integer> actualList = new ArrayList<>();
|
||||
|
||||
// Convert Iterator to List using while loop dsf
|
||||
while (iterator.hasNext()) {
|
||||
|
@ -44,7 +44,7 @@ public class ConvertIteratorToListServiceUnitTest {
|
|||
|
||||
@Test
|
||||
public void givenAnIterator_whenConvertIteratorToListAfterJava8_thenReturnAList() {
|
||||
List<Integer> actualList = new ArrayList<Integer>();
|
||||
List<Integer> actualList = new ArrayList<>();
|
||||
|
||||
// Convert Iterator to List using Java 8
|
||||
iterator.forEachRemaining(actualList::add);
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
### Relevant Articles:
|
||||
|
||||
- [Java Map With Case-Insensitive Keys](https://www.baeldung.com/java-map-with-case-insensitive-keys)
|
|
@ -17,4 +17,4 @@ Remember, for advanced libraries like [Jackson](/jackson) and [JUnit](/testing-m
|
|||
- [Using NullAway to Avoid NullPointerExceptions](https://www.baeldung.com/java-nullaway)
|
||||
- [Introduction to Alibaba Arthas](https://www.baeldung.com/java-alibaba-arthas-intro)
|
||||
- [Quick Guide to Spring Cloud Circuit Breaker](https://www.baeldung.com/spring-cloud-circuit-breaker)
|
||||
- More articles [[<-- prev]](/libraries-2) [[next -->]](/libraries-4)
|
||||
- More articles [[<-- prev]](/libraries-2) [[next -->]](/libraries-4)
|
||||
|
|
|
@ -11,4 +11,4 @@ This module contains articles about test libraries.
|
|||
- [Introduction to Awaitlity](https://www.baeldung.com/awaitlity-testing)
|
||||
- [Introduction to Hoverfly in Java](https://www.baeldung.com/hoverfly)
|
||||
- [Testing with Hamcrest](https://www.baeldung.com/java-junit-hamcrest-guide)
|
||||
- [Introduction To DBUnit](https://www.baeldung.com/dbunit)
|
||||
- [Introduction To DBUnit](https://www.baeldung.com/java-dbunit)
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
### Relevant Articles:
|
||||
|
||||
- [HTTP/2 in Netty](https://www.baeldung.com/netty-http2)
|
|
@ -1,3 +0,0 @@
|
|||
### Relevant Articles:
|
||||
|
||||
- [Implementing The OAuth 2.0 Authorization Framework Using Jakarta EE](https://www.baeldung.com/java-ee-oauth2-implementation)
|
|
@ -1,3 +0,0 @@
|
|||
### Relevant Articles:
|
||||
|
||||
- [Implementing The OAuth 2.0 Authorization Framework Using Jakarta EE](https://www.baeldung.com/java-ee-oauth2-implementation)
|
|
@ -14,3 +14,4 @@ This module contains articles specific to use of Hibernate as a JPA implementati
|
|||
- [TransactionRequiredException Error](https://www.baeldung.com/jpa-transaction-required-exception)
|
||||
- [JPA/Hibernate Persistence Context](https://www.baeldung.com/jpa-hibernate-persistence-context)
|
||||
- [Quick Guide to EntityManager#getReference()](https://www.baeldung.com/jpa-entity-manager-get-reference)
|
||||
- [Hibernate Error “No Persistence Provider for EntityManager”](https://www.baeldung.com/hibernate-no-persistence-provider)
|
||||
|
|
|
@ -11,3 +11,4 @@ This module contains articles about MongoDB in Java.
|
|||
- [Introduction to Morphia – Java ODM for MongoDB](https://www.baeldung.com/mongodb-morphia)
|
||||
- [MongoDB Aggregations Using Java](https://www.baeldung.com/java-mongodb-aggregations)
|
||||
- [MongoDB BSON to JSON](https://www.baeldung.com/bson-to-json)
|
||||
- [BSON to JSON Document Conversion in Java](https://www.baeldung.com/java-convert-bson-to-json)
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
### Relevant Articles:
|
||||
|
||||
- [Using JDBI with Spring Boot](https://www.baeldung.com/spring-boot-jdbi)
|
||||
- [Oracle Connection Pooling With Spring](https://www.baeldung.com/spring-oracle-connection-pooling)
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
package com.baeldung.spring.transactional;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
class TransactionalCompareApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(TransactionalCompareApplication.class, args);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package com.baeldung.spring.transactional.entity;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
|
||||
@Entity
|
||||
public class Car {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private Long id;
|
||||
|
||||
private String make;
|
||||
|
||||
private String model;
|
||||
|
||||
public Car() {
|
||||
}
|
||||
|
||||
public Car(Long id, String make, String model) {
|
||||
this.id = id;
|
||||
this.make = make;
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getMake() {
|
||||
return make;
|
||||
}
|
||||
|
||||
public void setMake(String make) {
|
||||
this.make = make;
|
||||
}
|
||||
|
||||
public String getModel() {
|
||||
return model;
|
||||
}
|
||||
|
||||
public void setModel(String model) {
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Car{" +
|
||||
"id=" + id +
|
||||
", make='" + make + '\'' +
|
||||
", model='" + model + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package com.baeldung.spring.transactional.repository;
|
||||
|
||||
import com.baeldung.spring.transactional.entity.Car;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface CarRepository extends JpaRepository<Car, Long> {
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package com.baeldung.spring.transactional.service;
|
||||
|
||||
import com.baeldung.spring.transactional.entity.Car;
|
||||
import com.baeldung.spring.transactional.repository.CarRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Isolation;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.persistence.EntityExistsException;
|
||||
|
||||
@Service
|
||||
@Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.SUPPORTS, readOnly = false, timeout = 30)
|
||||
public class CarService {
|
||||
|
||||
@Autowired
|
||||
private CarRepository carRepository;
|
||||
|
||||
@Transactional(rollbackFor = IllegalArgumentException.class, noRollbackFor = EntityExistsException.class,
|
||||
rollbackForClassName = "IllegalArgumentException", noRollbackForClassName = "EntityExistsException")
|
||||
public Car save(Car car) {
|
||||
return carRepository.save(car);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package com.baeldung.spring.transactional.service;
|
||||
|
||||
import com.baeldung.spring.transactional.entity.Car;
|
||||
import com.baeldung.spring.transactional.repository.CarRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.persistence.EntityExistsException;
|
||||
import javax.transaction.Transactional;
|
||||
|
||||
@Service
|
||||
@Transactional(Transactional.TxType.SUPPORTS)
|
||||
public class RentalService {
|
||||
|
||||
@Autowired
|
||||
private CarRepository carRepository;
|
||||
|
||||
@Transactional(rollbackOn = IllegalArgumentException.class, dontRollbackOn = EntityExistsException.class)
|
||||
public Car rent(Car car) {
|
||||
return carRepository.save(car);
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
- [JPA Entity Lifecycle Events](https://www.baeldung.com/jpa-entity-lifecycle-events)
|
||||
- [Working with Lazy Element Collections in JPA](https://www.baeldung.com/java-jpa-lazy-collections)
|
||||
- [Calling Stored Procedures from Spring Data JPA Repositories](https://www.baeldung.com/spring-data-jpa-stored-procedures)
|
||||
- [Custom Naming Convention with Spring Data JPA](https://www.baeldung.com/spring-data-jpa-custom-naming)
|
||||
|
||||
### Eclipse Config
|
||||
After importing the project into Eclipse, you may see the following error:
|
||||
|
|
|
@ -7,3 +7,4 @@ This module contains articles about Reactor Core.
|
|||
- [Intro To Reactor Core](https://www.baeldung.com/reactor-core)
|
||||
- [Combining Publishers in Project Reactor](https://www.baeldung.com/reactor-combine-streams)
|
||||
- [Programmatically Creating Sequences with Project Reactor](https://www.baeldung.com/flux-sequences-reactor)
|
||||
- [How to Extract a Mono’s Content in Java](https://www.baeldung.com/java-string-from-mono)
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
### Relevant Articles:
|
||||
|
||||
- [How to Test GraphQL Using Postman](https://www.baeldung.com/graphql-postman)
|
|
@ -3,3 +3,5 @@
|
|||
This module contains articles about Spring Cloud Circuit Breaker
|
||||
|
||||
### Relevant Articles:
|
||||
|
||||
- [Quick Guide to Spring Cloud Circuit Breaker](https://www.baeldung.com/spring-cloud-circuit-breaker)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>spring-cloud-gateway</artifactId>
|
||||
<name>spring-cloud-gateway</name>
|
||||
|
@ -49,6 +49,26 @@
|
|||
<artifactId>spring-cloud-starter-gateway</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Circuit Breaker -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Redis -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Embedded Redis -->
|
||||
<dependency>
|
||||
<groupId>it.ozimov</groupId>
|
||||
<artifactId>embedded-redis</artifactId>
|
||||
<version>${redis.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-validator-cdi</artifactId>
|
||||
|
@ -69,8 +89,8 @@
|
|||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
@ -84,11 +104,10 @@
|
|||
</build>
|
||||
|
||||
<properties>
|
||||
<spring-cloud-dependencies.version>Greenwich.SR3</spring-cloud-dependencies.version>
|
||||
|
||||
<!-- Spring Boot version compatible with Spring Cloud Release train -->
|
||||
<spring-boot.version>2.1.9.RELEASE</spring-boot.version>
|
||||
<spring-cloud-dependencies.version>Hoxton.SR3</spring-cloud-dependencies.version>
|
||||
<spring-boot.version>2.2.6.RELEASE</spring-boot.version>
|
||||
<hibernate-validator.version>6.0.2.Final</hibernate-validator.version>
|
||||
<redis.version>0.7.2</redis.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
package com.baeldung.springcloudgateway.webfilters;
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
|
||||
@SpringBootApplication
|
||||
public class WebFilterGatewayApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
new SpringApplicationBuilder(WebFilterGatewayApplication.class)
|
||||
.profiles("webfilters")
|
||||
.run(args);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package com.baeldung.springcloudgateway.webfilters.config;
|
||||
|
||||
import org.springframework.cloud.gateway.route.RouteLocator;
|
||||
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.MediaType;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@Configuration
|
||||
public class ModifyBodyRouteConfig {
|
||||
|
||||
@Bean
|
||||
public RouteLocator routes(RouteLocatorBuilder builder) {
|
||||
return builder.routes()
|
||||
.route("modify_request_body", r -> r.path("/post")
|
||||
.filters(f -> f.modifyRequestBody(String.class, Hello.class, MediaType.APPLICATION_JSON_VALUE,
|
||||
(exchange, s) -> Mono.just(new Hello(s.toUpperCase())))).uri("https://httpbin.org"))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RouteLocator responseRoutes(RouteLocatorBuilder builder) {
|
||||
return builder.routes()
|
||||
.route("modify_response_body", r -> r.path("/put/**")
|
||||
.filters(f -> f.modifyResponseBody(String.class, Hello.class, MediaType.APPLICATION_JSON_VALUE,
|
||||
(exchange, s) -> Mono.just(new Hello("New Body")))).uri("https://httpbin.org"))
|
||||
.build();
|
||||
}
|
||||
|
||||
static class Hello {
|
||||
String message;
|
||||
|
||||
public Hello() { }
|
||||
|
||||
public Hello(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package com.baeldung.springcloudgateway.webfilters.config;
|
||||
|
||||
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@Configuration
|
||||
public class RequestRateLimiterResolverConfig {
|
||||
|
||||
@Bean
|
||||
KeyResolver userKeyResolver() {
|
||||
return exchange -> Mono.just("1");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
logging:
|
||||
level:
|
||||
org.springframework.cloud.gateway: INFO
|
||||
reactor.netty.http.client: INFO
|
||||
|
||||
spring:
|
||||
redis:
|
||||
host: localhost
|
||||
port: 6379
|
||||
cloud:
|
||||
gateway:
|
||||
routes:
|
||||
- id: request_header_route
|
||||
uri: https://httpbin.org
|
||||
predicates:
|
||||
- Path=/get/**
|
||||
filters:
|
||||
- AddRequestHeader=My-Header-Good,Good
|
||||
- AddRequestHeader=My-Header-Remove,Remove
|
||||
- AddRequestParameter=var, good
|
||||
- AddRequestParameter=var2, remove
|
||||
- MapRequestHeader=My-Header-Good, My-Header-Bad
|
||||
- MapRequestHeader=My-Header-Set, My-Header-Bad
|
||||
- SetRequestHeader=My-Header-Set, Set
|
||||
- RemoveRequestHeader=My-Header-Remove
|
||||
- RemoveRequestParameter=var2
|
||||
- PreserveHostHeader
|
||||
|
||||
- id: response_header_route
|
||||
uri: https://httpbin.org
|
||||
predicates:
|
||||
- Path=/header/post/**
|
||||
filters:
|
||||
- AddResponseHeader=My-Header-Good,Good
|
||||
- AddResponseHeader=My-Header-Set,Good
|
||||
- AddResponseHeader=My-Header-Rewrite, password=12345678
|
||||
- DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin
|
||||
- AddResponseHeader=My-Header-Remove,Remove
|
||||
- SetResponseHeader=My-Header-Set, Set
|
||||
- RemoveResponseHeader=My-Header-Remove
|
||||
- RewriteResponseHeader=My-Header-Rewrite, password=[^&]+, password=***
|
||||
- RewriteLocationResponseHeader=AS_IN_REQUEST, Location, ,
|
||||
- StripPrefix=1
|
||||
|
||||
- id: path_route
|
||||
uri: https://httpbin.org
|
||||
predicates:
|
||||
- Path=/new/post/**
|
||||
filters:
|
||||
- RewritePath=/new(?<segment>/?.*), $\{segment}
|
||||
- SetPath=/post
|
||||
|
||||
- id: redirect_route
|
||||
uri: https://httpbin.org
|
||||
predicates:
|
||||
- Path=/fake/post/**
|
||||
filters:
|
||||
- RedirectTo=302, https://httpbin.org
|
||||
|
||||
- id: status_route
|
||||
uri: https://httpbin.org
|
||||
predicates:
|
||||
- Path=/delete/**
|
||||
filters:
|
||||
- SetStatus=401
|
||||
|
||||
- id: size_route
|
||||
uri: https://httpbin.org
|
||||
predicates:
|
||||
- Path=/anything
|
||||
filters:
|
||||
- name: RequestSize
|
||||
args:
|
||||
maxSize: 5000000
|
||||
|
||||
- id: retry_test
|
||||
uri: https://httpbin.org
|
||||
predicates:
|
||||
- Path=/status/502
|
||||
filters:
|
||||
- name: Retry
|
||||
args:
|
||||
retries: 3
|
||||
statuses: BAD_GATEWAY
|
||||
methods: GET,POST
|
||||
backoff:
|
||||
firstBackoff: 10ms
|
||||
maxBackoff: 50ms
|
||||
factor: 2
|
||||
basedOnPreviousValue: false
|
||||
|
||||
- id: request_rate_limiter
|
||||
uri: https://httpbin.org
|
||||
predicates:
|
||||
- Path=/redis/get/**
|
||||
filters:
|
||||
- StripPrefix=1
|
||||
- name: RequestRateLimiter
|
||||
args:
|
||||
redis-rate-limiter.replenishRate: 10
|
||||
redis-rate-limiter.burstCapacity: 5
|
||||
key-resolver: "#{@userKeyResolver}"
|
|
@ -0,0 +1,64 @@
|
|||
package com.baeldung.springcloudgateway.webfilters;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.jupiter.api.RepeatedTest;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.context.TestConfiguration;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
|
||||
import redis.embedded.RedisServer;
|
||||
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
@ActiveProfiles("webfilters")
|
||||
@TestConfiguration
|
||||
public class RedisWebFilterFactoriesLiveTest {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(RedisWebFilterFactoriesLiveTest.class);
|
||||
|
||||
private RedisServer redisServer;
|
||||
|
||||
public RedisWebFilterFactoriesLiveTest() {
|
||||
}
|
||||
|
||||
@Before
|
||||
public void postConstruct() {
|
||||
this.redisServer = new RedisServer(6379);
|
||||
redisServer.start();
|
||||
}
|
||||
|
||||
@LocalServerPort
|
||||
String port;
|
||||
|
||||
@Autowired
|
||||
private TestRestTemplate restTemplate;
|
||||
|
||||
@Autowired
|
||||
TestRestTemplate template;
|
||||
|
||||
@RepeatedTest(25)
|
||||
public void whenCallRedisGetThroughGateway_thenOKStatusOrIsReceived() {
|
||||
String url = "http://localhost:" + port + "/redis/get";
|
||||
|
||||
ResponseEntity<String> r = restTemplate.getForEntity(url, String.class);
|
||||
// assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
|
||||
LOGGER.info("Received: status->{}, reason->{}, remaining->{}",
|
||||
r.getStatusCodeValue(), r.getStatusCode().getReasonPhrase(),
|
||||
r.getHeaders().get("X-RateLimit-Remaining"));
|
||||
}
|
||||
|
||||
@After
|
||||
public void preDestroy() {
|
||||
redisServer.stop();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
package com.baeldung.springcloudgateway.webfilters;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.assertj.core.api.Condition;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient.ResponseSpec;
|
||||
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
@ActiveProfiles("webfilters")
|
||||
public class WebFilterFactoriesLiveTest {
|
||||
|
||||
@LocalServerPort
|
||||
String port;
|
||||
|
||||
@Autowired
|
||||
private WebTestClient client;
|
||||
|
||||
@Autowired
|
||||
private TestRestTemplate restTemplate;
|
||||
|
||||
@BeforeEach
|
||||
public void configureClient() {
|
||||
client = WebTestClient.bindToServer()
|
||||
.baseUrl("http://localhost:" + port)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCallGetThroughGateway_thenAllHTTPRequestHeadersParametersAreSet() throws JSONException {
|
||||
String url = "http://localhost:" + port + "/get";
|
||||
ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
|
||||
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
|
||||
JSONObject json = new JSONObject(response.getBody());
|
||||
JSONObject headers = json.getJSONObject("headers");
|
||||
assertThat(headers.getString("My-Header-Good")).isEqualTo("Good");
|
||||
assertThat(headers.getString("My-Header-Bad")).isEqualTo("Good");
|
||||
assertThat(headers.getString("My-Header-Set")).isEqualTo("Set");
|
||||
assertTrue(headers.isNull("My-Header-Remove"));
|
||||
JSONObject vars = json.getJSONObject("args");
|
||||
assertThat(vars.getString("var")).isEqualTo("good");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCallHeaderPostThroughGateway_thenAllHTTPResponseHeadersAreSet() {
|
||||
ResponseSpec response = client.post()
|
||||
.uri("/header/post")
|
||||
.exchange();
|
||||
|
||||
response.expectStatus()
|
||||
.isOk()
|
||||
.expectHeader()
|
||||
.valueEquals("My-Header-Rewrite", "password=***")
|
||||
.expectHeader()
|
||||
.valueEquals("My-Header-Set", "Set")
|
||||
.expectHeader()
|
||||
.valueEquals("My-Header-Good", "Good")
|
||||
.expectHeader()
|
||||
.doesNotExist("My-Header-Remove");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCallPostThroughGateway_thenBodyIsRetrieved() throws JSONException {
|
||||
String url = "http://localhost:" + port + "/post";
|
||||
|
||||
HttpEntity<String> entity = new HttpEntity<>("content", new HttpHeaders());
|
||||
|
||||
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
|
||||
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
|
||||
JSONObject json = new JSONObject(response.getBody());
|
||||
JSONObject data = json.getJSONObject("json");
|
||||
assertThat(data.getString("message")).isEqualTo("CONTENT");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCallPutThroughGateway_thenBodyIsRetrieved() throws JSONException {
|
||||
String url = "http://localhost:" + port + "/put";
|
||||
|
||||
HttpEntity<String> entity = new HttpEntity<>("CONTENT", new HttpHeaders());
|
||||
|
||||
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.PUT, entity, String.class);
|
||||
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
|
||||
JSONObject json = new JSONObject(response.getBody());
|
||||
assertThat(json.getString("message")).isEqualTo("New Body");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCallDeleteThroughGateway_thenIsUnauthorizedCodeIsSet() {
|
||||
ResponseSpec response = client.delete()
|
||||
.uri("/delete")
|
||||
.exchange();
|
||||
|
||||
response.expectStatus()
|
||||
.isUnauthorized();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCallFakePostThroughGateway_thenIsUnauthorizedCodeIsSet() {
|
||||
ResponseSpec response = client.post()
|
||||
.uri("/fake/post")
|
||||
.exchange();
|
||||
|
||||
response.expectStatus()
|
||||
.is3xxRedirection();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCallStatus504ThroughGateway_thenCircuitBreakerIsExecuted() throws JSONException {
|
||||
String url = "http://localhost:" + port + "/status/504";
|
||||
ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
|
||||
|
||||
JSONObject json = new JSONObject(response.getBody());
|
||||
assertThat(json.getString("url")).contains("anything");
|
||||
}
|
||||
}
|
|
@ -3,7 +3,15 @@
|
|||
<appender name="LISTAPPENDER"
|
||||
class="com.baeldung.springcloudgateway.customfilters.gatewayapp.utils.LoggerListAppender">
|
||||
</appender>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
<root level="info">
|
||||
<appender-ref ref="LISTAPPENDER" />
|
||||
</root>
|
||||
<root level="info">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
</configuration>
|
|
@ -14,4 +14,5 @@ This module contains articles about core Spring functionality
|
|||
- [Spring Events](https://www.baeldung.com/spring-events)
|
||||
- [Spring Null-Safety Annotations](https://www.baeldung.com/spring-null-safety-annotations)
|
||||
- [Using @Autowired in Abstract Classes](https://www.baeldung.com/spring-autowired-abstract-class)
|
||||
- [Running Setup Data on Startup in Spring](https://www.baeldung.com/running-setup-logic-on-startup-in-spring)
|
||||
- More articles: [[<-- prev]](/spring-core)[[next -->]](/spring-core-3)
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
package com.baeldung.dynamic.autowire;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class BeanFactoryDynamicAutowireService {
|
||||
private static final String SERVICE_NAME_SUFFIX = "regionService";
|
||||
private final BeanFactory beanFactory;
|
||||
|
||||
@Autowired
|
||||
public BeanFactoryDynamicAutowireService(BeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
public boolean isServerActive(String isoCountryCode, int serverId) {
|
||||
RegionService service = beanFactory.getBean(getRegionServiceBeanName(isoCountryCode), RegionService.class);
|
||||
|
||||
return service.isServerActive(serverId);
|
||||
}
|
||||
|
||||
private String getRegionServiceBeanName(String isoCountryCode) {
|
||||
return isoCountryCode + SERVICE_NAME_SUFFIX;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package com.baeldung.dynamic.autowire;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class CustomMapFromListDynamicAutowireService {
|
||||
private final Map<String, RegionService> servicesByCountryCode;
|
||||
|
||||
@Autowired
|
||||
public CustomMapFromListDynamicAutowireService(List<RegionService> regionServices) {
|
||||
servicesByCountryCode = regionServices.stream()
|
||||
.collect(Collectors.toMap(RegionService::getISOCountryCode, Function.identity()));
|
||||
}
|
||||
|
||||
public boolean isServerActive(String isoCountryCode, int serverId) {
|
||||
RegionService service = servicesByCountryCode.get(isoCountryCode);
|
||||
|
||||
return service.isServerActive(serverId);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package com.baeldung.dynamic.autowire;
|
||||
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@ComponentScan("com.baeldung.dynamic.autowire")
|
||||
public class DynamicAutowireConfig {
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package com.baeldung.dynamic.autowire;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service("GBregionService")
|
||||
public class GBRegionService implements RegionService {
|
||||
@Override
|
||||
public boolean isServerActive(int serverId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getISOCountryCode() {
|
||||
return "GB";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package com.baeldung.dynamic.autowire;
|
||||
|
||||
public interface RegionService {
|
||||
boolean isServerActive(int serverId);
|
||||
|
||||
String getISOCountryCode();
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package com.baeldung.dynamic.autowire;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service("USregionService")
|
||||
public class USRegionService implements RegionService {
|
||||
@Override
|
||||
public boolean isServerActive(int serverId) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getISOCountryCode() {
|
||||
return "US";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package com.baeldung.dynamic.autowire;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(classes = DynamicAutowireConfig.class)
|
||||
public class DynamicAutowireIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
private BeanFactoryDynamicAutowireService beanFactoryDynamicAutowireService;
|
||||
|
||||
@Autowired
|
||||
private CustomMapFromListDynamicAutowireService customMapFromListDynamicAutowireService;
|
||||
|
||||
@Test
|
||||
public void givenDynamicallyAutowiredBean_whenCheckingServerInGB_thenServerIsNotActive() {
|
||||
assertThat(beanFactoryDynamicAutowireService.isServerActive("GB", 101), is(false));
|
||||
assertThat(customMapFromListDynamicAutowireService.isServerActive("GB", 101), is(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenDynamicallyAutowiredBean_whenCheckingServerInUS_thenServerIsActive() {
|
||||
assertThat(beanFactoryDynamicAutowireService.isServerActive("US", 101), is(true));
|
||||
assertThat(customMapFromListDynamicAutowireService.isServerActive("US", 101), is(true));
|
||||
}
|
||||
}
|
|
@ -9,7 +9,7 @@ This module contains articles about Spring MVC
|
|||
- [Servlet Redirect vs Forward](https://www.baeldung.com/servlet-redirect-forward)
|
||||
- [Apache Tiles Integration with Spring MVC](https://www.baeldung.com/spring-mvc-apache-tiles)
|
||||
- [Guide to Spring Email](https://www.baeldung.com/spring-email)
|
||||
- [Using ThymeLeaf and FreeMarker Emails Templates with Spring](https://www.baeldung.com/thymeleaf-freemarker-email)
|
||||
- [Using ThymeLeaf and FreeMarker Emails Templates with Spring](https://www.baeldung.com/spring-email-templates)
|
||||
- [Request Method Not Supported (405) in Spring](https://www.baeldung.com/spring-request-method-not-supported-405)
|
||||
- [Spring @RequestParam Annotation](https://www.baeldung.com/spring-request-param)
|
||||
- More articles: [[more -->]](/spring-mvc-basics-3)
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
<module>spring-security-mvc-persisted-remember-me</module>
|
||||
<module>spring-security-mvc-socket</module>
|
||||
<module>spring-security-oidc</module>
|
||||
<module>spring-security-okta</module>
|
||||
<module>spring-security-react</module>
|
||||
<module>spring-security-rest</module>
|
||||
<module>spring-security-rest-basic-auth</module>
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
<?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/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>spring-security-okta</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<name>spring-security-okta</name>
|
||||
<packaging>war</packaging>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-boot-2</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<relativePath>../../parent-boot-2</relativePath>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.okta.spring</groupId>
|
||||
<artifactId>okta-spring-boot-starter</artifactId>
|
||||
<version>${okta.spring.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.okta.spring</groupId>
|
||||
<artifactId>okta-spring-sdk</artifactId>
|
||||
<version>${okta.spring.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>spring-security-okta</finalName>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<addResources>true</addResources>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>repackage</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
<okta.spring.version>1.4.0</okta.spring.version>
|
||||
</properties>
|
||||
</project>
|
|
@ -0,0 +1,13 @@
|
|||
package com.baeldung.okta;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package com.baeldung.okta.controller;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.okta.sdk.client.Client;
|
||||
import com.okta.sdk.resource.user.User;
|
||||
import com.okta.sdk.resource.user.UserBuilder;
|
||||
import com.okta.sdk.resource.user.UserList;
|
||||
|
||||
@RestController
|
||||
public class AdminController {
|
||||
|
||||
@Autowired
|
||||
public Client client;
|
||||
|
||||
@GetMapping("/users")
|
||||
public UserList getUsers() {
|
||||
return client.listUsers();
|
||||
}
|
||||
|
||||
@GetMapping("/user")
|
||||
public UserList searchUserByEmail(@RequestParam String query) {
|
||||
return client.listUsers(query, null, null, null, null);
|
||||
}
|
||||
|
||||
@GetMapping("/createUser")
|
||||
public User createUser() {
|
||||
char[] tempPassword = {'P','a','$','$','w','0','r','d'};
|
||||
User user = UserBuilder.instance()
|
||||
.setEmail("norman.lewis@email.com")
|
||||
.setFirstName("Norman")
|
||||
.setLastName("Lewis")
|
||||
.setPassword(tempPassword)
|
||||
.setActive(true)
|
||||
.buildAndCreate(client);
|
||||
return user;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package com.baeldung.okta.controller;
|
||||
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
public class HomeController {
|
||||
|
||||
@GetMapping("/")
|
||||
public String home(@AuthenticationPrincipal OidcUser user) {
|
||||
return "Welcome, "+ user.getFullName() +"!";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
okta.oauth2.issuer= //Auth server issuer URL
|
||||
okta.oauth2.client-id= //Client ID of our Okta application
|
||||
okta.oauth2.client-secret= //Client secret of our Okta application
|
||||
okta.oauth2.redirect-uri=/authorization-code/callback
|
||||
|
||||
#Okta Spring SDK configs
|
||||
okta.client.orgUrl= //orgURL
|
||||
okta.client.token= //token generated
|
|
@ -1,3 +1,3 @@
|
|||
## Spring Swagger Codegen App
|
||||
|
||||
This module contains the code for [Generate Spring Boot REST Client with Swagger](http://www.baeldung.com/spring-boot-rest-client-swagger-codegen).
|
||||
This module contains the code for Generate Spring Boot REST Client with Swagger.
|
||||
|
|
|
@ -13,4 +13,5 @@ This module contains articles about Spring with Thymeleaf
|
|||
- [Working with Boolean in Thymeleaf](https://www.baeldung.com/thymeleaf-boolean)
|
||||
- [Working With Custom HTML Attributes in Thymeleaf](https://www.baeldung.com/thymeleaf-custom-html-attributes)
|
||||
- [How to Create an Executable JAR with Maven](https://www.baeldung.com/executable-jar-with-maven)
|
||||
- [Spring MVC Data and Thymeleaf](https://www.baeldung.com/spring-mvc-thymeleaf-data)
|
||||
- [[<-- prev]](/spring-thymeleaf)
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
### Relevant Articles:
|
||||
|
||||
- [Introduction to Terraform](https://www.baeldung.com/ops/terraform-intro)
|
|
@ -7,3 +7,4 @@ This module contains articles about JUnit 5 Annotations
|
|||
- [JUnit 5 Conditional Test Execution with Annotations](https://www.baeldung.com/junit-5-conditional-test-execution)
|
||||
- [JUnit5 Programmatic Extension Registration with @RegisterExtension](https://www.baeldung.com/junit-5-registerextension-annotation)
|
||||
- [Guide to JUnit 5 Parameterized Tests](https://www.baeldung.com/parameterized-tests-junit-5)
|
||||
- [Writing Templates for Test Cases Using JUnit 5](https://www.baeldung.com/junit5-test-templates)
|
||||
|
|
|
@ -5,3 +5,4 @@
|
|||
- [Mockito Strict Stubbing and The UnnecessaryStubbingException](https://www.baeldung.com/mockito-unnecessary-stubbing-exception)
|
||||
- [Mockito and Fluent APIs](https://www.baeldung.com/mockito-fluent-apis)
|
||||
- [Mocking the ObjectMapper readValue() Method](https://www.baeldung.com/mockito-mock-jackson-read-value)
|
||||
- [Introduction to Mockito’s AdditionalAnswers](https://www.baeldung.com/mockito-additionalanswers)
|
||||
|
|
Loading…
Reference in New Issue