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:
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.
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?)