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

Upgrade to Micronaut 3.1.1 breaks cli application native-image binary #6406

Closed
miguelaferreira opened this issue Oct 23, 2021 · 12 comments
Closed

Comments

@miguelaferreira
Copy link
Contributor

Expected Behavior

After following the Micronaut upgrade guide instructions I expected the compiled native binary to execute as before.

Actual Behaviour

When I execute the native binary I get the following error.

picocli.CommandLine$InitializationException: Could not instantiate class devex.GitlabCloneCommand: io.micronaut.context.exceptions.BeanInstantiationException: Error instantiating bean of type  [devex.gitlab.GitlabService]

Message: Multiple possible bean candidates found: [io.micronaut.aop.InterceptorRegistry, io.micronaut.aop.InterceptorRegistry]
Path Taken: new GitlabCloneCommand() --> GitlabCloneCommand.gitlabService --> new GitlabService([GitlabClient client],String gitlabUrl)
        at picocli.CommandLine$DefaultFactory.create(CommandLine.java:5516)
        at picocli.CommandLine$Model$CommandUserObject.getInstance(CommandLine.java:11813)
        at picocli.CommandLine$Model$CommandSpec.userObject(CommandLine.java:6251)
        at picocli.CommandLine$Interpreter.clear(CommandLine.java:13006)
        at picocli.CommandLine$Interpreter.parse(CommandLine.java:13051)
        at picocli.CommandLine$Interpreter.processSubcommand(CommandLine.java:13343)
        at picocli.CommandLine$Interpreter.processArguments(CommandLine.java:13260)
        at picocli.CommandLine$Interpreter.parse(CommandLine.java:13072)
        at picocli.CommandLine$Interpreter.processSubcommand(CommandLine.java:13343)
        at picocli.CommandLine$Interpreter.processArguments(CommandLine.java:13260)
        at picocli.CommandLine$Interpreter.parse(CommandLine.java:13072)
        at picocli.CommandLine$Interpreter.parse(CommandLine.java:13041)
        at picocli.CommandLine$Interpreter.parse(CommandLine.java:12942)
        at picocli.CommandLine.parseArgs(CommandLine.java:1478)
        at picocli.CommandLine.execute(CommandLine.java:2077)
        at devex.DevexCommand.execute(DevexCommand.java:96)
        at devex.DevexCommand.execute(DevexCommand.java:86)
        at devex.DevexCommand.main(DevexCommand.java:101)
Caused by: io.micronaut.context.exceptions.BeanInstantiationException: Error instantiating bean of type  [devex.gitlab.GitlabService]

