diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index 7ec850c8..0a8142c2 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -22,6 +22,7 @@ Picocli follows [semantic versioning](http://semver.org/). * [#1124] Enhancement: automatically generate a better summary in the `AutoComplete.GenerateCompletion` generated man page. * [#1126] Enhancement: Make picocli trace levels case-insensitive. * [#1128] Enhancement: `ParameterException` caused by `TypeConversionException` now have their cause exception set. +* [#1137] Bugfix: The `picocli-codegen` annotation processor causes the build to fail with a `ClassCastException` when an option has `completionCandidates` defined. * [#1127] DOC: Custom ShortErrorMessageHandler manual example should use bold red for error message. * [#1130] DOC: Clarify how to run picocli-based applications. * [#1131] DOC: Add anchor links before section titles in user manual. diff --git a/picocli-annotation-processing-tests/src/main/java/picocli/annotation/processing/tests/CommandSpecYamlPrinter.java b/picocli-annotation-processing-tests/src/main/java/picocli/annotation/processing/tests/CommandSpecYamlPrinter.java index ae35ddd2..01f0b2ca 100644 --- a/picocli-annotation-processing-tests/src/main/java/picocli/annotation/processing/tests/CommandSpecYamlPrinter.java +++ b/picocli-annotation-processing-tests/src/main/java/picocli/annotation/processing/tests/CommandSpecYamlPrinter.java @@ -225,15 +225,8 @@ public class CommandSpecYamlPrinter { } private String iter(Iterable iterable) { - if (iterable == null) { return "null"; } - StringBuilder sb = new StringBuilder(); - sb.append("["); - String sep = ""; - for (String str : iterable) { - sb.append(sep).append(str); - sep = ", "; - } - return sb.append("]").toString(); + // cannot list actual completion candidates: class cannot be instantiated at compile time + return String.valueOf(iterable); } @Command(name = "CommandSpecYamlPrinter", mixinStandardHelpOptions = true, diff --git a/picocli-annotation-processing-tests/src/test/java/picocli/annotation/processing/tests/Issue1137Test.java b/picocli-annotation-processing-tests/src/test/java/picocli/annotation/processing/tests/Issue1137Test.java new file mode 100644 index 00000000..60322374 --- /dev/null +++ b/picocli-annotation-processing-tests/src/test/java/picocli/annotation/processing/tests/Issue1137Test.java @@ -0,0 +1,41 @@ +package picocli.annotation.processing.tests; + +import com.google.testing.compile.Compilation; +import com.google.testing.compile.JavaFileObjects; +import org.junit.Test; + +import javax.annotation.processing.Processor; +import javax.tools.StandardLocation; + +import static com.google.testing.compile.CompilationSubject.assertThat; +import static com.google.testing.compile.Compiler.javac; +import static picocli.annotation.processing.tests.Resources.slurp; +import static picocli.annotation.processing.tests.YamlAssert.compareCommandYamlDump; + +public class Issue1137Test { + @Test + public void testIssue1137() { + Processor processor = new AnnotatedCommandSourceGeneratorProcessor(); + Compilation compilation = + javac() + .withProcessors(processor) + .compile(JavaFileObjects.forResource( + "picocli/issue1137/Issue1137.java")); + + assertThat(compilation).succeeded(); + } + + @Test + public void testIssue1137Details() { + + Compilation compilation = compareCommandYamlDump(slurp("/picocli/issue1137/Issue1137.yaml"), + JavaFileObjects.forResource("picocli/issue1137/Issue1137.java")); + + assertOnlySourceVersionWarning(compilation); + } + + private void assertOnlySourceVersionWarning(Compilation compilation) { + assertThat(compilation).hadWarningCount(0); // #826 version warnings are now suppressed + // assertThat(compilation).hadWarningContaining("Supported source version 'RELEASE_6' from annotation processor 'picocli.annotation.processing.tests"); + } +} diff --git a/picocli-annotation-processing-tests/src/test/resources/picocli/issue1137/Issue1137.java b/picocli-annotation-processing-tests/src/test/resources/picocli/issue1137/Issue1137.java new file mode 100644 index 00000000..f2bbeee1 --- /dev/null +++ b/picocli-annotation-processing-tests/src/test/resources/picocli/issue1137/Issue1137.java @@ -0,0 +1,39 @@ +package picocli.issue1137; + +import picocli.CommandLine; +import picocli.CommandLine.Command; +import picocli.CommandLine.Model.CommandSpec; +import picocli.CommandLine.Option; +import picocli.CommandLine.Spec; + +import java.util.Arrays; +import java.util.ArrayList; +import java.util.UUID; +import java.util.concurrent.Callable; + +@Command(name = "top", + version = {"test 1.0"}, + resourceBundle = "mybundle5") +public class Issue1137 implements Callable { + + @CommandLine.Option(names = "--level", + description = "Level.", + defaultValue = "OFF", + showDefaultValue = CommandLine.Help.Visibility.ALWAYS, + completionCandidates = LevelCompletion.class) + private String level; + + @Spec + CommandSpec spec; + + @Override + public Integer call() throws Exception { + return 0; + } + + public static class LevelCompletion extends ArrayList { + public LevelCompletion() { + super(Arrays.asList("OFF", "INFO", "WARN")); + } + } +} \ No newline at end of file diff --git a/picocli-annotation-processing-tests/src/test/resources/picocli/issue1137/Issue1137.yaml b/picocli-annotation-processing-tests/src/test/resources/picocli/issue1137/Issue1137.yaml new file mode 100644 index 00000000..92479935 --- /dev/null +++ b/picocli-annotation-processing-tests/src/test/resources/picocli/issue1137/Issue1137.yaml @@ -0,0 +1,70 @@ +--- +CommandSpec: + name: 'top' + aliases: [] + userObject: picocli.issue1137.Issue1137 + helpCommand: false + defaultValueProvider: null + versionProvider: null + version: [test 1.0] + ArgGroups: [] + Options: + - names: [--level] + usageHelp: false + versionHelp: false + description: [Level.] + descriptionKey: '' + typeInfo: CompileTimeTypeInfo(java.lang.String, aux=[java.lang.String], collection=false, map=false) + arity: 1 + splitRegex: '' + interactive: false + required: false + hidden: false + hideParamSyntax: false + defaultValue: 'OFF' + showDefaultValue: ALWAYS + hasInitialValue: false + initialValue: 'null' + paramLabel: '' + converters: [] + completionCandidates: CompletionCandidatesMetaData(picocli.issue1137.Issue1137.LevelCompletion) + getter: AnnotatedElementHolder(FIELD level in picocli.issue1137.Issue1137) + setter: AnnotatedElementHolder(FIELD level in picocli.issue1137.Issue1137) + PositionalParams: [] + UnmatchedArgsBindings: [] + Mixins: [] + UsageMessageSpec: + width: 80 + abbreviateSynopsis: false + hidden: false + showDefaultValues: false + sortOptions: true + requiredOptionMarker: ' ' + headerHeading: '' + header: [] + synopsisHeading: 'Usage: ' + customSynopsis: [] + descriptionHeading: '' + description: [] + parameterListHeading: '' + optionListHeading: '' + commandListHeading: 'Commands:%n' + footerHeading: '' + footer: [] + ParserSpec: + separator: '=' + endOfOptionsDelimiter: '--' + expandAtFiles: true + atFileCommentChar: '#' + overwrittenOptionsAllowed: false + unmatchedArgumentsAllowed: false + unmatchedOptionsArePositionalParams: false + stopAtUnmatched: false + stopAtPositional: false + posixClusteredShortOptionsAllowed: true + aritySatisfiedByAttachedOptionParam: false + caseInsensitiveEnumValuesAllowed: false + collectErrors: false + limitSplit: false + toggleBooleanFlags: false + Subcommands: [] diff --git a/picocli-codegen/src/main/java/picocli/codegen/annotation/processing/CompletionCandidatesMetaData.java b/picocli-codegen/src/main/java/picocli/codegen/annotation/processing/CompletionCandidatesMetaData.java index 9bf1bb3e..ba9e0f35 100644 --- a/picocli-codegen/src/main/java/picocli/codegen/annotation/processing/CompletionCandidatesMetaData.java +++ b/picocli-codegen/src/main/java/picocli/codegen/annotation/processing/CompletionCandidatesMetaData.java @@ -41,7 +41,7 @@ class CompletionCandidatesMetaData implements Iterable, ITypeMetaData { for (ExecutableElement attribute : elementValues.keySet()) { if ("completionCandidates".equals(attribute.getSimpleName().toString())) { AnnotationValue typeMirror = elementValues.get(attribute); - return new CompletionCandidatesMetaData((TypeMirror) typeMirror); + return new CompletionCandidatesMetaData((TypeMirror) typeMirror.getValue()); } } } @@ -72,7 +72,7 @@ class CompletionCandidatesMetaData implements Iterable, ITypeMetaData { /** Always returns {@code null}. */ @Override public Iterator iterator() { - return null; + throw new UnsupportedOperationException("Cannot instantiate " + typeMirror + " at compile time."); } /**