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

GraalVM error with Micronaut 3: Multiple possible bean candidates found: io.micronaut.aop.InterceptorRegistry #6579

Closed
tobiasschaefer opened this issue Nov 28, 2021 · 18 comments
Assignees
Labels
info: workaround available A workaround is available for the issue type: docs

Comments

@tobiasschaefer
Copy link
Contributor

tobiasschaefer commented Nov 28, 2021

Expected Behavior

Building and executing the native image of the provided and minimal application should succeed. Actually, it was successful on Micronaut 2.5.x but fails since Micronaut 3.0.0

The bug is triggered by injecting a configuration interface:

@ConfigurationProperties("myconfig")
public interface Config {

    String getBaseUrl();
}

into a class which is annotated with @Context:

@Context
public class Bean {

    private final Config config;

    public Bean(Config config) {
        this.config = config;
    }
}

and building and executing the native image based on a generated native image configuration.

The error message is the same as in #6406 but they don't seem to be related.

Actual Behaviour

build/native/nativeCompile/context fails with

Message: Multiple possible bean candidates found: [io.micronaut.aop.InterceptorRegistry, io.micronaut.aop.InterceptorRegistry]
Path Taken: new Bean([Config config])
        at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:2364)
        at io.micronaut.context.DefaultBeanContext.createAndRegisterSingletonInternal(DefaultBeanContext.java:3282)
        at io.micronaut.context.DefaultBeanContext.createAndRegisterSingleton(DefaultBeanContext.java:3268)
        at io.micronaut.context.DefaultBeanContext.getBeanForDefinition(DefaultBeanContext.java:2821)
        at io.micronaut.context.DefaultBeanContext.getBeanInternal(DefaultBeanContext.java:2783)
        at io.micronaut.context.DefaultBeanContext.getBean(DefaultBeanContext.java:1639)
        at io.micronaut.context.AbstractInitializableBeanDefinition.resolveBean(AbstractInitializableBeanDefinition.java:1933)
        at io.micronaut.context.AbstractInitializableBeanDefinition.getBeanForConstructorArgument(AbstractInitializableBeanDefinition.java:1189)
        at context.$Bean$Definition.build(Unknown Source)
        at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:2337)
        at io.micronaut.context.DefaultBeanContext.createAndRegisterSingletonInternal(DefaultBeanContext.java:3282)
        at io.micronaut.context.DefaultBeanContext.loadContextScopeBean(DefaultBeanContext.java:2665)
        at io.micronaut.context.DefaultBeanContext.initializeContext(DefaultBeanContext.java:1933)
        ... 8 common frames omitted
Caused by: io.micronaut.context.exceptions.NonUniqueBeanException: Multiple possible bean candidates found: [io.micronaut.aop.InterceptorRegistry, io.micronaut.aop.InterceptorRegistry]
        at io.micronaut.context.DefaultBeanContext.findConcreteCandidate(DefaultBeanContext.java:2430)
        at io.micronaut.context.DefaultApplicationContext.findConcreteCandidate(DefaultApplicationContext.java:455)
        at io.micronaut.context.DefaultBeanContext.lastChanceResolve(DefaultBeanContext.java:3254)

Steps To Reproduce

  1. git clone https://github.com/tobiasschaefer/bug-interceptor-registry.git

  2. Setup

sdk use java 21.3.0.r17-grl
export PATH=/Library/Java/JavaVirtualMachines/graalvm-ce-java17-21.3.0/Contents/Home/bin:$PATH
export JAVA_HOME=/Library/Java/JavaVirtualMachines/graalvm-ce-java17-21.3.0/Contents/Home 
  1. Create reflection configuration

Create the native image configuration with the following steps and cancel with Ctrl-C when the application is running:

./gradlew clean build
rm -rf src/main/resources/META-INF/native-image/
mkdir -p src/main/resources/META-INF/native-image/
java -agentlib:native-image-agent=config-output-dir=src/main/resources/META-INF/native-image/ -jar build/libs/context-0.1-all.jar

