I am adding support for the @PreAuthorize, @PreFilter, @PostAuthorize, and @PostFilter annotations from Spring Security.

The hints are being added using a PrePostSecuredBeanRegistrationAotProcessor and PrePostSecuredBeanRegistrationAotContribution, which can be seen here, that's pretty much what we had before in the native repository.

However, the application fails when running on native with the following stacktrace:

org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'greetingServiceImpl' is expected to be of type 'com.example.methodsecurity.GreetingService' but was actually of type 'jdk.proxy4.$Proxy235'
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.checkBeanNotOfRequiredType(DefaultListableBeanFactory.java:1800) ~[security-method:6.0.0-SNAPSHOT]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1777) ~[security-method:6.0.0-SNAPSHOT]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1340) ~[security-method:6.0.0-SNAPSHOT]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1294) ~[security-method:6.0.0-SNAPSHOT]
        at org.springframework.beans.factory.aot.AutowiredInstantiationArgumentsResolver.resolveArgument(AutowiredInstantiationArgumentsResolver.java:302) ~[na:na]
        at org.springframework.beans.factory.aot.AutowiredInstantiationArgumentsResolver.resolveArguments(AutowiredInstantiationArgumentsResolver.java:232) ~[na:na]
        at org.springframework.beans.factory.aot.AutowiredInstantiationArgumentsResolver.resolve(AutowiredInstantiationArgumentsResolver.java:154) ~[na:na]
        at com.example.methodsecurity.MainController__BeanDefinitions.getMainControllerInstance(MainController__BeanDefinitions.java:30) ~[na:na]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainInstanceFromSupplier(AbstractAutowireCapableBeanFactory.java:1223) ~[security-method:6.0.0-SNAPSHOT]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainFromSupplier(AbstractAutowireCapableBeanFactory.java:1209) ~[security-method:6.0.0-SNAPSHOT]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1156) ~[security-method:6.0.0-SNAPSHOT]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:566) ~[security-method:6.0.0-SNAPSHOT]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:526) ~[security-method:6.0.0-SNAPSHOT]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) ~[security-method:6.0.0-SNAPSHOT]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[security-method:6.0.0-SNAPSHOT]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) ~[security-method:6.0.0-SNAPSHOT]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[security-method:6.0.0-SNAPSHOT]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:930) ~[security-method:6.0.0-SNAPSHOT]
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:926) ~[security-method:6.0.0-SNAPSHOT]
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:592) ~[security-method:6.0.0-SNAPSHOT]
        at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) ~[security-method:3.0.0-SNAPSHOT]
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:729) ~[security-method:3.0.0-SNAPSHOT]
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:428) ~[security-method:3.0.0-SNAPSHOT]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:310) ~[security-method:3.0.0-SNAPSHOT]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1301) ~[security-method:3.0.0-SNAPSHOT]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1290) ~[security-method:3.0.0-SNAPSHOT]
        at com.example.methodsecurity.MethodSecurityApplication.main(MethodSecurityApplication.java:19) ~[security-method:0.0.1-SNAPSHOT]

It runs fine in AOT only.

To Reproduce:

Run the build.sh script from this sample.

Comment From: sbrannen

@marcusdacoregio, why are you registering both a JDK and a Class proxy in the else block?

https://github.com/marcusdacoregio/spring-native/blob/0c96a5ef43e5eb54b9bafec95992349f418da637/samples/security-method/src/main/java/com/example/methodsecurity/PrePostSecuredBeanRegistrationAotProcessor.java#L107-L108

What happens if you delete line 107 (registerJdkProxy)?

Comment From: marcusdacoregio

