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

Unable to build SpringContext with MicronautApplicationContext as parent #521

Closed
sascha-frinken opened this issue Jan 16, 2024 · 13 comments · Fixed by #540
Closed

Unable to build SpringContext with MicronautApplicationContext as parent #521

sascha-frinken opened this issue Jan 16, 2024 · 13 comments · Fixed by #540
Assignees

Comments

@sascha-frinken
Copy link
Contributor

sascha-frinken commented Jan 16, 2024

Expected Behavior

Run an application with SpringContext and MicronautApplicationContext as parent.

Actual Behaviour

Application won't start.

Same was working with micronaut 3.

Error
Exception in thread "main" io.micronaut.core.io.service.SoftServiceLoader$ServiceLoadingException: Failed to load a service: io.micronaut.context.exceptions.BeanContextException: Unexpected error loading bean definition [com.example.$Application$AutoConfigurationPackages$Registrar0$Definition]: failed to access class org.springframework.boot.autoconfigure.AutoConfigurationPackages$Registrar from class com.example.$Application$AutoConfigurationPackages$Registrar0$Definition$Reference (org.springframework.boot.autoconfigure.AutoConfigurationPackages$Registrar and com.example.$Application$AutoConfigurationPackages$Registrar0$Definition$Reference are in unnamed module of loader 'app')
	at io.micronaut.core.io.service.ServiceScanner$ServiceInstanceLoader.collect(ServiceScanner.java:364)
	at io.micronaut.core.io.service.ServiceScanner$MicronautMetaServicesLoader.collect(ServiceScanner.java:289)
	at io.micronaut.core.io.service.ServiceScanner$DefaultServiceCollector.collect(ServiceScanner.java:246)
	at io.micronaut.core.io.service.SoftServiceLoader.collectDynamicServices(SoftServiceLoader.java:201)
	at io.micronaut.core.io.service.SoftServiceLoader.collectAll(SoftServiceLoader.java:176)
	at io.micronaut.context.DefaultBeanContext.resolveBeanDefinitionReferences(DefaultBeanContext.java:1865)
	at io.micronaut.context.DefaultApplicationContext.isBootstrapPropertySourceLocatorPresent(DefaultApplicationContext.java:162)
	at java.base/java.util.Objects.requireNonNullElseGet(Objects.java:310)
	at io.micronaut.context.DefaultApplicationContext.isBootstrapEnabled(DefaultApplicationContext.java:158)
	at io.micronaut.context.DefaultApplicationContext.createEnvironment(DefaultApplicationContext.java:146)
	at io.micronaut.context.DefaultApplicationContext.getEnvironment(DefaultApplicationContext.java:180)
	at io.micronaut.context.DefaultApplicationContextBuilder.build(DefaultApplicationContextBuilder.java:322)
	at io.micronaut.spring.context.MicronautApplicationContext.(MicronautApplicationContext.java:114)
	at io.micronaut.spring.context.MicronautApplicationContext.(MicronautApplicationContext.java:106)
	at com.example.Application.main(Application.groovy:16)
Caused by: io.micronaut.core.io.service.SoftServiceLoader$ServiceLoadingException: io.micronaut.context.exceptions.BeanContextException: Unexpected error loading bean definition [com.example.$Application$AutoConfigurationPackages$Registrar0$Definition]: failed to access class org.springframework.boot.autoconfigure.AutoConfigurationPackages$Registrar from class com.example.$Application$AutoConfigurationPackages$Registrar0$Definition$Reference (org.springframework.boot.autoconfigure.AutoConfigurationPackages$Registrar and com.example.$Application$AutoConfigurationPackages$Registrar0$Definition$Reference are in unnamed module of loader 'app')
	at io.micronaut.core.io.service.SoftServiceLoader.lambda$collectDynamicServices$2(SoftServiceLoader.java:197)
	at io.micronaut.core.io.service.ServiceScanner$ServiceInstanceLoader.compute(ServiceScanner.java:355)
	at java.base/java.util.concurrent.RecursiveAction.exec(RecursiveAction.java:194)
	at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373)
	at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182)
	at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655)
	at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622)
	at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165)
Caused by: io.micronaut.context.exceptions.BeanContextException: Unexpected error loading bean definition [com.example.$Application$AutoConfigurationPackages$Registrar0$Definition]: failed to access class org.springframework.boot.autoconfigure.AutoConfigurationPackages$Registrar from class com.example.$Application$AutoConfigurationPackages$Registrar0$Definition$Reference (org.springframework.boot.autoconfigure.AutoConfigurationPackages$Registrar and com.example.$Application$AutoConfigurationPackages$Registrar0$Definition$Reference are in unnamed module of loader 'app')
	at io.micronaut.context.AbstractInitializableBeanDefinitionReference.isPresent(AbstractInitializableBeanDefinitionReference.java:205)
	at io.micronaut.core.io.service.SoftServiceLoader.lambda$collectDynamicServices$2(SoftServiceLoader.java:190)
	... 7 more