(or simply execute the provided script ./create-reflection-config.sh)

  1. Create image

Create image with ./gradlew clean nativeCompile

  1. Run image

Starting the native application with build/native/nativeCompile/contextfails with the error mentioned above.

Environment Information

  • MacOS 12.01
  • JDK 17 - GraalVM (also occurs on JDK 11)
  • Micronaut 3.2.0 (also occurs on 3.1.x and 3.0.x) - works with Micronaut 2.5.x

Example Application

https://github.com/tobiasschaefer/bug-interceptor-registry.git

Version

3.2.0

@tobiasschaefer tobiasschaefer changed the title GraalVM compile error with Micronaut 3: Multiple possible bean candidates found: io.micronaut.aop.InterceptorRegistry GraalVM error with Micronaut 3: Multiple possible bean candidates found: io.micronaut.aop.InterceptorRegistry Nov 28, 2021
@graemerocher
Copy link
Contributor

Running the agent means you get duplicate classes registered with GraalVM since they are registered already via service loader and then again via the native image metadata.

You can resolve this by adding:

graalvmNative {
    binaries {
        main {
            buildArgs.add("-H:-UseServiceLoaderFeature")
        }
    }
}

Or deleting all of the entries ending with $Definition$Reference from the generated config

@graemerocher graemerocher added info: workaround available A workaround is available for the issue type: docs labels Nov 29, 2021
@tobiasschaefer
Copy link
Contributor Author

Thanks @graemerocher

That actually fixed my issue.

I'll let it up you to decide if this is only a documentation issue or something should actually be fixed because it worked with Micronaut 2.5.x out-of-the-box.

@graemerocher
Copy link
Contributor

It actually didn't work in 2.5.x you actually ended up with duplicate beans everywhere but there just happened to not manifest as a non unique bean exception by chance

@avirkar
Copy link

avirkar commented Jan 31, 2022

How do you configure these build args in maven
graalvmNative { binaries { main { buildArgs.add("-H:-UseServiceLoaderFeature") } } }

@rodrigar-mx
Copy link

<plugin>
  <groupId>org.graalvm.buildtools</groupId>
  <artifactId>native-maven-plugin</artifactId>
  <configuration>
    <buildArgs combine.children="append">
      <buildArg>-H:-UseServiceLoaderFeature</buildArg>
    </buildArgs>
  </configuration>
</plugin>

@avirkar
Copy link

avirkar commented Jan 31, 2022

I tried this but that did not work. The following is my configuration
<plugin> <groupId>org.graalvm.buildtools</groupId> <artifactId>native-maven-plugin</artifactId> <version>0.9.9</version> <executions> <execution> <id>build-native</id> <goals> <goal>build</goal> </goals> <phase>package</phase> </execution> </executions> <configuration> <buildArgs combine.children="append"> <buildArg>--force-fallback</buildArg> <buildArg>-H:-UseServiceLoaderFeature</buildArg> </buildArgs> <imageName>agent</imageName> <mainClass>com.company.agent.Application</mainClass> </configuration> </plugin>

@avirkar
Copy link

avirkar commented Feb 1, 2022

Thanks @rodrigar-mx for your support. What we noticed is that the <buildArg>-H:-UseServiceLoaderFeature</buildArg> does not do what it is expected to and I had to manually delete some of the references from the config files generated by the tracing agent. I think this should be treated as a bug.

@wetted
Copy link
Contributor

wetted commented Feb 14, 2022

We are getting this same error, but aren't using native/GraalVM at all. It all worked fine in Micronaut 2.5.x, We started getting this error when we upgraded to 3.2.7 and get the same behavior with 3.3. as well. This is part of a thick client (using Swing) that uses a REST client to access services we stand up in a separate VM on localhost.

