Merge branch 'master' of https://github.com/Maiklins/tutorials into Java-1524-split-move-spring-boot-persistence

 Conflicts:
	persistence-modules/spring-boot-persistence-2/README.md
This commit is contained in:
mikr 2020-05-16 16:47:19 +02:00
commit 8c1e57cc58
113 changed files with 2887 additions and 100 deletions

View File

@ -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)

56
aws-app-sync/pom.xml Normal file
View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.baeldung</groupId>
<artifactId>aws-app-sync</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>aws-app-sync</name>
<description>Spring Boot using AWS App Sync</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,32 @@
package com.baeldung.awsappsync;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;
import java.nio.charset.StandardCharsets;
import java.util.Map;
public class AppSyncClientHelper {
static String apiUrl = "https://m4i3b6icrrb7livfbypfspiifi.appsync-api.us-east-2.amazonaws.com";
static String apiKey = "da2-bm4rpatkkrc5jfyhvvq7itjeke";
static String API_KEY_HEADER = "x-api-key";
public static WebClient.ResponseSpec getResponseBodySpec(Map<String, Object> requestBody) {
return WebClient
.builder()
.baseUrl(apiUrl)
.defaultHeader(API_KEY_HEADER, apiKey)
.defaultHeader("Content-Type", "application/json")
.build()
.method(HttpMethod.POST)
.uri("/graphql")
.body(BodyInserters.fromValue(requestBody))
.accept(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML)
.acceptCharset(StandardCharsets.UTF_8)
.retrieve();
}
}

View File

@ -0,0 +1,13 @@
package com.baeldung.awsappsync;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class AwsAppSyncApplication {
public static void main(String[] args) {
SpringApplication.run(AwsAppSyncApplication.class, args);
}
}

View File

@ -0,0 +1,72 @@
package com.baeldung.awsappsync;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.web.reactive.function.client.WebClient;
import java.util.HashMap;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest
class AwsAppSyncApplicationTests {
@Test
void givenGraphQuery_whenListEvents_thenReturnAllEvents() {
Map<String, Object> requestBody = new HashMap<>();
requestBody.put("query", "query ListEvents {"
+ " listEvents {"
+ " items {"
+ " id"
+ " name"
+ " where"
+ " when"
+ " description"
+ " }"
+ " }"
+ "}");
requestBody.put("variables", "");
requestBody.put("operationName", "ListEvents");
String bodyString = AppSyncClientHelper.getResponseBodySpec(requestBody)
.bodyToMono(String.class).block();
assertNotNull(bodyString);
assertTrue(bodyString.contains("My First Event"));
assertTrue(bodyString.contains("where"));
assertTrue(bodyString.contains("when"));
}
@Test
void givenGraphAdd_whenMutation_thenReturnIdNameDesc() {
String queryString = "mutation add {"
+ " createEvent("
+ " name:\"My added GraphQL event\""
+ " where:\"Day 2\""
+ " when:\"Saturday night\""
+ " description:\"Studying GraphQL\""
+ " ){"
+ " id"
+ " name"
+ " description"
+ " }"
+ "}";
Map<String, Object> requestBody = new HashMap<>();
requestBody.put("query", queryString);
requestBody.put("variables", "");
requestBody.put("operationName", "add");
WebClient.ResponseSpec response = AppSyncClientHelper.getResponseBodySpec(requestBody);
String bodyString = response.bodyToMono(String.class).block();
assertNotNull(bodyString);
assertTrue(bodyString.contains("My added GraphQL event"));
assertFalse(bodyString.contains("where"));
assertFalse(bodyString.contains("when"));
}
}

View File

@ -1,3 +0,0 @@
### Relevant Articles:
- [Building Java Applications with Bazel](https://www.baeldung.com/bazel-build-tool)

View File

@ -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)

View File

@ -0,0 +1,22 @@
package com.baeldung.java14.record;
import java.util.Objects;
public record Person (String name, String address) {
public static String UNKWOWN_ADDRESS = "Unknown";
public static String UNNAMED = "Unnamed";
public Person {
Objects.requireNonNull(name);
Objects.requireNonNull(address);
}
public Person(String name) {
this(name, UNKWOWN_ADDRESS);
}
public static Person unnamed(String address) {
return new Person(UNNAMED, address);
}
}

View File

@ -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));
}
}

View File

