spring-bootkotlinspring-webfluxinsomnia

@ControllerAdvice not working for Kotlin Spring Webflux


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.


Solution

  • 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?)