Hi @sbrannen, if I remove that line the error changes to this:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'controller2': Proxy class defined by interfaces [interface org.springframework.aop.SpringProxy, interface org.springframework.aop.framework.Advised, interface org.springframework.core.DecoratingProxy] not found. Generating proxy classes at runtime is not supported. Proxy classes need to be defined at image build time by specifying the list of interfaces that they implement. To define proxy classes use -H:DynamicProxyConfigurationFiles=<comma-separated-config-files> and -H:DynamicProxyConfigurationResources=<comma-separated-config-resources> options.
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:611) ~[security-method:6.0.0-SNAPSHOT]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:526) ~[security-method:6.0.0-SNAPSHOT]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) ~[security-method:6.0.0-SNAPSHOT]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[security-method:6.0.0-SNAPSHOT]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) ~[security-method:6.0.0-SNAPSHOT]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[security-method:6.0.0-SNAPSHOT]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:930) ~[security-method:6.0.0-SNAPSHOT]
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:926) ~[security-method:6.0.0-SNAPSHOT]
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:592) ~[security-method:6.0.0-SNAPSHOT]
        at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) ~[security-method:3.0.0-SNAPSHOT]
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:729) ~[security-method:3.0.0-SNAPSHOT]
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:428) ~[security-method:3.0.0-SNAPSHOT]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:310) ~[security-method:3.0.0-SNAPSHOT]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1301) ~[security-method:3.0.0-SNAPSHOT]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1290) ~[security-method:3.0.0-SNAPSHOT]
        at com.example.methodsecurity.MethodSecurityApplication.main(MethodSecurityApplication.java:19) ~[security-method:0.0.1-SNAPSHOT]
Caused by: com.oracle.svm.core.jdk.UnsupportedFeatureError: Proxy class defined by interfaces [interface org.springframework.aop.SpringProxy, interface org.springframework.aop.framework.Advised, interface org.springframework.core.DecoratingProxy] not found. Generating proxy classes at runtime is not supported. Proxy classes need to be defined at image build time by specifying the list of interfaces that they implement. To define proxy classes use -H:DynamicProxyConfigurationFiles=<comma-separated-config-files> and -H:DynamicProxyConfigurationResources=<comma-separated-config-resources> options.
        at com.oracle.svm.core.util.VMError.unsupportedFeature(VMError.java:89) ~[na:na]
        at com.oracle.svm.reflect.proxy.DynamicProxySupport.getProxyClass(DynamicProxySupport.java:158) ~[na:na]
        at java.lang.reflect.Proxy.getProxyConstructor(Proxy.java:48) ~[security-method:na]
        at java.lang.reflect.Proxy.newProxyInstance(Proxy.java:1037) ~[security-method:na]
        at org.springframework.aop.framework.JdkDynamicAopProxy.getProxy(JdkDynamicAopProxy.java:126) ~[na:na]
        at org.springframework.aop.framework.ProxyFactory.getProxy(ProxyFactory.java:110) ~[na:na]
        at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.createProxy(AbstractAutoProxyCreator.java:480) ~[security-method:0.0.1-SNAPSHOT]
        at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:344) ~[security-method:0.0.1-SNAPSHOT]
        at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:293) ~[security-method:0.0.1-SNAPSHOT]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:440) ~[security-method:6.0.0-SNAPSHOT]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1756) ~[security-method:6.0.0-SNAPSHOT]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:604) ~[security-method:6.0.0-SNAPSHOT]
        ... 15 common frames omitted

Comment From: sbrannen

Thanks for trying it out and reporting back.

Both of the errors point to the same underlying issue.

The first error tells us that you got back a dynamic proxy instead of class-based proxy.

The second error tells us that a dynamic proxy could not be created for the interfaces SpringProxy,Advised, and DecoratingProxy, but Spring should never attempt to create a JDK dynamic proxy based solely on those three interfaces. Rather, the dynamic proxy must implement the user's interface(s) as well.

Controller2 does not implement any interfaces. So in order to proxy it for @PreAuthorize support, Spring has to create a class-based proxy.

I have not debugged your application, but both of these errors point to org.springframework.aop.framework.DefaultAopProxyFactory.createAopProxy(AdvisedSupport).

Specifically, if NativeDetector.inNativeImage() returns true, DefaultAopProxyFactory will create a JdkDynamicAopProxy instead of a ObjenesisCglibAopProxy.

In summary, I think this is effectively a duplicate of #28115, but I will leave it open for @jhoeller to assess once he addresses #28115.

Comment From: snicoll

@marcusdacoregio please subscribe to #28115 and try again when it's fixed. If it turns out to be another issue, we can always reopen this one.