Reputation: 41
So I want to achieve the functionality of saving an user
for that first i check whether user is present
if present throw an exception
else save the user
But when I throw an exception from service layer .flatMap(user -> Mono.error(new IllegalArgumentException("User Exists with email " + user.getEmail())))
@Service
@RequiredArgsConstructor
public class AppUserService {
private final AppUserRepository appUserRepository;
public Flux<AppUser> getAllUsers() {
return appUserRepository.findAll();
}
public Mono<AppUser> saveUser(AppUser appUser) {
return getUser(appUser.getEmail())
.flatMap(user -> Mono.error(new IllegalArgumentException("User Exists with email " + user.getEmail())))
.switchIfEmpty(Mono.defer(() -> appUserRepository.save(appUser))).cast(AppUser.class).log();
}
public Mono<AppUser> getUser(String email) {
return appUserRepository.findFirstByEmail(email);
}
}
and in the controller layer if I handle it like .onErrorResume(error -> ServerResponse.badRequest().bodyValue(error))
@RestController
@RequiredArgsConstructor
@RequestMapping("/user")
public class AppUserController {
private final AppUserService appUserService;
private final PasswordEncoder encoder;
@GetMapping
public Flux<AppUser> getAllUsers(@RequestHeader("email") String email) {
return appUserService.getAllUsers();
}
@PostMapping
@CrossOrigin
public Mono<ResponseEntity<Object>> saveUser(@RequestBody Mono<AppUser> appUserMono) {
return appUserMono
.doOnSuccess(appUser -> appUser.setPassword(encoder.encode(appUser.getPassword())))
.subscribeOn(Schedulers.parallel())
.flatMap(appUserService::saveUser)
.flatMap(savedAppUser -> ResponseEntity.created(URI.create("/user/" + savedAppUser.getId())).build())
.onErrorResume(error -> Response entity.badRequest().bodyValue(error))
.log();
}
}
it throws an error on the console
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.springframework.web.reactive.function.server.DefaultEntityResponseBuilder$DefaultEntityResponse and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)
and returns 200 to the client
what am i doing wrong
After reading the error it seems its getting an empty value
but if i debug the flow at the onErrorResume(error -> ..)
the error variable has the error
can't understand why it still throws the jackson error
is it because jackson can't subscribe to ServerResponse or something around that
Upvotes: 2
Views: 2257
Reputation: 6144
There are few issues in your code.
Here's how you can get it to run (without the repository):
package test;
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class AppUser {
private String id;
private String username;
private String firstName;
private String password;
private String email;
}
@Service
@RequiredArgsConstructor
public class AppUserService {
public Mono<AppUser> saveUser(AppUser appUser) {
return getUser(appUser.getEmail())
.flatMap(user -> Mono.<AppUser>error(
new IllegalArgumentException("User Exists with email " + user.getEmail())))
.switchIfEmpty(Mono.defer(() -> Mono.just(AppUser.builder().username("mustafa").build())));
}
public Mono<AppUser> getUser(String email) {
// return Mono.defer(() -> Mono.just(AppUser.builder().email(email).build()));
return Mono.defer(Mono::empty);
}
}
@RestController
@RequiredArgsConstructor
@RequestMapping("/user")
public class AppUserController {
private final AppUserService appUserService;
@PostMapping
@CrossOrigin
public Mono<ResponseEntity<AppUser>> saveUser(@RequestBody Mono<AppUser> appUserMono,
@RequestHeader("email") String email) {
return appUserMono
.subscribeOn(Schedulers.parallel())
.flatMap(appUserService::saveUser)
.flatMap(savedAppUser -> Mono.just(
ResponseEntity.created(URI.create("/user/" + savedAppUser.getId())).body(savedAppUser)))
.onErrorResume(error -> Mono.just(ResponseEntity.badRequest().build()))
.log();
}
}
Your controller's return type is Mono<ResponseEntity<AppUser>>
but you are returning ServerResponse
. I fixed this and removed the cast from your service code.
You can experiment with producing a 400 or a valid result by commenting/uncommenting the getUser
body.
Maybe a clearer way to write the email check logic is with the good old if/else statement:
public Mono<AppUser> saveUser(AppUser appUser) {
if (emailExists(appUser.getEmail())) {
return Mono.error(new IllegalArgumentException("User Exists with email "
+ appUser.getEmail()));
} else {
return Mono.just(AppUser.builder().username("mustafa").build());
}
}
Upvotes: 2