From a3af6f70fc3c8e168133e1d27cc9e9c65b32644f Mon Sep 17 00:00:00 2001 From: reza ganji Date: Sat, 30 Mar 2024 13:02:36 +0330 Subject: [PATCH 1/8] BAEL-7540 --- spring-5-webflux-2/README.md | 1 + spring-5-webflux-2/pom.xml | 6 +-- .../com/baeldung/webflux/caching/Item.java | 6 +-- .../baeldung/webflux/caching/ItemService.java | 10 ++-- .../controller/UserController.java | 35 ++++++++++++++ .../ex/NotFoundException.java | 12 +++++ .../exceptionhandeling/model/User.java | 29 +++++++++++ .../repository/UserRepository.java | 24 ++++++++++ .../webflux/filerecord/FileRecord.java | 4 +- .../filerecord/FileRecordApplication.java | 3 +- .../filerecord/FileRecordController.java | 7 +-- .../webflux/filerecord/FileRecordService.java | 1 + .../com/baeldung/webflux/model/Payment.java | 1 - .../webflux/zipwhen/service/EmailService.java | 10 ++-- .../webflux/zipwhen/web/UserController.java | 16 +++---- .../src/main/resources/logback.xml | 2 +- .../MonoFluxResultCachingLiveTest.java | 41 ++++++++-------- .../UserControllerUnitTest.java | 48 +++++++++++++++++++ .../FileRecordControllerIntegrationTest.java | 11 +++-- .../FirstElementOfFluxUnitTest.java | 1 + .../zipwhen/UserControllerUnitTest.java | 12 ++--- 21 files changed, 217 insertions(+), 63 deletions(-) create mode 100644 spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/controller/UserController.java create mode 100644 spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/ex/NotFoundException.java create mode 100644 spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/model/User.java create mode 100644 spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/repository/UserRepository.java create mode 100644 spring-5-webflux-2/src/test/java/com/baeldung/webflux/exceptionhandeling/UserControllerUnitTest.java diff --git a/spring-5-webflux-2/README.md b/spring-5-webflux-2/README.md index 5232d86643..5579e1cec5 100644 --- a/spring-5-webflux-2/README.md +++ b/spring-5-webflux-2/README.md @@ -3,6 +3,7 @@ This module contains articles about Spring 5 WebFlux ## Relevant articles: + - [Spring Webflux and @Cacheable Annotation](https://www.baeldung.com/spring-webflux-cacheable) - [Comparison Between Mono’s doOnNext() and doOnSuccess()](https://www.baeldung.com/mono-doonnext-doonsuccess) - [How to Access the First Element of a Flux](https://www.baeldung.com/java-flux-first-element) diff --git a/spring-5-webflux-2/pom.xml b/spring-5-webflux-2/pom.xml index 38cbbc8bf0..85e451c075 100644 --- a/spring-5-webflux-2/pom.xml +++ b/spring-5-webflux-2/pom.xml @@ -1,7 +1,7 @@ - + 4.0.0 spring-5-webflux-2 1.0-SNAPSHOT diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/caching/Item.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/caching/Item.java index 54b7d63f33..6ad03baafc 100644 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/caching/Item.java +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/caching/Item.java @@ -41,10 +41,6 @@ public class Item { @Override public String toString() { - return "Item{" + - "id='" + _id + '\'' + - ", name='" + name + '\'' + - ", price=" + price + - '}'; + return "Item{" + "id='" + _id + '\'' + ", name='" + name + '\'' + ", price=" + price + '}'; } } diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/caching/ItemService.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/caching/ItemService.java index 9bf934b504..9286cecef8 100644 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/caching/ItemService.java +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/caching/ItemService.java @@ -16,7 +16,8 @@ public class ItemService { public ItemService(ItemRepository repository) { this.repository = repository; - this.cache = Caffeine.newBuilder().build(this::getItem_withCaffeine); + this.cache = Caffeine.newBuilder() + .build(this::getItem_withCaffeine); } @Cacheable("items") @@ -30,11 +31,14 @@ public class ItemService { @Cacheable("items") public Mono getItem_withCache(String id) { - return repository.findById(id).cache(); + return repository.findById(id) + .cache(); } @Cacheable("items") public Mono getItem_withCaffeine(String id) { - return cache.asMap().computeIfAbsent(id, k -> repository.findById(id).cast(Item.class)); + return cache.asMap() + .computeIfAbsent(id, k -> repository.findById(id) + .cast(Item.class)); } } diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/controller/UserController.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/controller/UserController.java new file mode 100644 index 0000000000..6490b997af --- /dev/null +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/controller/UserController.java @@ -0,0 +1,35 @@ +package com.baeldung.webflux.exceptionhandeling.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RestController; + +import com.baeldung.webflux.exceptionhandeling.ex.NotFoundException; +import com.baeldung.webflux.exceptionhandeling.repository.UserRepository; +import com.baeldung.webflux.zipwhen.model.User; + +import reactor.core.publisher.Mono; + +@RestController +public class UserController { + + private final UserRepository userRepository; + + @Autowired + public UserController(UserRepository userRepository) { + this.userRepository = userRepository; + } + + @GetMapping("/user/{id}") + public Mono getUserByIdThrowingException(@PathVariable String id) { + return userRepository.findById(id) + .switchIfEmpty(Mono.error(new NotFoundException("User not found"))); + } + + @GetMapping("/user/{id}") + public Mono getUserByIdUsingMonoError(@PathVariable String id) { + return userRepository.findById(id) + .switchIfEmpty(Mono.error(() -> new NotFoundException("User not found"))); + } +} diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/ex/NotFoundException.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/ex/NotFoundException.java new file mode 100644 index 0000000000..5401a4d133 --- /dev/null +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/ex/NotFoundException.java @@ -0,0 +1,12 @@ +package com.baeldung.webflux.exceptionhandeling.ex; + +public class NotFoundException extends RuntimeException { + + public NotFoundException(String message) { + super(message); + } + + public NotFoundException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/model/User.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/model/User.java new file mode 100644 index 0000000000..42e1293ee8 --- /dev/null +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/model/User.java @@ -0,0 +1,29 @@ +package com.baeldung.webflux.exceptionhandeling.model; + +public class User { + private String id; + private String username; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public User(String userId, String userName) { + this.id=userId; + this.username=userName; + + } +} + diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/repository/UserRepository.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/repository/UserRepository.java new file mode 100644 index 0000000000..7d4ac0af86 --- /dev/null +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/repository/UserRepository.java @@ -0,0 +1,24 @@ +package com.baeldung.webflux.exceptionhandeling.repository; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.springframework.stereotype.Repository; + +import com.baeldung.webflux.zipwhen.model.User; + +import reactor.core.publisher.Mono; + +@Repository +public class UserRepository { + private final Map userDatabase = new ConcurrentHashMap<>(); + + public UserRepository() { + userDatabase.put("1", new User("1", "John Doe")); + userDatabase.put("2", new User("2", "Jane Smith")); + } + + public Mono findById(String id) { + return Mono.justOrEmpty(userDatabase.get(id)); + } +} diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecord.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecord.java index 5c0e265e13..bd339bf849 100644 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecord.java +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecord.java @@ -1,9 +1,9 @@ package com.baeldung.webflux.filerecord; -import org.springframework.data.annotation.Id; - import java.util.List; +import org.springframework.data.annotation.Id; + public class FileRecord { @Id private int id; diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordApplication.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordApplication.java index 9c20e10040..0388bdb0b8 100644 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordApplication.java +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordApplication.java @@ -1,6 +1,5 @@ package com.baeldung.webflux.filerecord; -import io.r2dbc.spi.ConnectionFactory; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; @@ -8,6 +7,8 @@ import org.springframework.core.io.ClassPathResource; import org.springframework.r2dbc.connection.init.ConnectionFactoryInitializer; import org.springframework.r2dbc.connection.init.ResourceDatabasePopulator; +import io.r2dbc.spi.ConnectionFactory; + @SpringBootApplication public class FileRecordApplication { diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordController.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordController.java index 943cec9a2d..b3cd0b89e4 100644 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordController.java +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordController.java @@ -1,12 +1,13 @@ package com.baeldung.webflux.filerecord; +import java.nio.file.Paths; + import org.springframework.http.codec.multipart.FilePart; import org.springframework.web.bind.annotation.*; + import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -import java.nio.file.Paths; - @RestController public class FileRecordController { @@ -28,7 +29,7 @@ public class FileRecordController { FileRecord fileRecord = new FileRecord(); return filePartFlux.flatMap(filePart -> filePart.transferTo(Paths.get(filePart.filename())) - .then(Mono.just(filePart.filename()))) + .then(Mono.just(filePart.filename()))) .collectList() .flatMap(filenames -> { fileRecord.setFilenames(filenames); diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordService.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordService.java index 6e74f3577b..bce8c82c39 100644 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordService.java +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordService.java @@ -1,6 +1,7 @@ package com.baeldung.webflux.filerecord; import org.springframework.stereotype.Service; + import reactor.core.publisher.Mono; @Service diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/model/Payment.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/model/Payment.java index f9be73ee44..1fc090446a 100644 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/model/Payment.java +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/model/Payment.java @@ -1,6 +1,5 @@ package com.baeldung.webflux.model; - public class Payment { private final int amount; diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/service/EmailService.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/service/EmailService.java index 9c0340b7ee..c4c5520d24 100644 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/service/EmailService.java +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/service/EmailService.java @@ -11,10 +11,10 @@ public class EmailService { public Mono sendEmail(String userId) { return userService.getUser(userId) - .flatMap(user -> { - System.out.println("Sending email to: " + user.getEmail()); - return Mono.just(true); - }) - .defaultIfEmpty(false); + .flatMap(user -> { + System.out.println("Sending email to: " + user.getEmail()); + return Mono.just(true); + }) + .defaultIfEmpty(false); } } diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/web/UserController.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/web/UserController.java index dbd89c45d3..fa0d083beb 100644 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/web/UserController.java +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/web/UserController.java @@ -28,16 +28,16 @@ public class UserController { public Mono> combineAllDataFor(@PathVariable String userId) { Mono userMono = userService.getUser(userId); Mono emailSentMono = emailService.sendEmail(userId) - .subscribeOn(Schedulers.parallel()); + .subscribeOn(Schedulers.parallel()); Mono databaseResultMono = userMono.flatMap(user -> databaseService.saveUserData(user) - .map(Object::toString)); + .map(Object::toString)); return userMono.zipWhen(user -> emailSentMono, Tuples::of) - .zipWhen(tuple -> databaseResultMono, (tuple, databaseResult) -> { - User user = tuple.getT1(); - Boolean emailSent = tuple.getT2(); - return ResponseEntity.ok() - .body("Response: " + user + ", Email Sent: " + emailSent + ", Database Result: " + databaseResult); - }); + .zipWhen(tuple -> databaseResultMono, (tuple, databaseResult) -> { + User user = tuple.getT1(); + Boolean emailSent = tuple.getT2(); + return ResponseEntity.ok() + .body("Response: " + user + ", Email Sent: " + emailSent + ", Database Result: " + databaseResult); + }); } } diff --git a/spring-5-webflux-2/src/main/resources/logback.xml b/spring-5-webflux-2/src/main/resources/logback.xml index 48b68c6bf1..122a79945b 100644 --- a/spring-5-webflux-2/src/main/resources/logback.xml +++ b/spring-5-webflux-2/src/main/resources/logback.xml @@ -1,7 +1,7 @@ + class="ch.qos.logback.core.ConsoleAppender"> %black(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %yellow(%C{1.}): %msg%n%throwable diff --git a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/caching/MonoFluxResultCachingLiveTest.java b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/caching/MonoFluxResultCachingLiveTest.java index 2075c1e77e..2ff2c15662 100644 --- a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/caching/MonoFluxResultCachingLiveTest.java +++ b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/caching/MonoFluxResultCachingLiveTest.java @@ -1,5 +1,6 @@ package com.baeldung.webflux.caching; +import static org.assertj.core.api.Assertions.assertThat; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -12,13 +13,10 @@ import org.testcontainers.utility.DockerImageName; import reactor.core.publisher.Mono; -import static org.assertj.core.api.Assertions.assertThat; - @SpringBootTest @ActiveProfiles("cache") public class MonoFluxResultCachingLiveTest { - @Autowired ItemService itemService; @@ -30,32 +28,34 @@ public class MonoFluxResultCachingLiveTest { registry.add("spring.data.mongodb.uri", mongoDBContainer::getReplicaSetUrl); } -@Test -public void givenItem_whenGetItemIsCalled_thenMonoIsCached() { - Mono glass = itemService.save(new Item("glass", 1.00)); + @Test + public void givenItem_whenGetItemIsCalled_thenMonoIsCached() { + Mono glass = itemService.save(new Item("glass", 1.00)); - String id = glass.block().get_id(); + String id = glass.block() + .get_id(); - Mono mono = itemService.getItem(id); - Item item = mono.block(); + Mono mono = itemService.getItem(id); + Item item = mono.block(); - assertThat(item).isNotNull(); - assertThat(item.getName()).isEqualTo("glass"); - assertThat(item.getPrice()).isEqualTo(1.00); + assertThat(item).isNotNull(); + assertThat(item.getName()).isEqualTo("glass"); + assertThat(item.getPrice()).isEqualTo(1.00); - Mono mono2 = itemService.getItem(id); - Item item2 = mono2.block(); + Mono mono2 = itemService.getItem(id); + Item item2 = mono2.block(); - assertThat(item2).isNotNull(); - assertThat(item2.getName()).isEqualTo("glass"); - assertThat(item2.getPrice()).isEqualTo(1.00); -} + assertThat(item2).isNotNull(); + assertThat(item2.getName()).isEqualTo("glass"); + assertThat(item2.getPrice()).isEqualTo(1.00); + } @Test public void givenItem_whenGetItemWithCacheIsCalled_thenMonoResultIsCached() { Mono glass = itemService.save(new Item("glass", 1.00)); - String id = glass.block().get_id(); + String id = glass.block() + .get_id(); Mono mono = itemService.getItem_withCache(id); Item item = mono.block(); @@ -76,7 +76,8 @@ public void givenItem_whenGetItemIsCalled_thenMonoIsCached() { public void givenItem_whenGetItemWithCaffeineIsCalled_thenMonoResultIsCached() { Mono glass = itemService.save(new Item("glass", 1.00)); - String id = glass.block().get_id(); + String id = glass.block() + .get_id(); Mono mono = itemService.getItem_withCaffeine(id); Item item = mono.block(); diff --git a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/exceptionhandeling/UserControllerUnitTest.java b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/exceptionhandeling/UserControllerUnitTest.java new file mode 100644 index 0000000000..d59ec52f3c --- /dev/null +++ b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/exceptionhandeling/UserControllerUnitTest.java @@ -0,0 +1,48 @@ +package com.baeldung.webflux.exceptionhandeling; + +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +import static org.mockito.Mockito.when; + +import com.baeldung.webflux.exceptionhandeling.controller.UserController; +import com.baeldung.webflux.exceptionhandeling.ex.NotFoundException; +import com.baeldung.webflux.exceptionhandeling.repository.UserRepository; + +public class UserControllerUnitTest { + @Mock + private UserRepository userRepository; + + @InjectMocks + private UserController userController; + + public UserControllerUnitTest() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void testGetUserByIdUsingMonoError_UserNotFound() { + String userId = "3"; + when(userRepository.findById(userId)).thenReturn(Mono.empty()); + StepVerifier.create(userController.getUserByIdUsingMonoError(userId)) + .expectError(NotFoundException.class) + .verify(); + } + + @Test + public void testGetUserByIdThrowingException_UserNotFound() { + String userId = "3"; + when(userRepository.findById(userId)).thenReturn(Mono.empty()); + assertThrows(NotFoundException.class, () -> userController.getUserByIdThrowingException(userId) + .block()); + } + +} + diff --git a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/filerecord/FileRecordControllerIntegrationTest.java b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/filerecord/FileRecordControllerIntegrationTest.java index c47d53632b..f8585852c1 100644 --- a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/filerecord/FileRecordControllerIntegrationTest.java +++ b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/filerecord/FileRecordControllerIntegrationTest.java @@ -1,5 +1,10 @@ package com.baeldung.webflux.filerecord; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import java.util.List; + import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; @@ -13,13 +18,9 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.web.reactive.server.WebTestClient; import org.springframework.util.LinkedMultiValueMap; + import reactor.core.publisher.Mono; -import java.util.List; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; - @ExtendWith(SpringExtension.class) @SpringBootTest(classes = FileRecordController.class) @ContextConfiguration(classes = { FileRecordController.class }) diff --git a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/firstelementofflux/FirstElementOfFluxUnitTest.java b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/firstelementofflux/FirstElementOfFluxUnitTest.java index a036011796..d7c084e3ec 100644 --- a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/firstelementofflux/FirstElementOfFluxUnitTest.java +++ b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/firstelementofflux/FirstElementOfFluxUnitTest.java @@ -7,6 +7,7 @@ import java.util.Optional; import org.junit.jupiter.api.Test; import com.baeldung.webflux.model.Payment; + import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.test.StepVerifier; diff --git a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/zipwhen/UserControllerUnitTest.java b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/zipwhen/UserControllerUnitTest.java index 8ed4cfb6c6..07c54fd531 100644 --- a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/zipwhen/UserControllerUnitTest.java +++ b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/zipwhen/UserControllerUnitTest.java @@ -25,19 +25,19 @@ public class UserControllerUnitTest { User user = new User(userId, "John Doe"); Mockito.when(userService.getUser(userId)) - .thenReturn(Mono.just(user)); + .thenReturn(Mono.just(user)); Mockito.when(emailService.sendEmail(userId)) - .thenReturn(Mono.just(true)); + .thenReturn(Mono.just(true)); Mockito.when(databaseService.saveUserData(user)) - .thenReturn(Mono.just(true)); + .thenReturn(Mono.just(true)); UserController userController = new UserController(userService, emailService, databaseService); Mono> responseMono = userController.combineAllDataFor(userId); StepVerifier.create(responseMono) - .expectNextMatches(responseEntity -> responseEntity.getStatusCode() == HttpStatus.OK && responseEntity.getBody() - .equals("Response: " + user + ", Email Sent: true, Database Result: " + true)) - .verifyComplete(); + .expectNextMatches(responseEntity -> responseEntity.getStatusCode() == HttpStatus.OK && responseEntity.getBody() + .equals("Response: " + user + ", Email Sent: true, Database Result: " + true)) + .verifyComplete(); } } From 2c5307571e6377e436e6f9cc5819e341b6d72cdd Mon Sep 17 00:00:00 2001 From: reza ganji Date: Sat, 30 Mar 2024 13:05:53 +0330 Subject: [PATCH 2/8] Revert "BAEL-7540" This reverts commit a3af6f70fc3c8e168133e1d27cc9e9c65b32644f. --- spring-5-webflux-2/README.md | 1 - spring-5-webflux-2/pom.xml | 6 +-- .../com/baeldung/webflux/caching/Item.java | 6 ++- .../baeldung/webflux/caching/ItemService.java | 10 ++-- .../controller/UserController.java | 35 -------------- .../ex/NotFoundException.java | 12 ----- .../exceptionhandeling/model/User.java | 29 ----------- .../repository/UserRepository.java | 24 ---------- .../webflux/filerecord/FileRecord.java | 4 +- .../filerecord/FileRecordApplication.java | 3 +- .../filerecord/FileRecordController.java | 7 ++- .../webflux/filerecord/FileRecordService.java | 1 - .../com/baeldung/webflux/model/Payment.java | 1 + .../webflux/zipwhen/service/EmailService.java | 10 ++-- .../webflux/zipwhen/web/UserController.java | 16 +++---- .../src/main/resources/logback.xml | 2 +- .../MonoFluxResultCachingLiveTest.java | 41 ++++++++-------- .../UserControllerUnitTest.java | 48 ------------------- .../FileRecordControllerIntegrationTest.java | 11 ++--- .../FirstElementOfFluxUnitTest.java | 1 - .../zipwhen/UserControllerUnitTest.java | 12 ++--- 21 files changed, 63 insertions(+), 217 deletions(-) delete mode 100644 spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/controller/UserController.java delete mode 100644 spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/ex/NotFoundException.java delete mode 100644 spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/model/User.java delete mode 100644 spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/repository/UserRepository.java delete mode 100644 spring-5-webflux-2/src/test/java/com/baeldung/webflux/exceptionhandeling/UserControllerUnitTest.java diff --git a/spring-5-webflux-2/README.md b/spring-5-webflux-2/README.md index 5579e1cec5..5232d86643 100644 --- a/spring-5-webflux-2/README.md +++ b/spring-5-webflux-2/README.md @@ -3,7 +3,6 @@ This module contains articles about Spring 5 WebFlux ## Relevant articles: - - [Spring Webflux and @Cacheable Annotation](https://www.baeldung.com/spring-webflux-cacheable) - [Comparison Between Mono’s doOnNext() and doOnSuccess()](https://www.baeldung.com/mono-doonnext-doonsuccess) - [How to Access the First Element of a Flux](https://www.baeldung.com/java-flux-first-element) diff --git a/spring-5-webflux-2/pom.xml b/spring-5-webflux-2/pom.xml index 85e451c075..38cbbc8bf0 100644 --- a/spring-5-webflux-2/pom.xml +++ b/spring-5-webflux-2/pom.xml @@ -1,7 +1,7 @@ - + 4.0.0 spring-5-webflux-2 1.0-SNAPSHOT diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/caching/Item.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/caching/Item.java index 6ad03baafc..54b7d63f33 100644 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/caching/Item.java +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/caching/Item.java @@ -41,6 +41,10 @@ public class Item { @Override public String toString() { - return "Item{" + "id='" + _id + '\'' + ", name='" + name + '\'' + ", price=" + price + '}'; + return "Item{" + + "id='" + _id + '\'' + + ", name='" + name + '\'' + + ", price=" + price + + '}'; } } diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/caching/ItemService.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/caching/ItemService.java index 9286cecef8..9bf934b504 100644 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/caching/ItemService.java +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/caching/ItemService.java @@ -16,8 +16,7 @@ public class ItemService { public ItemService(ItemRepository repository) { this.repository = repository; - this.cache = Caffeine.newBuilder() - .build(this::getItem_withCaffeine); + this.cache = Caffeine.newBuilder().build(this::getItem_withCaffeine); } @Cacheable("items") @@ -31,14 +30,11 @@ public class ItemService { @Cacheable("items") public Mono getItem_withCache(String id) { - return repository.findById(id) - .cache(); + return repository.findById(id).cache(); } @Cacheable("items") public Mono getItem_withCaffeine(String id) { - return cache.asMap() - .computeIfAbsent(id, k -> repository.findById(id) - .cast(Item.class)); + return cache.asMap().computeIfAbsent(id, k -> repository.findById(id).cast(Item.class)); } } diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/controller/UserController.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/controller/UserController.java deleted file mode 100644 index 6490b997af..0000000000 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/controller/UserController.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.baeldung.webflux.exceptionhandeling.controller; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RestController; - -import com.baeldung.webflux.exceptionhandeling.ex.NotFoundException; -import com.baeldung.webflux.exceptionhandeling.repository.UserRepository; -import com.baeldung.webflux.zipwhen.model.User; - -import reactor.core.publisher.Mono; - -@RestController -public class UserController { - - private final UserRepository userRepository; - - @Autowired - public UserController(UserRepository userRepository) { - this.userRepository = userRepository; - } - - @GetMapping("/user/{id}") - public Mono getUserByIdThrowingException(@PathVariable String id) { - return userRepository.findById(id) - .switchIfEmpty(Mono.error(new NotFoundException("User not found"))); - } - - @GetMapping("/user/{id}") - public Mono getUserByIdUsingMonoError(@PathVariable String id) { - return userRepository.findById(id) - .switchIfEmpty(Mono.error(() -> new NotFoundException("User not found"))); - } -} diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/ex/NotFoundException.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/ex/NotFoundException.java deleted file mode 100644 index 5401a4d133..0000000000 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/ex/NotFoundException.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.baeldung.webflux.exceptionhandeling.ex; - -public class NotFoundException extends RuntimeException { - - public NotFoundException(String message) { - super(message); - } - - public NotFoundException(String message, Throwable cause) { - super(message, cause); - } -} diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/model/User.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/model/User.java deleted file mode 100644 index 42e1293ee8..0000000000 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/model/User.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.baeldung.webflux.exceptionhandeling.model; - -public class User { - private String id; - private String username; - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public User(String userId, String userName) { - this.id=userId; - this.username=userName; - - } -} - diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/repository/UserRepository.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/repository/UserRepository.java deleted file mode 100644 index 7d4ac0af86..0000000000 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/repository/UserRepository.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.baeldung.webflux.exceptionhandeling.repository; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import org.springframework.stereotype.Repository; - -import com.baeldung.webflux.zipwhen.model.User; - -import reactor.core.publisher.Mono; - -@Repository -public class UserRepository { - private final Map userDatabase = new ConcurrentHashMap<>(); - - public UserRepository() { - userDatabase.put("1", new User("1", "John Doe")); - userDatabase.put("2", new User("2", "Jane Smith")); - } - - public Mono findById(String id) { - return Mono.justOrEmpty(userDatabase.get(id)); - } -} diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecord.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecord.java index bd339bf849..5c0e265e13 100644 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecord.java +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecord.java @@ -1,9 +1,9 @@ package com.baeldung.webflux.filerecord; -import java.util.List; - import org.springframework.data.annotation.Id; +import java.util.List; + public class FileRecord { @Id private int id; diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordApplication.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordApplication.java index 0388bdb0b8..9c20e10040 100644 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordApplication.java +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordApplication.java @@ -1,5 +1,6 @@ package com.baeldung.webflux.filerecord; +import io.r2dbc.spi.ConnectionFactory; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; @@ -7,8 +8,6 @@ import org.springframework.core.io.ClassPathResource; import org.springframework.r2dbc.connection.init.ConnectionFactoryInitializer; import org.springframework.r2dbc.connection.init.ResourceDatabasePopulator; -import io.r2dbc.spi.ConnectionFactory; - @SpringBootApplication public class FileRecordApplication { diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordController.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordController.java index b3cd0b89e4..943cec9a2d 100644 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordController.java +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordController.java @@ -1,13 +1,12 @@ package com.baeldung.webflux.filerecord; -import java.nio.file.Paths; - import org.springframework.http.codec.multipart.FilePart; import org.springframework.web.bind.annotation.*; - import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import java.nio.file.Paths; + @RestController public class FileRecordController { @@ -29,7 +28,7 @@ public class FileRecordController { FileRecord fileRecord = new FileRecord(); return filePartFlux.flatMap(filePart -> filePart.transferTo(Paths.get(filePart.filename())) - .then(Mono.just(filePart.filename()))) + .then(Mono.just(filePart.filename()))) .collectList() .flatMap(filenames -> { fileRecord.setFilenames(filenames); diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordService.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordService.java index bce8c82c39..6e74f3577b 100644 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordService.java +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordService.java @@ -1,7 +1,6 @@ package com.baeldung.webflux.filerecord; import org.springframework.stereotype.Service; - import reactor.core.publisher.Mono; @Service diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/model/Payment.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/model/Payment.java index 1fc090446a..f9be73ee44 100644 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/model/Payment.java +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/model/Payment.java @@ -1,5 +1,6 @@ package com.baeldung.webflux.model; + public class Payment { private final int amount; diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/service/EmailService.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/service/EmailService.java index c4c5520d24..9c0340b7ee 100644 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/service/EmailService.java +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/service/EmailService.java @@ -11,10 +11,10 @@ public class EmailService { public Mono sendEmail(String userId) { return userService.getUser(userId) - .flatMap(user -> { - System.out.println("Sending email to: " + user.getEmail()); - return Mono.just(true); - }) - .defaultIfEmpty(false); + .flatMap(user -> { + System.out.println("Sending email to: " + user.getEmail()); + return Mono.just(true); + }) + .defaultIfEmpty(false); } } diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/web/UserController.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/web/UserController.java index fa0d083beb..dbd89c45d3 100644 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/web/UserController.java +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/web/UserController.java @@ -28,16 +28,16 @@ public class UserController { public Mono> combineAllDataFor(@PathVariable String userId) { Mono userMono = userService.getUser(userId); Mono emailSentMono = emailService.sendEmail(userId) - .subscribeOn(Schedulers.parallel()); + .subscribeOn(Schedulers.parallel()); Mono databaseResultMono = userMono.flatMap(user -> databaseService.saveUserData(user) - .map(Object::toString)); + .map(Object::toString)); return userMono.zipWhen(user -> emailSentMono, Tuples::of) - .zipWhen(tuple -> databaseResultMono, (tuple, databaseResult) -> { - User user = tuple.getT1(); - Boolean emailSent = tuple.getT2(); - return ResponseEntity.ok() - .body("Response: " + user + ", Email Sent: " + emailSent + ", Database Result: " + databaseResult); - }); + .zipWhen(tuple -> databaseResultMono, (tuple, databaseResult) -> { + User user = tuple.getT1(); + Boolean emailSent = tuple.getT2(); + return ResponseEntity.ok() + .body("Response: " + user + ", Email Sent: " + emailSent + ", Database Result: " + databaseResult); + }); } } diff --git a/spring-5-webflux-2/src/main/resources/logback.xml b/spring-5-webflux-2/src/main/resources/logback.xml index 122a79945b..48b68c6bf1 100644 --- a/spring-5-webflux-2/src/main/resources/logback.xml +++ b/spring-5-webflux-2/src/main/resources/logback.xml @@ -1,7 +1,7 @@ + class="ch.qos.logback.core.ConsoleAppender"> %black(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %yellow(%C{1.}): %msg%n%throwable diff --git a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/caching/MonoFluxResultCachingLiveTest.java b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/caching/MonoFluxResultCachingLiveTest.java index 2ff2c15662..2075c1e77e 100644 --- a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/caching/MonoFluxResultCachingLiveTest.java +++ b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/caching/MonoFluxResultCachingLiveTest.java @@ -1,6 +1,5 @@ package com.baeldung.webflux.caching; -import static org.assertj.core.api.Assertions.assertThat; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -13,10 +12,13 @@ import org.testcontainers.utility.DockerImageName; import reactor.core.publisher.Mono; +import static org.assertj.core.api.Assertions.assertThat; + @SpringBootTest @ActiveProfiles("cache") public class MonoFluxResultCachingLiveTest { + @Autowired ItemService itemService; @@ -28,34 +30,32 @@ public class MonoFluxResultCachingLiveTest { registry.add("spring.data.mongodb.uri", mongoDBContainer::getReplicaSetUrl); } - @Test - public void givenItem_whenGetItemIsCalled_thenMonoIsCached() { - Mono glass = itemService.save(new Item("glass", 1.00)); +@Test +public void givenItem_whenGetItemIsCalled_thenMonoIsCached() { + Mono glass = itemService.save(new Item("glass", 1.00)); - String id = glass.block() - .get_id(); + String id = glass.block().get_id(); - Mono mono = itemService.getItem(id); - Item item = mono.block(); + Mono mono = itemService.getItem(id); + Item item = mono.block(); - assertThat(item).isNotNull(); - assertThat(item.getName()).isEqualTo("glass"); - assertThat(item.getPrice()).isEqualTo(1.00); + assertThat(item).isNotNull(); + assertThat(item.getName()).isEqualTo("glass"); + assertThat(item.getPrice()).isEqualTo(1.00); - Mono mono2 = itemService.getItem(id); - Item item2 = mono2.block(); + Mono mono2 = itemService.getItem(id); + Item item2 = mono2.block(); - assertThat(item2).isNotNull(); - assertThat(item2.getName()).isEqualTo("glass"); - assertThat(item2.getPrice()).isEqualTo(1.00); - } + assertThat(item2).isNotNull(); + assertThat(item2.getName()).isEqualTo("glass"); + assertThat(item2.getPrice()).isEqualTo(1.00); +} @Test public void givenItem_whenGetItemWithCacheIsCalled_thenMonoResultIsCached() { Mono glass = itemService.save(new Item("glass", 1.00)); - String id = glass.block() - .get_id(); + String id = glass.block().get_id(); Mono mono = itemService.getItem_withCache(id); Item item = mono.block(); @@ -76,8 +76,7 @@ public class MonoFluxResultCachingLiveTest { public void givenItem_whenGetItemWithCaffeineIsCalled_thenMonoResultIsCached() { Mono glass = itemService.save(new Item("glass", 1.00)); - String id = glass.block() - .get_id(); + String id = glass.block().get_id(); Mono mono = itemService.getItem_withCaffeine(id); Item item = mono.block(); diff --git a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/exceptionhandeling/UserControllerUnitTest.java b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/exceptionhandeling/UserControllerUnitTest.java deleted file mode 100644 index d59ec52f3c..0000000000 --- a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/exceptionhandeling/UserControllerUnitTest.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.baeldung.webflux.exceptionhandeling; - -import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import reactor.core.publisher.Mono; -import reactor.test.StepVerifier; - -import static org.junit.jupiter.api.Assertions.assertThrows; - -import static org.mockito.Mockito.when; - -import com.baeldung.webflux.exceptionhandeling.controller.UserController; -import com.baeldung.webflux.exceptionhandeling.ex.NotFoundException; -import com.baeldung.webflux.exceptionhandeling.repository.UserRepository; - -public class UserControllerUnitTest { - @Mock - private UserRepository userRepository; - - @InjectMocks - private UserController userController; - - public UserControllerUnitTest() { - MockitoAnnotations.initMocks(this); - } - - @Test - public void testGetUserByIdUsingMonoError_UserNotFound() { - String userId = "3"; - when(userRepository.findById(userId)).thenReturn(Mono.empty()); - StepVerifier.create(userController.getUserByIdUsingMonoError(userId)) - .expectError(NotFoundException.class) - .verify(); - } - - @Test - public void testGetUserByIdThrowingException_UserNotFound() { - String userId = "3"; - when(userRepository.findById(userId)).thenReturn(Mono.empty()); - assertThrows(NotFoundException.class, () -> userController.getUserByIdThrowingException(userId) - .block()); - } - -} - diff --git a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/filerecord/FileRecordControllerIntegrationTest.java b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/filerecord/FileRecordControllerIntegrationTest.java index f8585852c1..c47d53632b 100644 --- a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/filerecord/FileRecordControllerIntegrationTest.java +++ b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/filerecord/FileRecordControllerIntegrationTest.java @@ -1,10 +1,5 @@ package com.baeldung.webflux.filerecord; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; - -import java.util.List; - import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; @@ -18,9 +13,13 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.web.reactive.server.WebTestClient; import org.springframework.util.LinkedMultiValueMap; - import reactor.core.publisher.Mono; +import java.util.List; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + @ExtendWith(SpringExtension.class) @SpringBootTest(classes = FileRecordController.class) @ContextConfiguration(classes = { FileRecordController.class }) diff --git a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/firstelementofflux/FirstElementOfFluxUnitTest.java b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/firstelementofflux/FirstElementOfFluxUnitTest.java index d7c084e3ec..a036011796 100644 --- a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/firstelementofflux/FirstElementOfFluxUnitTest.java +++ b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/firstelementofflux/FirstElementOfFluxUnitTest.java @@ -7,7 +7,6 @@ import java.util.Optional; import org.junit.jupiter.api.Test; import com.baeldung.webflux.model.Payment; - import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.test.StepVerifier; diff --git a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/zipwhen/UserControllerUnitTest.java b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/zipwhen/UserControllerUnitTest.java index 07c54fd531..8ed4cfb6c6 100644 --- a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/zipwhen/UserControllerUnitTest.java +++ b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/zipwhen/UserControllerUnitTest.java @@ -25,19 +25,19 @@ public class UserControllerUnitTest { User user = new User(userId, "John Doe"); Mockito.when(userService.getUser(userId)) - .thenReturn(Mono.just(user)); + .thenReturn(Mono.just(user)); Mockito.when(emailService.sendEmail(userId)) - .thenReturn(Mono.just(true)); + .thenReturn(Mono.just(true)); Mockito.when(databaseService.saveUserData(user)) - .thenReturn(Mono.just(true)); + .thenReturn(Mono.just(true)); UserController userController = new UserController(userService, emailService, databaseService); Mono> responseMono = userController.combineAllDataFor(userId); StepVerifier.create(responseMono) - .expectNextMatches(responseEntity -> responseEntity.getStatusCode() == HttpStatus.OK && responseEntity.getBody() - .equals("Response: " + user + ", Email Sent: true, Database Result: " + true)) - .verifyComplete(); + .expectNextMatches(responseEntity -> responseEntity.getStatusCode() == HttpStatus.OK && responseEntity.getBody() + .equals("Response: " + user + ", Email Sent: true, Database Result: " + true)) + .verifyComplete(); } } From fa1c5598b0429200709856c932301ae682a42678 Mon Sep 17 00:00:00 2001 From: reza ganji Date: Sat, 30 Mar 2024 13:08:12 +0330 Subject: [PATCH 3/8] Revert "Revert "BAEL-7540"" This reverts commit 2c5307571e6377e436e6f9cc5819e341b6d72cdd. --- spring-5-webflux-2/README.md | 1 + spring-5-webflux-2/pom.xml | 6 +-- .../com/baeldung/webflux/caching/Item.java | 6 +-- .../baeldung/webflux/caching/ItemService.java | 10 ++-- .../controller/UserController.java | 35 ++++++++++++++ .../ex/NotFoundException.java | 12 +++++ .../exceptionhandeling/model/User.java | 29 +++++++++++ .../repository/UserRepository.java | 24 ++++++++++ .../webflux/filerecord/FileRecord.java | 4 +- .../filerecord/FileRecordApplication.java | 3 +- .../filerecord/FileRecordController.java | 7 +-- .../webflux/filerecord/FileRecordService.java | 1 + .../com/baeldung/webflux/model/Payment.java | 1 - .../webflux/zipwhen/service/EmailService.java | 10 ++-- .../webflux/zipwhen/web/UserController.java | 16 +++---- .../src/main/resources/logback.xml | 2 +- .../MonoFluxResultCachingLiveTest.java | 41 ++++++++-------- .../UserControllerUnitTest.java | 48 +++++++++++++++++++ .../FileRecordControllerIntegrationTest.java | 11 +++-- .../FirstElementOfFluxUnitTest.java | 1 + .../zipwhen/UserControllerUnitTest.java | 12 ++--- 21 files changed, 217 insertions(+), 63 deletions(-) create mode 100644 spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/controller/UserController.java create mode 100644 spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/ex/NotFoundException.java create mode 100644 spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/model/User.java create mode 100644 spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/repository/UserRepository.java create mode 100644 spring-5-webflux-2/src/test/java/com/baeldung/webflux/exceptionhandeling/UserControllerUnitTest.java diff --git a/spring-5-webflux-2/README.md b/spring-5-webflux-2/README.md index 5232d86643..5579e1cec5 100644 --- a/spring-5-webflux-2/README.md +++ b/spring-5-webflux-2/README.md @@ -3,6 +3,7 @@ This module contains articles about Spring 5 WebFlux ## Relevant articles: + - [Spring Webflux and @Cacheable Annotation](https://www.baeldung.com/spring-webflux-cacheable) - [Comparison Between Mono’s doOnNext() and doOnSuccess()](https://www.baeldung.com/mono-doonnext-doonsuccess) - [How to Access the First Element of a Flux](https://www.baeldung.com/java-flux-first-element) diff --git a/spring-5-webflux-2/pom.xml b/spring-5-webflux-2/pom.xml index 38cbbc8bf0..85e451c075 100644 --- a/spring-5-webflux-2/pom.xml +++ b/spring-5-webflux-2/pom.xml @@ -1,7 +1,7 @@ - + 4.0.0 spring-5-webflux-2 1.0-SNAPSHOT diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/caching/Item.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/caching/Item.java index 54b7d63f33..6ad03baafc 100644 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/caching/Item.java +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/caching/Item.java @@ -41,10 +41,6 @@ public class Item { @Override public String toString() { - return "Item{" + - "id='" + _id + '\'' + - ", name='" + name + '\'' + - ", price=" + price + - '}'; + return "Item{" + "id='" + _id + '\'' + ", name='" + name + '\'' + ", price=" + price + '}'; } } diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/caching/ItemService.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/caching/ItemService.java index 9bf934b504..9286cecef8 100644 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/caching/ItemService.java +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/caching/ItemService.java @@ -16,7 +16,8 @@ public class ItemService { public ItemService(ItemRepository repository) { this.repository = repository; - this.cache = Caffeine.newBuilder().build(this::getItem_withCaffeine); + this.cache = Caffeine.newBuilder() + .build(this::getItem_withCaffeine); } @Cacheable("items") @@ -30,11 +31,14 @@ public class ItemService { @Cacheable("items") public Mono getItem_withCache(String id) { - return repository.findById(id).cache(); + return repository.findById(id) + .cache(); } @Cacheable("items") public Mono getItem_withCaffeine(String id) { - return cache.asMap().computeIfAbsent(id, k -> repository.findById(id).cast(Item.class)); + return cache.asMap() + .computeIfAbsent(id, k -> repository.findById(id) + .cast(Item.class)); } } diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/controller/UserController.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/controller/UserController.java new file mode 100644 index 0000000000..6490b997af --- /dev/null +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/controller/UserController.java @@ -0,0 +1,35 @@ +package com.baeldung.webflux.exceptionhandeling.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RestController; + +import com.baeldung.webflux.exceptionhandeling.ex.NotFoundException; +import com.baeldung.webflux.exceptionhandeling.repository.UserRepository; +import com.baeldung.webflux.zipwhen.model.User; + +import reactor.core.publisher.Mono; + +@RestController +public class UserController { + + private final UserRepository userRepository; + + @Autowired + public UserController(UserRepository userRepository) { + this.userRepository = userRepository; + } + + @GetMapping("/user/{id}") + public Mono getUserByIdThrowingException(@PathVariable String id) { + return userRepository.findById(id) + .switchIfEmpty(Mono.error(new NotFoundException("User not found"))); + } + + @GetMapping("/user/{id}") + public Mono getUserByIdUsingMonoError(@PathVariable String id) { + return userRepository.findById(id) + .switchIfEmpty(Mono.error(() -> new NotFoundException("User not found"))); + } +} diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/ex/NotFoundException.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/ex/NotFoundException.java new file mode 100644 index 0000000000..5401a4d133 --- /dev/null +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/ex/NotFoundException.java @@ -0,0 +1,12 @@ +package com.baeldung.webflux.exceptionhandeling.ex; + +public class NotFoundException extends RuntimeException { + + public NotFoundException(String message) { + super(message); + } + + public NotFoundException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/model/User.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/model/User.java new file mode 100644 index 0000000000..42e1293ee8 --- /dev/null +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/model/User.java @@ -0,0 +1,29 @@ +package com.baeldung.webflux.exceptionhandeling.model; + +public class User { + private String id; + private String username; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public User(String userId, String userName) { + this.id=userId; + this.username=userName; + + } +} + diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/repository/UserRepository.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/repository/UserRepository.java new file mode 100644 index 0000000000..7d4ac0af86 --- /dev/null +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/repository/UserRepository.java @@ -0,0 +1,24 @@ +package com.baeldung.webflux.exceptionhandeling.repository; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.springframework.stereotype.Repository; + +import com.baeldung.webflux.zipwhen.model.User; + +import reactor.core.publisher.Mono; + +@Repository +public class UserRepository { + private final Map userDatabase = new ConcurrentHashMap<>(); + + public UserRepository() { + userDatabase.put("1", new User("1", "John Doe")); + userDatabase.put("2", new User("2", "Jane Smith")); + } + + public Mono findById(String id) { + return Mono.justOrEmpty(userDatabase.get(id)); + } +} diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecord.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecord.java index 5c0e265e13..bd339bf849 100644 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecord.java +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecord.java @@ -1,9 +1,9 @@ package com.baeldung.webflux.filerecord; -import org.springframework.data.annotation.Id; - import java.util.List; +import org.springframework.data.annotation.Id; + public class FileRecord { @Id private int id; diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordApplication.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordApplication.java index 9c20e10040..0388bdb0b8 100644 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordApplication.java +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordApplication.java @@ -1,6 +1,5 @@ package com.baeldung.webflux.filerecord; -import io.r2dbc.spi.ConnectionFactory; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; @@ -8,6 +7,8 @@ import org.springframework.core.io.ClassPathResource; import org.springframework.r2dbc.connection.init.ConnectionFactoryInitializer; import org.springframework.r2dbc.connection.init.ResourceDatabasePopulator; +import io.r2dbc.spi.ConnectionFactory; + @SpringBootApplication public class FileRecordApplication { diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordController.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordController.java index 943cec9a2d..b3cd0b89e4 100644 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordController.java +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordController.java @@ -1,12 +1,13 @@ package com.baeldung.webflux.filerecord; +import java.nio.file.Paths; + import org.springframework.http.codec.multipart.FilePart; import org.springframework.web.bind.annotation.*; + import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -import java.nio.file.Paths; - @RestController public class FileRecordController { @@ -28,7 +29,7 @@ public class FileRecordController { FileRecord fileRecord = new FileRecord(); return filePartFlux.flatMap(filePart -> filePart.transferTo(Paths.get(filePart.filename())) - .then(Mono.just(filePart.filename()))) + .then(Mono.just(filePart.filename()))) .collectList() .flatMap(filenames -> { fileRecord.setFilenames(filenames); diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordService.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordService.java index 6e74f3577b..bce8c82c39 100644 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordService.java +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordService.java @@ -1,6 +1,7 @@ package com.baeldung.webflux.filerecord; import org.springframework.stereotype.Service; + import reactor.core.publisher.Mono; @Service diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/model/Payment.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/model/Payment.java index f9be73ee44..1fc090446a 100644 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/model/Payment.java +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/model/Payment.java @@ -1,6 +1,5 @@ package com.baeldung.webflux.model; - public class Payment { private final int amount; diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/service/EmailService.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/service/EmailService.java index 9c0340b7ee..c4c5520d24 100644 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/service/EmailService.java +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/service/EmailService.java @@ -11,10 +11,10 @@ public class EmailService { public Mono sendEmail(String userId) { return userService.getUser(userId) - .flatMap(user -> { - System.out.println("Sending email to: " + user.getEmail()); - return Mono.just(true); - }) - .defaultIfEmpty(false); + .flatMap(user -> { + System.out.println("Sending email to: " + user.getEmail()); + return Mono.just(true); + }) + .defaultIfEmpty(false); } } diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/web/UserController.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/web/UserController.java index dbd89c45d3..fa0d083beb 100644 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/web/UserController.java +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/web/UserController.java @@ -28,16 +28,16 @@ public class UserController { public Mono> combineAllDataFor(@PathVariable String userId) { Mono userMono = userService.getUser(userId); Mono emailSentMono = emailService.sendEmail(userId) - .subscribeOn(Schedulers.parallel()); + .subscribeOn(Schedulers.parallel()); Mono databaseResultMono = userMono.flatMap(user -> databaseService.saveUserData(user) - .map(Object::toString)); + .map(Object::toString)); return userMono.zipWhen(user -> emailSentMono, Tuples::of) - .zipWhen(tuple -> databaseResultMono, (tuple, databaseResult) -> { - User user = tuple.getT1(); - Boolean emailSent = tuple.getT2(); - return ResponseEntity.ok() - .body("Response: " + user + ", Email Sent: " + emailSent + ", Database Result: " + databaseResult); - }); + .zipWhen(tuple -> databaseResultMono, (tuple, databaseResult) -> { + User user = tuple.getT1(); + Boolean emailSent = tuple.getT2(); + return ResponseEntity.ok() + .body("Response: " + user + ", Email Sent: " + emailSent + ", Database Result: " + databaseResult); + }); } } diff --git a/spring-5-webflux-2/src/main/resources/logback.xml b/spring-5-webflux-2/src/main/resources/logback.xml index 48b68c6bf1..122a79945b 100644 --- a/spring-5-webflux-2/src/main/resources/logback.xml +++ b/spring-5-webflux-2/src/main/resources/logback.xml @@ -1,7 +1,7 @@ + class="ch.qos.logback.core.ConsoleAppender"> %black(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %yellow(%C{1.}): %msg%n%throwable diff --git a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/caching/MonoFluxResultCachingLiveTest.java b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/caching/MonoFluxResultCachingLiveTest.java index 2075c1e77e..2ff2c15662 100644 --- a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/caching/MonoFluxResultCachingLiveTest.java +++ b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/caching/MonoFluxResultCachingLiveTest.java @@ -1,5 +1,6 @@ package com.baeldung.webflux.caching; +import static org.assertj.core.api.Assertions.assertThat; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -12,13 +13,10 @@ import org.testcontainers.utility.DockerImageName; import reactor.core.publisher.Mono; -import static org.assertj.core.api.Assertions.assertThat; - @SpringBootTest @ActiveProfiles("cache") public class MonoFluxResultCachingLiveTest { - @Autowired ItemService itemService; @@ -30,32 +28,34 @@ public class MonoFluxResultCachingLiveTest { registry.add("spring.data.mongodb.uri", mongoDBContainer::getReplicaSetUrl); } -@Test -public void givenItem_whenGetItemIsCalled_thenMonoIsCached() { - Mono glass = itemService.save(new Item("glass", 1.00)); + @Test + public void givenItem_whenGetItemIsCalled_thenMonoIsCached() { + Mono glass = itemService.save(new Item("glass", 1.00)); - String id = glass.block().get_id(); + String id = glass.block() + .get_id(); - Mono mono = itemService.getItem(id); - Item item = mono.block(); + Mono mono = itemService.getItem(id); + Item item = mono.block(); - assertThat(item).isNotNull(); - assertThat(item.getName()).isEqualTo("glass"); - assertThat(item.getPrice()).isEqualTo(1.00); + assertThat(item).isNotNull(); + assertThat(item.getName()).isEqualTo("glass"); + assertThat(item.getPrice()).isEqualTo(1.00); - Mono mono2 = itemService.getItem(id); - Item item2 = mono2.block(); + Mono mono2 = itemService.getItem(id); + Item item2 = mono2.block(); - assertThat(item2).isNotNull(); - assertThat(item2.getName()).isEqualTo("glass"); - assertThat(item2.getPrice()).isEqualTo(1.00); -} + assertThat(item2).isNotNull(); + assertThat(item2.getName()).isEqualTo("glass"); + assertThat(item2.getPrice()).isEqualTo(1.00); + } @Test public void givenItem_whenGetItemWithCacheIsCalled_thenMonoResultIsCached() { Mono glass = itemService.save(new Item("glass", 1.00)); - String id = glass.block().get_id(); + String id = glass.block() + .get_id(); Mono mono = itemService.getItem_withCache(id); Item item = mono.block(); @@ -76,7 +76,8 @@ public void givenItem_whenGetItemIsCalled_thenMonoIsCached() { public void givenItem_whenGetItemWithCaffeineIsCalled_thenMonoResultIsCached() { Mono glass = itemService.save(new Item("glass", 1.00)); - String id = glass.block().get_id(); + String id = glass.block() + .get_id(); Mono mono = itemService.getItem_withCaffeine(id); Item item = mono.block(); diff --git a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/exceptionhandeling/UserControllerUnitTest.java b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/exceptionhandeling/UserControllerUnitTest.java new file mode 100644 index 0000000000..d59ec52f3c --- /dev/null +++ b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/exceptionhandeling/UserControllerUnitTest.java @@ -0,0 +1,48 @@ +package com.baeldung.webflux.exceptionhandeling; + +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +import static org.mockito.Mockito.when; + +import com.baeldung.webflux.exceptionhandeling.controller.UserController; +import com.baeldung.webflux.exceptionhandeling.ex.NotFoundException; +import com.baeldung.webflux.exceptionhandeling.repository.UserRepository; + +public class UserControllerUnitTest { + @Mock + private UserRepository userRepository; + + @InjectMocks + private UserController userController; + + public UserControllerUnitTest() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void testGetUserByIdUsingMonoError_UserNotFound() { + String userId = "3"; + when(userRepository.findById(userId)).thenReturn(Mono.empty()); + StepVerifier.create(userController.getUserByIdUsingMonoError(userId)) + .expectError(NotFoundException.class) + .verify(); + } + + @Test + public void testGetUserByIdThrowingException_UserNotFound() { + String userId = "3"; + when(userRepository.findById(userId)).thenReturn(Mono.empty()); + assertThrows(NotFoundException.class, () -> userController.getUserByIdThrowingException(userId) + .block()); + } + +} + diff --git a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/filerecord/FileRecordControllerIntegrationTest.java b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/filerecord/FileRecordControllerIntegrationTest.java index c47d53632b..f8585852c1 100644 --- a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/filerecord/FileRecordControllerIntegrationTest.java +++ b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/filerecord/FileRecordControllerIntegrationTest.java @@ -1,5 +1,10 @@ package com.baeldung.webflux.filerecord; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import java.util.List; + import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; @@ -13,13 +18,9 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.web.reactive.server.WebTestClient; import org.springframework.util.LinkedMultiValueMap; + import reactor.core.publisher.Mono; -import java.util.List; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; - @ExtendWith(SpringExtension.class) @SpringBootTest(classes = FileRecordController.class) @ContextConfiguration(classes = { FileRecordController.class }) diff --git a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/firstelementofflux/FirstElementOfFluxUnitTest.java b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/firstelementofflux/FirstElementOfFluxUnitTest.java index a036011796..d7c084e3ec 100644 --- a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/firstelementofflux/FirstElementOfFluxUnitTest.java +++ b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/firstelementofflux/FirstElementOfFluxUnitTest.java @@ -7,6 +7,7 @@ import java.util.Optional; import org.junit.jupiter.api.Test; import com.baeldung.webflux.model.Payment; + import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.test.StepVerifier; diff --git a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/zipwhen/UserControllerUnitTest.java b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/zipwhen/UserControllerUnitTest.java index 8ed4cfb6c6..07c54fd531 100644 --- a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/zipwhen/UserControllerUnitTest.java +++ b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/zipwhen/UserControllerUnitTest.java @@ -25,19 +25,19 @@ public class UserControllerUnitTest { User user = new User(userId, "John Doe"); Mockito.when(userService.getUser(userId)) - .thenReturn(Mono.just(user)); + .thenReturn(Mono.just(user)); Mockito.when(emailService.sendEmail(userId)) - .thenReturn(Mono.just(true)); + .thenReturn(Mono.just(true)); Mockito.when(databaseService.saveUserData(user)) - .thenReturn(Mono.just(true)); + .thenReturn(Mono.just(true)); UserController userController = new UserController(userService, emailService, databaseService); Mono> responseMono = userController.combineAllDataFor(userId); StepVerifier.create(responseMono) - .expectNextMatches(responseEntity -> responseEntity.getStatusCode() == HttpStatus.OK && responseEntity.getBody() - .equals("Response: " + user + ", Email Sent: true, Database Result: " + true)) - .verifyComplete(); + .expectNextMatches(responseEntity -> responseEntity.getStatusCode() == HttpStatus.OK && responseEntity.getBody() + .equals("Response: " + user + ", Email Sent: true, Database Result: " + true)) + .verifyComplete(); } } From 7c93d400445165fe38d3ba14f46a484e3892428e Mon Sep 17 00:00:00 2001 From: reza ganji Date: Sat, 30 Mar 2024 13:10:46 +0330 Subject: [PATCH 4/8] Revert "Revert "Revert "BAEL-7540""" This reverts commit fa1c5598b0429200709856c932301ae682a42678. --- spring-5-webflux-2/README.md | 1 - spring-5-webflux-2/pom.xml | 6 +-- .../com/baeldung/webflux/caching/Item.java | 6 ++- .../baeldung/webflux/caching/ItemService.java | 10 ++-- .../controller/UserController.java | 35 -------------- .../ex/NotFoundException.java | 12 ----- .../exceptionhandeling/model/User.java | 29 ----------- .../repository/UserRepository.java | 24 ---------- .../webflux/filerecord/FileRecord.java | 4 +- .../filerecord/FileRecordApplication.java | 3 +- .../filerecord/FileRecordController.java | 7 ++- .../webflux/filerecord/FileRecordService.java | 1 - .../com/baeldung/webflux/model/Payment.java | 1 + .../webflux/zipwhen/service/EmailService.java | 10 ++-- .../webflux/zipwhen/web/UserController.java | 16 +++---- .../src/main/resources/logback.xml | 2 +- .../MonoFluxResultCachingLiveTest.java | 41 ++++++++-------- .../UserControllerUnitTest.java | 48 ------------------- .../FileRecordControllerIntegrationTest.java | 11 ++--- .../FirstElementOfFluxUnitTest.java | 1 - .../zipwhen/UserControllerUnitTest.java | 12 ++--- 21 files changed, 63 insertions(+), 217 deletions(-) delete mode 100644 spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/controller/UserController.java delete mode 100644 spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/ex/NotFoundException.java delete mode 100644 spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/model/User.java delete mode 100644 spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/repository/UserRepository.java delete mode 100644 spring-5-webflux-2/src/test/java/com/baeldung/webflux/exceptionhandeling/UserControllerUnitTest.java diff --git a/spring-5-webflux-2/README.md b/spring-5-webflux-2/README.md index 5579e1cec5..5232d86643 100644 --- a/spring-5-webflux-2/README.md +++ b/spring-5-webflux-2/README.md @@ -3,7 +3,6 @@ This module contains articles about Spring 5 WebFlux ## Relevant articles: - - [Spring Webflux and @Cacheable Annotation](https://www.baeldung.com/spring-webflux-cacheable) - [Comparison Between Mono’s doOnNext() and doOnSuccess()](https://www.baeldung.com/mono-doonnext-doonsuccess) - [How to Access the First Element of a Flux](https://www.baeldung.com/java-flux-first-element) diff --git a/spring-5-webflux-2/pom.xml b/spring-5-webflux-2/pom.xml index 85e451c075..38cbbc8bf0 100644 --- a/spring-5-webflux-2/pom.xml +++ b/spring-5-webflux-2/pom.xml @@ -1,7 +1,7 @@ - + 4.0.0 spring-5-webflux-2 1.0-SNAPSHOT diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/caching/Item.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/caching/Item.java index 6ad03baafc..54b7d63f33 100644 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/caching/Item.java +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/caching/Item.java @@ -41,6 +41,10 @@ public class Item { @Override public String toString() { - return "Item{" + "id='" + _id + '\'' + ", name='" + name + '\'' + ", price=" + price + '}'; + return "Item{" + + "id='" + _id + '\'' + + ", name='" + name + '\'' + + ", price=" + price + + '}'; } } diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/caching/ItemService.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/caching/ItemService.java index 9286cecef8..9bf934b504 100644 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/caching/ItemService.java +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/caching/ItemService.java @@ -16,8 +16,7 @@ public class ItemService { public ItemService(ItemRepository repository) { this.repository = repository; - this.cache = Caffeine.newBuilder() - .build(this::getItem_withCaffeine); + this.cache = Caffeine.newBuilder().build(this::getItem_withCaffeine); } @Cacheable("items") @@ -31,14 +30,11 @@ public class ItemService { @Cacheable("items") public Mono getItem_withCache(String id) { - return repository.findById(id) - .cache(); + return repository.findById(id).cache(); } @Cacheable("items") public Mono getItem_withCaffeine(String id) { - return cache.asMap() - .computeIfAbsent(id, k -> repository.findById(id) - .cast(Item.class)); + return cache.asMap().computeIfAbsent(id, k -> repository.findById(id).cast(Item.class)); } } diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/controller/UserController.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/controller/UserController.java deleted file mode 100644 index 6490b997af..0000000000 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/controller/UserController.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.baeldung.webflux.exceptionhandeling.controller; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RestController; - -import com.baeldung.webflux.exceptionhandeling.ex.NotFoundException; -import com.baeldung.webflux.exceptionhandeling.repository.UserRepository; -import com.baeldung.webflux.zipwhen.model.User; - -import reactor.core.publisher.Mono; - -@RestController -public class UserController { - - private final UserRepository userRepository; - - @Autowired - public UserController(UserRepository userRepository) { - this.userRepository = userRepository; - } - - @GetMapping("/user/{id}") - public Mono getUserByIdThrowingException(@PathVariable String id) { - return userRepository.findById(id) - .switchIfEmpty(Mono.error(new NotFoundException("User not found"))); - } - - @GetMapping("/user/{id}") - public Mono getUserByIdUsingMonoError(@PathVariable String id) { - return userRepository.findById(id) - .switchIfEmpty(Mono.error(() -> new NotFoundException("User not found"))); - } -} diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/ex/NotFoundException.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/ex/NotFoundException.java deleted file mode 100644 index 5401a4d133..0000000000 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/ex/NotFoundException.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.baeldung.webflux.exceptionhandeling.ex; - -public class NotFoundException extends RuntimeException { - - public NotFoundException(String message) { - super(message); - } - - public NotFoundException(String message, Throwable cause) { - super(message, cause); - } -} diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/model/User.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/model/User.java deleted file mode 100644 index 42e1293ee8..0000000000 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/model/User.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.baeldung.webflux.exceptionhandeling.model; - -public class User { - private String id; - private String username; - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public User(String userId, String userName) { - this.id=userId; - this.username=userName; - - } -} - diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/repository/UserRepository.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/repository/UserRepository.java deleted file mode 100644 index 7d4ac0af86..0000000000 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/repository/UserRepository.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.baeldung.webflux.exceptionhandeling.repository; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import org.springframework.stereotype.Repository; - -import com.baeldung.webflux.zipwhen.model.User; - -import reactor.core.publisher.Mono; - -@Repository -public class UserRepository { - private final Map userDatabase = new ConcurrentHashMap<>(); - - public UserRepository() { - userDatabase.put("1", new User("1", "John Doe")); - userDatabase.put("2", new User("2", "Jane Smith")); - } - - public Mono findById(String id) { - return Mono.justOrEmpty(userDatabase.get(id)); - } -} diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecord.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecord.java index bd339bf849..5c0e265e13 100644 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecord.java +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecord.java @@ -1,9 +1,9 @@ package com.baeldung.webflux.filerecord; -import java.util.List; - import org.springframework.data.annotation.Id; +import java.util.List; + public class FileRecord { @Id private int id; diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordApplication.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordApplication.java index 0388bdb0b8..9c20e10040 100644 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordApplication.java +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordApplication.java @@ -1,5 +1,6 @@ package com.baeldung.webflux.filerecord; +import io.r2dbc.spi.ConnectionFactory; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; @@ -7,8 +8,6 @@ import org.springframework.core.io.ClassPathResource; import org.springframework.r2dbc.connection.init.ConnectionFactoryInitializer; import org.springframework.r2dbc.connection.init.ResourceDatabasePopulator; -import io.r2dbc.spi.ConnectionFactory; - @SpringBootApplication public class FileRecordApplication { diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordController.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordController.java index b3cd0b89e4..943cec9a2d 100644 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordController.java +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordController.java @@ -1,13 +1,12 @@ package com.baeldung.webflux.filerecord; -import java.nio.file.Paths; - import org.springframework.http.codec.multipart.FilePart; import org.springframework.web.bind.annotation.*; - import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import java.nio.file.Paths; + @RestController public class FileRecordController { @@ -29,7 +28,7 @@ public class FileRecordController { FileRecord fileRecord = new FileRecord(); return filePartFlux.flatMap(filePart -> filePart.transferTo(Paths.get(filePart.filename())) - .then(Mono.just(filePart.filename()))) + .then(Mono.just(filePart.filename()))) .collectList() .flatMap(filenames -> { fileRecord.setFilenames(filenames); diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordService.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordService.java index bce8c82c39..6e74f3577b 100644 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordService.java +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/filerecord/FileRecordService.java @@ -1,7 +1,6 @@ package com.baeldung.webflux.filerecord; import org.springframework.stereotype.Service; - import reactor.core.publisher.Mono; @Service diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/model/Payment.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/model/Payment.java index 1fc090446a..f9be73ee44 100644 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/model/Payment.java +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/model/Payment.java @@ -1,5 +1,6 @@ package com.baeldung.webflux.model; + public class Payment { private final int amount; diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/service/EmailService.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/service/EmailService.java index c4c5520d24..9c0340b7ee 100644 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/service/EmailService.java +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/service/EmailService.java @@ -11,10 +11,10 @@ public class EmailService { public Mono sendEmail(String userId) { return userService.getUser(userId) - .flatMap(user -> { - System.out.println("Sending email to: " + user.getEmail()); - return Mono.just(true); - }) - .defaultIfEmpty(false); + .flatMap(user -> { + System.out.println("Sending email to: " + user.getEmail()); + return Mono.just(true); + }) + .defaultIfEmpty(false); } } diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/web/UserController.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/web/UserController.java index fa0d083beb..dbd89c45d3 100644 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/web/UserController.java +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/zipwhen/web/UserController.java @@ -28,16 +28,16 @@ public class UserController { public Mono> combineAllDataFor(@PathVariable String userId) { Mono userMono = userService.getUser(userId); Mono emailSentMono = emailService.sendEmail(userId) - .subscribeOn(Schedulers.parallel()); + .subscribeOn(Schedulers.parallel()); Mono databaseResultMono = userMono.flatMap(user -> databaseService.saveUserData(user) - .map(Object::toString)); + .map(Object::toString)); return userMono.zipWhen(user -> emailSentMono, Tuples::of) - .zipWhen(tuple -> databaseResultMono, (tuple, databaseResult) -> { - User user = tuple.getT1(); - Boolean emailSent = tuple.getT2(); - return ResponseEntity.ok() - .body("Response: " + user + ", Email Sent: " + emailSent + ", Database Result: " + databaseResult); - }); + .zipWhen(tuple -> databaseResultMono, (tuple, databaseResult) -> { + User user = tuple.getT1(); + Boolean emailSent = tuple.getT2(); + return ResponseEntity.ok() + .body("Response: " + user + ", Email Sent: " + emailSent + ", Database Result: " + databaseResult); + }); } } diff --git a/spring-5-webflux-2/src/main/resources/logback.xml b/spring-5-webflux-2/src/main/resources/logback.xml index 122a79945b..48b68c6bf1 100644 --- a/spring-5-webflux-2/src/main/resources/logback.xml +++ b/spring-5-webflux-2/src/main/resources/logback.xml @@ -1,7 +1,7 @@ + class="ch.qos.logback.core.ConsoleAppender"> %black(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %yellow(%C{1.}): %msg%n%throwable diff --git a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/caching/MonoFluxResultCachingLiveTest.java b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/caching/MonoFluxResultCachingLiveTest.java index 2ff2c15662..2075c1e77e 100644 --- a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/caching/MonoFluxResultCachingLiveTest.java +++ b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/caching/MonoFluxResultCachingLiveTest.java @@ -1,6 +1,5 @@ package com.baeldung.webflux.caching; -import static org.assertj.core.api.Assertions.assertThat; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -13,10 +12,13 @@ import org.testcontainers.utility.DockerImageName; import reactor.core.publisher.Mono; +import static org.assertj.core.api.Assertions.assertThat; + @SpringBootTest @ActiveProfiles("cache") public class MonoFluxResultCachingLiveTest { + @Autowired ItemService itemService; @@ -28,34 +30,32 @@ public class MonoFluxResultCachingLiveTest { registry.add("spring.data.mongodb.uri", mongoDBContainer::getReplicaSetUrl); } - @Test - public void givenItem_whenGetItemIsCalled_thenMonoIsCached() { - Mono glass = itemService.save(new Item("glass", 1.00)); +@Test +public void givenItem_whenGetItemIsCalled_thenMonoIsCached() { + Mono glass = itemService.save(new Item("glass", 1.00)); - String id = glass.block() - .get_id(); + String id = glass.block().get_id(); - Mono mono = itemService.getItem(id); - Item item = mono.block(); + Mono mono = itemService.getItem(id); + Item item = mono.block(); - assertThat(item).isNotNull(); - assertThat(item.getName()).isEqualTo("glass"); - assertThat(item.getPrice()).isEqualTo(1.00); + assertThat(item).isNotNull(); + assertThat(item.getName()).isEqualTo("glass"); + assertThat(item.getPrice()).isEqualTo(1.00); - Mono mono2 = itemService.getItem(id); - Item item2 = mono2.block(); + Mono mono2 = itemService.getItem(id); + Item item2 = mono2.block(); - assertThat(item2).isNotNull(); - assertThat(item2.getName()).isEqualTo("glass"); - assertThat(item2.getPrice()).isEqualTo(1.00); - } + assertThat(item2).isNotNull(); + assertThat(item2.getName()).isEqualTo("glass"); + assertThat(item2.getPrice()).isEqualTo(1.00); +} @Test public void givenItem_whenGetItemWithCacheIsCalled_thenMonoResultIsCached() { Mono glass = itemService.save(new Item("glass", 1.00)); - String id = glass.block() - .get_id(); + String id = glass.block().get_id(); Mono mono = itemService.getItem_withCache(id); Item item = mono.block(); @@ -76,8 +76,7 @@ public class MonoFluxResultCachingLiveTest { public void givenItem_whenGetItemWithCaffeineIsCalled_thenMonoResultIsCached() { Mono glass = itemService.save(new Item("glass", 1.00)); - String id = glass.block() - .get_id(); + String id = glass.block().get_id(); Mono mono = itemService.getItem_withCaffeine(id); Item item = mono.block(); diff --git a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/exceptionhandeling/UserControllerUnitTest.java b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/exceptionhandeling/UserControllerUnitTest.java deleted file mode 100644 index d59ec52f3c..0000000000 --- a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/exceptionhandeling/UserControllerUnitTest.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.baeldung.webflux.exceptionhandeling; - -import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import reactor.core.publisher.Mono; -import reactor.test.StepVerifier; - -import static org.junit.jupiter.api.Assertions.assertThrows; - -import static org.mockito.Mockito.when; - -import com.baeldung.webflux.exceptionhandeling.controller.UserController; -import com.baeldung.webflux.exceptionhandeling.ex.NotFoundException; -import com.baeldung.webflux.exceptionhandeling.repository.UserRepository; - -public class UserControllerUnitTest { - @Mock - private UserRepository userRepository; - - @InjectMocks - private UserController userController; - - public UserControllerUnitTest() { - MockitoAnnotations.initMocks(this); - } - - @Test - public void testGetUserByIdUsingMonoError_UserNotFound() { - String userId = "3"; - when(userRepository.findById(userId)).thenReturn(Mono.empty()); - StepVerifier.create(userController.getUserByIdUsingMonoError(userId)) - .expectError(NotFoundException.class) - .verify(); - } - - @Test - public void testGetUserByIdThrowingException_UserNotFound() { - String userId = "3"; - when(userRepository.findById(userId)).thenReturn(Mono.empty()); - assertThrows(NotFoundException.class, () -> userController.getUserByIdThrowingException(userId) - .block()); - } - -} - diff --git a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/filerecord/FileRecordControllerIntegrationTest.java b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/filerecord/FileRecordControllerIntegrationTest.java index f8585852c1..c47d53632b 100644 --- a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/filerecord/FileRecordControllerIntegrationTest.java +++ b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/filerecord/FileRecordControllerIntegrationTest.java @@ -1,10 +1,5 @@ package com.baeldung.webflux.filerecord; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; - -import java.util.List; - import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; @@ -18,9 +13,13 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.web.reactive.server.WebTestClient; import org.springframework.util.LinkedMultiValueMap; - import reactor.core.publisher.Mono; +import java.util.List; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + @ExtendWith(SpringExtension.class) @SpringBootTest(classes = FileRecordController.class) @ContextConfiguration(classes = { FileRecordController.class }) diff --git a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/firstelementofflux/FirstElementOfFluxUnitTest.java b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/firstelementofflux/FirstElementOfFluxUnitTest.java index d7c084e3ec..a036011796 100644 --- a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/firstelementofflux/FirstElementOfFluxUnitTest.java +++ b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/firstelementofflux/FirstElementOfFluxUnitTest.java @@ -7,7 +7,6 @@ import java.util.Optional; import org.junit.jupiter.api.Test; import com.baeldung.webflux.model.Payment; - import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.test.StepVerifier; diff --git a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/zipwhen/UserControllerUnitTest.java b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/zipwhen/UserControllerUnitTest.java index 07c54fd531..8ed4cfb6c6 100644 --- a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/zipwhen/UserControllerUnitTest.java +++ b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/zipwhen/UserControllerUnitTest.java @@ -25,19 +25,19 @@ public class UserControllerUnitTest { User user = new User(userId, "John Doe"); Mockito.when(userService.getUser(userId)) - .thenReturn(Mono.just(user)); + .thenReturn(Mono.just(user)); Mockito.when(emailService.sendEmail(userId)) - .thenReturn(Mono.just(true)); + .thenReturn(Mono.just(true)); Mockito.when(databaseService.saveUserData(user)) - .thenReturn(Mono.just(true)); + .thenReturn(Mono.just(true)); UserController userController = new UserController(userService, emailService, databaseService); Mono> responseMono = userController.combineAllDataFor(userId); StepVerifier.create(responseMono) - .expectNextMatches(responseEntity -> responseEntity.getStatusCode() == HttpStatus.OK && responseEntity.getBody() - .equals("Response: " + user + ", Email Sent: true, Database Result: " + true)) - .verifyComplete(); + .expectNextMatches(responseEntity -> responseEntity.getStatusCode() == HttpStatus.OK && responseEntity.getBody() + .equals("Response: " + user + ", Email Sent: true, Database Result: " + true)) + .verifyComplete(); } } From 0b1672898e3a5ffcd86871f3ffc658dde6a7752b Mon Sep 17 00:00:00 2001 From: reza ganji Date: Sat, 30 Mar 2024 13:13:45 +0330 Subject: [PATCH 5/8] BAEL-7540 --- .../controller/UserController.java | 35 +++++++++++++++++++ .../ex/NotFoundException.java | 12 +++++++ .../exceptionhandeling/model/User.java | 29 +++++++++++++++ .../repository/UserRepository.java | 24 +++++++++++++ 4 files changed, 100 insertions(+) create mode 100644 spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/controller/UserController.java create mode 100644 spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/ex/NotFoundException.java create mode 100644 spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/model/User.java create mode 100644 spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/repository/UserRepository.java diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/controller/UserController.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/controller/UserController.java new file mode 100644 index 0000000000..6490b997af --- /dev/null +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/controller/UserController.java @@ -0,0 +1,35 @@ +package com.baeldung.webflux.exceptionhandeling.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RestController; + +import com.baeldung.webflux.exceptionhandeling.ex.NotFoundException; +import com.baeldung.webflux.exceptionhandeling.repository.UserRepository; +import com.baeldung.webflux.zipwhen.model.User; + +import reactor.core.publisher.Mono; + +@RestController +public class UserController { + + private final UserRepository userRepository; + + @Autowired + public UserController(UserRepository userRepository) { + this.userRepository = userRepository; + } + + @GetMapping("/user/{id}") + public Mono getUserByIdThrowingException(@PathVariable String id) { + return userRepository.findById(id) + .switchIfEmpty(Mono.error(new NotFoundException("User not found"))); + } + + @GetMapping("/user/{id}") + public Mono getUserByIdUsingMonoError(@PathVariable String id) { + return userRepository.findById(id) + .switchIfEmpty(Mono.error(() -> new NotFoundException("User not found"))); + } +} diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/ex/NotFoundException.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/ex/NotFoundException.java new file mode 100644 index 0000000000..5401a4d133 --- /dev/null +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/ex/NotFoundException.java @@ -0,0 +1,12 @@ +package com.baeldung.webflux.exceptionhandeling.ex; + +public class NotFoundException extends RuntimeException { + + public NotFoundException(String message) { + super(message); + } + + public NotFoundException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/model/User.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/model/User.java new file mode 100644 index 0000000000..42e1293ee8 --- /dev/null +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/model/User.java @@ -0,0 +1,29 @@ +package com.baeldung.webflux.exceptionhandeling.model; + +public class User { + private String id; + private String username; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public User(String userId, String userName) { + this.id=userId; + this.username=userName; + + } +} + diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/repository/UserRepository.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/repository/UserRepository.java new file mode 100644 index 0000000000..7d4ac0af86 --- /dev/null +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/repository/UserRepository.java @@ -0,0 +1,24 @@ +package com.baeldung.webflux.exceptionhandeling.repository; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.springframework.stereotype.Repository; + +import com.baeldung.webflux.zipwhen.model.User; + +import reactor.core.publisher.Mono; + +@Repository +public class UserRepository { + private final Map userDatabase = new ConcurrentHashMap<>(); + + public UserRepository() { + userDatabase.put("1", new User("1", "John Doe")); + userDatabase.put("2", new User("2", "Jane Smith")); + } + + public Mono findById(String id) { + return Mono.justOrEmpty(userDatabase.get(id)); + } +} From dab8be8a01c6306f553d0c20d0603e2cb80ad45a Mon Sep 17 00:00:00 2001 From: reza ganji Date: Fri, 5 Apr 2024 13:03:28 +0330 Subject: [PATCH 6/8] BAEL-7540 --- .../UserService.java} | 16 ++++++++++------ .../UserControllerUnitTest.java | 2 ++ 2 files changed, 12 insertions(+), 6 deletions(-) rename spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/{controller/UserController.java => service/UserService.java} (65%) create mode 100644 spring-5-webflux-2/src/test/java/com/baeldung/webflux/exceptionhandeling/UserControllerUnitTest.java diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/controller/UserController.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/service/UserService.java similarity index 65% rename from spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/controller/UserController.java rename to spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/service/UserService.java index 6490b997af..98d503bb23 100644 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/controller/UserController.java +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/service/UserService.java @@ -6,8 +6,8 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; import com.baeldung.webflux.exceptionhandeling.ex.NotFoundException; +import com.baeldung.webflux.exceptionhandeling.model.User; import com.baeldung.webflux.exceptionhandeling.repository.UserRepository; -import com.baeldung.webflux.zipwhen.model.User; import reactor.core.publisher.Mono; @@ -17,19 +17,23 @@ public class UserController { private final UserRepository userRepository; @Autowired - public UserController(UserRepository userRepository) { + public UserController(MyRepository userRepository) { this.userRepository = userRepository; } @GetMapping("/user/{id}") public Mono getUserByIdThrowingException(@PathVariable String id) { - return userRepository.findById(id) - .switchIfEmpty(Mono.error(new NotFoundException("User not found"))); + User user= userRepository.findById(id); + if(user==null) + throw new NotFoundException("User Not Found"); + return Mono.justOrEmpty(user); } @GetMapping("/user/{id}") public Mono getUserByIdUsingMonoError(@PathVariable String id) { - return userRepository.findById(id) - .switchIfEmpty(Mono.error(() -> new NotFoundException("User not found"))); + User user= userRepository.findById(id); + if(user==null) + return Mono.error(new NotFoundException("User Not Found")); + return Mono.justOrEmpty(user); } } diff --git a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/exceptionhandeling/UserControllerUnitTest.java b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/exceptionhandeling/UserControllerUnitTest.java new file mode 100644 index 0000000000..d81c553d41 --- /dev/null +++ b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/exceptionhandeling/UserControllerUnitTest.java @@ -0,0 +1,2 @@ +package com.baeldung.webflux.exceptionhandeling;public class UserControllerUnitTest { +} From 2b1ef2752765f60bbee97d1dc29c873a6fee81d2 Mon Sep 17 00:00:00 2001 From: reza ganji Date: Fri, 5 Apr 2024 13:06:23 +0330 Subject: [PATCH 7/8] BAEL-7540 --- .../exceptionhandeling/model/User.java | 4 +-- .../repository/UserRepository.java | 8 ++--- .../service/UserService.java | 23 ++++++------ .../UserControllerUnitTest.java | 36 ++++++++++++++++++- 4 files changed, 50 insertions(+), 21 deletions(-) diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/model/User.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/model/User.java index 42e1293ee8..6bc39da062 100644 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/model/User.java +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/model/User.java @@ -21,8 +21,8 @@ public class User { } public User(String userId, String userName) { - this.id=userId; - this.username=userName; + this.id = userId; + this.username = userName; } } diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/repository/UserRepository.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/repository/UserRepository.java index 7d4ac0af86..8c153aa2e6 100644 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/repository/UserRepository.java +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/repository/UserRepository.java @@ -5,9 +5,7 @@ import java.util.concurrent.ConcurrentHashMap; import org.springframework.stereotype.Repository; -import com.baeldung.webflux.zipwhen.model.User; - -import reactor.core.publisher.Mono; +import com.baeldung.webflux.exceptionhandeling.model.User; @Repository public class UserRepository { @@ -18,7 +16,7 @@ public class UserRepository { userDatabase.put("2", new User("2", "Jane Smith")); } - public Mono findById(String id) { - return Mono.justOrEmpty(userDatabase.get(id)); + public User findById(String id) { + return userDatabase.get(id); } } diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/service/UserService.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/service/UserService.java index 98d503bb23..eafaf421b9 100644 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/service/UserService.java +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/service/UserService.java @@ -1,9 +1,8 @@ -package com.baeldung.webflux.exceptionhandeling.controller; +package com.baeldung.webflux.exceptionhandeling.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RestController; import com.baeldung.webflux.exceptionhandeling.ex.NotFoundException; import com.baeldung.webflux.exceptionhandeling.model.User; @@ -11,29 +10,27 @@ import com.baeldung.webflux.exceptionhandeling.repository.UserRepository; import reactor.core.publisher.Mono; -@RestController -public class UserController { +public class UserService { private final UserRepository userRepository; @Autowired - public UserController(MyRepository userRepository) { + public UserService(UserRepository userRepository) { this.userRepository = userRepository; } @GetMapping("/user/{id}") public Mono getUserByIdThrowingException(@PathVariable String id) { - User user= userRepository.findById(id); - if(user==null) - throw new NotFoundException("User Not Found"); - return Mono.justOrEmpty(user); + User user = userRepository.findById(id); + if (user == null) + throw new NotFoundException("User Not Found"); + return Mono.justOrEmpty(user); } @GetMapping("/user/{id}") public Mono getUserByIdUsingMonoError(@PathVariable String id) { - User user= userRepository.findById(id); - if(user==null) - return Mono.error(new NotFoundException("User Not Found")); - return Mono.justOrEmpty(user); + User user = userRepository.findById(id); + return (user != null) ? Mono.justOrEmpty(user) : Mono.error(new NotFoundException("User Not Found")); + } } diff --git a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/exceptionhandeling/UserControllerUnitTest.java b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/exceptionhandeling/UserControllerUnitTest.java index d81c553d41..e968cfeea3 100644 --- a/spring-5-webflux-2/src/test/java/com/baeldung/webflux/exceptionhandeling/UserControllerUnitTest.java +++ b/spring-5-webflux-2/src/test/java/com/baeldung/webflux/exceptionhandeling/UserControllerUnitTest.java @@ -1,2 +1,36 @@ -package com.baeldung.webflux.exceptionhandeling;public class UserControllerUnitTest { +package com.baeldung.webflux.exceptionhandeling; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.junit.jupiter.api.Test; + +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import com.baeldung.webflux.exceptionhandeling.ex.NotFoundException; +import com.baeldung.webflux.exceptionhandeling.model.User; +import com.baeldung.webflux.exceptionhandeling.service.UserService; +import com.baeldung.webflux.exceptionhandeling.repository.UserRepository; + +public class UserControllerUnitTest { + UserRepository repositoryMock = mock(UserRepository.class); + private final UserService userService = new UserService(repositoryMock); + + @Test + public void givenNonExistUser_whenFailureCall_then_Throws_exception() { + assertThrows(NotFoundException.class, () -> userService.getUserByIdThrowingException("3")); + + } + + @Test + public void givenNonExistUser_whenFailureCall_then_returnMonoError() { + Mono result = userService.getUserByIdUsingMonoError("3"); + StepVerifier.create(result) + .expectError(NotFoundException.class) + .verify(); + + } + } From 23f1b4cbf3b64c93ebe1784ebe1ce18b3b06e85b Mon Sep 17 00:00:00 2001 From: reza ganji Date: Fri, 5 Apr 2024 13:24:42 +0330 Subject: [PATCH 8/8] BAEL-7540 --- .../webflux/exceptionhandeling/service/UserService.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/service/UserService.java b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/service/UserService.java index eafaf421b9..da5a672183 100644 --- a/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/service/UserService.java +++ b/spring-5-webflux-2/src/main/java/com/baeldung/webflux/exceptionhandeling/service/UserService.java @@ -19,16 +19,14 @@ public class UserService { this.userRepository = userRepository; } - @GetMapping("/user/{id}") - public Mono getUserByIdThrowingException(@PathVariable String id) { + public Mono getUserByIdThrowingException(String id) { User user = userRepository.findById(id); if (user == null) throw new NotFoundException("User Not Found"); return Mono.justOrEmpty(user); } - @GetMapping("/user/{id}") - public Mono getUserByIdUsingMonoError(@PathVariable String id) { + public Mono getUserByIdUsingMonoError(String id) { User user = userRepository.findById(id); return (user != null) ? Mono.justOrEmpty(user) : Mono.error(new NotFoundException("User Not Found"));