mirror of
https://github.com/jlengrand/picocli.git
synced 2026-03-10 08:41:17 +00:00
[#1134] Bugfix: annotation processor should allow @Spec-annotated field in version provider
Closes #1134
This commit is contained in:
@@ -23,6 +23,7 @@ Picocli follows [semantic versioning](http://semver.org/).
|
||||
* [#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.
|
||||
* [#1134] Bugfix: The `picocli-codegen` annotation processor should allow `@Spec`-annotated field in classes implementing `IVersionProvider`.
|
||||
* [#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.
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
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 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 Issue1134Test {
|
||||
@Test
|
||||
public void testIssue1134() {
|
||||
Processor processor = new AnnotatedCommandSourceGeneratorProcessor();
|
||||
Compilation compilation =
|
||||
javac()
|
||||
.withProcessors(processor)
|
||||
.compile(JavaFileObjects.forResource(
|
||||
"picocli/issue1134/Issue1134.java"));
|
||||
|
||||
assertThat(compilation).succeeded();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIssue1134Details() {
|
||||
|
||||
Compilation compilation = compareCommandYamlDump(slurp("/picocli/issue1134/Issue1134.yaml"),
|
||||
JavaFileObjects.forResource("picocli/issue1134/Issue1134.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");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package picocli.issue1134;
|
||||
|
||||
import picocli.CommandLine;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.IVersionProvider;
|
||||
import picocli.CommandLine.Model.CommandSpec;
|
||||
import picocli.CommandLine.Option;
|
||||
import picocli.CommandLine.Spec;
|
||||
|
||||
|
||||
@Command(name = "top",
|
||||
versionProvider = MyVersionProvider.class,
|
||||
resourceBundle = "mybundle5")
|
||||
public class Issue1134 {
|
||||
|
||||
@CommandLine.Option(names = "--level")
|
||||
private String level;
|
||||
|
||||
@Spec
|
||||
CommandSpec spec;
|
||||
}
|
||||
|
||||
class MyVersionProvider implements IVersionProvider {
|
||||
@Spec
|
||||
CommandSpec spec;
|
||||
|
||||
public String[] getVersion() {
|
||||
return new String[] {spec.qualifiedName() + " 1.0"};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
---
|
||||
CommandSpec:
|
||||
name: 'top'
|
||||
aliases: []
|
||||
userObject: picocli.issue1134.Issue1134
|
||||
helpCommand: false
|
||||
defaultValueProvider: null
|
||||
versionProvider: VersionProviderMetaData(picocli.issue1134.MyVersionProvider)
|
||||
version: []
|
||||
ArgGroups: []
|
||||
Options:
|
||||
- names: [--level]
|
||||
usageHelp: false
|
||||
versionHelp: false
|
||||
description: []
|
||||
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: 'null'
|
||||
showDefaultValue: ON_DEMAND
|
||||
hasInitialValue: false
|
||||
initialValue: 'null'
|
||||
paramLabel: '<level>'
|
||||
converters: []
|
||||
completionCandidates: null
|
||||
getter: AnnotatedElementHolder(FIELD level in picocli.issue1134.Issue1134)
|
||||
setter: AnnotatedElementHolder(FIELD level in picocli.issue1134.Issue1134)
|
||||
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: []
|
||||
@@ -33,7 +33,9 @@ import javax.lang.model.type.DeclaredType;
|
||||
import javax.lang.model.type.ExecutableType;
|
||||
import javax.lang.model.type.TypeKind;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
import javax.lang.model.type.TypeVisitor;
|
||||
import javax.lang.model.util.SimpleElementVisitor6;
|
||||
import javax.lang.model.util.TypeKindVisitor6;
|
||||
import javax.lang.model.util.Types;
|
||||
import javax.tools.Diagnostic;
|
||||
import java.io.PrintWriter;
|
||||
@@ -840,7 +842,23 @@ public abstract class AbstractCommandSpecProcessor extends AbstractProcessor {
|
||||
logger.fine("Adding " + entry + " to commandSpec " + commandSpec1);
|
||||
commandSpec1.addSpecElement(entry.getValue());
|
||||
} else {
|
||||
proc.error(entry.getKey(), "@Spec must be enclosed in a @Command, but was %s: %s", entry.getKey().getEnclosingElement(), entry.getKey().getEnclosingElement().getSimpleName());
|
||||
Element enclosingElement = entry.getKey().getEnclosingElement();
|
||||
if (enclosingElement.getKind() == ElementKind.CLASS || enclosingElement.getKind() == ENUM) {
|
||||
TypeMirror typeMirror = enclosingElement.asType();
|
||||
TypeElement typeElement = (TypeElement) ((DeclaredType) typeMirror).asElement();
|
||||
List<? extends TypeMirror> interfaces = typeElement.getInterfaces();
|
||||
boolean valid = false;
|
||||
for (TypeMirror interf : interfaces) {
|
||||
if (interf.toString().equals("picocli.CommandLine.IVersionProvider")) {
|
||||
valid = true;
|
||||
}
|
||||
}
|
||||
if (!valid) {
|
||||
proc.error(entry.getKey(), "@Spec must be enclosed in a @Command, or in a class that implements IVersionProvider but was %s: %s", entry.getKey().getEnclosingElement(), entry.getKey().getEnclosingElement().getSimpleName());
|
||||
}
|
||||
} else {
|
||||
proc.error(entry.getKey(), "@Spec must be enclosed in a @Command, but was %s: %s", entry.getKey().getEnclosingElement(), entry.getKey().getEnclosingElement().getSimpleName());
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Map.Entry<Element, IAnnotatedElement> entry : parentCommandElements.entrySet()) {
|
||||
|
||||
Reference in New Issue
Block a user