How to use problem-spring-web only for @RestController classes, but retain regular handling for fullstack (Controller + Thymeleaf + databinding)
This may be a question that others have answered previously; however, I haven't found a good resource on this topic.
Context: I have an existing REST controller based microservice where I need to add a few fullstack pages to. I've attempted adding,
@ControllerAdvice(assignableTypes = RestController.class)
public final class ExceptionTranslator implements ProblemHandling, SecurityAdviceTrait {
in order to constrain the exception handling to just my REST controllers; however, that didn't quite do the trick -- I got the usual whitelabel error page instead. I'm sure I'm missing some additional detail to fallback to the regular spring error handling so thymeleaf-based forms can receive the usual validation errors when say a ConstraintViolation is encountered.
Are there some documentation references that would be of use in this blended REST + Fullstack situation?
Thanks!
Note sure if I follow, but... RestController is an annotation, which is why assignableTypes won't work.
Why not simply make the REST controllers implement a marker interface in addition to annotating them with @RestController? I believe assignableTypes would work with an interface.
This is a Spring question, BTW, and not directly related to problem-spring-web
I've been struggling with this as well. Unfortunately I can't think of a way to make assignableTypes or even something like @ControllerAdvice(annotations = [RestController::class]) work with the library's recommended approach, due to Spring Internals.
The problem seems to boils down to all exception resolution getting lumped together in the global HandlerExceptionResolverComposite bean, and an AuthenticationException not having an associated handler or controller. Assuming HttpSecurity's authenticationEntryPoint is set to SecurityProblemSupport, it calls AuthenticationEntryPoint#commence which delegates to the global composite resolver HandlerExceptionResolver#resolveException with a null handler parameter.
Eventually the exception resolver iterates over all of its exception handling advices, but the problem-spring-web advice bean will never satisfy the condition due to it's HandlerTypePredicate only knowing null as the controllerType, but also having a restriction/selector to operate only on handlers annotated with RestController in my example.
Here's a similar problem presented on SO: https://stackoverflow.com/q/47679897
In the end, I've burned enough time on it to settle on what feels hacky, but lets me accomplish my goal of only having RestControllers return problem responses. I've stopped using SecurityProblemSupport in favor of a custom implementation:
@ControllerAdvice(annotations = [RestController::class])
class TheAdvice : ProblemHandling, SecurityAdviceTrait
@Component
class ApiSecurityExceptionHandler(
private val objectMapper: ObjectMapper
) : AuthenticationEntryPoint, AccessDeniedHandler, SecurityAdviceTrait {
override fun commence(
request: HttpServletRequest,
response: HttpServletResponse,
authException: AuthenticationException
) = writeProblemResponse(response, handleAuthentication(authException, ServletWebRequest(request)))
override fun handle(
request: HttpServletRequest,
response: HttpServletResponse,
accessDeniedException: AuthenticationException
) = writeProblemResponse(response, handleAccessDenied(accessDeniedException, ServletWebRequest(request)))
private fun writeProblemResponse(response: HttpServletResponse, problem: ResponseEntity<Problem>) {
response.status = problem.statusCodeValue
response.contentType = MediaType.APPLICATION_JSON.toString()
objectMapper.writeValue(response.writer, problem.body)
}
}