Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Infer hints required for aspects #28711

Closed
mhalbritter opened this issue Jun 27, 2022 · 10 comments
Closed

Infer hints required for aspects #28711

mhalbritter opened this issue Jun 27, 2022 · 10 comments
Assignees
Labels
in: core Issues in core modules (aop, beans, core, context, expression) theme: aot An issue related to Ahead-of-time processing type: enhancement A general enhancement
Milestone

Comments

@mhalbritter
Copy link
Contributor

In the spring-native sample class-proxies-aop in the branch sb-3.0.x, the @Aspect works when running in AOT mode, but not in a native-image.
There's no exception, the aspect just doesn't get executed.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Jun 27, 2022
@sdeleuze
Copy link
Contributor

Likely depends on #28115.

@sdeleuze sdeleuze added this to the 6.0.0-M6 milestone Jun 28, 2022
@sdeleuze sdeleuze added type: enhancement A general enhancement theme: aot An issue related to Ahead-of-time processing and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Jun 28, 2022
@snicoll
Copy link
Member

snicoll commented Aug 22, 2022

The proxy is now created properly but the aspect smoke test still fails.

@sdeleuze sdeleuze self-assigned this Aug 22, 2022
@sdeleuze
Copy link
Contributor

I was able to make it work with:

static class AspectRuntimeHints implements RuntimeHintsRegistrar {
		@Override
		public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
			hints.reflection().registerType(TestAspect.class,
					builder -> builder.withMembers(MemberCategory.INVOKE_DECLARED_METHODS));
			hints.proxies().registerJdkProxy(FactoryBean.class, BeanClassLoaderAware.class, ApplicationListener.class);
			hints.proxies().registerJdkProxy(ApplicationAvailability.class, ApplicationListener.class);
		}
	}

Reflection hint should probably be inferred on Spring Framework side.

The 2 proxies are required by org.springframework.boot.availability.ApplicationAvailabilityBean and org.springframework.boot.admin.SpringApplicationAdminMXBeanRegistrar and are not created automatically by my #28980 local fix (@jhoeller could you please confirm that's expected?). Related stacktrace is:

at java.lang.reflect.Proxy.getProxyConstructor(Proxy.java:48) ~[aspect:na]
	at java.lang.reflect.Proxy.getProxyClass(Proxy.java:398) ~[aspect:na]
	at org.springframework.util.ClassUtils.createCompositeInterface(ClassUtils.java:784) ~[na:na]
	at org.springframework.aop.aspectj.AspectJExpressionPointcut.getTargetShadowMatch(AspectJExpressionPointcut.java:437) ~[na:na]
	at org.springframework.aop.aspectj.AspectJExpressionPointcut.matches(AspectJExpressionPointcut.java:295) ~[na:na]
	at org.springframework.aop.support.AopUtils.canApply(AopUtils.java:251) ~[na:na]
	at org.springframework.aop.support.AopUtils.canApply(AopUtils.java:288) ~[na:na]
	at org.springframework.aop.support.AopUtils.findAdvisorsThatCanApply(AopUtils.java:320) ~[na:na]
	at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findAdvisorsThatCanApply(AbstractAdvisorAutoProxyCreator.java:128) ~[aspect:6.0.0-SNAPSHOT]
	at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findEligibleAdvisors(AbstractAdvisorAutoProxyCreator.java:97) ~[aspect:6.0.0-SNAPSHOT]
	at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean(AbstractAdvisorAutoProxyCreator.java:78) ~[aspect:6.0.0-SNAPSHOT]
	at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:366) ~[aspect:6.0.0-SNAPSHOT]
	at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:318) ~[aspect:6.0.0-SNAPSHOT]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:435) ~[aspect:6.0.0-SNAPSHOT]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1757) ~[aspect:6.0.0-SNAPSHOT]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:599) ~[aspect:6.0.0-SNAPSHOT]

If it is confirmed those can't be inferred, I guess those proxies hints should be contributed on Boot side

@sdeleuze
Copy link
Contributor

sdeleuze commented Jan 4, 2023

Looks like the aspect smoke test samples now work, but there are other issues preventing it to work in a reliable fashion for various use case. #29519 is likely one of the blockers.

@sdeleuze
Copy link
Contributor

sdeleuze commented Jan 4, 2023

