-1

I'm writing a simple Kotlin Spring Boot Webflux application. I now want to add some Exception handling which isn't showing the message no matter what I try out.

When I run the application in debug mode in Intellij, I can see it actually gets to my @ControllerAdvice class and correctly populates my custom message object, but it just won't display it as the response message.

My Controller code is:

@RestController
@RequestMapping("/api")
class AppUserController(private val appUserService: AppUserService) {
   @PostMapping("/users")
    @ResponseStatus(HttpStatus.CREATED)
    fun addUser(@Valid @RequestBody appUserRequest: AppUserRequest): Mono<AppUserRequest> =
        appUserService.addUser(appUserRequest)
}

My service code is:

@Service
class AppUserServiceImpl(private val appUserRepository: AppUserRepository): AppUserService {
override fun addUser(appUserRequest: AppUserRequest): Mono<AppUserRequest> {
        val appUser: AppUser = toEntity(appUserRequest)
        val userEmail: String = appUser.email

        return appUserRepository.findByEmail(userEmail)
            .flatMap<AppUserRequest> { Mono.error(BadRequestException("User with email $userEmail already exists.")) }
            .switchIfEmpty(appUserRepository.save(appUser)
                               .map { savedAppUser -> toApi(savedAppUser) }
                               .log("New app user has been added"))
    }
}

And my controller advice code is:

@ControllerAdvice
class ExceptionControllerAdvice {

    @ExceptionHandler(BadRequestException::class)
    fun handleBadRequestException(exception: BadRequestException): ResponseEntity<AppError> {

        val errorMessage = AppError(HttpStatus.BAD_REQUEST.value(),
                                    HttpStatus.BAD_REQUEST.reasonPhrase,
                                    Instant.now(),
                                    exception.localizedMessage)
        return ResponseEntity(errorMessage, HttpStatus.BAD_REQUEST)
    }
}

What I see as response from Insomnia is:

enter image description here

Please, any assistance would be greatly appreciated! I suspect it's something simple I'm missing.

Update: Immediately I remove my custom error message data class for a String, it actually displays the expected String message. My custom error data class is:

data class AppError(private var errorCode: Int?,
               private var status: String?,
               @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'hh:mm:ssZ", timezone = "Europe/London")
               private val timestamp: Instant,
               private var message: String?) 

Maybe the issue is hiding there somewhere.

Sammy65
  • 627
  • 2
  • 12
  • 28

2 Answers2

1

I have just take a quick look on it. As far as i know Mono.error is a wrapper class and sending a signal to a client on a reactive application. To handle mono error in a customized entity use onErrorReturn

  • Hello and welcome to Stackoverflow! Thanks for the response. Are you saying using the `@RestControllerAdvice` or `@ControllerAdvice` pattern isn't possible with reactor types? I'm aware of the onErrorReturn but wanted to follow the same pattern as the non-reactive WebMVC for handling errors globally. – Sammy65 Aug 13 '23 at 17:52
0

I've discovered the issue is with my custom AppError model.
This is how it actually should be for it to work!
It didn't like the 'private' modifier I added to the fields.

data class AppError(var errorCode: Int?,
               var status: String?,
               @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'hh:mm:ssZ", timezone = "Europe/London")
               val timestamp: Instant,
               var message: String?)
Sammy65
  • 627
  • 2
  • 12
  • 28