spring-boot: Enabling Problem Details doesn't work with proxying
Using Spring Boot 3.0.2, combining Problem Details (e.g., spring.mvc.problemdetails.enabled=true
) with proxying (e.g., due to AOP) doesn’t work since ProblemDetailsExceptionHandler
classes (duplicated in both servlet
and reactive
) are final
.
Use case
I want to perform certain operations (e.g., logging) on the Problem Details returned. For this purpose, I am intercepting ExceptionHandler
return values using AspectJ.
Reproduction
Consider the following example trying to intercept ExceptionHandler
s to log ErrorResponse
details:
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.http.ResponseEntity;
import org.springframework.lang.Nullable;
import org.springframework.web.ErrorResponse;
@EnableAspectJAutoProxy
@WebMvcTest(value = ProblemTest.TestConfig.class, properties = "spring.mvc.problemdetails.enabled=true")
class ProblemTest {
@Test
void contextLoads() {}
@Configuration
static class TestConfig {
@Bean
ProblemLoggingAspect problemLoggingAspect() {
return new ProblemLoggingAspect();
}
}
@Aspect
static class ProblemLoggingAspect {
@AfterReturning(
pointcut = "@annotation(org.springframework.web.bind.annotation.ExceptionHandler)",
returning = "returnValue")
public void exceptionHandlerIntercept(JoinPoint joinPoint, Object returnValue) {
ErrorResponse errorResponse = errorResponse(joinPoint, returnValue);
if (errorResponse != null) {
System.out.format("problem detail: %s%n", errorResponse.getBody().getDetail());
}
}
@Nullable
private ErrorResponse errorResponse(JoinPoint ignored, Object returnValue) {
if (returnValue instanceof ErrorResponse errorResponse) {
return errorResponse;
} else if (returnValue instanceof ResponseEntity<?> responseEntity &&
responseEntity.getBody() instanceof ErrorResponse errorResponse) {
return errorResponse;
}
return null;
}
}
}
Running this test results in the following failure:
...
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'problemDetailsExceptionHandler' defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration$ProblemDetailsErrorHandlingConfiguration.class]: Could not generate CGLIB subclass of class org.springframework.boot.autoconfigure.web.servlet.ProblemDetailsExceptionHandler: Common causes of this problem include using a final class or a non-visible class
...
Caused by: org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class org.springframework.boot.autoconfigure.web.servlet.ProblemDetailsExceptionHandler: Common causes of this problem include using a final class or a non-visible class
...
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.createProxy(AbstractAutoProxyCreator.java:464) ~[spring-aop-6.0.4.jar:6.0.4]
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:369) ~[spring-aop-6.0.4.jar:6.0.4]
...
Caused by: java.lang.IllegalArgumentException: Cannot subclass final class org.springframework.boot.autoconfigure.web.servlet.ProblemDetailsExceptionHandler
at org.springframework.cglib.proxy.Enhancer.generateClass(Enhancer.java:653) ~[spring-core-6.0.4.jar:6.0.4]
at org.springframework.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:26) ~[spring-core-6.0.4.jar:6.0.4]
...
Notes
ProblemTest
succeeds against Spring Boot 2.x and, when spring.mvc.problemdetails.enabled=false
, 3.x. It only fails on 3.x when spring.mvc.problemdetails.enabled=true
.
About this issue
- Original URL
- State: closed
- Created a year ago
- Comments: 17 (17 by maintainers)
@rstoyanchev, @sbrannen, @bclozel, thanks so much for the prompt responses. I will locally try out removing
final
modifiers and updating the aspect point-cut, and share the outcome here. Please allow me some time for this check.