Caused by: java.lang.IllegalAccessError: failed to access class org.springframework.boot.autoconfigure.AutoConfigurationPackages$Registrar from class com.example.$Application$AutoConfigurationPackages$Registrar0$Definition$Reference (org.springframework.boot.autoconfigure.AutoConfigurationPackages$Registrar and com.example.$Application$AutoConfigurationPackages$Registrar0$Definition$Reference are in unnamed module of loader 'app')
	at com.example.$Application$AutoConfigurationPackages$Registrar0$Definition$Reference.getBeanType(Unknown Source)
	at io.micronaut.context.AbstractInitializableBeanDefinitionReference.isPresent(AbstractInitializableBeanDefinitionReference.java:197)
	... 8 more

Steps To Reproduce

  1. create a micronaut application
  2. add spring
  3. Replace main in Application.class with:
new SpringApplicationBuilder()
              .parent(new MicronautApplicationContext().tap { start() })
              .sources(Application)
              .build()
              .run()

Environment Information

OS: Linux
JDK: 17 & 21

Example Application

https://github.com/safri-net/mn4-spring-issue

Version

4.2.3

@altro3
Copy link
Contributor

altro3 commented Jan 18, 2024

@graemerocher @dstepanov I confirm that there is indeed a bug and now it is not possible to launch the application with spring annotations

In general, I think we need to pay more attention to this library and refine it to maximum spring support. I think this will help to popularize micronaut even more. if he can work with the spring code.

@sascha-frinken
Copy link
Contributor Author

@altro3 I hope you mean Micronaut not Microsoft ;)

@altro3
Copy link
Contributor

altro3 commented Jan 18, 2024

@sascha-frinken yeah, thanks. This is a dumb online translator. He doesn't understand what micronaut is :-). Usually, he translates it as minecraft, but it seems like today is a special day.

@sascha-frinken
Copy link
Contributor Author

@altro3 @graemerocher
Sorry to rush, but we need to make a decision on whether we can continue to work with micronaut in our GUIs. It would be helpful just to know if and when the problem will be fixed.

@sdelamo
Copy link
Contributor

sdelamo commented Feb 2, 2024

@sascha-frinken I am going to check this on Monday.

@timyates
Copy link
Contributor

timyates commented Feb 5, 2024

It seems to work when using Java 🤔

https://github.com/grails-core-issues-forks/micronaut-spring-521

@timyates
Copy link
Contributor

timyates commented Feb 5, 2024

It looks like under groovy we are generating AbstractInitializableBeanDefinition classes which relate to AutoConfigurationPackages.Registrar.class. This class is package private, which I believe is the cause of the failure

@graemerocher
Copy link
Contributor

ok so a bug in the Groovy compiler

@timyates
Copy link
Contributor

timyates commented Feb 7, 2024

ok so a bug in the Groovy compiler

Do you mean the compiler itself, or something we are doing?

@timyates timyates self-assigned this Feb 8, 2024
@timyates
Copy link
Contributor

timyates commented Feb 9, 2024

So adding

diff --git a/spring-annotation/src/main/java/io/micronaut/spring/annotation/beans/ImportAnnotationVisitor.java b/spring-annotation/src/main/java/io/micronaut/spring/annotation/beans/ImportAnnotationVisitor.java
index de4b9c8f..79b83865 100644
--- a/spring-annotation/src/main/java/io/micronaut/spring/annotation/beans/ImportAnnotationVisitor.java
+++ b/spring-annotation/src/main/java/io/micronaut/spring/annotation/beans/ImportAnnotationVisitor.java
@@ -80,7 +80,9 @@ public final class ImportAnnotationVisitor implements TypeElementVisitor<Object,
                     for (AnnotationClassValue<?> a : acv) {
                         String className = a.getName();
                         context.getClassElement(className).ifPresent(typeToImport -> {
-                            handleImport(element, context, typeToImport);
+                            if (typeToImport.isPublic()) {
+                                handleImport(element, context, typeToImport);
+                            }
                         });
                     }
                 }

Makes this work, but I suspect it isn't the fix, and we may need a fix in core somewhere in inject-groovy

We also (under groovy) see

WARNING: Spring ImportSelector [org.springframework.boot.autoconfigure.AutoConfigurationImportSelector] found in @import declaration on element [boot4groovy.Application] was ignored. Ensure that the type is present on the annotation processor classpath. Note that only simple ImportSelector implementations that do no implement Aware interfaces (which cannot run at build time) are supported.

@SpringBootApplication
^

But I am not currently sure if this is part of the same issue...

@dstepanov
Copy link
Contributor

The only solution is to avoid loading this class or copy and create an alternative of that class registered by:

@Import({AutoConfigurationPackages.Registrar.class})
public @interface AutoConfigurationPackage {

The same problem might be with: ImportAutoConfigurationImportSelector registered by:

@Import({ImportAutoConfigurationImportSelector.class})
public @interface ImportAutoConfiguration 

timyates added a commit that referenced this issue Feb 12, 2024
The ImportAnnotationVisitor would walk the spring hierarchy and cause package-private classes to have definitions created for them.

This would then fail at runtime, as Micronaut could not access these defined beans.

This fix only visits public classes to prevent this problem.

Closes #521
@timyates
Copy link
Contributor

@sascha-frinken We've just released v5.4.1 of micronaut spring which we believe fixes this issue (by not creating bean definitions for spring's private configuration classes)

@sascha-frinken
Copy link
Contributor Author

@timyates
Thank you very much!

The test project is working now. As soon as we get around to working on our Micronaut 4 migration, I'll let you know if we have any problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
No open projects
Status: Done
Development

Successfully merging a pull request may close this issue.

6 participants