We should also check if aspect annotations and the methods and classes where they are applied are available via reflection, I suspect #29765 sample is broken by annotation not accessible via reflection on native.

@sdeleuze sdeleuze changed the title Aspects don't work in native-image Infer hints required for aspects Jan 10, 2023
@sdeleuze sdeleuze modified the milestones: 6.0.x, 6.0.5 Jan 10, 2023
@sdeleuze
Copy link
Contributor

sdeleuze commented Jan 23, 2023

We could potentially reuse Spring AOP infrastructure to identify the reflection entries needed to make aspects working out of the box. We could create a dedicated BeanFactoryInitializationAotProcessor that would use BeanFactoryAspectJAdvisorsBuilder to get the List<Advisor> and process each of them. Maybe we could get the needed information for inference via instanceof PointcutAdvisor and instanceof AbstractAspectJAdvice checks.

@sdeleuze sdeleuze modified the milestones: 6.0.5, 6.0.6 Feb 14, 2023
@jhoeller jhoeller added the in: core Issues in core modules (aop, beans, core, context, expression) label Feb 28, 2023
@sdeleuze sdeleuze removed this from the 6.0.6 milestone Feb 28, 2023
@sdeleuze
Copy link
Contributor

sdeleuze commented Apr 3, 2023

Sorry for moving that again, but I won't have the bandwidth to tackle that in Spring 6.0 timeframe, so let's target 6.1.

@sdeleuze
Copy link
Contributor

sdeleuze commented Jun 16, 2023

This fix has been tested successfully with a few samples (including spring-aot-smoke-test/framework/aspect one).
#30529 repro is still broken for reasons that remain to be identified, but this will be handle via the dedicated issue.

Feedback welcome.

@snicoll
Copy link
Member

snicoll commented Jun 20, 2023

I believe this broke the batch AOT sample as follows:

Exception in thread "main" java.lang.NoClassDefFoundError: org/aspectj/lang/annotation/Pointcut
        at org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory.<clinit>(AbstractAspectJAdvisorFactory.java:61)
        at org.springframework.aop.aspectj.annotation.BeanFactoryAspectJAdvisorsBuilder.<init>(BeanFactoryAspectJAdvisorsBuilder.java:60)
        at org.springframework.aop.aspectj.annotation.AspectJBeanFactoryInitializationAotProcessor.processAheadOfTime(AspectJBeanFactoryInitializationAotProcessor.java:44)
        at org.springframework.context.aot.BeanFactoryInitializationAotContributions.getContributions(BeanFactoryInitializationAotContributions.java:67)
        at org.springframework.context.aot.BeanFactoryInitializationAotContributions.<init>(BeanFactoryInitializationAotContributions.java:49)
        at org.springframework.context.aot.BeanFactoryInitializationAotContributions.<init>(BeanFactoryInitializationAotContributions.java:44)
        at org.springframework.context.aot.ApplicationContextAotGenerator.lambda$processAheadOfTime$0(ApplicationContextAotGenerator.java:58)
        at org.springframework.context.aot.ApplicationContextAotGenerator.withCglibClassHandler(ApplicationContextAotGenerator.java:67)
        at org.springframework.context.aot.ApplicationContextAotGenerator.processAheadOfTime(ApplicationContextAotGenerator.java:53)
        at org.springframework.context.aot.ContextAotProcessor.performAotProcessing(ContextAotProcessor.java:106)
        at org.springframework.context.aot.ContextAotProcessor.doProcess(ContextAotProcessor.java:84)
        at org.springframework.context.aot.ContextAotProcessor.doProcess(ContextAotProcessor.java:49)
        at org.springframework.context.aot.AbstractAotProcessor.process(AbstractAotProcessor.java:82)
        at org.springframework.boot.SpringApplicationAotProcessor.main(SpringApplicationAotProcessor.java:80)
Caused by: java.lang.ClassNotFoundException: org.aspectj.lang.annotation.Pointcut
        at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
        at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
        ... 14 more

The batch sample is failing. I don't know if it is special or if something else is involved.

@snicoll
Copy link
Member

snicoll commented Jun 20, 2023

Fixed by 74155e3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: core Issues in core modules (aop, beans, core, context, expression) theme: aot An issue related to Ahead-of-time processing type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

5 participants