@ -0,0 +1,150 @@
package com.baeldung.java14.record;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
public class PersonTest {
@Test
public void givenSameNameAndAddress_whenEquals_thenPersonsEqual() {
String name = "John Doe";
String address = "100 Linda Ln.";
Person person1 = new Person(name, address);
Person person2 = new Person(name, address);
assertTrue(person1.equals(person2));
}
@Test
public void givenDifferentObject_whenEquals_thenNotEqual() {
Person person = new Person("John Doe", "100 Linda Ln.");
assertFalse(person.equals(new Object()));
}
@Test
public void givenDifferentName_whenEquals_thenPersonsNotEqual() {
String address = "100 Linda Ln.";
Person person1 = new Person("Jane Doe", address);
Person person2 = new Person("John Doe", address);
assertFalse(person1.equals(person2));
}
@Test
public void givenDifferentAddress_whenEquals_thenPersonsNotEqual() {
String name = "John Doe";
Person person1 = new Person(name, "100 Linda Ln.");
Person person2 = new Person(name, "200 London Ave.");
assertFalse(person1.equals(person2));
}
@Test
public void givenSameNameAndAddress_whenHashCode_thenPersonsEqual() {
String name = "John Doe";
String address = "100 Linda Ln.";
Person person1 = new Person(name, address);
Person person2 = new Person(name, address);
assertEquals(person1.hashCode(), person2.hashCode());
}
@Test
public void givenDifferentObject_whenHashCode_thenNotEqual() {
Person person = new Person("John Doe", "100 Linda Ln.");
assertNotEquals(person.hashCode(), new Object().hashCode());
}
@Test
public void givenDifferentName_whenHashCode_thenPersonsNotEqual() {
String address = "100 Linda Ln.";
Person person1 = new Person("Jane Doe", address);
Person person2 = new Person("John Doe", address);
assertNotEquals(person1.hashCode(), person2.hashCode());
}
@Test
public void givenDifferentAddress_whenHashCode_thenPersonsNotEqual() {
String name = "John Doe";
Person person1 = new Person(name, "100 Linda Ln.");
Person person2 = new Person(name, "200 London Ave.");
assertNotEquals(person1.hashCode(), person2.hashCode());
}
@Test
public void givenValidNameAndAddress_whenGetNameAndAddress_thenExpectedValuesReturned() {
String name = "John Doe";
String address = "100 Linda Ln.";
Person person = new Person(name, address);
assertEquals(name, person.name());
assertEquals(address, person.address());
}
@Test
public void givenValidNameAndAddress_whenToString_thenCorrectStringReturned() {
String name = "John Doe";
String address = "100 Linda Ln.";
Person person = new Person(name, address);
assertEquals("Person[name=" + name + ", address=" + address + "]", person.toString());
}
@Test(expected = NullPointerException.class)
public void givenNullName_whenConstruct_thenErrorThrown() {
new Person(null, "100 Linda Ln.");
}
@Test(expected = NullPointerException.class)
public void givenNullAddress_whenConstruct_thenErrorThrown() {
new Person("John Doe", null);
}
@Test
public void givenUnknownAddress_whenConstructing_thenAddressPopulated() {
String name = "John Doe";
Person person = new Person(name);
assertEquals(name, person.name());
assertEquals(Person.UNKWOWN_ADDRESS, person.address());
}
@Test
public void givenUnnamed_whenConstructingThroughFactory_thenNamePopulated() {
String address = "100 Linda Ln.";
Person person = Person.unnamed(address);
assertEquals(Person.UNNAMED, person.name());
assertEquals(address, person.address());
}
}

View File

@ -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)

View File

@ -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)

View File

@ -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;
}
}
}

View File

@ -0,0 +1,41 @@
package com.baeldung.weeknumber;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
public class WeekNumberUsingCalendar {
public int getWeekNumberFrom(String day, String dateFormat, Locale locale) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
Calendar calendar = Calendar.getInstance(locale);
Date date = sdf.parse(day);
calendar.setTime(date);
return calendar.get(Calendar.WEEK_OF_YEAR);
}
public int getWeekNumberFrom(int year, int month, int day, Locale locale) {
Calendar calendar = Calendar.getInstance(locale);
calendar.set(year, month, day);
return calendar.get(Calendar.WEEK_OF_YEAR);
}
public int getWeekNumberFrom(int year, int month, int day, int firstDayOfWeek, int minimalDaysInFirstWeek, Locale locale) {
Calendar calendar = Calendar.getInstance(locale);
calendar.setFirstDayOfWeek(firstDayOfWeek);
calendar.setMinimalDaysInFirstWeek(minimalDaysInFirstWeek);
calendar.set(year, month, day);
return calendar.get(Calendar.WEEK_OF_YEAR);
}
public static void main(String[] args) {
WeekNumberUsingCalendar calendar = new WeekNumberUsingCalendar();
System.out.println(calendar.getWeekNumberFrom(2020, 2, 22, Locale.CANADA));
}
}

View File

@ -0,0 +1,30 @@
package com.baeldung.weeknumber;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoField;
import java.time.temporal.WeekFields;
import java.util.Locale;
public class WeekNumberUsingLocalDate {
public Integer getWeekNumberUsingWeekFiedsFrom(String day, String dayFormat, Locale locale) {
LocalDate date = LocalDate.parse(day, DateTimeFormatter.ofPattern(dayFormat));
return date.get(WeekFields.of(locale)
.weekOfYear());
}
public Integer getWeekNumberUsinWeekFieldsFrom(int year, int month, int day, Locale locale) {
LocalDate date = LocalDate.of(year, month, day);
return date.get(WeekFields.of(locale)
.weekOfYear());
}
public Integer getWeekNumberUsingChronoFieldFrom(int year, int month, int day) {
LocalDate date = LocalDate.of(year, month, day);
return date.get(ChronoField.ALIGNED_WEEK_OF_YEAR);
}
}

View File

@ -0,0 +1,46 @@
package com.baeldung.weeknumber;
import static org.junit.Assert.assertEquals;
import java.text.ParseException;
import java.util.Calendar;
import java.util.Locale;
import org.junit.Test;
public class WeekNumberUsingCalendarUnitTest {
@Test
public void givenDateInStringAndDateFormatUsingLocaleItaly_thenGettingWeekNumberUsingCalendarIsCorrectlyReturned() throws ParseException {
WeekNumberUsingCalendar calendar = new WeekNumberUsingCalendar();
assertEquals(12, calendar.getWeekNumberFrom("20200322", "yyyyMMdd", Locale.ITALY));
}
@Test
public void givenDateInStringAndDateFormatUsingLocaleCanada_thenGettingWeekNumberUsingCalendarIsCorrectlyReturned() throws ParseException {
WeekNumberUsingCalendar calendar = new WeekNumberUsingCalendar();
assertEquals(13, calendar.getWeekNumberFrom("20200322", "yyyyMMdd", Locale.CANADA));
}
@Test
public void givenDateInYearMonthDayNumbersLocaleItaly_thenGettingWeekNumberUsingCalendarIsCorrectlyReturned() {
WeekNumberUsingCalendar calendar = new WeekNumberUsingCalendar();
assertEquals(12, calendar.getWeekNumberFrom(2020, 2, 22, Locale.ITALY));
}
@Test
public void givenDateInYearMonthDayNumbersLocaleItalyChangingWeekCalculationSettings_thenGettingWeekNumberUsingCalendarIsCorrectlyReturned() {
WeekNumberUsingCalendar calendar = new WeekNumberUsingCalendar();
assertEquals(13, calendar.getWeekNumberFrom(2020, 2, 22, Calendar.SUNDAY, 4, Locale.ITALY));
}
@Test
public void givenDateInYearMonthDayNumbersLocaleCanada_thenGettingWeekNumberUsingCalendarIsCorrectlyReturned() {
WeekNumberUsingCalendar calendar = new WeekNumberUsingCalendar();
assertEquals(13, calendar.getWeekNumberFrom(2020, 2, 22, Locale.CANADA));
}
}

View File

@ -0,0 +1,49 @@
package com.baeldung.weeknumber;
import static org.junit.Assert.assertEquals;
import java.util.Locale;
import org.junit.Test;
public class WeekNumberUsingLocalDateUnitTest {
@Test
public void givenDateInStringAndDateFormatUsingWeekFieldsWithLocaleItaly_thenGettingWeekNumberUsingLocalDateIsCorrectlyReturned() {
WeekNumberUsingLocalDate localDate = new WeekNumberUsingLocalDate();
assertEquals(12, localDate.getWeekNumberUsingWeekFiedsFrom("20200322", "yyyyMMdd", Locale.ITALY)
.longValue());
}
@Test
public void givenDateInStringAndDateFormatUsingWeekFieldsWithLocaleCanada_thenGettingWeekNumberUsingLocalDateIsCorrectlyReturned() {
WeekNumberUsingLocalDate localDate = new WeekNumberUsingLocalDate();
assertEquals(13, localDate.getWeekNumberUsingWeekFiedsFrom("20200322", "yyyyMMdd", Locale.CANADA)
.longValue());
}
@Test
public void givenDateInStringAndDateFormatUsingChronoFieds_thenGettingWeekNumberUsingLocalDateIsCorrectlyReturned() {
WeekNumberUsingLocalDate localDate = new WeekNumberUsingLocalDate();
assertEquals(12, localDate.getWeekNumberUsingChronoFieldFrom(2020, 3, 22)
.longValue());
}
@Test
public void givenDateInYearMonthDayNumbersUsingWeekFieldsWithLocaleItaly_thenGettingWeekNumberUsingLocalDateIsCorrectlyReturned() {
WeekNumberUsingLocalDate localDate = new WeekNumberUsingLocalDate();
assertEquals(12, localDate.getWeekNumberUsinWeekFieldsFrom(2020, 3, 22, Locale.ITALY)
.longValue());
}
@Test
public void givenDateInYearMonthDayNumbersUsingWeekFieldsWithLocaleCanada_thenGettingWeekNumberUsingLocalDateIsCorrectlyReturned() {
WeekNumberUsingLocalDate localDate = new WeekNumberUsingLocalDate();
assertEquals(13, localDate.getWeekNumberUsinWeekFieldsFrom(2020, 3, 22, Locale.CANADA)
.longValue());
}
}

View File

@ -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)

View File

@ -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) {

View File

@ -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());
}
}
}

View File

@ -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)

View File

@ -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 }
}
}

View File

@ -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;
}

View File

@ -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));
}

View File

@ -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);

View File