Message: Multiple possible bean candidates found: [io.micronaut.aop.InterceptorRegistry, io.micronaut.aop.InterceptorRegistry]
Path Taken: new SAFEAnalyzerServiceImpl(JobTracker jobTracker,SafeAnalyzerClient client,XSASafeConversionService xsaSafeConversionService,ObjectMapper mapper,long timeout) --> new SAFEAnalyzerServiceImpl(JobTracker jobTracker,[SafeAnalyzerClient client],XSASafeConversionService xsaSafeConversionService,ObjectMapper mapper,long timeout)
	at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:2363)
	at io.micronaut.context.DefaultBeanContext.createAndRegisterSingletonInternal(DefaultBeanContext.java:3281)
	at io.micronaut.context.DefaultBeanContext.createAndRegisterSingleton(DefaultBeanContext.java:3267)
	at io.micronaut.context.DefaultBeanContext.getBeanForDefinition(DefaultBeanContext.java:2820)
	at io.micronaut.context.DefaultBeanContext.getBeanInternal(DefaultBeanContext.java:2782)
	at io.micronaut.context.DefaultBeanContext.getBean(DefaultBeanContext.java:1638)
	at io.micronaut.context.AbstractInitializableBeanDefinition.resolveBean(AbstractInitializableBeanDefinition.java:1933)
	at io.micronaut.context.AbstractInitializableBeanDefinition.getBeanForConstructorArgument(AbstractInitializableBeanDefinition.java:1189)
	at com.boeing.xsasafeservices.$SAFEAnalyzerServiceImpl$Definition.build(Unknown Source)

Here's the weird part. SAFEAnalyzerServiceImpl is a Singleton. I changed it to add @primary (which is sensible for it anyway), This only happens when we run old Jemmy/JUnit4-based GUI integration tests (yeah, I know, we're stuck with that). The services seem to run fine otherwise. After adding @primary the behavior changes a bit. If we do a clean checkout of the project and run the Jemmy integration tests, they still fail with the above error. However, they then pass on subsequent runs (using gradlew --refresh-dependencies clean test), and we're baffled why. Maybe we're doing something wrong standing up our Jemmy tests - so I am investigating that - but this didn't start until Micronaut 3.x.

@caw-ishikajain
Copy link

I am facing same error above things didn't worked for me. I am facing it with Repository. more details are at https://stackoverflow.com/questions/71665667/micronaut-error-multiple-possible-bean-candidates-found-io-micronaut-aop-int

"Internal Server Error: Error instantiating bean of type [com.cawstudios.authentication_service.controllers.UserController]\n\nMessage: Multiple possible bean candidates found: [io.micronaut.aop.InterceptorRegistry, io.micronaut.aop.InterceptorRegistry]\nPath Taken: new UserController(UserRepository userRepository) --> new UserController([UserRepository userRepository])"

@drew-corporate-creations
Copy link

drew-corporate-creations commented Apr 4, 2022

I'm running into the same error (NOT using native/Graal). Currently upgrading from micronaut 2 -> 3.4.1.

Did not have this error in MN 2.

Message: Multiple possible bean candidates found: [io.micronaut.aop.InterceptorRegistry, io.micronaut.aop.InterceptorRegistry, io.micronaut.aop.InterceptorRegistry, io.micronaut.aop.InterceptorRegistry...]

I'm using the micronaut library Gradle plugin to build libraries, and the micronaut application Gradle plugin to build a service that is dependent on those libraries.

The class throwing the error is an @singleton, but it appears it might have to do with injecting an interface using the @client annotation which extends an interface containing REST methods.

@graemerocher graemerocher self-assigned this Apr 5, 2022
@lmachacek
Copy link

lmachacek commented Apr 6, 2022

I'm facing the same error in Micronaut 3.4.1 but only when the application is running in a Docker container (locally or in Kubernetes):

Failed to inject value for parameter [emailSender] of class: com.company.application.service.$DefaultEventService$Definition$Intercepted

Message: Multiple possible bean candidates found: [io.micronaut.email.$DefaultEmailSender$Definition$Intercepted, io.micronaut.email.$DefaultEmailSender$Definition$Intercepted]

