diff --git a/extensions/picocli/deployment/src/main/java/io/quarkus/picocli/deployment/PicocliNativeImageProcessor.java b/extensions/picocli/deployment/src/main/java/io/quarkus/picocli/deployment/PicocliNativeImageProcessor.java index d813694d62b5c..d301acd20b2b1 100644 --- a/extensions/picocli/deployment/src/main/java/io/quarkus/picocli/deployment/PicocliNativeImageProcessor.java +++ b/extensions/picocli/deployment/src/main/java/io/quarkus/picocli/deployment/PicocliNativeImageProcessor.java @@ -4,6 +4,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.HashSet; +import java.util.List; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; @@ -11,10 +12,12 @@ import org.jboss.jandex.AnnotationInstance; import org.jboss.jandex.AnnotationTarget; import org.jboss.jandex.AnnotationValue; +import org.jboss.jandex.AnnotationValue.Kind; import org.jboss.jandex.ClassInfo; import org.jboss.jandex.DotName; import org.jboss.jandex.FieldInfo; import org.jboss.jandex.IndexView; +import org.jboss.jandex.Type; import org.jboss.logging.Logger; import io.quarkus.deployment.annotations.BuildProducer; @@ -32,9 +35,6 @@ public class PicocliNativeImageProcessor { private static final Logger LOGGER = Logger.getLogger(PicocliNativeImageProcessor.class); - private static final DotName PARAMETERS = DotName.createSimple(CommandLine.Parameters.class.getName()); - private static final String PARAMETERS_COMPLETION_CANDIDATES = "completionCandidates"; - @BuildStep(onlyIf = NativeBuild.class) void reflectionConfiguration(CombinedIndexBuildItem combinedIndexBuildItem, BuildProducer reflectiveFields, @@ -48,13 +48,15 @@ void reflectionConfiguration(CombinedIndexBuildItem combinedIndexBuildItem, DotName.createSimple(CommandLine.Command.class.getName()), DotName.createSimple(CommandLine.Mixin.class.getName()), DotName.createSimple(CommandLine.Option.class.getName()), - PARAMETERS, + DotName.createSimple(CommandLine.Parameters.class.getName()), DotName.createSimple(CommandLine.ParentCommand.class.getName()), DotName.createSimple(CommandLine.Spec.class.getName()), DotName.createSimple(CommandLine.Unmatched.class.getName())); Set foundClasses = new HashSet<>(); Set foundFields = new HashSet<>(); + Set typeAnnotationValues = new HashSet<>(); + for (DotName analyzedAnnotation : annotationsToAnalyze) { for (AnnotationInstance ann : index.getAnnotations(analyzedAnnotation)) { AnnotationTarget target = ann.target(); @@ -78,13 +80,21 @@ void reflectionConfiguration(CombinedIndexBuildItem combinedIndexBuildItem, LOGGER.warnf("Unsupported type %s annotated with %s", target.kind().name(), analyzedAnnotation); break; } + + // register classes references in Picocli annotations for reflection + List values = ann.valuesWithDefaults(index); + for (AnnotationValue value : values) { + if (value.kind() == Kind.CLASS) { + typeAnnotationValues.add(value.asClass()); + } else if (value.kind() == Kind.ARRAY && value.componentKind() == Kind.CLASS) { + for (Type componentClass : value.asClassArray()) { + typeAnnotationValues.add(componentClass); + } + } + } } } - Arrays.asList(DotName.createSimple(CommandLine.IVersionProvider.class.getName()), - DotName.createSimple(CommandLine.class.getName())) - .forEach(interfaceName -> foundClasses.addAll(index.getAllKnownImplementors(interfaceName))); - foundClasses.forEach(classInfo -> { if (Modifier.isInterface(classInfo.flags())) { nativeImageProxies @@ -97,22 +107,10 @@ void reflectionConfiguration(CombinedIndexBuildItem combinedIndexBuildItem, } }); foundFields.forEach(fieldInfo -> reflectiveFields.produce(new ReflectiveFieldBuildItem(fieldInfo))); - - // register @Parameters(completionCandidates = ...) for reflection - Collection parametersAnnotationInstances = index - .getAnnotations(PARAMETERS); - for (AnnotationInstance parametersAnnotationInstance : parametersAnnotationInstances) { - AnnotationValue completionCandidates = parametersAnnotationInstance.value(PARAMETERS_COMPLETION_CANDIDATES); - - if (completionCandidates == null) { - continue; - } - - reflectiveHierarchies.produce(new ReflectiveHierarchyBuildItem.Builder() - .type(completionCandidates.asClass()) - .source(PicocliNativeImageProcessor.class.getSimpleName() + " > " + parametersAnnotationInstance.target()) - .build()); - } + typeAnnotationValues.forEach(type -> reflectiveHierarchies.produce(new ReflectiveHierarchyBuildItem.Builder() + .type(type) + .source(PicocliNativeImageProcessor.class.getSimpleName()) + .build())); } @BuildStep(onlyIf = NativeBuild.class) diff --git a/integration-tests/picocli-native/src/main/java/io/quarkus/it/picocli/CustomDefaultValueProvider.java b/integration-tests/picocli-native/src/main/java/io/quarkus/it/picocli/CustomDefaultValueProvider.java new file mode 100644 index 0000000000000..eff3cceedcff2 --- /dev/null +++ b/integration-tests/picocli-native/src/main/java/io/quarkus/it/picocli/CustomDefaultValueProvider.java @@ -0,0 +1,12 @@ +package io.quarkus.it.picocli; + +import picocli.CommandLine.IDefaultValueProvider; +import picocli.CommandLine.Model.ArgSpec; + +public class CustomDefaultValueProvider implements IDefaultValueProvider { + + @Override + public String defaultValue(ArgSpec argSpec) throws Exception { + return "false"; + } +} diff --git a/integration-tests/picocli-native/src/main/java/io/quarkus/it/picocli/DefaultValueProviderCommand.java b/integration-tests/picocli-native/src/main/java/io/quarkus/it/picocli/DefaultValueProviderCommand.java new file mode 100644 index 0000000000000..5b22fce355b87 --- /dev/null +++ b/integration-tests/picocli-native/src/main/java/io/quarkus/it/picocli/DefaultValueProviderCommand.java @@ -0,0 +1,12 @@ +package io.quarkus.it.picocli; + +import picocli.CommandLine; + +@CommandLine.Command(name = "defaultvalueprovider", mixinStandardHelpOptions = true, defaultValueProvider = CustomDefaultValueProvider.class) +public class DefaultValueProviderCommand implements Runnable { + + @Override + public void run() { + } + +} diff --git a/integration-tests/picocli-native/src/main/java/io/quarkus/it/picocli/TestResource.java b/integration-tests/picocli-native/src/main/java/io/quarkus/it/picocli/TestResource.java index 2dc9d3332535a..6c6f9d7d0f861 100644 --- a/integration-tests/picocli-native/src/main/java/io/quarkus/it/picocli/TestResource.java +++ b/integration-tests/picocli-native/src/main/java/io/quarkus/it/picocli/TestResource.java @@ -41,6 +41,7 @@ public String getTestResults() throws UnknownHostException { testUnmatched(); testI18s(); testCompletionReflection(); + testDefaultValueProvider(); return "OK"; } @@ -115,4 +116,9 @@ private void testCompletionReflection() { CommandLine completionReflectionCommand = new CommandLine(CompletionReflectionCommand.class, factory); completionReflectionCommand.execute("one"); } + + private void testDefaultValueProvider() { + CommandLine cmd = new CommandLine(DefaultValueProviderCommand.class, factory); + Assertions.assertThat(cmd.execute()).isZero(); + } }