@ -0,0 +1,3 @@
### Relevant Articles:
- [Java Map With Case-Insensitive Keys](https://www.baeldung.com/java-map-with-case-insensitive-keys)

View File

@ -0,0 +1,5 @@
## Java Python Interop
This module contains articles about Java and Python interoperability.
### Relevant Articles:

View File

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8" ?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>java-python-interop</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>java-python-interop</name>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>org.python</groupId>
<artifactId>jython-slim</artifactId>
<version>${jython.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-exec</artifactId>
<version>${commons-exec.version}</version>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>${assertj.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>java-python-interop</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/test/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
<properties>
<jython.version>2.7.2</jython.version>
<commons-exec.version>1.3</commons-exec.version>
<assertj.version>3.6.1</assertj.version>
</properties>
</project>

View File

@ -0,0 +1,34 @@
package com.baeldung.python.interop;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptEngineManager;
public class ScriptEngineManagerUtils {
private static final Logger LOGGER = LoggerFactory.getLogger(ScriptEngineManagerUtils.class);
private ScriptEngineManagerUtils() {
}
public static void listEngines() {
ScriptEngineManager manager = new ScriptEngineManager();
List<ScriptEngineFactory> engines = manager.getEngineFactories();
for (ScriptEngineFactory engine : engines) {
LOGGER.info("Engine name: {}", engine.getEngineName());
LOGGER.info("Version: {}", engine.getEngineVersion());
LOGGER.info("Language: {}", engine.getLanguageName());
LOGGER.info("Short Names:");
for (String names : engine.getNames()) {
LOGGER.info(names);
}
}
}
}

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<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="STDOUT" />
</root>
</configuration>

View File

@ -0,0 +1,131 @@
package com.baeldung.python.interop;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.util.List;
import java.util.stream.Collectors;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.SimpleScriptContext;
import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.ExecuteException;
import org.apache.commons.exec.PumpStreamHandler;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.python.core.PyException;
import org.python.core.PyObject;
import org.python.util.PythonInterpreter;
public class JavaPythonInteropUnitTest {
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void givenPythonScript_whenPythonProcessInvoked_thenSuccess() throws Exception {
ProcessBuilder processBuilder = new ProcessBuilder("python", resolvePythonScriptPath("hello.py"));
processBuilder.redirectErrorStream(true);
Process process = processBuilder.start();
List<String> results = readProcessOutput(process.getInputStream());
assertThat("Results should not be empty", results, is(not(empty())));
assertThat("Results should contain output of script: ", results, hasItem(containsString("Hello Baeldung Readers!!")));
int exitCode = process.waitFor();
assertEquals("No errors should be detected", 0, exitCode);
}
@Test
public void givenPythonScriptEngineIsAvailable_whenScriptInvoked_thenOutputDisplayed() throws Exception {
StringWriter output = new StringWriter();
ScriptContext context = new SimpleScriptContext();
context.setWriter(output);
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("python");
engine.eval(new FileReader(resolvePythonScriptPath("hello.py")), context);
assertEquals("Should contain script output: ", "Hello Baeldung Readers!!", output.toString()
.trim());
}
@Test
public void givenPythonInterpreter_whenPrintExecuted_thenOutputDisplayed() {
try (PythonInterpreter pyInterp = new PythonInterpreter()) {
StringWriter output = new StringWriter();
pyInterp.setOut(output);
pyInterp.exec("print('Hello Baeldung Readers!!')");
assertEquals("Should contain script output: ", "Hello Baeldung Readers!!", output.toString()
.trim());
}
}
@Test
public void givenPythonInterpreter_whenNumbersAdded_thenOutputDisplayed() {
try (PythonInterpreter pyInterp = new PythonInterpreter()) {
pyInterp.exec("x = 10+10");
PyObject x = pyInterp.get("x");
assertEquals("x: ", 20, x.asInt());
}
}
@Test
public void givenPythonInterpreter_whenErrorOccurs_thenExceptionIsThrown() {
thrown.expect(PyException.class);
thrown.expectMessage("ImportError: No module named syds");
try (PythonInterpreter pyInterp = new PythonInterpreter()) {
pyInterp.exec("import syds");
}
}
@Test
public void givenPythonScript_whenPythonProcessExecuted_thenSuccess() throws ExecuteException, IOException {
String line = "python " + resolvePythonScriptPath("hello.py");
CommandLine cmdLine = CommandLine.parse(line);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
PumpStreamHandler streamHandler = new PumpStreamHandler(outputStream);
DefaultExecutor executor = new DefaultExecutor();
executor.setStreamHandler(streamHandler);
int exitCode = executor.execute(cmdLine);
assertEquals("No errors should be detected", 0, exitCode);
assertEquals("Should contain script output: ", "Hello Baeldung Readers!!", outputStream.toString()
.trim());
}
private List<String> readProcessOutput(InputStream inputStream) throws IOException {
try (BufferedReader output = new BufferedReader(new InputStreamReader(inputStream))) {
return output.lines()
.collect(Collectors.toList());
}
}
private String resolvePythonScriptPath(String filename) {
File file = new File("src/test/resources/" + filename);
return file.getAbsolutePath();
}
}

View File

@ -0,0 +1 @@
print("Hello Baeldung Readers!!")

View File

@ -0,0 +1,27 @@
package com.baeldung.jsonproxy;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import org.jsoup.Jsoup;
import org.junit.Test;
public class JsoupProxyLiveTest {
@Test
public void whenUsingHostAndPort_thenConnect() throws IOException {
Jsoup.connect("https://spring.io/blog")
.proxy("200.216.227.141", 53281)
.get();
}
@Test
public void whenUsingProxyClass_thenConnect() throws IOException {
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("200.216.227.141", 53281));
Jsoup.connect("https://spring.io/blog")
.proxy(proxy)
.get();
}
}

View File

@ -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)

35
libraries-rpc/pom.xml Normal file
View File

@ -0,0 +1,35 @@
<?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>libraries-rpc</artifactId>
<name>libraries-rpc</name>
<packaging>jar</packaging>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>com.twitter</groupId>
<artifactId>finagle-core_2.13</artifactId>
<version>${finagle.core.version}</version>
</dependency>
<dependency>
<groupId>com.twitter</groupId>
<artifactId>finagle-http_2.13</artifactId>
<version>${finagle.http.version}</version>
</dependency>
</dependencies>
<properties>
<finagle.core.version>20.4.0</finagle.core.version>
<finagle.http.version>20.4.0</finagle.http.version>
</properties>
</project>

View File

@ -0,0 +1,18 @@
package com.baeldung.rpc.finagle;
import com.twitter.finagle.Service;
import com.twitter.finagle.http.Request;
import com.twitter.finagle.http.Response;
import com.twitter.finagle.http.Status;
import com.twitter.io.Buf;
import com.twitter.io.Reader;
import com.twitter.util.Future;
public class GreetingService extends Service<Request, Response> {
@Override
public Future<Response> apply(Request request) {
String greeting = "Hello " + request.getParam("name");
Reader<Buf> reader = Reader.fromBuf(new Buf.ByteArray(greeting.getBytes(), 0, greeting.length()));
return Future.value(Response.apply(request.version(), Status.Ok(), reader));
}
}

View File

@ -0,0 +1,22 @@
package com.baeldung.rpc.finagle;
import com.twitter.finagle.Service;
import com.twitter.finagle.SimpleFilter;
import com.twitter.finagle.http.Request;
import com.twitter.finagle.http.Response;
import com.twitter.util.Future;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LogFilter extends SimpleFilter<Request, Response> {
private static final Logger logger = LoggerFactory.getLogger(LogFilter.class);
@Override
public Future<Response> apply(Request request, Service<Request, Response> service) {
logger.info("Request host:" + request.host().getOrElse(() -> ""));
logger.info("Request params:");
request.getParams().forEach(entry -> logger.info("\t" + entry.getKey() + " : " + entry.getValue()));
return service.apply(request);
}
}

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<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="STDOUT" />
</root>
</configuration>

View File

@ -0,0 +1,40 @@
package com.baeldung.rpc.finagle;
import com.twitter.finagle.Http;
import com.twitter.finagle.Service;
import com.twitter.finagle.http.Method;
import com.twitter.finagle.http.Request;
import com.twitter.finagle.http.Response;
import com.twitter.util.Await;
import com.twitter.util.Future;
import org.junit.Test;
import scala.runtime.BoxedUnit;
import static org.junit.Assert.assertEquals;
public class FinagleIntegrationTest {
@Test
public void givenServerAndClient_whenRequestSent_thenClientShouldReceiveResponseFromServer() throws Exception {
// given
Service serverService = new LogFilter().andThen(new GreetingService());
Http.serve(":8080", serverService);
Service<Request, Response> clientService = new LogFilter().andThen(Http.newService(":8080"));
// when
Request request = Request.apply(Method.Get(), "/?name=John");
request.host("localhost");
Future<Response> response = clientService.apply(request);
// then
Await.result(response
.onSuccess(r -> {
assertEquals("Hello John", r.getContentString());
return BoxedUnit.UNIT;
})
.onFailure(r -> {
throw new RuntimeException(r);
})
);
}
}

View File

@ -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)

