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.
https://picocli.info
Apache License 2.0
4.79k stars 414 forks source link

GraalVM: Options from superclass not visible #1444

Open rsenden opened 2 years ago

rsenden commented 2 years ago

I have an abstract base command class that defines an ArgGroup as follows:

public abstract class AbstractSomeBaseCommand implements Runnable {
    @ArgGroup(heading = "Some arg group:%n", order = 1000)
    @Getter private MyArgGroup argGroup;

    private static class MyArgGroup {
                // This option is not recognized by picocli for concrete command subclasses when running as native image
        @Option(names = {"--someOption", "-s"}, required = false, defaultValue = "default")
        @Getter private String someOption;
    }
   ...
}

This base class is extended by an actual command class, defining some additional options or argument groups. When running as a normal jar file (or from within my IDE), all options from both base class and actual command class are properly recognized by Picocli.

However, when running as a GraalVM native image, Picocli doesn't recognize the options defined in the abstract base class; they do not show up in the help output, and you get an 'Unknown option' error when trying to use these options from the base class.

A similar issue can be seen with argument group classes that extend from some other class (also if the base class is not abstract). In the following example, again the options from MyArgGroupNonAbstractBaseClass are not recognized in the native image:

    @ArgGroup(heading = "My xyz options:%n", order = 1000)
    @Getter private MyArgGroup argGroup;

        // Any options defined in MyArgGroupNonAbstractBaseClass are not visible when running as native image
    private static class MyArgGroup extends from MyArgGroupNonAbstractBaseClass  {
        @Option(names = {"--extra-option", "-e"}, required = false, defaultValue = "default")
        @Getter private String extraOption;
    }

Any idea on how this can be fixed?

remkop commented 2 years ago

Can you try making the annotated fields protected instead of private?

rsenden commented 2 years ago

Can you try making the annotated fields protected instead of private?

Thanks, I'll try that and let you know the results. In the meantime I did try using the default access modifier together with Micronauts @ReflectiveAccess annotation for the affected fields , however this results in the following stacktrace:

Error: Exception in thread "main" picocli.CommandLine$InitializationException: Could not access or modify mixin member com.myapp.cli.session.command.consumer.LoginSessionConsumerMixin com.myapp.cli.session.command.logout.AbstractSessionLogoutCommand.loginSessionConsumerMixin: java.lang.NoSuchMethodException: com.myapp.cli.session.command.consumer.LoginSessionConsumerMixin.<init>()
    at picocli.CommandLine$Model$CommandReflection.buildMixinForMember(CommandLine.java:11612)
    at picocli.CommandLine$Model$CommandReflection.initFromAnnotatedTypedMembers(CommandLine.java:11487)
    at picocli.CommandLine$Model$CommandReflection.initFromAnnotatedFields(CommandLine.java:11466)
    at picocli.CommandLine$Model$CommandReflection.extractCommandSpec(CommandLine.java:11399)
    at picocli.CommandLine$Model$CommandSpec.forAnnotatedObject(CommandLine.java:6202)
    at picocli.CommandLine.<init>(CommandLine.java:227)
    at picocli.CommandLine.<init>(CommandLine.java:221)
    at com.myapp.cli.MyApp.addSubcommands(MyApp.java:52)
    at com.myapp.cli.MyApp.addSubcommands(MyApp.java:54)
    at com.myapp.cli.MyApp.addSubcommands(MyApp.java:44)
    at com.myapp.cli.MyApp.execute(MyApp.java:36)
    at com.myapp.cli.MyApp.main(MyApp.java:85)
Caused by: java.lang.NoSuchMethodException: com.myapp.cli.session.command.consumer.LoginSessionConsumerMixin.<init>()
    at java.lang.Class.getConstructor0(DynamicHub.java:3349)
    at java.lang.Class.getDeclaredConstructor(DynamicHub.java:2553)
    at picocli.CommandLine$DefaultFactory.create(CommandLine.java:5489)
    at io.micronaut.configuration.picocli.MicronautFactory.create(MicronautFactory.java:74)
    at picocli.CommandLine$Model$CommandReflection.buildMixinForMember(CommandLine.java:11604)
    ... 11 more

LoginSessionConsumerMixin is (as the name implies) used as an @Mixin in an abstract class, so at least picocli seems to see this mixin now. LoginSessionConsumerMixin doesn't declare any constructors, so not sure why picocli can't find a no-arg constructor...

rsenden commented 2 years ago

