remkop / picocli

Picocli is a modern framework for building powerful, user-friendly, GraalVM-enabled command line apps with ease. It supports colors, autocompletion, subcommands, and more. In 1 source file so apps can include as source & avoid adding a dependency. Written in Java, usable from Groovy, Kotlin, Scala, etc.

Home Page:https://picocli.info

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Use picocli without Reflection API

AresEkb opened this issue · comments

We are trying to use https://github.com/keycloak/keycloak on JVM with Reflection API disabled. And get the following error:

WARNING: An illegal reflective access (setAccessible) operation has occurred
WARNING: Illegal reflective access (setAccessible) by picocli.CommandLine$Model$TypedMember (file:/opt/keycloak/lib/lib/main/info.picocli.picocli-4.6.3.jar) to field org.keycloak.quarkus.runtime.cli.command.AbstractCommand.spec
WARNING: Please consider reporting this to the maintainers of picocli.CommandLine$Model$TypedMember
WARNING: The use of the function setAccessible is ignored by the system
Exception in thread "main" java.lang.reflect.InvocationTargetException
      at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
      at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.base/java.lang.reflect.Method.invoke(Method.java:568)
      at io.quarkus.bootstrap.runner.QuarkusEntryPoint.doRun(QuarkusEntryPoint.java:61)
      at io.quarkus.bootstrap.runner.QuarkusEntryPoint.main(QuarkusEntryPoint.java:32)
Caused by: picocli.CommandLine$InitializationException: Could not inject spec
      at picocli.CommandLine$Model$CommandReflection.initFromAnnotatedTypedMembers(CommandLine.java:11636)
      at picocli.CommandLine$Model$CommandReflection.initFromAnnotatedMembers(CommandLine.java:11570)
      at picocli.CommandLine$Model$CommandReflection.extractCommandSpec(CommandLine.java:11503)
      at picocli.CommandLine$Model$CommandSpec.forAnnotatedObject(CommandLine.java:6236)
      at picocli.CommandLine.<init>(CommandLine.java:227)
      at picocli.CommandLine.toCommandLine(CommandLine.java:3526)
      at picocli.CommandLine.access$16100(CommandLine.java:145)
      at picocli.CommandLine$Model$CommandReflection.initSubcommands(CommandLine.java:11535)
      at picocli.CommandLine$Model$CommandReflection.extractCommandSpec(CommandLine.java:11501)
      at picocli.CommandLine$Model$CommandSpec.forAnnotatedObject(CommandLine.java:6236)
      at org.keycloak.quarkus.runtime.cli.Picocli.createCommandLine(Picocli.java:335)
      at org.keycloak.quarkus.runtime.cli.Picocli.parseAndRun(Picocli.java:86)
      at org.keycloak.quarkus.runtime.KeycloakMain.main(KeycloakMain.java:88)
      ... 6 more
Caused by: picocli.CommandLine$PicocliException: Could not set value for field protected picocli.CommandLine$Model$CommandSpec org.keycloak.quarkus.runtime.cli.command.AbstractCommand.spec to command 'null' (user object: org.keycloak.quarkus.runtime.cli.command.Build@6ef888f6)
      at picocli.CommandLine$Model$FieldBinding.set(CommandLine.java:11772)
      ... 19 more
Caused by: java.lang.IllegalAccessException: class picocli.CommandLine$Model$FieldBinding cannot access a member of class org.keycloak.quarkus.runtime.cli.command.AbstractCommand with modifiers "protected"
      at java.base/jdk.internal.reflect.Reflection.newIllegalAccessException(Reflection.java:361)
      at java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:610)
      at java.base/java.lang.reflect.Field.checkAccess(Field.java:1077)
      at java.base/java.lang.reflect.Field.get(Field.java:418)
      at picocli.CommandLine$Model$FieldBinding.set(CommandLine.java:11768)
      ... 19 more

The error is caused by the following line

CommandSpec spec = CommandSpec.forAnnotatedObject(new Main(), new DefaultFactory()).name(Environment.getCommand());

at https://github.com/keycloak/keycloak/blob/21.1.2/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/Picocli.java#L335

Is it possible to use picocli without Reflection API at all?

@AresEkb Apologies for the very late response.

Yes, picocli does also provide a programmatic API to construct command line applications.
With this approach, you cannot use the annotations, and instead you need to declare each option and each command programmatically.