View File

@ -0,0 +1,30 @@
package com.baeldung.logging.log4j2.plugins;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.pattern.ConverterKeys;
import org.apache.logging.log4j.core.pattern.LogEventPatternConverter;
import org.apache.logging.log4j.core.pattern.PatternConverter;
@Plugin(name = "DockerPatternConverter", category = PatternConverter.CATEGORY)
@ConverterKeys({"docker", "container"})
public class DockerPatternConverter extends LogEventPatternConverter {
private DockerPatternConverter(String[] options) {
super("Docker", "docker");
}
public static DockerPatternConverter newInstance(String[] options) {
return new DockerPatternConverter(options);
}
@Override
public void format(LogEvent event, StringBuilder toAppendTo) {
toAppendTo.append(dockerContainer());
}
private String dockerContainer() {
//get docker container ID inside which application is running here
return "container-1";
}
}

View File

@ -0,0 +1,133 @@
package com.baeldung.logging.log4j2.plugins;
import org.apache.logging.log4j.core.Core;
import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.appender.AbstractAppender;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
import org.apache.logging.log4j.core.config.plugins.PluginElement;
import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
import java.io.Serializable;
@Plugin(name = "Kafka2", category = Core.CATEGORY_NAME)
public class KafkaAppender extends AbstractAppender {
@PluginBuilderFactory
public static Builder newBuilder() {
return new Builder();
}
public static class Builder implements org.apache.logging.log4j.core.util.Builder<KafkaAppender> {
@PluginBuilderAttribute("name")
@Required
private String name;
@PluginBuilderAttribute("ip")
private String ipAddress;
@PluginBuilderAttribute("port")
private int port;
@PluginBuilderAttribute("topic")
private String topic;
@PluginBuilderAttribute("partition")
private String partition;
@PluginElement("Layout")
private Layout<? extends Serializable> layout;
@PluginElement("Filter")
private Filter filter;
public Layout<? extends Serializable> getLayout() {
return layout;
}
public Builder setLayout(Layout<? extends Serializable> layout) {
this.layout = layout;
return this;
}
public Filter getFilter() {
return filter;
}
public String getName() {
return name;
}
public Builder setName(String name) {
this.name = name;
return this;
}
public Builder setFilter(Filter filter) {
this.filter = filter;
return this;
}
public String getIpAddress() {
return ipAddress;
}
public Builder setIpAddress(String ipAddress) {
this.ipAddress = ipAddress;
return this;
}
public int getPort() {
return port;
}
public Builder setPort(int port) {
this.port = port;
return this;
}
public String getTopic() {
return topic;
}
public Builder setTopic(String topic) {
this.topic = topic;
return this;
}
public String getPartition() {
return partition;
}
public Builder setPartition(String partition) {
this.partition = partition;
return this;
}
@Override
public KafkaAppender build() {
return new KafkaAppender(getName(), getFilter(), getLayout(), true, new KafkaBroker(ipAddress, port, topic, partition));
}
}
private KafkaBroker broker;
private KafkaAppender(String name, Filter filter, Layout<? extends Serializable> layout, boolean ignoreExceptions, KafkaBroker broker) {
super(name, filter, layout, ignoreExceptions);
this.broker = broker;
}
@Override
public void append(LogEvent event) {
connectAndSendToKafka(broker, event);
}
private void connectAndSendToKafka(KafkaBroker broker, LogEvent event) {
//send to Kafka
}
}

View File

@ -0,0 +1,38 @@
package com.baeldung.logging.log4j2.plugins;
import java.io.Serializable;
public class KafkaBroker implements Serializable {
private final String ipAddress;
private final int port;
public KafkaBroker(String ipAddress, int port, String topic, String partition) {
this.ipAddress = ipAddress;
this.port = port;
this.topic = topic;
this.partition = partition;
}
public String getTopic() {
return topic;
}
public String getPartition() {
return partition;
}
private final String topic;
private final String partition;
public String getIpAddress() {
return ipAddress;
}
public int getPort() {
return port;
}
}

View File

@ -0,0 +1,24 @@
package com.baeldung.logging.log4j2.plugins;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.lookup.StrLookup;
@Plugin(name = "kafka", category = StrLookup.CATEGORY)
public class KafkaLookup implements StrLookup {
@Override
public String lookup(String key) {
return getFromKafka(key);
}
@Override
public String lookup(LogEvent event, String key) {
return getFromKafka(key);
}
private String getFromKafka(String topicName) {
//kafka search logic should go here
return "topic1-p1";
}
}

View File

@ -0,0 +1,48 @@
/**
*
*/
package com.baeldung.logging.log4j2.plugins;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.Core;
import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.appender.AbstractAppender;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
import org.apache.logging.log4j.core.config.plugins.PluginElement;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static java.util.Collections.synchronizedList;
@Plugin(name = "ListAppender", category = Core.CATEGORY_NAME, elementType = Appender.ELEMENT_TYPE)
public class ListAppender extends AbstractAppender {
private List<LogEvent> logList;
protected ListAppender(String name, Filter filter) {
super(name, filter, null);
logList = synchronizedList(new ArrayList<>());
}
@PluginFactory
public static ListAppender createAppender(@PluginAttribute("name") String name, @PluginElement("Filter") final Filter filter) {
return new ListAppender(name, filter);
}
@Override
public void append(LogEvent event) {
if (event.getLevel()
.isLessSpecificThan(Level.WARN)) {
error("Unable to log less than WARN level.");
return;
}
logList.add(event);
}
}

View File