Can you try making the annotated fields protected instead of private?

Thanks, I'll try that and let you know the results.

Tried making all relevant option & mixin fields protected, but unfortunately those options are still not being recognized by picocli when running in GraalVM native image. I also noticed that for example @ParentCommand doesn't get properly injected when defined in an (abstract) superclass of the actual command implementation.

remkop commented 2 years ago

Can you show your class and the generated reflect.json?

rsenden commented 2 years ago

(Edited) In the meantime I've been able to make this work by declaring Micronaut's @ReflectiveAccess annotation at class-level (rather than field-level) for the affected classes, allowing picocli to use reflection to call the default constructors of these classes and then inject the appropriate fields.

It does seem a bit cumbersome though having to annotate almost every picocli-related class with @ReflectiveAccess if that class can potentially be used in a class hierarchy. I'm also wondering whether this has any negative consequences; I'm assuming that GraalVM disables reflection by default for a reason.

So although this is working now, I still have some questions:

Thanks!

remkop commented 2 years ago

Could this be related to programmatically registering the commands and subcommands (based on the idea in Bottom-up sub-commands declaration #1442), rather than declaratively?

Yes definitely. The annotation processor only processes the annotations. Any other relationships are not detected and will not be represented in the generated reflect.json.

Would it be possible to add support for Micronaut's @Introspected annotation (...)

Recently I have very little time to spend on picocli, so if there is a workaround then let's go with that.

rsenden commented 2 years ago

Looking somewhat closer at this, I seems like picocli is including @Command-annotated classes in reflect-config.json, but fails to also add any superclasses of those command classes. Is this something that can be fixed easily?

Manually adding @ReflectiveAccess adds these superclasses to the Micronaut-generated reflect-config.json files, allowing picocli to function correctly, but it's not ideal.

remkop commented 2 years ago

If superclasses have picocli annotations then those superclasses should also be included in the reflect.json generated by the annotation processor. Are you saying that this is not the case?

rsenden commented 2 years ago

Depends on what you mean with 'if superclasses have picocli annotations'; the class itself doesn't have any picocli annotations but the fields do. See example below.

Base class:

@ReflectiveAccess
public abstract class AbstractSessionLoginCommand<C> extends AbstractCommandWithLoginSessionHelper implements Runnable {
    @ArgGroup(heading = "Optional login session name:%n", order = 1000)
    @Getter protected LoginSessionNameOptions loginSessionNameOptions;

    private static class LoginSessionNameOptions {
        @Option(names = {"--login-session-name", "-n"}, required = false, defaultValue = "default")
        @Getter protected String loginSessionName;
    }
...
@Singleton @ReflectiveAccess
@SubcommandOf(SessionLoginRootCommand.class)
@Command(name = "dummy", description = "Login to MySystem", sortOptions = false)
public class MyLoginCommand extends AbstractSessionLoginCommand<MyConnectionConfig> {
    @ArgGroup(exclusive = false, multiplicity = "1", heading = "Connection options:%n", order = 1)
    @Getter private LoginConnectionOptions connectionOptions;
...

In the resulting jar file, META-INF/native-image/picocli-generated/reflect-config.json contains entries for MyLoginCommand and the appropriate inner classes defining ArgGroups. However it doesn't contain any entries for AbstractSessionLoginCommand or its inner classes.

Current work-around is to add the @ReflectiveAccess annotation to the base class in order to have Micronaut generate the appropriate reflection configuration, but obviously it would be much better if picocli handled this by itself.

remkop commented 2 years ago

I was able to reproduce the issue in a unit test. Investigating now...

remkop commented 2 years ago

Hmm... this may be a problem caused by incremental compilation.

In my test, if I only compile the concrete subclass, then the generated reflect-config.json contains only entries for that class. When I compile both the concrete subclass and the abstract superclass, the generated reflect-config.json is correct and contains entries for both the concrete subclass and the abstract superclass. I updated the test to demonstrate this.

I am not sure how to make progress with this. Any ideas?

rsenden commented 2 years ago

It's been a while since I last looked at this, but I think the problem was also present when doing a full, clean build. In my case though, the parent class was (most likely) in a separate Gradle module. So, by the time the subclass got compiled, the superclass would have been already compiled by a different javac invocation.

I'm not really familiar with all the ins and outs of Java compilation and annotation processors, so I wouldn't really know how to fix something like this. Can the annotation processor use reflection to inspect the superclass and generate the appropriate reflect-config.json?

remkop commented 2 years ago

If the superclass is in a separate Gradle module, then one idea is to generate a separate reflect-config.json for that module, by specifying the annotation processor for that module also.

To answer your question, yes I think it’s theoretically possible to climb the class hierarchy and inspect all child elements (and nested grandchild elements of the child elements, recursively) for picocli annotations. But that’s kind of what the annotation processor API is supposed to do for us. It appears to be a lot of work for something that should already be working: the annotation processor should already get callbacks for each picocli-annotated element in the superclass. So there’s something strange going on…

rsenden commented 1 year ago

@remkop, some new information on this issue:

For reference, the classes listed below are missing from reflect-config.json generated by the Gradle build. It seems like this mostly affects (abstract) superclasses of command implementations, and any Mixins and ArgGroups that are referenced (only) from these superclasses. Potentially this also applies to (abstract) superclasses of Mixin and/or ArgGroup implementations. This also applies to abstract base classes located in the same module as the command implementation.

Any idea why this is happening?

-"com.fortify.cli.common.cli.cmd.AbstractFortifyCLICommand"
-"com.fortify.cli.common.cli.cmd.AbstractFortifyCLICommand$GenericOptionsArgGroup"
-"com.fortify.cli.common.cli.cmd.AbstractFortifyCLICommand$LogLevel"
-"com.fortify.cli.common.output.cli.cmd.basic.AbstractBasicOutputCommand"
-"com.fortify.cli.common.output.cli.cmd.unirest.AbstractUnirestOutputCommand"
-"com.fortify.cli.common.output.cli.mixin.BasicOutputHelperMixins$DeleteAll"
-"com.fortify.cli.common.output.cli.mixin.BasicOutputHelperMixins$Other"
-"com.fortify.cli.common.output.cli.mixin.BasicOutputHelperMixins$TableNoQuery"
-"com.fortify.cli.common.output.cli.mixin.BasicOutputHelperMixins$TableWithQuery"
-"com.fortify.cli.common.output.cli.mixin.BasicOutputHelperMixins$WaitFor"
-"com.fortify.cli.common.output.cli.mixin.UnirestOutputHelperMixins$Add"
-"com.fortify.cli.common.output.cli.mixin.UnirestOutputHelperMixins$Cancel"
-"com.fortify.cli.common.output.cli.mixin.UnirestOutputHelperMixins$Create"
-"com.fortify.cli.common.output.cli.mixin.UnirestOutputHelperMixins$Delete"
-"com.fortify.cli.common.output.cli.mixin.UnirestOutputHelperMixins$Disable"
-"com.fortify.cli.common.output.cli.mixin.UnirestOutputHelperMixins$Download"
-"com.fortify.cli.common.output.cli.mixin.UnirestOutputHelperMixins$Enable"
-"com.fortify.cli.common.output.cli.mixin.UnirestOutputHelperMixins$Get"
-"com.fortify.cli.common.output.cli.mixin.UnirestOutputHelperMixins$Import"
-"com.fortify.cli.common.output.cli.mixin.UnirestOutputHelperMixins$Install"
-"com.fortify.cli.common.output.cli.mixin.UnirestOutputHelperMixins$List"
-"com.fortify.cli.common.output.cli.mixin.UnirestOutputHelperMixins$Other"
-"com.fortify.cli.common.output.cli.mixin.UnirestOutputHelperMixins$Set"
-"com.fortify.cli.common.output.cli.mixin.UnirestOutputHelperMixins$Start"
-"com.fortify.cli.common.output.cli.mixin.UnirestOutputHelperMixins$TableNoQuery"
-"com.fortify.cli.common.output.cli.mixin.UnirestOutputHelperMixins$TableWithQuery"
-"com.fortify.cli.common.output.cli.mixin.UnirestOutputHelperMixins$Uninstall"
-"com.fortify.cli.common.output.cli.mixin.UnirestOutputHelperMixins$Update"
-"com.fortify.cli.common.output.cli.mixin.UnirestOutputHelperMixins$Upload"
-"com.fortify.cli.common.output.cli.mixin.impl.OutputOptionsArgGroup"
-"com.fortify.cli.common.output.cli.mixin.impl.QueryOptionsArgGroup"
-"com.fortify.cli.common.output.cli.mixin.spi.AbstractOutputHelper"
-"com.fortify.cli.common.output.cli.mixin.spi.basic.AbstractBasicOutputHelper"
-"com.fortify.cli.common.output.cli.mixin.spi.unirest.AbstractUnirestOutputHelper"
-"com.fortify.cli.common.output.cli.mixin.writer.OutputWriterWithQueryFactoryMixin"
-"com.fortify.cli.common.output.cli.mixin.writer.StandardOutputWriterFactoryMixin"
-"com.fortify.cli.common.output.query.OutputQuery"
-"com.fortify.cli.common.output.query.OutputQueryConverter"
-"com.fortify.cli.common.output.writer.output.standard.OutputFormatConfig"
-"com.fortify.cli.common.output.writer.output.standard.OutputFormatConfigConverter"
-"com.fortify.cli.common.output.writer.output.standard.OutputFormatConfigConverter$OutputFormatIterable"
-"com.fortify.cli.common.output.writer.output.standard.VariableStoreConfig"
-"com.fortify.cli.common.output.writer.output.standard.VariableStoreConfigConverter"
-"com.fortify.cli.common.rest.cli.cmd.AbstractRestCallCommand"
-"com.fortify.cli.common.rest.cli.cmd.AbstractUnirestRunnerCommand"
-"com.fortify.cli.common.rest.cli.cmd.AbstractWaitForCommand"
-"com.fortify.cli.common.rest.cli.mixin.AbstractSimpleUnirestRunnerMixin"
-"com.fortify.cli.common.rest.cli.mixin.AbstractUnirestRunnerMixin"
-"com.fortify.cli.common.rest.cli.mixin.StandardWaitHelperProgressMonitorMixin"
-"com.fortify.cli.common.rest.cli.mixin.WaitHelperControlOptions"
-"com.fortify.cli.common.rest.cli.mixin.WaitHelperWaitOptions"
-"com.fortify.cli.common.rest.cli.mixin.WaitHelperWaitOptions$WaitHelperWaitOptionsArgGroup"
-"com.fortify.cli.common.rest.wait.WaitTimeoutAction"
-"com.fortify.cli.common.rest.wait.WaitUnknownOrFailureStateAction"
-"com.fortify.cli.common.rest.wait.WaitUnknownStateRequestedAction"
-"com.fortify.cli.common.session.cli.cmd.AbstractSessionCommand"
-"com.fortify.cli.common.session.cli.cmd.AbstractSessionListCommand"
-"com.fortify.cli.common.session.cli.cmd.AbstractSessionLoginCommand"
-"com.fortify.cli.common.session.cli.cmd.AbstractSessionLogoutCommand"
-"com.fortify.cli.common.session.cli.mixin.SessionNameMixin$AbstractSessionNameMixin"
-"com.fortify.cli.common.session.cli.mixin.SessionNameMixin$OptionalOption"
-"com.fortify.cli.common.session.cli.mixin.SessionNameMixin$OptionalOption$SessionNameArgGroup"
-"com.fortify.cli.common.session.cli.mixin.SessionNameMixin$OptionalParameter"
-"com.fortify.cli.common.session.cli.mixin.SessionNameMixin$OptionalParameter$SessionNameArgGroup"
-"com.fortify.cli.config.proxy.cli.mixin.AbstractProxyOptions"
-"com.fortify.cli.config.proxy.cli.mixin.AbstractProxyOptions$ProxyTargetHostsArgGroup"
-"com.fortify.cli.fod.app.cli.mixin.FoDAppResolverMixin$AbstractFoDAppResolverMixin"
-"com.fortify.cli.fod.app.cli.mixin.FoDAppTypeOptions$AbstractFoDAppType"
-"com.fortify.cli.fod.app.cli.mixin.FoDCriticalityTypeOptions$AbstractFoDCriticalityType"
-"com.fortify.cli.fod.app.cli.mixin.FoDSdlcStatusTypeOptions$AbstractFoDSdlcStatusType"
-"com.fortify.cli.fod.attribute.cli.mixin.FoDAttributeUpdateOptions$AbstractFoDAppAttributeUpdateMixin"
-"com.fortify.cli.fod.lookup.cli.mixin.FoDLookupTypeOptions$AbstractFoDLookupType"
-"com.fortify.cli.fod.microservice.cli.mixin.FoDAppAndMicroserviceNameResolverMixin$AbstractFoDAppAndMicroserviceNameResolverMixin"
-"com.fortify.cli.fod.microservice.cli.mixin.FoDAppMicroserviceResolverMixin$AbstractFoDAppMicroserviceResolverMixin"
-"com.fortify.cli.fod.microservice.cli.mixin.FoDAppMicroserviceUpdateOptions$AbstractFoDAppMicroserviceRenameMixin"
-"com.fortify.cli.fod.microservice.cli.mixin.FoDAppMicroserviceUpdateOptions$AbstractFoDAppMicroserviceUpdateMixin"
-"com.fortify.cli.fod.oss_scan.cli.mixin.FoDSbomFormatOptions$AbstractFoDSbomFormat"
-"com.fortify.cli.fod.output.cli.AbstractFoDOutputCommand"
-"com.fortify.cli.fod.release.cli.mixin.FoDAppAndRelNameResolverMixin$AbstractFoDAppAndRelNameResolverMixin"
-"com.fortify.cli.fod.release.cli.mixin.FoDAppMicroserviceRelResolverMixin$AbstractFoDAppMicroserviceRelResolverMixin"
-"com.fortify.cli.fod.release.cli.mixin.FoDAppRelResolverMixin$AbstractFoDAppRelResolverMixin"
-"com.fortify.cli.fod.release.cli.mixin.FoDDelimiterMixin"
-"com.fortify.cli.fod.rest.cli.mixin.FoDTimePeriodOptions$AbstractFoDTimePeriodType"
-"com.fortify.cli.fod.scan.cli.mixin.FoDAnalysisStatusTypeOptions$AbstractFoDAnalysisStatusType"
-"com.fortify.cli.fod.scan.cli.mixin.FoDAssessmentTypeOptions$AbstractFoDAssessmentType"
-"com.fortify.cli.fod.scan.cli.mixin.FoDEntitlementPreferenceTypeOptions$AbstractFoDEntitlementPreferenceType"
-"com.fortify.cli.fod.scan.cli.mixin.FoDInProgressScanActionTypeOptions$AbstractFoDEntitlementType"
-"com.fortify.cli.fod.scan.cli.mixin.FoDRemediationScanPreferenceTypeOptions$AbstractFoDEntitlementType"
-"com.fortify.cli.fod.scan.cli.mixin.FoDScanFormatOptions$AbstractFoDScanType"
-"com.fortify.cli.fod.scan.cli.mixin.FoDScanResolverMixin$AbstractFoDMultiScanResolverMixin"
-"com.fortify.cli.fod.scan.cli.mixin.FoDScanResolverMixin$AbstractFoDScanResolverMixin"
-"com.fortify.cli.fod.user.cli.mixin.FoDUserResolverMixin$AbstractFoDUserResolverMixin"
-"com.fortify.cli.fod.user_group.cli.mixin.FoDUserGroupResolverMixin$AbstractFoDUserGroupResolverMixin"
-"com.fortify.cli.sc_dast.output.cli.cmd.AbstractSCDastOutputCommand"
-"com.fortify.cli.sc_dast.scan.cli.cmd.AbstractSCDastScanOutputCommand"
-"com.fortify.cli.sc_dast.scan.cli.cmd.action.AbstractSCDastScanActionCommand"
-"com.fortify.cli.sc_dast.scan.cli.mixin.SCDastScanResolverMixin$AbstractSSCDastMultiScanResolverMixin"
-"com.fortify.cli.sc_dast.scan.cli.mixin.SCDastScanResolverMixin$AbstractSSCDastScanResolverMixin"
-"com.fortify.cli.sc_dast.scan_policy.cli.mixin.SCDastScanPolicyResolverMixin$AbstractSSCDastScanPolicyResolverMixin"
-"com.fortify.cli.sc_dast.scan_settings.cli.mixin.SCDastScanSettingsResolverMixin$AbstractSSCDastScanSettingsResolverMixin"
-"com.fortify.cli.sc_dast.sensor.cli.mixin.SCDastSensorResolverMixin$AbstractSSCDastSensorResolverMixin"
-"com.fortify.cli.sc_sast.output.cli.cmd.AbstractSCSastControllerOutputCommand"
-"com.fortify.cli.sc_sast.rest.cli.mixin.AbstractSCSastUnirestRunnerMixin"
-"com.fortify.cli.sc_sast.scan.cli.mixin.SCSastScanJobResolverMixin$AbstractSCSastMultiScanJobResolverMixin"
-"com.fortify.cli.sc_sast.scan.cli.mixin.SCSastScanJobResolverMixin$AbstractSCSastScanJobResolverMixin"
-"com.fortify.cli.ssc.app.cli.mixin.SSCAppResolverMixin$AbstractSSCAppResolverMixin"
-"com.fortify.cli.ssc.appversion.cli.mixin.SSCAppAndVersionNameResolverMixin$AbstractSSCAppAndVersionNameResolverMixin"
-"com.fortify.cli.ssc.appversion.cli.mixin.SSCAppVersionResolverMixin$AbstractSSCAppVersionResolverMixin"
-"com.fortify.cli.ssc.appversion.cli.mixin.SSCDelimiterMixin"
-"com.fortify.cli.ssc.appversion_artifact.cli.cmd.AbstractSSCAppVersionArtifactOutputCommand"
-"com.fortify.cli.ssc.appversion_artifact.cli.cmd.AbstractSSCAppVersionArtifactUploadCommand"
-"com.fortify.cli.ssc.appversion_artifact.cli.mixin.SSCAppVersionArtifactResolverMixin$AbstractSSCAppVersionArtifactResolverMixin"
-"com.fortify.cli.ssc.appversion_artifact.cli.mixin.SSCAppVersionArtifactResolverMixin$AbstractSSCAppVersionMultiArtifactResolverMixin"
-"com.fortify.cli.ssc.appversion_attribute.cli.mixin.SSCAppVersionAttributeUpdateMixin$AbstractSSCAppVersionAttributeUpdateMixin"
-"com.fortify.cli.ssc.appversion_filterset.cli.mixin.SSCAppVersionFilterSetResolverMixin$AbstractSSCFilterSetResolverMixin"
-"com.fortify.cli.ssc.appversion_user.cli.mixin.SSCAppVersionAuthEntityMixin$AbstractSSCAppVersionAuthEntityMixin"
-"com.fortify.cli.ssc.attribute_definition.cli.mixin.SSCAttributeDefinitionResolverMixin$AbstractSSCAttributeDefinitionResolverMixin"
-"com.fortify.cli.ssc.issue_template.cli.mixin.SSCIssueTemplateResolverMixin$AbstractSSCIssueTemplateResolverMixin"
-"com.fortify.cli.ssc.job.cli.mixin.SSCJobResolverMixin$AbstractSSCJobResolverMixin"
-"com.fortify.cli.ssc.output.cli.cmd.AbstractSSCOutputCommand"
-"com.fortify.cli.ssc.plugin.cli.mixin.SSCPluginResolverMixin$AbstractSSCPluginResolverMixin"
-"com.fortify.cli.ssc.report_template.cli.mixin.SSCReportTemplateResolverMixin$AbstractSSCReportTemplateResolverMixin"
-"com.fortify.cli.ssc.role.cli.mixin.SSCRoleResolverMixin$AbstractSSCRoleMixin"
-"com.fortify.cli.ssc.role_permission.cli.mixin.SSCRolePermissionResolverMixin$AbstractSSCRolePermissionMixin"
-"com.fortify.cli.ssc.token.cli.cmd.AbstractSSCTokenCommand"
-"com.fortify.cli.ssc.token.cli.mixin.SSCTokenCommandUrlConfigMixin"
-"com.fortify.cli.ssc.token.cli.mixin.SSCTokenCommandUrlConfigMixin$SSCUrlConfigOrSessionName"
-"com.fortify.cli.ssc.user.cli.mixin.SSCAuthEntityResolverMixin$AbstractSSCAuthEntityResolverMixin"
-"com.fortify.cli.state.variable.cli.mixin.VariableResolverMixin$AbstractRequiredVariableResolverMixin"
-"com.fortify.cli.state.variable.cli.mixin.VariableResolverMixin$AbstractVariableResolverMixin"
-"com.fortify.cli.tool.common.cli.cmd.AbstractToolInstallCommand"
-"com.fortify.cli.tool.common.cli.cmd.AbstractToolInstallCommand$DigestMismatchAction"
-"com.fortify.cli.tool.common.cli.cmd.AbstractToolListCommand"
-"com.fortify.cli.tool.common.cli.cmd.AbstractToolUninstallCommand"
remkop commented 1 year ago

Are you doing gradlew clean build or using incremental builds?

rsenden commented 1 year ago

Both clean and incremental builds show the same behavior. We normally build native binaries only from our GitHub Actions workflow, with a clean workspace, and the missing reflect-config.json entries cause errors in those native binaries.

remkop commented 1 year ago

Are these abstract superclasses marked with the @Command annotation?