Message: Multiple possible bean candidates found: [io.micronaut.aop.InterceptorRegistry, io.micronaut.aop.InterceptorRegistry]
Path Taken: new GitlabCloneCommand() --> GitlabCloneCommand.gitlabService --> new GitlabService([GitlabClient client],String gitlabUrl)
        at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:2368)
        at io.micronaut.context.DefaultBeanContext.createAndRegisterSingletonInternal(DefaultBeanContext.java:3289)
        at io.micronaut.context.DefaultBeanContext.createAndRegisterSingleton(DefaultBeanContext.java:3275)
        at io.micronaut.context.DefaultBeanContext.getBeanForDefinition(DefaultBeanContext.java:2825)
        at io.micronaut.context.DefaultBeanContext.getBeanInternal(DefaultBeanContext.java:2787)
        at io.micronaut.context.DefaultBeanContext.getBean(DefaultBeanContext.java:1643)
        at io.micronaut.context.AbstractInitializableBeanDefinition.resolveBean(AbstractInitializableBeanDefinition.java:1566)
        at io.micronaut.context.AbstractInitializableBeanDefinition.getBeanForConstructorArgument(AbstractInitializableBeanDefinition.java:1044)
        at devex.gitlab.$GitlabService$Definition.build(Unknown Source)
        at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:2341)
        at io.micronaut.context.DefaultBeanContext.createAndRegisterSingletonInternal(DefaultBeanContext.java:3289)
        at io.micronaut.context.DefaultBeanContext.createAndRegisterSingleton(DefaultBeanContext.java:3275)
        at io.micronaut.context.DefaultBeanContext.getBeanForDefinition(DefaultBeanContext.java:2825)
        at io.micronaut.context.DefaultBeanContext.getBeanInternal(DefaultBeanContext.java:2787)
        at io.micronaut.context.DefaultBeanContext.getBean(DefaultBeanContext.java:1643)
        at io.micronaut.context.AbstractInitializableBeanDefinition.resolveBean(AbstractInitializableBeanDefinition.java:1566)
        at io.micronaut.context.AbstractInitializableBeanDefinition.resolveBean(AbstractInitializableBeanDefinition.java:1549)
        at io.micronaut.context.AbstractInitializableBeanDefinition.getBeanForField(AbstractInitializableBeanDefinition.java:1259)
        at devex.$GitlabCloneCommand$Definition.injectBean(Unknown Source)
        at devex.$GitlabCloneCommand$Definition.build(Unknown Source)
        at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:2341)
        at io.micronaut.context.DefaultBeanContext.getScopedBeanForDefinition(DefaultBeanContext.java:2932)
        at io.micronaut.context.DefaultBeanContext.getBeanForDefinition(DefaultBeanContext.java:2827)
        at io.micronaut.context.DefaultBeanContext.getBeanInternal(DefaultBeanContext.java:2787)
        at io.micronaut.context.DefaultBeanContext.findBean(DefaultBeanContext.java:1709)
        at io.micronaut.context.DefaultBeanContext.findBean(DefaultBeanContext.java:1683)
        at io.micronaut.context.DefaultBeanContext.findBean(DefaultBeanContext.java:910)
        at io.micronaut.context.BeanLocator.findOrInstantiateBean(BeanLocator.java:305)
        at io.micronaut.configuration.picocli.MicronautFactory.create(MicronautFactory.java:73)
        at picocli.CommandLine$DefaultFactory.create(CommandLine.java:5512)
        ... 17 more
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:2434)
        at io.micronaut.context.DefaultApplicationContext.findConcreteCandidate(DefaultApplicationContext.java:452)
        at io.micronaut.context.DefaultBeanContext.lastChanceResolve(DefaultBeanContext.java:3261)
        at io.micronaut.context.DefaultBeanContext.findConcreteCandidateNoCache(DefaultBeanContext.java:3148)
        at io.micronaut.context.DefaultBeanContext.findConcreteCandidate(DefaultBeanContext.java:3062)
        at io.micronaut.context.DefaultBeanContext.getBeanInternal(DefaultBeanContext.java:2755)
        at io.micronaut.context.DefaultBeanContext.getBean(DefaultBeanContext.java:893)
        at io.micronaut.aop.chain.InterceptorChain.resolveInterceptors(InterceptorChain.java:205)
        at io.micronaut.aop.chain.InterceptorChain.resolveIntroductionInterceptors(InterceptorChain.java:144)
        at devex.gitlab.GitlabClient$Intercepted.<init>(Unknown Source)
        at devex.gitlab.$GitlabClient$Intercepted$Definition.build(Unknown Source)
        at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:2341)
        ... 46 more

Steps To Reproduce

  1. Install GraalVM 21.2.0.r16-grl (also tried with 21.3.0.r17-grl)
sdk install java 21.2.0.r16-grl
sdk use java 21.2.0.r16-grl
  1. Install native-image
 gu install native-image
  1. Clone the project
git clone [email protected]:miguelaferreira/devex-cli.git
cd devex-cli
  1. Checkout the upgrade branch
git checkout upgrade-to-micronaut-3
  1. Build the native binary
./gradlew build nativeImage -x test
  1. Execute the native binary
 build/native-image/application gitlab clone gitlab-clone-example tmp-clone-directory

Step 6 will generate the error, while what should happen is that the GitLab group gitlab-clone-example should be cloned in the local directory tmp-clone-directory.

Environment Information

  • Operating System
    • macOS Big Sur, 11.6 (20G165)
    • GitHub Actions ubuntu-latest (build)
  • JDK Version:
openjdk version "16.0.2" 2021-07-20
OpenJDK Runtime Environment GraalVM CE 21.2.0 (build 16.0.2+7-jvmci-21.2-b08)
OpenJDK 64-Bit Server VM GraalVM CE 21.2.0 (build 16.0.2+7-jvmci-21.2-b08, mixed mode, sharing)

Example Application

miguelaferreira/devex-cli#10

Version

3.1.1

@graemerocher
Copy link
Contributor

From the error it looks like you either have duplicate JARs on your classpath or duplicate native image config where types are being registered twice. The linked project seems to be a custom native image build so it is hard to tell.

@RiccardoManzan
Copy link

RiccardoManzan commented Nov 15, 2021

Got same issue.
I checked out OC repo, but problem it's still there.

@graemerocher i think that if we have a duplicate jar, or duplicate image config, we would get this error using micronaut 2.x too.
Am i right?

I'm using maven, and OC is using gradle so that's not a build tool fault.
Do it comes to mind of anything else which can be the cause?

Cheers.

Edit: This happens only in tests, application can run correctly with mn:run