@ -50,6 +50,12 @@
</Policies>
</RollingFile>
<MapAppender name="MapAppender"/>
<Console name="DockerConsoleLogger" target="SYSTEM_OUT">
<PatternLayout pattern="%pid %docker" />
</Console>
<Kafka2 name="KafkaLogger" ip ="127.0.0.1" port="9010" topic="log" partition="p-1">
<PatternLayout pattern="%pid%style{%message}{red}%n" />
</Kafka2>
</Appenders>
<Loggers>
<Logger name="CONSOLE_PATTERN_APPENDER_MARKER" level="TRACE"
@ -80,6 +86,9 @@
additivity="false">
<AppenderRef ref="ConsoleJSONAppender" />
</Logger>
<Logger name="com.baeldung.logging.log4j2.plugins" level="INFO">
<AppenderRef ref="KafkaLogger" />
</Logger>
<Root level="DEBUG">
<AppenderRef ref="ConsoleAppender" />
<AppenderRef ref="MapAppender" />

3
netty/README.md Normal file
View File

@ -0,0 +1,3 @@
### Relevant Articles:
- [HTTP/2 in Netty](https://www.baeldung.com/netty-http2)

View File

@ -1,3 +0,0 @@
### Relevant Articles:
- [Implementing The OAuth 2.0 Authorization Framework Using Jakarta EE](https://www.baeldung.com/java-ee-oauth2-implementation)

View File

@ -1,3 +0,0 @@
### Relevant Articles:
- [Implementing The OAuth 2.0 Authorization Framework Using Jakarta EE](https://www.baeldung.com/java-ee-oauth2-implementation)

View File

@ -60,6 +60,16 @@
<artifactId>poi-ooxml</artifactId>
<version>${poi-ooxml.version}</version>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>3.0.11.RELEASE</version>
</dependency>
<dependency>
<groupId>org.xhtmlrenderer</groupId>
<artifactId>flying-saucer-pdf</artifactId>
<version>9.1.20</version>
</dependency>
</dependencies>
<build>

View File

@ -0,0 +1,48 @@
package com.baeldung.pdf;
import com.lowagie.text.DocumentException;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class PDFThymeleafExample {
public static void main(String[] args) throws IOException, DocumentException {
PDFThymeleafExample thymeleaf2Pdf = new PDFThymeleafExample();
String html = thymeleaf2Pdf.parseThymeleafTemplate();
thymeleaf2Pdf.generatePdfFromHtml(html);
}
public void generatePdfFromHtml(String html) throws IOException, DocumentException {
String outputFolder = System.getProperty("user.home") + File.separator + "thymeleaf.pdf";
OutputStream outputStream = new FileOutputStream(outputFolder);
ITextRenderer renderer = new ITextRenderer();
renderer.setDocumentFromString(html);
renderer.layout();
renderer.createPDF(outputStream);
outputStream.close();
}
private String parseThymeleafTemplate() {
ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode(TemplateMode.HTML);
TemplateEngine templateEngine = new TemplateEngine();
templateEngine.setTemplateResolver(templateResolver);
Context context = new Context();
context.setVariable("to", "Baeldung.com");
return templateEngine.process("thymeleaf_template", context);
}
}

View File

@ -0,0 +1,7 @@
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<body>
<h3 style="text-align: center; color: green">
<span th:text="'Welcome to ' + ${to} + '!'"></span>
</h3>
</body>
</html>

View File

@ -0,0 +1,52 @@
package com.baeldung.pdf;
import com.lowagie.text.DocumentException;
import org.junit.Test;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import static org.junit.Assert.assertTrue;
public class PDFThymeleafUnitTest {
@Test
public void givenThymeleafTemplate_whenParsedAndRenderedToPDF_thenItShouldNotBeEmpty() throws DocumentException, IOException {
String html = parseThymeleafTemplate();
ByteArrayOutputStream outputStream = generatePdfOutputStreamFromHtml(html);
assertTrue(outputStream.size() > 0);
}
private ByteArrayOutputStream generatePdfOutputStreamFromHtml(String html) throws IOException, DocumentException {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ITextRenderer renderer = new ITextRenderer();
renderer.setDocumentFromString(html);
renderer.layout();
renderer.createPDF(outputStream);
outputStream.close();
return outputStream;
}
private String parseThymeleafTemplate() {
ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode(TemplateMode.HTML);
TemplateEngine templateEngine = new TemplateEngine();
templateEngine.setTemplateResolver(templateResolver);
Context context = new Context();
context.setVariable("to", "Baeldung.com");
return templateEngine.process("thymeleaf_template", context);
}
}

View File

@ -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)

View File

@ -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)

View File

@ -0,0 +1,168 @@
package com.baeldung.bsontojson;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.Set;
import dev.morphia.annotations.Embedded;
import dev.morphia.annotations.Entity;
import dev.morphia.annotations.Field;
import dev.morphia.annotations.Id;
import dev.morphia.annotations.Index;
import dev.morphia.annotations.IndexOptions;
import dev.morphia.annotations.Indexes;
import dev.morphia.annotations.Property;
import dev.morphia.annotations.Reference;
import dev.morphia.annotations.Validation;
@Entity("Books")
@Indexes({ @Index(fields = @Field("title"), options = @IndexOptions(name = "book_title")) })
@Validation("{ price : { $gt : 0 } }")
public class Book {
@Id
private String isbn;
@Property
private String title;
private String author;
@Embedded
private Publisher publisher;
@Property("price")
private double cost;
@Reference
private Set<Book> companionBooks;
@Property
private LocalDateTime publishDate;
public Book() {
}
public Book(String isbn, String title, String author, double cost, Publisher publisher) {
this.isbn = isbn;
this.title = title;
this.author = author;
this.cost = cost;
this.publisher = publisher;
this.companionBooks = new HashSet<>();
}
// Getters and setters ...
public String getIsbn() {
return isbn;
}
public Book setIsbn(String isbn) {
this.isbn = isbn;
return this;
}
public String getTitle() {
return title;
}
public Book setTitle(String title) {
this.title = title;
return this;
}
public String getAuthor() {
return author;
}
public Book setAuthor(String author) {
this.author = author;
return this;
}
public Publisher getPublisher() {
return publisher;
}
public Book setPublisher(Publisher publisher) {
this.publisher = publisher;
return this;
}
public double getCost() {
return cost;
}
public Book setCost(double cost) {
this.cost = cost;
return this;
}
public LocalDateTime getPublishDate() {
return publishDate;
}
public Book setPublishDate(LocalDateTime publishDate) {
this.publishDate = publishDate;
return this;
}
public Set<Book> getCompanionBooks() {
return companionBooks;
}
public Book addCompanionBooks(Book book) {
if (companionBooks != null)
this.companionBooks.add(book);
return this;
}
@Override
public String toString() {
return "Book [isbn=" + isbn + ", title=" + title + ", author=" + author + ", publisher=" + publisher + ", cost=" + cost + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((author == null) ? 0 : author.hashCode());
long temp;
temp = Double.doubleToLongBits(cost);
result = prime * result + (int) (temp ^ (temp >>> 32));
result = prime * result + ((isbn == null) ? 0 : isbn.hashCode());
result = prime * result + ((publisher == null) ? 0 : publisher.hashCode());
result = prime * result + ((title == null) ? 0 : title.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Book other = (Book) obj;
if (author == null) {
if (other.author != null)
return false;
} else if (!author.equals(other.author))
return false;
if (Double.doubleToLongBits(cost) != Double.doubleToLongBits(other.cost))
return false;
if (isbn == null) {
if (other.isbn != null)
return false;
} else if (!isbn.equals(other.isbn))
return false;
if (publisher == null) {
if (other.publisher != null)
return false;
} else if (!publisher.equals(other.publisher))
return false;
if (title == null) {
if (other.title != null)
return false;
} else if (!title.equals(other.title))
return false;
return true;
}
}

View File

@ -0,0 +1,70 @@
package com.baeldung.bsontojson;
import org.bson.types.ObjectId;
import dev.morphia.annotations.Entity;
import dev.morphia.annotations.Id;
@Entity
public class Publisher {
@Id
private ObjectId id;
private String name;
public Publisher() {
}
public Publisher(ObjectId id, String name) {
this.id = id;
this.name = name;
}
public ObjectId getId() {
return id;
}
public void setId(ObjectId id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Catalog [id=" + id + ", name=" + name + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Publisher other = (Publisher) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}

View File

@ -2,32 +2,18 @@ package com.baeldung.bsontojson;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.sql.Timestamp;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.bson.Document;
import org.bson.json.Converter;
import org.bson.json.JsonMode;
import org.bson.json.JsonWriterSettings;
import org.bson.json.StrictJsonWriter;
import org.bson.types.ObjectId;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.jupiter.api.AfterEach;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.baeldung.morphia.domain.Book;
import com.baeldung.morphia.domain.Publisher;
import com.mongodb.MongoClient;
import com.mongodb.client.MongoDatabase;
@ -42,7 +28,7 @@ public class BsonToJsonLiveTest {
@BeforeClass
public static void setUp() {
Morphia morphia = new Morphia();
morphia.mapPackage("com.baeldung.morphia");
morphia.mapPackage("com.baeldung.bsontojson");
datastore = morphia.createDatastore(new MongoClient(), DB_NAME);
datastore.ensureIndexes();
@ -72,7 +58,7 @@ public class BsonToJsonLiveTest {
}
String expectedJson = "{\"_id\": \"isbn\", " +
"\"className\": \"com.baeldung.morphia.domain.Book\", " +
"\"className\": \"com.baeldung.bsontojson.Book\", " +
"\"title\": \"title\", " +
"\"author\": \"author\", " +
"\"publisher\": {\"_id\": {\"$oid\": \"fffffffffffffffffffffffa\"}, " +
@ -100,7 +86,7 @@ public class BsonToJsonLiveTest {
}
String expectedJson = "{\"_id\": \"isbn\", " +
"\"className\": \"com.baeldung.morphia.domain.Book\", " +
"\"className\": \"com.baeldung.bsontojson.Book\", " +
"\"title\": \"title\", " +
"\"author\": \"author\", " +
"\"publisher\": {\"_id\": {\"$oid\": \"fffffffffffffffffffffffa\"}, " +
@ -127,7 +113,7 @@ public class BsonToJsonLiveTest {
}
String expectedJson = "{\"_id\": \"isbn\", " +
"\"className\": \"com.baeldung.morphia.domain.Book\", " +
"\"className\": \"com.baeldung.bsontojson.Book\", " +
"\"title\": \"title\", " +
"\"author\": \"author\", " +
"\"publisher\": {\"_id\": {\"$oid\": \"fffffffffffffffffffffffa\"}, " +

View File

@ -4,4 +4,5 @@
- [Configuring a Tomcat Connection Pool in Spring Boot](https://www.baeldung.com/spring-boot-tomcat-connection-pool)
- [Integrating Spring Boot with HSQLDB](https://www.baeldung.com/spring-boot-hsqldb)
- [List of In-Memory Databases](http://www.baeldung.com/java-in-memory-databases)
- More articles: [[<-- prev]](../spring-boot-persistence)
- [Oracle Connection Pooling With Spring](https://www.baeldung.com/spring-oracle-connection-pooling)
- More articles: [[<-- prev]](../spring-boot-persistence)

View File

@ -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);
}
}

View File

@ -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 + '\'' +
'}';
}
}

View File

@ -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> {
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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:

View File

@ -461,7 +461,8 @@
<module>java-lite</module>
<module>java-numbers</module>
<module>java-numbers-2</module>
<module>java-numbers-3</module>
<module>java-numbers-3</module>
<module>java-python-interop</module>
<module>java-rmi</module>
<module>java-spi</module>
<module>java-vavr-stream</module>
@ -508,6 +509,7 @@
<module>libraries-http-2</module>
<module>libraries-io</module>
<module>libraries-primitive</module>
<module>libraries-rpc</module>
<module>libraries-security</module>
<module>libraries-server</module>
<module>libraries-testing</module>
@ -896,6 +898,7 @@
<module>atomix</module>
<module>aws</module>
<module>aws-app-sync</module>
<module>aws-lambda</module>
<module>aws-reactive</module>

View File

@ -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 Monos Content in Java](https://www.baeldung.com/java-string-from-mono)

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd"
>
<context:property-placeholder location="classpath:database.properties"/>
<bean id="dataSource" class="com.baeldung.configurationproperties.Database">
<property name="url" value="${jdbc.url}" />
<property name="username" value="${database.username}" />
<property name="password" value="${database.password}" />
</bean>
</beans>

View File

@ -7,7 +7,8 @@
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd"
>
<context:property-placeholder location="classpath:foo.properties,classpath:bar.properties, classpath:database.properties"/>
<context:property-placeholder location="classpath:foo.properties,classpath:bar.properties,classpath:database.properties"/>
<bean id="componentInXmlUsingProperties" class="com.baeldung.properties.core.ComponentInXmlUsingProperties">
<constructor-arg value="${key.something}"/>

View File

@ -1,4 +1,5 @@
database.url=jdbc:postgresql:/localhost:5432/instance
jdbc.url=jdbc:postgresql:/localhost:5432
database.username=foo
database.password=bar
jdbc.url=jdbc:postgresql:/localhost:5432

View File

@ -6,7 +6,7 @@ import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import static org.assertj.core.api.Assertions.assertThat;
@SpringJUnitConfig(locations = "classpath:configForProperties.xml")
@SpringJUnitConfig(locations = {"classpath:configForProperties.xml", "classpath:configForDbProperties.xml"})
public class MultiplePropertiesXmlConfigIntegrationTest {
@Value("${key.something}") private String something;

View File

@ -0,0 +1,3 @@
### Relevant Articles:
- [How to Test GraphQL Using Postman](https://www.baeldung.com/graphql-postman)

View File

@ -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)

View File

@ -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>

View File

@ -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);
}
}

View File

@ -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;
}
}
}

View File

@ -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");
}
}

View File

@ -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}"

View File

@ -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();
}
}

View File

@ -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");
}
}

View File

@ -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>

View File

@ -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)

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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 {
}

View File

@ -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";
}
}

View File

@ -0,0 +1,7 @@
package com.baeldung.dynamic.autowire;
public interface RegionService {
boolean isServerActive(int serverId);
String getISOCountryCode();
}

View File

@ -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";
}
}

View File

@ -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));
}
}

View File

@ -10,9 +10,9 @@
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-boot-1</artifactId>
<artifactId>parent-boot-2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../parent-boot-1</relativePath>
<relativePath>../parent-boot-2</relativePath>
</parent>
<dependencies>
@ -23,11 +23,24 @@
<dependency>
<groupId>org.springframework.mobile</groupId>
<artifactId>spring-mobile-device</artifactId>
<version>${spring-mobile-device.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
</dependencies>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/libs-milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<properties>
<spring-mobile-device.version>2.0.0.M3</spring-mobile-device.version>
</properties>
</project>

View File

@ -0,0 +1,36 @@
package com.baeldung;
import java.util.List;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.mobile.device.DeviceHandlerMethodArgumentResolver;
import org.springframework.mobile.device.DeviceResolverHandlerInterceptor;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class AppConfig implements WebMvcConfigurer {
@Bean
public DeviceResolverHandlerInterceptor deviceResolverHandlerInterceptor() {
return new DeviceResolverHandlerInterceptor();
}
@Bean
public DeviceHandlerMethodArgumentResolver deviceHandlerMethodArgumentResolver() {
return new DeviceHandlerMethodArgumentResolver();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(deviceResolverHandlerInterceptor());
}
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(deviceHandlerMethodArgumentResolver());
}
}

