From 1c6ece18d92f048e6263e79f8f04a60860f982c6 Mon Sep 17 00:00:00 2001 From: Ahmed Tawila Date: Sat, 16 Dec 2017 21:33:15 +0200 Subject: [PATCH 1/9] wait for some time before retrieving values --- .../com/baeldung/vavr/future/FutureTest.java | 44 +++++++++++++------ 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/vavr/src/test/java/com/baeldung/vavr/future/FutureTest.java b/vavr/src/test/java/com/baeldung/vavr/future/FutureTest.java index 1f2a3761eb..2d2e6939f1 100644 --- a/vavr/src/test/java/com/baeldung/vavr/future/FutureTest.java +++ b/vavr/src/test/java/com/baeldung/vavr/future/FutureTest.java @@ -17,29 +17,32 @@ import io.vavr.control.Try; public class FutureTest { @Test - public void whenChangeExecutorService_thenCorrect() { + public void whenChangeExecutorService_thenCorrect() throws InterruptedException { String initialValue = "Welcome to "; Future resultFuture = Future.of( Executors.newSingleThreadExecutor(), () -> Util.appendData(initialValue)); + Thread.sleep(20); String result = resultFuture.get(); assertThat(result).isEqualTo("Welcome to Baeldung!"); } @Test - public void whenAppendData_thenCorrect1() { + public void whenAppendData_thenCorrect1() throws InterruptedException { String initialValue = "Welcome to "; Future resultFuture = Future.of(() -> Util.appendData(initialValue)); + Thread.sleep(20); String result = resultFuture.get(); assertThat(result).isEqualTo("Welcome to Baeldung!"); } @Test - public void whenAppendData_thenCorrect2() { + public void whenAppendData_thenCorrect2() throws InterruptedException { String initialValue = "Welcome to "; Future resultFuture = Future.of(() -> Util.appendData(initialValue)); + Thread.sleep(20); resultFuture.await(); Option> futureOption = resultFuture.getValue(); Try futureTry = futureOption.get(); @@ -49,31 +52,34 @@ public class FutureTest { } @Test - public void whenAppendData_thenSuccess() { + public void whenAppendData_thenSuccess() throws InterruptedException { String initialValue = "Welcome to "; Future resultFuture = Future.of(() -> Util.appendData(initialValue)) .onSuccess(finalResult -> System.out.println("Successfully Completed - Result: " + finalResult)) .onFailure(finalResult -> System.out.println("Failed - Result: " + finalResult)); + Thread.sleep(20); String result = resultFuture.get(); assertThat(result).isEqualTo("Welcome to Baeldung!"); } @Test - public void whenChainingCallbacks_thenCorrect() { + public void whenChainingCallbacks_thenCorrect() throws InterruptedException { String initialValue = "Welcome to "; Future resultFuture = Future.of(() -> Util.appendData(initialValue)) .andThen(finalResult -> System.out.println("Completed - 1: " + finalResult)) .andThen(finalResult -> System.out.println("Completed - 2: " + finalResult)); + Thread.sleep(20); String result = resultFuture.get(); assertThat(result).isEqualTo("Welcome to Baeldung!"); } @Test - public void whenCallAwait_thenCorrect() { + public void whenCallAwait_thenCorrect() throws InterruptedException { String initialValue = "Welcome to "; Future resultFuture = Future.of(() -> Util.appendData(initialValue)); + Thread.sleep(20); resultFuture = resultFuture.await(); String result = resultFuture.get(); @@ -81,8 +87,9 @@ public class FutureTest { } @Test - public void whenDivideByZero_thenGetThrowable1() { + public void whenDivideByZero_thenGetThrowable1() throws InterruptedException { Future resultFuture = Future.of(() -> Util.divideByZero(10)); + Thread.sleep(20); Future throwableFuture = resultFuture.failed(); Throwable throwable = throwableFuture.get(); @@ -90,8 +97,9 @@ public class FutureTest { } @Test - public void whenDivideByZero_thenGetThrowable2() { + public void whenDivideByZero_thenGetThrowable2() throws InterruptedException { Future resultFuture = Future.of(() -> Util.divideByZero(10)); + Thread.sleep(20); resultFuture.await(); Option throwableOption = resultFuture.getCause(); Throwable throwable = throwableOption.get(); @@ -102,6 +110,7 @@ public class FutureTest { @Test public void whenDivideByZero_thenCorrect() throws InterruptedException { Future resultFuture = Future.of(() -> Util.divideByZero(10)); + Thread.sleep(20); resultFuture.await(); assertThat(resultFuture.isCompleted()).isTrue(); @@ -110,18 +119,20 @@ public class FutureTest { } @Test - public void whenAppendData_thenFutureNotEmpty() { + public void whenAppendData_thenFutureNotEmpty() throws InterruptedException { String initialValue = "Welcome to "; Future resultFuture = Future.of(() -> Util.appendData(initialValue)); + Thread.sleep(20); resultFuture.await(); assertThat(resultFuture.isEmpty()).isFalse(); } @Test - public void whenCallZip_thenCorrect() { + public void whenCallZip_thenCorrect() throws InterruptedException { Future> future = Future.of(() -> "John") .zip(Future.of(() -> new Integer(5))); + Thread.sleep(20); future.await(); assertThat(future.get()).isEqualTo(Tuple.of("John", new Integer(5))); @@ -131,23 +142,26 @@ public class FutureTest { public void whenConvertToCompletableFuture_thenCorrect() throws InterruptedException, ExecutionException { String initialValue = "Welcome to "; Future resultFuture = Future.of(() -> Util.appendData(initialValue)); + Thread.sleep(20); CompletableFuture convertedFuture = resultFuture.toCompletableFuture(); assertThat(convertedFuture.get()).isEqualTo("Welcome to Baeldung!"); } @Test - public void whenCallMap_thenCorrect() { + public void whenCallMap_thenCorrect() throws InterruptedException { Future futureResult = Future.of(() -> new StringBuilder("from Baeldung")) .map(a -> "Hello " + a); + Thread.sleep(20); futureResult.await(); assertThat(futureResult.get()).isEqualTo("Hello from Baeldung"); } @Test - public void whenFutureFails_thenGetErrorMessage() { + public void whenFutureFails_thenGetErrorMessage() throws InterruptedException { Future resultFuture = Future.of(() -> Util.getSubstringMinusOne("Hello")); + Thread.sleep(20); Future errorMessageFuture = resultFuture.recover(Throwable::getMessage); String errorMessage = errorMessageFuture.get(); @@ -155,8 +169,9 @@ public class FutureTest { } @Test - public void whenFutureFails_thenGetAnotherFuture() { + public void whenFutureFails_thenGetAnotherFuture() throws InterruptedException { Future resultFuture = Future.of(() -> Util.getSubstringMinusOne("Hello")); + Thread.sleep(20); Future errorMessageFuture = resultFuture.recoverWith(a -> Future.of(a::getMessage)); String errorMessage = errorMessageFuture.get(); @@ -164,9 +179,10 @@ public class FutureTest { } @Test - public void whenBothFuturesFail_thenGetErrorMessage() { + public void whenBothFuturesFail_thenGetErrorMessage() throws InterruptedException { Future future1 = Future.of(() -> Util.getSubstringMinusOne("Hello")); Future future2 = Future.of(() -> Util.getSubstringMinusTwo("Hello")); + Thread.sleep(20); Future errorMessageFuture = future1.fallbackTo(future2); Future errorMessage = errorMessageFuture.failed(); From ff2cf57772a8317f857d9d250986475660d310a9 Mon Sep 17 00:00:00 2001 From: Ahmed Tawila Date: Sat, 30 Dec 2017 23:23:08 +0200 Subject: [PATCH 2/9] BAEL-1080 Introduction to Future in Vavr --- .../com/baeldung/vavr/future/FutureTest.java | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/vavr/src/test/java/com/baeldung/vavr/future/FutureTest.java b/vavr/src/test/java/com/baeldung/vavr/future/FutureTest.java index 2d2e6939f1..dd678bcad0 100644 --- a/vavr/src/test/java/com/baeldung/vavr/future/FutureTest.java +++ b/vavr/src/test/java/com/baeldung/vavr/future/FutureTest.java @@ -15,6 +15,8 @@ import io.vavr.control.Option; import io.vavr.control.Try; public class FutureTest { + + private static final String error = "Failed to get underlying value."; @Test public void whenChangeExecutorService_thenCorrect() throws InterruptedException { @@ -23,7 +25,7 @@ public class FutureTest { Executors.newSingleThreadExecutor(), () -> Util.appendData(initialValue)); Thread.sleep(20); - String result = resultFuture.get(); + String result = resultFuture.getOrElse(error); assertThat(result).isEqualTo("Welcome to Baeldung!"); } @@ -33,7 +35,7 @@ public class FutureTest { String initialValue = "Welcome to "; Future resultFuture = Future.of(() -> Util.appendData(initialValue)); Thread.sleep(20); - String result = resultFuture.get(); + String result = resultFuture.getOrElse(new String(error)); assertThat(result).isEqualTo("Welcome to Baeldung!"); } @@ -46,7 +48,7 @@ public class FutureTest { resultFuture.await(); Option> futureOption = resultFuture.getValue(); Try futureTry = futureOption.get(); - String result = futureTry.get(); + String result = futureTry.getOrElse(error); assertThat(result).isEqualTo("Welcome to Baeldung!"); } @@ -58,7 +60,7 @@ public class FutureTest { .onSuccess(finalResult -> System.out.println("Successfully Completed - Result: " + finalResult)) .onFailure(finalResult -> System.out.println("Failed - Result: " + finalResult)); Thread.sleep(20); - String result = resultFuture.get(); + String result = resultFuture.getOrElse(error); assertThat(result).isEqualTo("Welcome to Baeldung!"); } @@ -70,7 +72,7 @@ public class FutureTest { .andThen(finalResult -> System.out.println("Completed - 1: " + finalResult)) .andThen(finalResult -> System.out.println("Completed - 2: " + finalResult)); Thread.sleep(20); - String result = resultFuture.get(); + String result = resultFuture.getOrElse(error); assertThat(result).isEqualTo("Welcome to Baeldung!"); } @@ -81,7 +83,7 @@ public class FutureTest { Future resultFuture = Future.of(() -> Util.appendData(initialValue)); Thread.sleep(20); resultFuture = resultFuture.await(); - String result = resultFuture.get(); + String result = resultFuture.getOrElse(error); assertThat(result).isEqualTo("Welcome to Baeldung!"); } @@ -91,7 +93,7 @@ public class FutureTest { Future resultFuture = Future.of(() -> Util.divideByZero(10)); Thread.sleep(20); Future throwableFuture = resultFuture.failed(); - Throwable throwable = throwableFuture.get(); + Throwable throwable = throwableFuture.getOrElse(new Throwable()); assertThat(throwable.getMessage()).isEqualTo("/ by zero"); } @@ -102,7 +104,7 @@ public class FutureTest { Thread.sleep(20); resultFuture.await(); Option throwableOption = resultFuture.getCause(); - Throwable throwable = throwableOption.get(); + Throwable throwable = throwableOption.getOrElse(new Throwable()); assertThat(throwable.getMessage()).isEqualTo("/ by zero"); } @@ -135,7 +137,8 @@ public class FutureTest { Thread.sleep(20); future.await(); - assertThat(future.get()).isEqualTo(Tuple.of("John", new Integer(5))); + assertThat(future.getOrElse(new Tuple2(error, 0))) + .isEqualTo(Tuple.of("John", new Integer(5))); } @Test @@ -155,7 +158,7 @@ public class FutureTest { Thread.sleep(20); futureResult.await(); - assertThat(futureResult.get()).isEqualTo("Hello from Baeldung"); + assertThat(futureResult.getOrElse(error)).isEqualTo("Hello from Baeldung"); } @Test @@ -163,7 +166,7 @@ public class FutureTest { Future resultFuture = Future.of(() -> Util.getSubstringMinusOne("Hello")); Thread.sleep(20); Future errorMessageFuture = resultFuture.recover(Throwable::getMessage); - String errorMessage = errorMessageFuture.get(); + String errorMessage = errorMessageFuture.getOrElse(error); assertThat(errorMessage).isEqualTo("String index out of range: -1"); } @@ -173,7 +176,7 @@ public class FutureTest { Future resultFuture = Future.of(() -> Util.getSubstringMinusOne("Hello")); Thread.sleep(20); Future errorMessageFuture = resultFuture.recoverWith(a -> Future.of(a::getMessage)); - String errorMessage = errorMessageFuture.get(); + String errorMessage = errorMessageFuture.getOrElse(error); assertThat(errorMessage).isEqualTo("String index out of range: -1"); } @@ -187,7 +190,7 @@ public class FutureTest { Future errorMessage = errorMessageFuture.failed(); assertThat( - errorMessage.get().getMessage()) + errorMessage.getOrElse(new Throwable()).getMessage()) .isEqualTo("String index out of range: -1"); } } From c7ba3a08aa7b77d77f99921f25b4d24b44a9d3bf Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Sat, 30 Dec 2017 23:10:54 +0100 Subject: [PATCH 3/9] Build optimize (#3328) * CustomConverterIntegrationTest * StringToEmployeeConverterControllerIntegrationTest * PersonsRepositoryIntegrationTest * Refactor spring-rest-embedded-tomcat pom * Disable Rxjava test --- ... => PersonsRepositoryIntegrationTest.java} | 5 +---- .../baeldung/rxjava/SchedulersLiveTest.java | 1 + ...va => CustomConverterIntegrationTest.java} | 2 +- ...eeConverterControllerIntegrationTest.java} | 2 +- spring-rest-embedded-tomcat/pom.xml | 20 +++++++++++++++++++ 5 files changed, 24 insertions(+), 6 deletions(-) rename persistence-modules/spring-data-eclipselink/src/test/java/com/baeldung/eclipselink/springdata/repo/{PersonsRepositoryTest.java => PersonsRepositoryIntegrationTest.java} (95%) rename spring-boot/src/test/java/org/baeldung/converter/{CustomConverterTest.java => CustomConverterIntegrationTest.java} (97%) rename spring-boot/src/test/java/org/baeldung/converter/controller/{StringToEmployeeConverterControllerTest.java => StringToEmployeeConverterControllerIntegrationTest.java} (95%) diff --git a/persistence-modules/spring-data-eclipselink/src/test/java/com/baeldung/eclipselink/springdata/repo/PersonsRepositoryTest.java b/persistence-modules/spring-data-eclipselink/src/test/java/com/baeldung/eclipselink/springdata/repo/PersonsRepositoryIntegrationTest.java similarity index 95% rename from persistence-modules/spring-data-eclipselink/src/test/java/com/baeldung/eclipselink/springdata/repo/PersonsRepositoryTest.java rename to persistence-modules/spring-data-eclipselink/src/test/java/com/baeldung/eclipselink/springdata/repo/PersonsRepositoryIntegrationTest.java index 1a7c28df6c..636f91cf8e 100644 --- a/persistence-modules/spring-data-eclipselink/src/test/java/com/baeldung/eclipselink/springdata/repo/PersonsRepositoryTest.java +++ b/persistence-modules/spring-data-eclipselink/src/test/java/com/baeldung/eclipselink/springdata/repo/PersonsRepositoryIntegrationTest.java @@ -14,13 +14,10 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.IsEqual.equalTo; import static org.hamcrest.core.IsNull.notNullValue; -/** - * Created by adam. - */ @RunWith(SpringRunner.class) @SpringBootTest @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) -public class PersonsRepositoryTest { +public class PersonsRepositoryIntegrationTest { @Autowired private PersonsRepository personsRepository; diff --git a/rxjava/src/test/java/com/baeldung/rxjava/SchedulersLiveTest.java b/rxjava/src/test/java/com/baeldung/rxjava/SchedulersLiveTest.java index 712f07324c..bc59f72fd9 100644 --- a/rxjava/src/test/java/com/baeldung/rxjava/SchedulersLiveTest.java +++ b/rxjava/src/test/java/com/baeldung/rxjava/SchedulersLiveTest.java @@ -194,6 +194,7 @@ public class SchedulersLiveTest { } @Test + @Ignore public void givenObservable_whenComputationScheduling_thenReturnThreadName() throws InterruptedException { System.out.println("computation"); Observable.just("computation") diff --git a/spring-boot/src/test/java/org/baeldung/converter/CustomConverterTest.java b/spring-boot/src/test/java/org/baeldung/converter/CustomConverterIntegrationTest.java similarity index 97% rename from spring-boot/src/test/java/org/baeldung/converter/CustomConverterTest.java rename to spring-boot/src/test/java/org/baeldung/converter/CustomConverterIntegrationTest.java index fb773fc44c..fc94fe7d7d 100644 --- a/spring-boot/src/test/java/org/baeldung/converter/CustomConverterTest.java +++ b/spring-boot/src/test/java/org/baeldung/converter/CustomConverterIntegrationTest.java @@ -19,7 +19,7 @@ import static org.assertj.core.api.Assertions.assertThat; @RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest(classes = Application.class) @WebAppConfiguration -public class CustomConverterTest { +public class CustomConverterIntegrationTest { @Autowired ConversionService conversionService; diff --git a/spring-boot/src/test/java/org/baeldung/converter/controller/StringToEmployeeConverterControllerTest.java b/spring-boot/src/test/java/org/baeldung/converter/controller/StringToEmployeeConverterControllerIntegrationTest.java similarity index 95% rename from spring-boot/src/test/java/org/baeldung/converter/controller/StringToEmployeeConverterControllerTest.java rename to spring-boot/src/test/java/org/baeldung/converter/controller/StringToEmployeeConverterControllerIntegrationTest.java index 06c3f740c2..3310eb9984 100644 --- a/spring-boot/src/test/java/org/baeldung/converter/controller/StringToEmployeeConverterControllerTest.java +++ b/spring-boot/src/test/java/org/baeldung/converter/controller/StringToEmployeeConverterControllerIntegrationTest.java @@ -19,7 +19,7 @@ import org.baeldung.boot.Application; @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class) @AutoConfigureMockMvc -public class StringToEmployeeConverterControllerTest { +public class StringToEmployeeConverterControllerIntegrationTest { @Autowired private MockMvc mockMvc; diff --git a/spring-rest-embedded-tomcat/pom.xml b/spring-rest-embedded-tomcat/pom.xml index 554040e763..cee9933c0d 100644 --- a/spring-rest-embedded-tomcat/pom.xml +++ b/spring-rest-embedded-tomcat/pom.xml @@ -69,10 +69,30 @@ spring-rest-embedded-tomcat + + + org.apache.maven.plugins + maven-surefire-plugin + ${maven-surefire-plugin.version} + + 3 + true + + **/*IntegrationTest.java + **/*LongRunningUnitTest.java + **/*ManualTest.java + **/JdbcTest.java + **/*LiveTest.java + + + + + 5.0.1.RELEASE + 2.19.1 4.12 2.9.2 1.8 From fc2521b4d6fb7c8d81891aecccf80ecae76c701d Mon Sep 17 00:00:00 2001 From: Jose Carvajal Date: Sun, 31 Dec 2017 10:49:13 +0100 Subject: [PATCH 4/9] Bael 1457 (#3330) * BAEL-399: A Guide to Multitenancy in Hibernate 5 * Removed unused properties in profile 2 * Changes after code review * Updated to use H2 for flyway plugin * Updated schema property * Fixed pom format * Undo things from another PR --- flyway/myFlywayConfig.properties | 6 +++--- flyway/pom.xml | 8 +++++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/flyway/myFlywayConfig.properties b/flyway/myFlywayConfig.properties index 8bb102930a..6b11f6f277 100644 --- a/flyway/myFlywayConfig.properties +++ b/flyway/myFlywayConfig.properties @@ -1,5 +1,5 @@ -flyway.user=root -flyway.password=mysql +flyway.user=sa +flyway.password= flyway.schemas=app-db -flyway.url=jdbc:mysql://localhost:3306/ +flyway.url=jdbc:h2:mem:DATABASE flyway.locations=filesystem:db/migration \ No newline at end of file diff --git a/flyway/pom.xml b/flyway/pom.xml index a090b9458e..84009e4579 100644 --- a/flyway/pom.xml +++ b/flyway/pom.xml @@ -58,6 +58,13 @@ org.flywaydb flyway-maven-plugin 5.0.2 + + + com.h2database + h2 + ${h2.version} + + org.springframework.boot @@ -66,5 +73,4 @@ - From 62e53959ef842ce6eace822cc67ec5c55b24bb8c Mon Sep 17 00:00:00 2001 From: Ganesh Date: Sun, 31 Dec 2017 20:24:02 +0530 Subject: [PATCH 5/9] PR for BAEL-1340 - Java StringJoiner class (#3324) * unit tests for stringjoiner * formatting changes * slit test cases and formatting fixes * minor formatting fix --- .../stringjoiner/StringJoinerUnitTest.java | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 core-java-8/src/test/java/com/baeldung/stringjoiner/StringJoinerUnitTest.java diff --git a/core-java-8/src/test/java/com/baeldung/stringjoiner/StringJoinerUnitTest.java b/core-java-8/src/test/java/com/baeldung/stringjoiner/StringJoinerUnitTest.java new file mode 100644 index 0000000000..a72f811336 --- /dev/null +++ b/core-java-8/src/test/java/com/baeldung/stringjoiner/StringJoinerUnitTest.java @@ -0,0 +1,101 @@ +package com.baeldung.stringjoiner; + +import static org.junit.Assert.assertEquals; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.StringJoiner; +import java.util.stream.Collectors; + +import org.junit.Test; + +public class StringJoinerUnitTest { + private final String DELIMITER_COMMA = ","; + private final String DELIMITER_HYPHEN = "-"; + private final String PREFIX = "["; + private final String SUFFIX = "]"; + private final String EMPTY_JOINER = "empty"; + + @Test + public void whenJoinerWithoutPrefixSuffixWithoutEmptyValue_thenReturnDefault() { + StringJoiner commaSeparatedJoiner = new StringJoiner(DELIMITER_COMMA); + assertEquals(0, commaSeparatedJoiner.toString().length()); + } + + @Test + public void whenJoinerWithPrefixSuffixWithoutEmptyValue_thenReturnDefault() { + StringJoiner commaSeparatedPrefixSuffixJoiner = new StringJoiner(DELIMITER_COMMA, PREFIX, SUFFIX); + assertEquals(commaSeparatedPrefixSuffixJoiner.toString(), PREFIX + SUFFIX); + } + + @Test + public void whenJoinerWithoutPrefixSuffixWithEmptyValue_thenReturnDefault() { + StringJoiner commaSeparatedJoiner = new StringJoiner(DELIMITER_COMMA); + commaSeparatedJoiner.setEmptyValue(EMPTY_JOINER); + + assertEquals(commaSeparatedJoiner.toString(), EMPTY_JOINER); + } + + @Test + public void whenJoinerWithPrefixSuffixWithEmptyValue_thenReturnDefault() { + StringJoiner commaSeparatedPrefixSuffixJoiner = new StringJoiner(DELIMITER_COMMA, PREFIX, SUFFIX); + commaSeparatedPrefixSuffixJoiner.setEmptyValue(EMPTY_JOINER); + + assertEquals(commaSeparatedPrefixSuffixJoiner.toString(), EMPTY_JOINER); + } + + @Test + public void whenAddElements_thenJoinElements() { + StringJoiner rgbJoiner = new StringJoiner(DELIMITER_COMMA, PREFIX, SUFFIX); + rgbJoiner.add("Red") + .add("Green") + .add("Blue"); + + assertEquals(rgbJoiner.toString(), "[Red,Green,Blue]"); + } + + @Test + public void whenAddListElements_thenJoinListElements() { + List rgbList = new ArrayList(); + rgbList.add("Red"); + rgbList.add("Green"); + rgbList.add("Blue"); + + StringJoiner rgbJoiner = new StringJoiner(DELIMITER_COMMA, PREFIX, SUFFIX); + + for (String color : rgbList) { + rgbJoiner.add(color); + } + + assertEquals(rgbJoiner.toString(), "[Red,Green,Blue]"); + } + + @Test + public void whenMergeJoiners_thenReturnMerged() { + StringJoiner rgbJoiner = new StringJoiner(DELIMITER_COMMA, PREFIX, SUFFIX); + StringJoiner cmybJoiner = new StringJoiner(DELIMITER_HYPHEN, PREFIX, SUFFIX); + + rgbJoiner.add("Red") + .add("Green") + .add("Blue"); + cmybJoiner.add("Cyan") + .add("Magenta") + .add("Yellow") + .add("Black"); + + rgbJoiner.merge(cmybJoiner); + + assertEquals(rgbJoiner.toString(), "[Red,Green,Blue,Cyan-Magenta-Yellow-Black]"); + } + + @Test + public void whenUsedWithinCollectors_thenJoin() { + List rgbList = Arrays.asList("Red", "Green", "Blue"); + String commaSeparatedRGB = rgbList.stream() + .map(color -> color.toString()) + .collect(Collectors.joining(",")); + + assertEquals(commaSeparatedRGB, "Red,Green,Blue"); + } +} From 8de8770eecc255e4dfea382c6848c4add1190e53 Mon Sep 17 00:00:00 2001 From: Bogdan Stoean <4540392+BogdanStoean@users.noreply.github.com> Date: Sun, 31 Dec 2017 17:04:37 +0200 Subject: [PATCH 6/9] [BAEL-1410] Spring Boot Security auto-configuration (#3329) * [BAEL-1410] Spring Boot Security Auto-Configuration * [BAEL-1410] Added some tests for incorrect credentials use case * [BAEL-1410] Added readme and some code improvements --- pom.xml | 3 +- spring-boot-security/README.md | 6 + spring-boot-security/pom.xml | 73 ++++++++++++ .../SpringBootSecurityApplication.java | 16 +++ .../config/BasicConfiguration.java | 37 ++++++ .../config/FormLoginConfiguration.java | 39 +++++++ .../src/main/resources/application.properties | 4 + .../src/main/resources/static/index.html | 10 ++ .../BasicConfigurationIntegrationTest.java | 56 +++++++++ .../FormConfigurationIntegrationTest.java | 106 ++++++++++++++++++ 10 files changed, 349 insertions(+), 1 deletion(-) create mode 100644 spring-boot-security/README.md create mode 100644 spring-boot-security/pom.xml create mode 100644 spring-boot-security/src/main/java/com/baeldung/springbootsecurity/SpringBootSecurityApplication.java create mode 100644 spring-boot-security/src/main/java/com/baeldung/springbootsecurity/config/BasicConfiguration.java create mode 100644 spring-boot-security/src/main/java/com/baeldung/springbootsecurity/config/FormLoginConfiguration.java create mode 100644 spring-boot-security/src/main/resources/application.properties create mode 100644 spring-boot-security/src/main/resources/static/index.html create mode 100644 spring-boot-security/src/test/java/com/baeldung/springbootsecurity/BasicConfigurationIntegrationTest.java create mode 100644 spring-boot-security/src/test/java/com/baeldung/springbootsecurity/FormConfigurationIntegrationTest.java diff --git a/pom.xml b/pom.xml index 8906b1c8d2..19e42009c9 100644 --- a/pom.xml +++ b/pom.xml @@ -152,6 +152,8 @@ spring-boot spring-boot-keycloak spring-boot-bootstrap + spring-boot-admin + spring-boot-security spring-cloud-data-flow spring-cloud spring-core @@ -263,7 +265,6 @@ vertx-and-rxjava saas deeplearning4j - spring-boot-admin lucene vraptor diff --git a/spring-boot-security/README.md b/spring-boot-security/README.md new file mode 100644 index 0000000000..26ab8b2337 --- /dev/null +++ b/spring-boot-security/README.md @@ -0,0 +1,6 @@ +### Spring Boot Security Auto-Configuration + +- mvn clean install +- uncomment in application.properties spring.profiles.active=basic # for basic auth config +- uncomment in application.properties spring.profiles.active=form # for form based auth config +- uncomment actuator dependency simultaneously with the line from main class diff --git a/spring-boot-security/pom.xml b/spring-boot-security/pom.xml new file mode 100644 index 0000000000..c35191a7fc --- /dev/null +++ b/spring-boot-security/pom.xml @@ -0,0 +1,73 @@ + + + 4.0.0 + + com.baeldung + spring-boot-security + 0.0.1-SNAPSHOT + jar + + spring-boot-security + Spring Boot Security Auto-Configuration + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + + + + + org.springframework.boot + spring-boot-dependencies + 1.5.9.RELEASE + pom + import + + + + + + UTF-8 + UTF-8 + 1.8 + + + + + + + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.security + spring-security-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + diff --git a/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/SpringBootSecurityApplication.java b/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/SpringBootSecurityApplication.java new file mode 100644 index 0000000000..3a85da72e5 --- /dev/null +++ b/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/SpringBootSecurityApplication.java @@ -0,0 +1,16 @@ +package com.baeldung.springbootsecurity; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration; + +@SpringBootApplication(exclude = { + SecurityAutoConfiguration.class + // ,ManagementWebSecurityAutoConfiguration.class +}) +public class SpringBootSecurityApplication { + + public static void main(String[] args) { + SpringApplication.run(SpringBootSecurityApplication.class, args); + } +} diff --git a/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/config/BasicConfiguration.java b/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/config/BasicConfiguration.java new file mode 100644 index 0000000000..1b08e5ee22 --- /dev/null +++ b/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/config/BasicConfiguration.java @@ -0,0 +1,37 @@ +package com.baeldung.springbootsecurity.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; + +@Configuration +@EnableWebSecurity +@Profile("basic") +public class BasicConfiguration extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth + .inMemoryAuthentication() + .withUser("user") + .password("password") + .roles("USER") + .and() + .withUser("admin") + .password("admin") + .roles("USER", "ADMIN"); + } + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .authorizeRequests() + .anyRequest() + .authenticated() + .and() + .httpBasic(); + } +} diff --git a/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/config/FormLoginConfiguration.java b/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/config/FormLoginConfiguration.java new file mode 100644 index 0000000000..b4902a9ffc --- /dev/null +++ b/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/config/FormLoginConfiguration.java @@ -0,0 +1,39 @@ +package com.baeldung.springbootsecurity.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; + +@Configuration +@EnableWebSecurity +@Profile("form") +public class FormLoginConfiguration extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth + .inMemoryAuthentication() + .withUser("user") + .password("password") + .roles("USER") + .and() + .withUser("admin") + .password("password") + .roles("USER", "ADMIN"); + } + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .authorizeRequests() + .anyRequest() + .authenticated() + .and() + .formLogin() + .and() + .httpBasic(); + } +} diff --git a/spring-boot-security/src/main/resources/application.properties b/spring-boot-security/src/main/resources/application.properties new file mode 100644 index 0000000000..6ca2edb175 --- /dev/null +++ b/spring-boot-security/src/main/resources/application.properties @@ -0,0 +1,4 @@ +#spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration +#spring.profiles.active=form +#spring.profiles.active=basic +#security.user.password=password \ No newline at end of file diff --git a/spring-boot-security/src/main/resources/static/index.html b/spring-boot-security/src/main/resources/static/index.html new file mode 100644 index 0000000000..5e3506dde6 --- /dev/null +++ b/spring-boot-security/src/main/resources/static/index.html @@ -0,0 +1,10 @@ + + + + + Index + + +Welcome to Baeldung Secured Page !!! + + \ No newline at end of file diff --git a/spring-boot-security/src/test/java/com/baeldung/springbootsecurity/BasicConfigurationIntegrationTest.java b/spring-boot-security/src/test/java/com/baeldung/springbootsecurity/BasicConfigurationIntegrationTest.java new file mode 100644 index 0000000000..63e1c2ac73 --- /dev/null +++ b/spring-boot-security/src/test/java/com/baeldung/springbootsecurity/BasicConfigurationIntegrationTest.java @@ -0,0 +1,56 @@ +package com.baeldung.springbootsecurity; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.context.embedded.LocalServerPort; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = RANDOM_PORT) +@ActiveProfiles("basic") +public class BasicConfigurationIntegrationTest { + + TestRestTemplate restTemplate; + URL base; + + @LocalServerPort int port; + + @Before + public void setUp() throws MalformedURLException { + restTemplate = new TestRestTemplate("user", "password"); + base = new URL("http://localhost:" + port); + } + + @Test + public void whenLoggedUserRequestsHomePage_ThenSuccess() throws IllegalStateException, IOException { + ResponseEntity response = restTemplate.getForEntity(base.toString(), String.class); + assertEquals(HttpStatus.OK, response.getStatusCode()); + assertTrue(response + .getBody() + .contains("Baeldung")); + } + + @Test + public void whenUserWithWrongCredentialsRequestsHomePage_ThenUnauthorizedPage() throws IllegalStateException, IOException { + restTemplate = new TestRestTemplate("user", "wrongpassword"); + ResponseEntity response = restTemplate.getForEntity(base.toString(), String.class); + assertEquals(HttpStatus.UNAUTHORIZED, response.getStatusCode()); + assertTrue(response + .getBody() + .contains("Unauthorized")); + } +} diff --git a/spring-boot-security/src/test/java/com/baeldung/springbootsecurity/FormConfigurationIntegrationTest.java b/spring-boot-security/src/test/java/com/baeldung/springbootsecurity/FormConfigurationIntegrationTest.java new file mode 100644 index 0000000000..697a4f2868 --- /dev/null +++ b/spring-boot-security/src/test/java/com/baeldung/springbootsecurity/FormConfigurationIntegrationTest.java @@ -0,0 +1,106 @@ +package com.baeldung.springbootsecurity; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.embedded.LocalServerPort; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.http.*; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +import java.util.Collections; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static org.junit.Assert.*; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = RANDOM_PORT) +@ActiveProfiles("form") +public class FormConfigurationIntegrationTest { + + @Autowired TestRestTemplate restTemplate; + @LocalServerPort int port; + + @Test + public void whenLoginPageIsRequested_ThenSuccess() { + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.setAccept(Collections.singletonList(MediaType.TEXT_HTML)); + ResponseEntity responseEntity = restTemplate.exchange("/login", HttpMethod.GET, new HttpEntity(httpHeaders), String.class); + assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); + assertTrue(responseEntity + .getBody() + .contains("_csrf")); + } + + @Test + public void whenTryingToLoginWithCorrectCredentials_ThenAuthenticateWithSuccess() { + HttpHeaders httpHeaders = getHeaders(); + httpHeaders.setAccept(Collections.singletonList(MediaType.TEXT_HTML)); + httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED); + MultiValueMap form = getFormSubmitCorrectCredentials(); + ResponseEntity responseEntity = this.restTemplate.exchange("/login", HttpMethod.POST, new HttpEntity<>(form, httpHeaders), String.class); + assertEquals(responseEntity.getStatusCode(), HttpStatus.FOUND); + assertTrue(responseEntity + .getHeaders() + .getLocation() + .toString() + .endsWith(this.port + "/")); + assertNotNull(responseEntity + .getHeaders() + .get("Set-Cookie")); + } + + @Test + public void whenTryingToLoginWithInorrectCredentials_ThenAuthenticationFailed() { + HttpHeaders httpHeaders = getHeaders(); + httpHeaders.setAccept(Collections.singletonList(MediaType.TEXT_HTML)); + httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED); + MultiValueMap form = getFormSubmitIncorrectCredentials(); + ResponseEntity responseEntity = this.restTemplate.exchange("/login", HttpMethod.POST, new HttpEntity<>(form, httpHeaders), String.class); + assertEquals(responseEntity.getStatusCode(), HttpStatus.FOUND); + assertTrue(responseEntity + .getHeaders() + .getLocation() + .toString() + .endsWith(this.port + "/login?error")); + assertNull(responseEntity + .getHeaders() + .get("Set-Cookie")); + } + + private MultiValueMap getFormSubmitCorrectCredentials() { + MultiValueMap form = new LinkedMultiValueMap<>(); + form.set("username", "user"); + form.set("password", "password"); + return form; + } + + private MultiValueMap getFormSubmitIncorrectCredentials() { + MultiValueMap form = new LinkedMultiValueMap<>(); + form.set("username", "user"); + form.set("password", "wrongpassword"); + return form; + } + + private HttpHeaders getHeaders() { + HttpHeaders headers = new HttpHeaders(); + ResponseEntity page = this.restTemplate.getForEntity("/login", String.class); + assertEquals(page.getStatusCode(), HttpStatus.OK); + String cookie = page + .getHeaders() + .getFirst("Set-Cookie"); + headers.set("Cookie", cookie); + Pattern pattern = Pattern.compile("(?s).*name=\"_csrf\".*?value=\"([^\"]+).*"); + Matcher matcher = pattern.matcher(page.getBody()); + assertTrue(matcher.matches()); + headers.set("X-CSRF-TOKEN", matcher.group(1)); + return headers; + } + +} From 23f7f658e48ae921787039adde5a289ac9270a2e Mon Sep 17 00:00:00 2001 From: Jose Carvajal Date: Mon, 1 Jan 2018 00:28:27 +0100 Subject: [PATCH 7/9] BAEL-399 A Guide to Multitenancy in Hibernate 5 (#3323) * BAEL-399: A Guide to Multitenancy in Hibernate 5 * Removed unused properties in profile 2 * Changes after code review --- .../SchemaMultiTenantConnectionProvider.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/hibernate5/src/test/java/com/baeldung/hibernate/multitenancy/schema/SchemaMultiTenantConnectionProvider.java b/hibernate5/src/test/java/com/baeldung/hibernate/multitenancy/schema/SchemaMultiTenantConnectionProvider.java index 5045c3ee8e..601eba651c 100644 --- a/hibernate5/src/test/java/com/baeldung/hibernate/multitenancy/schema/SchemaMultiTenantConnectionProvider.java +++ b/hibernate5/src/test/java/com/baeldung/hibernate/multitenancy/schema/SchemaMultiTenantConnectionProvider.java @@ -8,12 +8,15 @@ import java.util.Properties; import org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl; import org.hibernate.engine.jdbc.connections.spi.AbstractMultiTenantConnectionProvider; import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; -import org.junit.Assert; @SuppressWarnings("serial") public class SchemaMultiTenantConnectionProvider extends AbstractMultiTenantConnectionProvider { - private final ConnectionProvider connectionProvider = initConnectionProvider(); + private final ConnectionProvider connectionProvider; + + public SchemaMultiTenantConnectionProvider() throws IOException { + connectionProvider = initConnectionProvider(); + } @Override protected ConnectionProvider getAnyConnectionProvider() { @@ -33,13 +36,9 @@ public class SchemaMultiTenantConnectionProvider extends AbstractMultiTenantConn return connection; } - private ConnectionProvider initConnectionProvider() { + private ConnectionProvider initConnectionProvider() throws IOException { Properties properties = new Properties(); - try { - properties.load(getClass().getResourceAsStream("/hibernate-schema-multitenancy.properties")); - } catch (IOException e) { - Assert.fail("Error loading resource. Cause: " + e.getMessage()); - } + properties.load(getClass().getResourceAsStream("/hibernate-schema-multitenancy.properties")); DriverManagerConnectionProviderImpl connectionProvider = new DriverManagerConnectionProviderImpl(); connectionProvider.configure(properties); From ccf1f4ed27c1781a2565b95582f8c4c741135105 Mon Sep 17 00:00:00 2001 From: abialas Date: Mon, 1 Jan 2018 13:07:35 +0100 Subject: [PATCH 8/9] BAEL-1412 add java 8 spring data features (#3306) --- .../baeldung/repository/UserRepository.java | 16 ++- .../repository/UserRepositoryTest.java | 97 +++++++++++++++++++ 2 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 spring-boot/src/test/java/org/baeldung/repository/UserRepositoryTest.java diff --git a/spring-boot/src/main/java/org/baeldung/repository/UserRepository.java b/spring-boot/src/main/java/org/baeldung/repository/UserRepository.java index 360dbf883c..c9a06b5bab 100644 --- a/spring-boot/src/main/java/org/baeldung/repository/UserRepository.java +++ b/spring-boot/src/main/java/org/baeldung/repository/UserRepository.java @@ -2,9 +2,23 @@ package org.baeldung.repository; import org.baeldung.model.User; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Repository; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Stream; + @Repository("userRepository") public interface UserRepository extends JpaRepository { - public int countByStatus(int status); + + int countByStatus(int status); + + Optional findOneByName(String name); + + Stream findAllByName(String name); + + @Async + CompletableFuture findOneByStatus(Integer status); + } diff --git a/spring-boot/src/test/java/org/baeldung/repository/UserRepositoryTest.java b/spring-boot/src/test/java/org/baeldung/repository/UserRepositoryTest.java new file mode 100644 index 0000000000..227bb02db2 --- /dev/null +++ b/spring-boot/src/test/java/org/baeldung/repository/UserRepositoryTest.java @@ -0,0 +1,97 @@ +package org.baeldung.repository; + +import org.baeldung.boot.Application; +import org.baeldung.model.User; +import org.junit.After; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.stream.Stream; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; + +/** + * Created by adam. + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = Application.class) +public class UserRepositoryTest { + + private final String USER_NAME_ADAM = "Adam"; + private final Integer ACTIVE_STATUS = 1; + + @Autowired + private UserRepository userRepository; + + @Test + public void shouldReturnEmptyOptionalWhenSearchByNameInEmptyDB() { + Optional foundUser = userRepository.findOneByName(USER_NAME_ADAM); + + assertThat(foundUser.isPresent(), equalTo(false)); + } + + @Test + public void shouldReturnOptionalWithPresentUserWhenExistsWithGivenName() { + User user = new User(); + user.setName(USER_NAME_ADAM); + userRepository.save(user); + + Optional foundUser = userRepository.findOneByName(USER_NAME_ADAM); + + assertThat(foundUser.isPresent(), equalTo(true)); + assertThat(foundUser.get() + .getName(), equalTo(USER_NAME_ADAM)); + } + + @Test + @Transactional + public void shouldReturnStreamOfUsersWithNameWhenExistWithSameGivenName() { + User user1 = new User(); + user1.setName(USER_NAME_ADAM); + userRepository.save(user1); + + User user2 = new User(); + user2.setName(USER_NAME_ADAM); + userRepository.save(user2); + + User user3 = new User(); + user3.setName(USER_NAME_ADAM); + userRepository.save(user3); + + User user4 = new User(); + user4.setName("SAMPLE"); + userRepository.save(user4); + + try (Stream foundUsersStream = userRepository.findAllByName(USER_NAME_ADAM)) { + assertThat(foundUsersStream.count(), equalTo(3l)); + } + } + + @Test + public void shouldReturnUserWithGivenStatusAsync() throws ExecutionException, InterruptedException { + User user = new User(); + user.setName(USER_NAME_ADAM); + user.setStatus(ACTIVE_STATUS); + userRepository.save(user); + + CompletableFuture userByStatus = userRepository.findOneByStatus(ACTIVE_STATUS); + + assertThat(userByStatus.get() + .getName(), equalTo(USER_NAME_ADAM)); + + } + + @After + public void cleanUp() { + userRepository.deleteAll(); + } + +} From f6f8f8debe151b41b49aed5c6720fad38d3f3fad Mon Sep 17 00:00:00 2001 From: Doha2012 Date: Tue, 2 Jan 2018 13:33:37 +0200 Subject: [PATCH 9/9] move url matching (#3326) * make sure modules using java8 * move url matching code --- spring-5-reactive/pom.xml | 2 +- .../controller}/PathPatternController.java | 2 +- .../com/baeldung/reactive/urlmatch/Actor.java | 23 ++++++ ...Spring5URLPatternUsingRouterFunctions.java | 2 +- .../reactive/urlmatch/FormHandler.java | 41 ++++++++++ .../urlmatch/FunctionalWebApplication.java | 80 +++++++++++++++++++ .../reactive/urlmatch/IndexRewriteFilter.java | 27 +++++++ .../src/main/resources/files/hello.txt | 1 + .../src/main/resources/files/test/test.txt | 1 + ...rnUsingRouterFunctionsIntegrationTest.java | 6 +- ...ernsUsingHandlerMethodIntegrationTest.java | 8 +- 11 files changed, 185 insertions(+), 8 deletions(-) rename {spring-5/src/main/java/com/baeldung/web => spring-5-reactive/src/main/java/com/baeldung/reactive/controller}/PathPatternController.java (93%) create mode 100644 spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/Actor.java rename {spring-5/src/main/java/com/baeldung/functional => spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch}/ExploreSpring5URLPatternUsingRouterFunctions.java (98%) create mode 100644 spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/FormHandler.java create mode 100644 spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/FunctionalWebApplication.java create mode 100644 spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/IndexRewriteFilter.java create mode 100644 spring-5-reactive/src/main/resources/files/hello.txt create mode 100644 spring-5-reactive/src/main/resources/files/test/test.txt rename spring-5/src/test/java/com/baeldung/functional/ExploreSpring5URLPatternUsingRouterFunctionsTest.java => spring-5-reactive/src/test/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctionsIntegrationTest.java (93%) rename {spring-5/src/test/java/com/baeldung/web => spring-5-reactive/src/test/java/com/baeldung/reactive/urlmatch}/PathPatternsUsingHandlerMethodIntegrationTest.java (92%) diff --git a/spring-5-reactive/pom.xml b/spring-5-reactive/pom.xml index 5d7cf0d7e5..e5b35de2f5 100644 --- a/spring-5-reactive/pom.xml +++ b/spring-5-reactive/pom.xml @@ -28,7 +28,7 @@ org.springframework.boot - spring-boot-starter-web + spring-boot-starter-tomcat org.springframework.boot diff --git a/spring-5/src/main/java/com/baeldung/web/PathPatternController.java b/spring-5-reactive/src/main/java/com/baeldung/reactive/controller/PathPatternController.java similarity index 93% rename from spring-5/src/main/java/com/baeldung/web/PathPatternController.java rename to spring-5-reactive/src/main/java/com/baeldung/reactive/controller/PathPatternController.java index 6fd972f2a4..f5a5d9e769 100644 --- a/spring-5/src/main/java/com/baeldung/web/PathPatternController.java +++ b/spring-5-reactive/src/main/java/com/baeldung/reactive/controller/PathPatternController.java @@ -1,4 +1,4 @@ -package com.baeldung.web; +package com.baeldung.reactive.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; diff --git a/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/Actor.java b/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/Actor.java new file mode 100644 index 0000000000..ee06b94be7 --- /dev/null +++ b/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/Actor.java @@ -0,0 +1,23 @@ +package com.baeldung.reactive.urlmatch; + +class Actor { + private String firstname; + private String lastname; + + public Actor() { + } + + public Actor(String firstname, String lastname) { + this.firstname = firstname; + this.lastname = lastname; + } + + public String getFirstname() { + return firstname; + } + + public String getLastname() { + return lastname; + } + +} diff --git a/spring-5/src/main/java/com/baeldung/functional/ExploreSpring5URLPatternUsingRouterFunctions.java b/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctions.java similarity index 98% rename from spring-5/src/main/java/com/baeldung/functional/ExploreSpring5URLPatternUsingRouterFunctions.java rename to spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctions.java index 2a6d04538c..78f40be57a 100644 --- a/spring-5/src/main/java/com/baeldung/functional/ExploreSpring5URLPatternUsingRouterFunctions.java +++ b/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctions.java @@ -1,4 +1,4 @@ -package com.baeldung.functional; +package com.baeldung.reactive.urlmatch; import static org.springframework.web.reactive.function.BodyInserters.fromObject; import static org.springframework.web.reactive.function.server.RequestPredicates.GET; diff --git a/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/FormHandler.java b/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/FormHandler.java new file mode 100644 index 0000000000..0781230379 --- /dev/null +++ b/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/FormHandler.java @@ -0,0 +1,41 @@ +package com.baeldung.reactive.urlmatch; + +import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.util.MultiValueMap; +import org.springframework.web.reactive.function.server.ServerRequest; +import org.springframework.web.reactive.function.server.ServerResponse; +import reactor.core.publisher.Mono; + +import java.util.List; +import java.util.concurrent.atomic.AtomicLong; + +import static org.springframework.web.reactive.function.BodyExtractors.toDataBuffers; +import static org.springframework.web.reactive.function.BodyExtractors.toFormData; +import static org.springframework.web.reactive.function.BodyInserters.fromObject; +import static org.springframework.web.reactive.function.server.ServerResponse.ok; + +public class FormHandler { + + Mono handleLogin(ServerRequest request) { + return request.body(toFormData()) + .map(MultiValueMap::toSingleValueMap) + .filter(formData -> "baeldung".equals(formData.get("user"))) + .filter(formData -> "you_know_what_to_do".equals(formData.get("token"))) + .flatMap(formData -> ok().body(Mono.just("welcome back!"), String.class)) + .switchIfEmpty(ServerResponse.badRequest() + .build()); + } + + Mono handleUpload(ServerRequest request) { + return request.body(toDataBuffers()) + .collectList() + .flatMap(dataBuffers -> ok().body(fromObject(extractData(dataBuffers).toString()))); + } + + private AtomicLong extractData(List dataBuffers) { + AtomicLong atomicLong = new AtomicLong(0); + dataBuffers.forEach(d -> atomicLong.addAndGet(d.asByteBuffer() + .array().length)); + return atomicLong; + } +} diff --git a/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/FunctionalWebApplication.java b/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/FunctionalWebApplication.java new file mode 100644 index 0000000000..2ea5420a2b --- /dev/null +++ b/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/FunctionalWebApplication.java @@ -0,0 +1,80 @@ +package com.baeldung.reactive.urlmatch; + +import static org.springframework.web.reactive.function.BodyInserters.fromObject; +import static org.springframework.web.reactive.function.server.RequestPredicates.GET; +import static org.springframework.web.reactive.function.server.RequestPredicates.POST; +import static org.springframework.web.reactive.function.server.RequestPredicates.path; +import static org.springframework.web.reactive.function.server.RouterFunctions.route; +import static org.springframework.web.reactive.function.server.RouterFunctions.toHttpHandler; +import static org.springframework.web.reactive.function.server.ServerResponse.ok; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +import org.apache.catalina.Context; +import org.apache.catalina.startup.Tomcat; +import org.springframework.boot.web.embedded.tomcat.TomcatWebServer; +import org.springframework.boot.web.server.WebServer; +import org.springframework.core.io.ClassPathResource; +import org.springframework.http.server.reactive.HttpHandler; +import org.springframework.http.server.reactive.ServletHttpHandlerAdapter; +import org.springframework.web.reactive.function.server.RouterFunction; +import org.springframework.web.reactive.function.server.RouterFunctions; +import org.springframework.web.reactive.function.server.ServerResponse; +import org.springframework.web.server.WebHandler; +import org.springframework.web.server.adapter.WebHttpHandlerBuilder; + +import reactor.core.publisher.Flux; + +public class FunctionalWebApplication { + + private static final Actor BRAD_PITT = new Actor("Brad", "Pitt"); + private static final Actor TOM_HANKS = new Actor("Tom", "Hanks"); + private static final List actors = new CopyOnWriteArrayList<>(Arrays.asList(BRAD_PITT, TOM_HANKS)); + + private RouterFunction routingFunction() { + FormHandler formHandler = new FormHandler(); + + RouterFunction restfulRouter = route(GET("/"), serverRequest -> ok().body(Flux.fromIterable(actors), Actor.class)).andRoute(POST("/"), serverRequest -> serverRequest.bodyToMono(Actor.class) + .doOnNext(actors::add) + .then(ok().build())); + + return route(GET("/test"), serverRequest -> ok().body(fromObject("helloworld"))).andRoute(POST("/login"), formHandler::handleLogin) + .andRoute(POST("/upload"), formHandler::handleUpload) + .and(RouterFunctions.resources("/files/**", new ClassPathResource("files/"))) + .andNest(path("/actor"), restfulRouter) + .filter((request, next) -> { + System.out.println("Before handler invocation: " + request.path()); + return next.handle(request); + }); + } + + WebServer start() throws Exception { + WebHandler webHandler = (WebHandler) toHttpHandler(routingFunction()); + HttpHandler httpHandler = WebHttpHandlerBuilder.webHandler(webHandler) + .filter(new IndexRewriteFilter()) + .build(); + + Tomcat tomcat = new Tomcat(); + tomcat.setHostname("localhost"); + tomcat.setPort(9090); + Context rootContext = tomcat.addContext("", System.getProperty("java.io.tmpdir")); + ServletHttpHandlerAdapter servlet = new ServletHttpHandlerAdapter(httpHandler); + Tomcat.addServlet(rootContext, "httpHandlerServlet", servlet); + rootContext.addServletMappingDecoded("/", "httpHandlerServlet"); + + TomcatWebServer server = new TomcatWebServer(tomcat); + server.start(); + return server; + + } + + public static void main(String[] args) { + try { + new FunctionalWebApplication().start(); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/IndexRewriteFilter.java b/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/IndexRewriteFilter.java new file mode 100644 index 0000000000..2eb252ed2b --- /dev/null +++ b/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/IndexRewriteFilter.java @@ -0,0 +1,27 @@ +package com.baeldung.reactive.urlmatch; + +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.server.WebFilter; +import org.springframework.web.server.WebFilterChain; +import reactor.core.publisher.Mono; + +class IndexRewriteFilter implements WebFilter { + + @Override + public Mono filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain) { + ServerHttpRequest request = serverWebExchange.getRequest(); + if (request.getURI() + .getPath() + .equals("/")) { + return webFilterChain.filter(serverWebExchange.mutate() + .request(builder -> builder.method(request.getMethod()) + .contextPath(request.getPath() + .toString()) + .path("/test")) + .build()); + } + return webFilterChain.filter(serverWebExchange); + } + +} diff --git a/spring-5-reactive/src/main/resources/files/hello.txt b/spring-5-reactive/src/main/resources/files/hello.txt new file mode 100644 index 0000000000..b6fc4c620b --- /dev/null +++ b/spring-5-reactive/src/main/resources/files/hello.txt @@ -0,0 +1 @@ +hello \ No newline at end of file diff --git a/spring-5-reactive/src/main/resources/files/test/test.txt b/spring-5-reactive/src/main/resources/files/test/test.txt new file mode 100644 index 0000000000..30d74d2584 --- /dev/null +++ b/spring-5-reactive/src/main/resources/files/test/test.txt @@ -0,0 +1 @@ +test \ No newline at end of file diff --git a/spring-5/src/test/java/com/baeldung/functional/ExploreSpring5URLPatternUsingRouterFunctionsTest.java b/spring-5-reactive/src/test/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctionsIntegrationTest.java similarity index 93% rename from spring-5/src/test/java/com/baeldung/functional/ExploreSpring5URLPatternUsingRouterFunctionsTest.java rename to spring-5-reactive/src/test/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctionsIntegrationTest.java index 7a38fa697f..21ba11616d 100644 --- a/spring-5/src/test/java/com/baeldung/functional/ExploreSpring5URLPatternUsingRouterFunctionsTest.java +++ b/spring-5-reactive/src/test/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctionsIntegrationTest.java @@ -1,4 +1,4 @@ -package com.baeldung.functional; +package com.baeldung.reactive.urlmatch; import org.junit.AfterClass; import org.junit.BeforeClass; @@ -6,7 +6,9 @@ import org.junit.Test; import org.springframework.boot.web.server.WebServer; import org.springframework.test.web.reactive.server.WebTestClient; -public class ExploreSpring5URLPatternUsingRouterFunctionsTest { +import com.baeldung.reactive.urlmatch.ExploreSpring5URLPatternUsingRouterFunctions; + +public class ExploreSpring5URLPatternUsingRouterFunctionsIntegrationTest { private static WebTestClient client; private static WebServer server; diff --git a/spring-5/src/test/java/com/baeldung/web/PathPatternsUsingHandlerMethodIntegrationTest.java b/spring-5-reactive/src/test/java/com/baeldung/reactive/urlmatch/PathPatternsUsingHandlerMethodIntegrationTest.java similarity index 92% rename from spring-5/src/test/java/com/baeldung/web/PathPatternsUsingHandlerMethodIntegrationTest.java rename to spring-5-reactive/src/test/java/com/baeldung/reactive/urlmatch/PathPatternsUsingHandlerMethodIntegrationTest.java index c2ed8ff071..9f31608ff7 100644 --- a/spring-5/src/test/java/com/baeldung/web/PathPatternsUsingHandlerMethodIntegrationTest.java +++ b/spring-5-reactive/src/test/java/com/baeldung/reactive/urlmatch/PathPatternsUsingHandlerMethodIntegrationTest.java @@ -1,6 +1,5 @@ -package com.baeldung.web; +package com.baeldung.reactive.urlmatch; -import com.baeldung.Spring5Application; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; @@ -8,8 +7,11 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.reactive.server.WebTestClient; +import com.baeldung.reactive.Spring5ReactiveApplication; +import com.baeldung.reactive.controller.PathPatternController; + @RunWith(SpringRunner.class) -@SpringBootTest(classes = Spring5Application.class) +@SpringBootTest(classes = Spring5ReactiveApplication.class) public class PathPatternsUsingHandlerMethodIntegrationTest { private static WebTestClient client;