Nested bean instance supplier invocation does not retain previous factory method #33180
Closed
Description
Hello,
I have a problem when running native build
here is my build.gradle
./gradlew --version
------------------------------------------------------------
Gradle 8.8
------------------------------------------------------------
Build time: 2024-05-31 21:46:56 UTC
Revision: 4bd1b3d3fc3f31db5a26eecb416a165b8cc36082
Kotlin: 1.9.22
Groovy: 3.0.21
Ant: Apache Ant(TM) version 1.10.13 compiled on January 4 2023
JVM: 21.0.3 (Oracle Corporation 21.0.3+7-LTS-jvmci-23.1-b37)
OS: Linux 6.8.0-36-generic amd64
uname -a
Linux homepc 6.8.0-36-generic spring-projects/spring-boot#36-Ubuntu SMP PREEMPT_DYNAMIC Mon Jun 10 10:49:14 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux
cat /etc/os-release
PRETTY_NAME="Ubuntu 24.04 LTS"
NAME="Ubuntu"
VERSION_ID="24.04"
VERSION="24.04 LTS (Noble Numbat)"
VERSION_CODENAME=noble
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=noble
LOGO=ubuntu-logo
Application code:
package org.example.testsb;
import java.io.Serializable;
import lombok.RequiredArgsConstructor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.Advisor;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Role;
import org.springframework.core.annotation.Order;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
import org.springframework.security.authorization.AuthorizationEventPublisher;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.authorization.SpringAuthorizationEventPublisher;
import org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor;
import org.springframework.security.authorization.method.PreAuthorizeAuthorizationManager;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;
import static org.springframework.beans.factory.config.BeanDefinition.ROLE_INFRASTRUCTURE;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Service
public static class PermissionEvaluatorTest implements PermissionEvaluator {
public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
return false;
}
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
return false;
}
}
@EnableWebSecurity
@EnableMethodSecurity(
securedEnabled = true,
proxyTargetClass = true
)
@RequiredArgsConstructor
@Configuration
public static class SecurityConfig {
@Configuration
@Order(2)
@RequiredArgsConstructor
public static class OAuthSecurityConfig {
@Bean
public AuthorizationEventPublisher authorizationEventPublisher(ApplicationEventPublisher publisher) {
return new SpringAuthorizationEventPublisher(publisher);
}
@Bean
public MethodSecurityExpressionHandler methodSecurityExpressionHandler(PermissionEvaluator permissionEvaluator) {
DefaultMethodSecurityExpressionHandler handler = new DefaultMethodSecurityExpressionHandler();
handler.setPermissionEvaluator(permissionEvaluator);
return handler;
}
@Bean
public AuthorizationManager<MethodInvocation> authorizationManager(
MethodSecurityExpressionHandler methodSecurityExpressionHandler) {
PreAuthorizeAuthorizationManager preAuthorizeAuthorizationManager = new PreAuthorizeAuthorizationManager();
preAuthorizeAuthorizationManager.setExpressionHandler(methodSecurityExpressionHandler);
return (authentication, object) -> null;
}
@Bean
@Role(ROLE_INFRASTRUCTURE)
public Advisor authorizationManagerBeforeMethodInterception(AuthorizationManager<MethodInvocation> authorizationManager,
AuthorizationEventPublisher publisher) {
AuthorizationManagerBeforeMethodInterceptor authorizationManagerBeforeMethodInterceptor =
AuthorizationManagerBeforeMethodInterceptor.preAuthorize(authorizationManager);
authorizationManagerBeforeMethodInterceptor.setAuthorizationEventPublisher(publisher);
return authorizationManagerBeforeMethodInterceptor;
}
}
}
}
I'm compiling using ./gradlew nativeCompile
build/native/nativeCompile/testSB
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'methodSecurityExpressionHandler': null
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:648)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:636)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1337)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1167)
Full error log error.log
Here are generated aot resources
resources.zip
if I remove implements PermissionEvaluator
from PermissionEvaluatorTest
, inject it in OAuthSecurityConfig
private final PermissionEvaluatorTest permissionEvaluatorTest;
and create bean
@Bean
public PermissionEvaluator permissionEvaluator() {
return new PermissionEvaluator() {
@Override
public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
return permissionEvaluatorTest.hasPermission(authentication, targetDomainObject, permission);
}
@Override
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
return permissionEvaluatorTest.hasPermission(authentication, targetId, targetType, permission);
}
};
}
then it works as expected
Full working code
package org.example.testsb;
import java.io.Serializable;
import lombok.RequiredArgsConstructor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.Advisor;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Role;
import org.springframework.core.annotation.Order;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
import org.springframework.security.authorization.AuthorizationEventPublisher;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.authorization.SpringAuthorizationEventPublisher;
import org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor;
import org.springframework.security.authorization.method.PreAuthorizeAuthorizationManager;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;
import static org.springframework.beans.factory.config.BeanDefinition.ROLE_INFRASTRUCTURE;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Service
public static class PermissionEvaluatorTest {
public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
return false;
}
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
return false;
}
}
@EnableWebSecurity
@EnableMethodSecurity(
securedEnabled = true,
proxyTargetClass = true
)
@RequiredArgsConstructor
@Configuration
public static class SecurityConfig {
@Configuration
@Order(2)
@RequiredArgsConstructor
public static class OAuthSecurityConfig {
private final PermissionEvaluatorTest permissionEvaluatorTest;
@Bean
public PermissionEvaluator permissionEvaluator() {
return new PermissionEvaluator() {
@Override
public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
return permissionEvaluatorTest.hasPermission(authentication, targetDomainObject, permission);
}
@Override
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
return permissionEvaluatorTest.hasPermission(authentication, targetId, targetType, permission);
}
};
}
@Bean
public AuthorizationEventPublisher authorizationEventPublisher(ApplicationEventPublisher publisher) {
return new SpringAuthorizationEventPublisher(publisher);
}
@Bean
public MethodSecurityExpressionHandler methodSecurityExpressionHandler(PermissionEvaluator permissionEvaluator) {
DefaultMethodSecurityExpressionHandler handler = new DefaultMethodSecurityExpressionHandler();
handler.setPermissionEvaluator(permissionEvaluator);
return handler;
}
@Bean
public AuthorizationManager<MethodInvocation> authorizationManager(
MethodSecurityExpressionHandler methodSecurityExpressionHandler) {
PreAuthorizeAuthorizationManager preAuthorizeAuthorizationManager = new PreAuthorizeAuthorizationManager();
preAuthorizeAuthorizationManager.setExpressionHandler(methodSecurityExpressionHandler);
return (authentication, object) -> null;
}
@Bean
@Role(ROLE_INFRASTRUCTURE)
public Advisor authorizationManagerBeforeMethodInterception(AuthorizationManager<MethodInvocation> authorizationManager,
AuthorizationEventPublisher publisher) {
AuthorizationManagerBeforeMethodInterceptor authorizationManagerBeforeMethodInterceptor =
AuthorizationManagerBeforeMethodInterceptor.preAuthorize(authorizationManager);
authorizationManagerBeforeMethodInterceptor.setAuthorizationEventPublisher(publisher);
return authorizationManagerBeforeMethodInterceptor;
}
}
}
}
It was perfectly worked in '3.2.5', but not works from '3.3.0'