View File

@ -16,13 +16,16 @@ public class IndexController {
String deviceType = "browser";
String platform = "browser";
String viewName = "index";
if (device.isNormal()) {
deviceType = "browser";
} else if (device.isMobile()) {
deviceType = "mobile";
viewName = "mobile/index";
} else if (device.isTablet()) {
deviceType = "tablet";
viewName = "tablet/index";
}
platform = device.getDevicePlatform().name();
@ -33,7 +36,7 @@ public class IndexController {
LOGGER.info("Client Device Type: " + deviceType + ", Platform: " + platform);
return "index";
return viewName;
}
}

View File

@ -1 +1,3 @@
spring.mobile.devicedelegatingviewresolver.enabled: true
spring.mobile.devicedelegatingviewresolver.enabled: true
spring.freemarker.template-loader-path: classpath:/templates
spring.freemarker.suffix: .ftl

View File

@ -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)

View File

@ -9,9 +9,9 @@
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-boot-1</artifactId>
<artifactId>parent-boot-2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../parent-boot-1</relativePath>
<relativePath>../parent-boot-2</relativePath>
</parent>
<dependencies>
@ -19,25 +19,26 @@
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-jpa -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-rest-hal-browser -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-rest-hal-browser</artifactId>
<version>${spring-data.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.h2database/h2 -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>${h2.version}</version>
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy-dep</artifactId>
<version>${bytebuddy.version}</version>
</dependency>
</dependencies>
@ -55,9 +56,7 @@
</build>
<properties>
<spring-boot.version>2.0.3.RELEASE</spring-boot.version>
<spring-data.version>3.0.8.RELEASE</spring-data.version>
<h2.version>1.4.197</h2.version>
<bytebuddy.version>1.10.10</bytebuddy.version>
<source.version>1.8</source.version>
<target.version>1.8</target.version>
</properties>

View File

@ -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>

View 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>

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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() +"!";
}
}

Some files were not shown because too many files have changed in this diff Show More