Edit: this solved my issue.

@miguelaferreira
Copy link
Contributor Author

Thanks for the reply @graemerocher. I've tried to followup on this but without much success.
Disabling the service loader (as mentioned in #6579) doesn't help me because the application does rely on the service loader. Next, I tried removing all of the entries ending with $Definition$Reference from the generated config but that results in the same "Multiple possible bean candidates found" error.

Since the class that is being loaded multiple times (io.micronaut.aop.InterceptorRegistry) is internal to micronaut I don't know where to start looking for the source of the duplication. It's definitely not declared in any entry of the native image config I'm using.

@graemerocher
Copy link
Contributor

@miguelaferreira do you have an example somewhere?

@graemerocher
Copy link
Contributor

oh hold on attached to the original issue

@graemerocher
Copy link
Contributor

I guess my question is why you need native image config at all in this app?

@miguelaferreira
Copy link
Contributor Author

Because without it the native binary wouldn't work. It would compile but then at runtime complain about missing classes.

I've setup system tests that execute the standalone jar (instrumented with the native image agent), while calling all the application commands. That generates multiple sets of native image configurations, so I've built native image from source to create the native-image-configure tool that is able to merge the configuration in a single set, that I can then use to build a working native binary.

I can try removing all that and just build the native binary with the default configuration generated by micronaut. I'll let you know the result of that.

@graemerocher
Copy link
Contributor

@miguelaferreira please try that and let us know what is wrong with the defaults

@miguelaferreira
Copy link
Contributor Author

miguelaferreira commented Jan 12, 2022

@graemerocher I've removed the custom native image config (from src/main/resources/META-INF/native-image/), and rebuilt the native image.
The code is pushed to this branch: https://github.com/miguelaferreira/devex-cli/tree/remove-custom-native-image-config

Then I built the native image with GraalVM 21.3.0.r17-grl.

sdk use java 21.3.0.r17-grl
~/.sdkman/candidates/java/current/bin/gu install native-image
./gradlew clean build nativeImage -x test

The result is that the native binary does not execute correctly anymore. In the examples bellow I'm comparing the execution of the native binary with the execution of the jar with all dependencies.

I would be happy to troubleshoot this, please let me know if there's anything I can do.

Example: print the tool version

Native binary:

$ build/native-image/application -V                                  
No version

Jar:

$ java -jar build/libs/devex-1.0.2-all.jar -V
java: 17.0.1
devex cli: v1.0.2

Example: clone a gitlab organisation using SSH protocol

Native binary:

$ build/native-image/application gitlab clone -v gitlab-clone-example /tmp/clone-test
DEBUG - Set application loggers to DEBUG
DEBUG - devex No version
INFO  - Cloning group 'gitlab-clone-example'
DEBUG - Looking for group named: gitlab-clone-example
DEBUG - Found group = GitlabGroup(id=11961707, name=gitlab-clone-example, path=gitlab-clone-example, fullPath=null)
DEBUG - Searching for projects in group 'null'
ERROR - Type [devex.gitlab.GitlabClient$Intercepted] executed with error: 401 Unauthorized
DEBUG - Could not detect GitLab server version without a valid token.
DEBUG - Could not clone repository 'null' because: java.lang.NoSuchMethodException: org.eclipse.jgit.internal.JGitText.<init>()
DEBUG - Could not clone repository 'null' because: java.lang.NoSuchMethodException: org.eclipse.jgit.internal.JGitText.<init>()
DEBUG - Could not clone repository 'null' because: java.lang.NoSuchMethodException: org.eclipse.jgit.internal.JGitText.<init>()
WARN  - Git operation failed
WARN  - Git operation failed
WARN  - Git operation failed
INFO  - All done

$  tree /tmp/clone-test
/tmp/clone-test  [error opening dir]

0 directories, 0 files

Jar:

$ java -jar build/libs/devex-1.0.2-all.jar gitlab clone -v gitlab-clone-example /tmp/clone-test 
DEBUG - Set application loggers to DEBUG
DEBUG - devex java: 17.0.1
devex cli: v1.0.2
INFO  - Cloning group 'gitlab-clone-example'
DEBUG - Looking for group named: gitlab-clone-example
DEBUG - Found group = GitlabGroup(id=11961707, name=gitlab-clone-example, path=gitlab-clone-example, fullPath=gitlab-clone-example)
DEBUG - Searching for projects in group 'gitlab-clone-example'
ERROR - Type [devex.gitlab.GitlabClient$Intercepted] executed with error: 401 Unauthorized
DEBUG - Could not detect GitLab server version without a valid token.
DEBUG - Connecting to gitlab.com port 22
DEBUG - Connection established
DEBUG - Remote version string: SSH-2.0-OpenSSH_7.9p1 Debian-10+deb10u2

// Omitting SSH protocol debug output

INFO  - Project 'gitlab-clone-example / a-project' updated.
INFO  - Project 'gitlab-clone-example / sub-group-1 / some-project' updated.
INFO  - Project 'gitlab-clone-example / sub-group-2 / sub-group-3 / another-project' updated.
INFO  - All done

$ tree /tmp/clone-test                                                                        
/tmp/clone-test
└── gitlab-clone-example
    ├── a-project
    │   ├── README.md
    │   └── some-project-sub-module
    ├── sub-group-1
    │   └── some-project
    │       └── README.md
    └── sub-group-2
        └── sub-group-3
            └── another-project
                └── README.md

8 directories, 3 files

Example: clone a gitlab organisation using HTTPS protocol

Native binary

$ build/native-image/application gitlab clone -v -c https gitlab-clone-example /tmp/clone-test
DEBUG - Set application loggers to DEBUG
DEBUG - devex No version
INFO  - Cloning group 'gitlab-clone-example'
DEBUG - Looking for group named: gitlab-clone-example
DEBUG - Found group = GitlabGroup(id=11961707, name=gitlab-clone-example, path=gitlab-clone-example, fullPath=null)
DEBUG - Searching for projects in group 'null'
ERROR - Type [devex.gitlab.GitlabClient$Intercepted] executed with error: 401 Unauthorized
DEBUG - Could not detect GitLab server version without a valid token.
DEBUG - Credentials for HTTPS remote not set, repository to clone must be public.
DEBUG - Could not clone repository 'null' because: java.lang.NoSuchMethodException: org.eclipse.jgit.internal.JGitText.<init>()
DEBUG - Credentials for HTTPS remote not set, repository to clone must be public.
DEBUG - Could not clone repository 'null' because: java.lang.NoSuchMethodException: org.eclipse.jgit.internal.JGitText.<init>()
DEBUG - Credentials for HTTPS remote not set, repository to clone must be public.
DEBUG - Could not clone repository 'null' because: java.lang.NoSuchMethodException: org.eclipse.jgit.internal.JGitText.<init>()
WARN  - Git operation failed
WARN  - Git operation failed
WARN  - Git operation failed
INFO  - All done

$  tree /tmp/clone-test
/tmp/clone-test  [error opening dir]

0 directories, 0 files

Jar:

$ java -jar build/libs/devex-1.0.2-all.jar gitlab clone -v -c https gitlab-clone-example /tmp/clone-test
DEBUG - Set application loggers to DEBUG
DEBUG - devex java: 17.0.1
devex cli: v1.0.2
INFO  - Cloning group 'gitlab-clone-example'
DEBUG - Looking for group named: gitlab-clone-example
DEBUG - Found group = GitlabGroup(id=11961707, name=gitlab-clone-example, path=gitlab-clone-example, fullPath=gitlab-clone-example)
DEBUG - Searching for projects in group 'gitlab-clone-example'
ERROR - Type [devex.gitlab.GitlabClient$Intercepted] executed with error: 401 Unauthorized
DEBUG - Could not detect GitLab server version without a valid token.
DEBUG - Credentials for HTTPS remote not set, repository to clone must be public.
DEBUG - Credentials for HTTPS remote not set, repository to clone must be public.
DEBUG - Credentials for HTTPS remote not set, repository to clone must be public.
INFO  - Project 'gitlab-clone-example / a-project' updated.
INFO  - Project 'gitlab-clone-example / sub-group-2 / sub-group-3 / another-project' updated.
INFO  - Project 'gitlab-clone-example / sub-group-1 / some-project' updated.
INFO  - All done

$ tree /tmp/clone-test                                                                                  
/tmp/clone-test
└── gitlab-clone-example
    ├── a-project
    │   ├── README.md
    │   └── some-project-sub-module
    ├── sub-group-1
    │   └── some-project
    │       └── README.md
    └── sub-group-2
        └── sub-group-3
            └── another-project
                └── README.md

8 directories, 3 files

@graemerocher
Copy link
Contributor

@miguelaferreira will take a look

@graemerocher
Copy link
Contributor

with PR miguelaferreira/devex-cli#18

Running:

./gradlew nativeCompile
./build/native/nativeCompile/devex --version
java: 17.0.1
devex cli: v1.0.2

@miguelaferreira
Copy link
Contributor Author

Thank for the help @graemerocher! I ran the other tests and the tools are working well. I'm going to merge your PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants