spring-projects / spring-projects/spring-framework
`AbstractAdvisingBeanPostProcessor` should gracefully skip `final` classes instead of throwing `IllegalArgumentException`
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 60.2k
- Forks
- 38.8k
- Avg merge
- 5d 2h
- Merged PRs (30d)
- 27
Description
When MethodValidationPostProcessor (which extends AbstractAdvisingBeanPostProcessor) encounters a bean whose class is final — such as a Java Record — it attempts to create a CGLIB proxy and fails with:
java.lang.IllegalArgumentException: Cannot subclass final class com.example.MyConfigurationProperties
With proxyTargetClass=false, it falls back to a JDK dynamic proxy, which then causes injection failures downstream when the bean is injected by concrete class type:
The bean 'my-config-com.example.MyConfigurationProperties' could not be injected because it is a JDK dynamic proxy
Use case
A third-party library defines a @ConfigurationProperties class as a Java Record implementing an interface with @NotNull constraints:
@ConfigurationProperties("my.config")
@Validated
public record MyConfigurationProperties(List<Entry> entries) implements MyInterface {
// ...
}
A service in the same library injects this bean by concrete type:
public class MyService {
public MyService(MyConfigurationProperties config) { /* ... */ }
}
The consuming application registers a MethodValidationPostProcessor bean. Because the record has @Validated, the post-processor attempts to create an AOP proxy — which is impossible for a final class regardless of the proxy strategy:
proxyTargetClass=true→IllegalArgumentException: Cannot subclass final classproxyTargetClass=false→ JDK proxy created, but injection by concrete type fails
Current workaround
Override postProcessAfterInitialization to skip final classes:
@Bean
public static MethodValidationPostProcessor methodValidationPostProcessor() {
return new MethodValidationPostProcessor() {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (Modifier.isFinal(bean.getClass().getModifiers())) {
return bean;
}
return super.postProcessAfterInitialization(bean, beanName);
}
};
}
Suggested improvement
AbstractAdvisingBeanPostProcessor.postProcessAfterInitialization (or AopUtils) should detect final classes and gracefully skip proxy creation — logging a debug/warning message instead of throwing an exception. This is especially relevant given that:
- Spring Boot recommends Java Records for
@ConfigurationPropertiessince 3.x @Validatedon@ConfigurationPropertiesis a common and documented pattern- Kotlin classes are
finalby default - The consuming application often cannot modify library classes
Spring Framework version: 6.2.15 (Spring Boot 3.5.10)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at AbstractAdvisingBeanPostProcessor.postProcessAfterInitialization and inspect the related proxy checks in AopUtils. Reproduce the final-class case described with MethodValidationPostProcessor, then determine how final classes should be skipped without causing the CGLIB exception or an unusable JDK proxy; done means the behavior is covered by appropriate tests.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, spring
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100