Skip to content
Advertisement

Spring is trying to subclass a record component when aop is present

I have a spring boot application in which I make use of aspects. Recently, I tried converting my @ConfigurationProperties classes to java records, but it fails with "Cannot subclass final class {..}Properties". It seems spring is trying to make cglib proxies for my records, which obviously fail. Is there any way to tell spring not to make proxies for specific classes?

Edit:

The properties:

@ConfigurationProperties(prefix = "foo.bar")
public record MyProperties(String a,
                           String b) {

}

Stacktrace:

Caused by: org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class {...}.MyProperties: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Cannot subclass final class {...}.MyProperties
at org.springframework.aop.framework.CglibAopProxy.getProxy(CglibAopProxy.java:209)
at org.springframework.aop.framework.ProxyFactory.getProxy(ProxyFactory.java:110)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.createProxy(AbstractAutoProxyCreator.java:478)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:342)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:291)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:437)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1790)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:602)
... 48 common frames omitted
Caused by: java.lang.IllegalArgumentException: Cannot subclass final class {...}.MyProperties
at org.springframework.cglib.proxy.Enhancer.generateClass(Enhancer.java:660)
at org.springframework.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
at org.springframework.cglib.core.ClassLoaderAwareGeneratorStrategy.generate(ClassLoaderAwareGeneratorStrategy.java:57)
at org.springframework.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:358)
at org.springframework.cglib.proxy.Enhancer.generate(Enhancer.java:585)
at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:131)
at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:319)
at org.springframework.cglib.proxy.Enhancer.createHelper(Enhancer.java:572)
at org.springframework.cglib.proxy.Enhancer.createClass(Enhancer.java:419)
at org.springframework.aop.framework.ObjenesisCglibAopProxy.createProxyClassAndInstance(ObjenesisCglibAopProxy.java:57)
at org.springframework.aop.framework.CglibAopProxy.getProxy(CglibAopProxy.java:206)
... 55 common frames omitted

Edit 2: A minimal, reproducible example: https://github.com/moxaj/aspect-mcve-2

Advertisement

Answer

I cloned your MCVE repository. Thanks, that was helpful.

Please note that Java records are implicitly final. Therefore, Spring AOP cannot subclass them in order to create dynamic proxies.

You need to change

@Pointcut("within(foo.bar..*) @target(org.springframework.stereotype.Service)")

(please also note the syntax error, missing &&) to

@Pointcut(
  "within(foo.bar..*) && " +
  "@target(org.springframework.stereotype.Service) && " +
  "!@within(org.springframework.boot.context.properties.ConfigurationProperties)"
)

I just added a few line breaks in order to make the pointcut more readable.

User contributions licensed under: CC BY-SA
4 People found this is helpful
Advertisement