It happens only for io.micronaut.email.DefaultEmailSender, others are OK.

When I try to inject AsyncEmailSender it behaves the same way:

Multiple possible bean candidates found: [io.micronaut.email.$DefaultAsyncEmailSender$Definition$Intercepted, io.micronaut.email.$DefaultAsyncEmailSender$Definition$Intercepted]

@ivanmartinvalle
Copy link

I worked around this by downgrading to Micronaut 3.3.2. This commit looks related but idk haha.

plugins {
  id "io.micronaut.application" version "3.3.2"
}

graemerocher added a commit that referenced this issue Apr 21, 2022
This is a significant change that alters Micronaut so that instead of a single registry of type names contains in META-INF/services entries a directory is created with file names of each type within META-INF/micronaut instead.

The benefit of this change is that we can now fully incrementally compile and avoid completely re-running the annotation processors on each change to an annotated type. We also simplify our annotation processing pipeline with the downstream service generating processor no longer necessary.

The change has implications to AOT and other areas but I don't consider it breaking as Micronaut will continue to work as previously with the change.

This change also addresses issues with Graal since we abuse META-INF/services by storing types that cannot actually be loaded with the standard Java service loader (Micronaut's bean references can reference types that not on the classpath).

This should also address improve the situation with #6579

Co-authored-by: Sergio del Amo <[email protected]>
@Ivan1pl
Copy link

Ivan1pl commented Apr 29, 2022

Running the agent means you get duplicate classes registered with GraalVM since they are registered already via service loader and then again via the native image metadata.

You can resolve this by adding:

graalvmNative {
    binaries {
        main {
            buildArgs.add("-H:-UseServiceLoaderFeature")
        }
    }
}

Or deleting all of the entries ending with $Definition$Reference from the generated config

None of the above worked for me. I resolved the issue by adding an access filter as described here: https://www.graalvm.org/22.0/reference-manual/native-image/Agent/#access-filters, the access filter:

{ "rules": [
  {"excludeClasses": "io.micronaut.**"}
]
}

Then I removed all resources containing io.micronaut from generated resource-config.json. This resolved the issue for me.

@stewmorg
Copy link

Posting this here incase others can benefit from what work around helped me overcome this.

As the error suggests there were multiple versions of the AOP library/jar being included, the dependency report showed that even though I was running micronaut 3.8.2, version 3.7.4 of aop was being included through the mac osx runtime dependency.

Adding the following the dependencies of build.gradle stops this error from appearing, but I'm not convinced it is addressing the root cause of why this starting happening for me.

developmentOnly ("io.micronaut:micronaut-runtime-osx:3.8.2")

@domlen2003
Copy link

Hey guys i think i found the reason.
I ran into this error when writing a new library (mn 3.8.5) and used it with an older application (mn 3.7.4).
Bringing the mn application version to the version of the mn library resolved it for me.

@graemerocher
Copy link
Contributor

right, the reason is normally a classpath issue where you have multiple versions of the same JAR on your classpath

@BramMeerten
Copy link

For others searching for a solution, and that don't have different versions of micronaut on the classpath.

This can also happen when you have multiple modules, solved it by disabling shading in a child module: #10251 (comment)

@RiccardoManzan
Copy link

RiccardoManzan commented May 27, 2024

I have this issue, i do not have multiple micronaut versions on my classpath and i do not have child modules.
I'm still debugging the issue but it looks like the registry gets instanciated multiple times only in when executing tests.
Not sure if this may be a micronaut-tests bug or whatever.

Edit

Turns out that i had this exact same issue years ago and i forgot that.
It looks like i also managed to solve this at that time.
Here's a hint i fortunately left behind: #6406

The issue was only reproducible in integration tests, adding this configuration to the failsafe plugin solved that:

<configuration>
    <classesDirectory>${project.build.outputDirectory}</classesDirectory>
</configuration>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
info: workaround available A workaround is available for the issue type: docs
Projects
None yet
Development

No branches or pull requests