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); | ||||
|  | ||||
							
								
								
									
										3
									
								
								java-collections-maps-3/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								java-collections-maps-3/README.md
									
									
									
									
									
										Normal file
									
								
							| @ -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) | ||||
|  | ||||
							
								
								
									
										3
									
								
								netty/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								netty/README.md
									
									
									
									
									
										Normal file
									
								
							| @ -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> | ||||
|  | ||||
							
								
								
									
										62
									
								
								spring-security-modules/spring-security-okta/pom.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								spring-security-modules/spring-security-okta/pom.xml
									
									
									
									
									
										Normal file
									
								
							| @ -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) | ||||
|  | ||||
							
								
								
									
										3
									
								
								terraform/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								terraform/README.md
									
									
									
									
									
										Normal file
									
								
							| @ -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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user