-
Notifications
You must be signed in to change notification settings - Fork 431
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
#500 Add picocli annotation processor
* add separate module picocli-annotation-processing-tests for testing (com.google.testing.compile:compile-testing requires Java 8) * (API) add ITypeInfo that encapsulated type information available at both runtime and compile time * add RuntimeTypeInfo implementation used at runtime (reflection) * (API) add IAnnotatedElement as public API for method and fields annotated with any picocli annotation * internal class TypedMember now implements IAnnotatedElement * (API) CommandSpec.resourceBundleBaseName() getter and setter * (API) Messages.resourceBundleBaseName() getter * (API) ArgSpec.userObject() getter * (API) made MethodParam public * IGetter/ISetter implementations now have informative toString() methods * removed internal class ArgsReflection
- Loading branch information
Showing
62 changed files
with
7,784 additions
and
355 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
############################################################ | ||
# Default Logging Configuration File | ||
# | ||
# You can use a different file by specifying a filename | ||
# with the java.util.logging.config.file system property. | ||
# For example java -Djava.util.logging.config.file=myfile | ||
############################################################ | ||
|
||
############################################################ | ||
# Global properties | ||
############################################################ | ||
|
||
# "handlers" specifies a comma separated list of log Handler | ||
# classes. These handlers will be installed during VM startup. | ||
# Note that these classes must be on the system classpath. | ||
# By default we only configure a ConsoleHandler, which will only | ||
# show messages at the INFO and above levels. | ||
handlers= java.util.logging.ConsoleHandler | ||
|
||
# To also add the FileHandler, use the following line instead. | ||
#handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler | ||
|
||
# Default global logging level. | ||
# This specifies which kinds of events are logged across | ||
# all loggers. For any given facility this global level | ||
# can be overriden by a facility specific level | ||
# Note that the ConsoleHandler also has a separate level | ||
# setting to limit messages printed to the console. | ||
.level= FINE | ||
|
||
############################################################ | ||
# Handler specific properties. | ||
# Describes specific configuration info for Handlers. | ||
############################################################ | ||
|
||
# default file output is in user's home directory. | ||
java.util.logging.FileHandler.pattern = %h/java%u.log | ||
java.util.logging.FileHandler.limit = 50000 | ||
java.util.logging.FileHandler.count = 1 | ||
java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter | ||
|
||
# Limit the message that are printed on the console to INFO and above. | ||
java.util.logging.ConsoleHandler.level = FINE | ||
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter | ||
|
||
# Example to customize the SimpleFormatter output format | ||
# to print one-line log message like this: | ||
# <level>: <log message> [<date/time>] | ||
# | ||
# java.util.logging.SimpleFormatter.format=%4$s: %5$s [%1$tc]%n | ||
|
||
############################################################ | ||
# Facility specific properties. | ||
# Provides extra control for each logger. | ||
############################################################ | ||
|
||
# For example, set the com.xyz.foo logger to only log SEVERE | ||
# messages: | ||
com.xyz.foo.level = SEVERE |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
plugins { | ||
id 'java' | ||
} | ||
|
||
group 'info.picocli' | ||
description 'Picocli Annotation Processing Tests - Tests Annotation Processors for picocli Annotations.' | ||
version "$projectVersion" | ||
sourceCompatibility = 1.8 | ||
targetCompatibility = 1.8 | ||
|
||
dependencies { | ||
compile rootProject | ||
compile project(':picocli-codegen') | ||
testCompile "junit:junit:$junitVersion", | ||
"com.google.testing.compile:compile-testing:$compileTestingVersion", | ||
files(org.gradle.internal.jvm.Jvm.current().getToolsJar()) // workaround https://github.com/google/compile-testing/issues/102 (and #28) | ||
} | ||
jar { | ||
manifest { | ||
attributes 'Specification-Title': 'Picocli Annotation Processing Tests', | ||
'Specification-Vendor' : 'Remko Popma', | ||
'Specification-Version' : version, | ||
'Implementation-Title' : 'Picocli Annotation Processing Tests', | ||
'Implementation-Vendor' : 'Remko Popma', | ||
'Implementation-Version': version, | ||
'Automatic-Module-Name' : 'info.picocli.annotation.processing.tests' | ||
} | ||
} |
36 changes: 36 additions & 0 deletions
36
...ng-tests/src/main/java/picocli/annotation/processing/tests/CommandSpec2YamlProcessor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package picocli.annotation.processing.tests; | ||
|
||
import picocli.CommandLine.Model.CommandSpec; | ||
import picocli.codegen.annotation.processing.AbstractCommandSpecProcessor; | ||
|
||
import javax.annotation.processing.RoundEnvironment; | ||
import javax.lang.model.element.Element; | ||
import javax.lang.model.element.TypeElement; | ||
import java.io.PrintWriter; | ||
import java.io.StringWriter; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Set; | ||
|
||
|
||
public class CommandSpec2YamlProcessor extends AbstractCommandSpecProcessor { | ||
|
||
public List<String> strings = new ArrayList<String>(); | ||
public Map<Element, CommandSpec> commands; | ||
|
||
@Override | ||
protected boolean handleCommands(Map<Element, CommandSpec> commands, | ||
Set<? extends TypeElement> annotations, | ||
RoundEnvironment roundEnv) { | ||
System.out.println(commands); | ||
this.commands = commands; | ||
CommandSpecYamlPrinter printer = new CommandSpecYamlPrinter(); | ||
for (Map.Entry<Element, CommandSpec> entry : commands.entrySet()) { | ||
StringWriter sw = new StringWriter(); | ||
printer.print(entry.getValue(), new PrintWriter(sw)); | ||
strings.add(sw.toString()); | ||
} | ||
return false; | ||
} | ||
} |
234 changes: 234 additions & 0 deletions
234
...ssing-tests/src/main/java/picocli/annotation/processing/tests/CommandSpecYamlPrinter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,234 @@ | ||
package picocli.annotation.processing.tests; | ||
|
||
import picocli.CommandLine; | ||
import picocli.CommandLine.Command; | ||
import picocli.CommandLine.Model.ArgSpec; | ||
import picocli.CommandLine.Model.CommandSpec; | ||
import picocli.CommandLine.Model.OptionSpec; | ||
import picocli.CommandLine.Model.ParserSpec; | ||
import picocli.CommandLine.Model.PositionalParamSpec; | ||
import picocli.CommandLine.Model.UnmatchedArgsBinding; | ||
import picocli.CommandLine.Model.UsageMessageSpec; | ||
import picocli.CommandLine.Parameters; | ||
|
||
import java.io.PrintWriter; | ||
import java.io.StringWriter; | ||
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
import java.util.Collections; | ||
import java.util.Comparator; | ||
import java.util.Enumeration; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.ResourceBundle; | ||
|
||
/** | ||
* Dumps a {@code CommandSpec} in YAML format. | ||
*/ | ||
public class CommandSpecYamlPrinter { | ||
|
||
public static void main(String... args) { | ||
CommandLine.run(new App(), args); | ||
} | ||
|
||
static void print(Object userObject) { | ||
print(CommandSpec.forAnnotatedObject(userObject)); | ||
} | ||
|
||
static void print(CommandSpec spec) { | ||
StringWriter sw = new StringWriter(); | ||
new CommandSpecYamlPrinter().print(spec, new PrintWriter(sw)); | ||
System.out.println(sw); | ||
} | ||
|
||
public void print(CommandSpec spec, PrintWriter pw) { | ||
pw.println("---"); | ||
printCommandSpec(spec, "CommandSpec:", pw, " ", " "); | ||
} | ||
private void printCommandSpec(CommandSpec spec, String label, PrintWriter pw, | ||
String initialIndent, String indent) { | ||
pw.printf("%s%n", label); | ||
pw.printf("%sname: '%s'%n", initialIndent, spec.name()); | ||
pw.printf("%saliases: %s%n", indent, Arrays.toString(spec.aliases())); | ||
pw.printf("%suserObject: %s%n", indent, spec.userObject()); | ||
pw.printf("%shelpCommand: %s%n", indent, spec.helpCommand()); | ||
pw.printf("%sdefaultValueProvider: %s%n", indent, spec.defaultValueProvider()); | ||
pw.printf("%sversionProvider: %s%n", indent, spec.versionProvider()); | ||
pw.printf("%sversion: %s%n", indent, Arrays.toString(spec.version())); | ||
|
||
List<OptionSpec> options = new ArrayList<OptionSpec>(spec.options()); | ||
Collections.sort(options, new Comparator<OptionSpec>() { | ||
public int compare(OptionSpec o1, OptionSpec o2) { | ||
return o1.shortestName().compareTo(o2.shortestName()); | ||
} | ||
}); | ||
printOptionList(options, pw, indent); | ||
printPositionalList(spec.positionalParameters(), pw, indent); | ||
printUnmatchedArgsBindingList(spec.unmatchedArgsBindings(), pw, indent); | ||
printMixinList(spec.mixins(), pw, indent); | ||
|
||
printUsageMessage(spec.usageMessage(), pw, indent); | ||
printParser(spec.parser(), pw, indent); | ||
printResourceBundle(spec.resourceBundle(), pw, indent); | ||
|
||
printSubcommandList(spec.subcommands(), pw, indent); | ||
} | ||
|
||
private void printResourceBundle(ResourceBundle resourceBundle, PrintWriter pw, String indent) { | ||
if (resourceBundle == null) { | ||
return; | ||
} | ||
pw.printf("%sResourceBundle:%n", indent); | ||
indent += " "; | ||
for (Enumeration<String> keys = resourceBundle.getKeys(); keys.hasMoreElements();) { | ||
String key = keys.nextElement(); | ||
pw.printf("%s%s: '%s'%n", indent, key, resourceBundle.getString(key)); | ||
} | ||
} | ||
|
||
private void printParser(ParserSpec parser, PrintWriter pw, String indent) { | ||
pw.printf("%sParserSpec:%n", indent); | ||
indent += " "; | ||
pw.printf("%sseparator: '%s'%n", indent, parser.separator()); | ||
pw.printf("%sendOfOptionsDelimiter: '%s'%n", indent, parser.endOfOptionsDelimiter()); | ||
pw.printf("%sexpandAtFiles: %s%n", indent, parser.expandAtFiles()); | ||
pw.printf("%satFileCommentChar: '%s'%n", indent, parser.atFileCommentChar()); | ||
pw.printf("%soverwrittenOptionsAllowed: %s%n", indent, parser.overwrittenOptionsAllowed()); | ||
pw.printf("%sunmatchedArgumentsAllowed: %s%n", indent, parser.unmatchedArgumentsAllowed()); | ||
pw.printf("%sunmatchedOptionsArePositionalParams: %s%n", indent, parser.unmatchedOptionsArePositionalParams()); | ||
pw.printf("%sstopAtUnmatched: %s%n", indent, parser.stopAtUnmatched()); | ||
pw.printf("%sstopAtPositional: %s%n", indent, parser.stopAtPositional()); | ||
pw.printf("%sposixClusteredShortOptionsAllowed: %s%n", indent, parser.posixClusteredShortOptionsAllowed()); | ||
pw.printf("%saritySatisfiedByAttachedOptionParam: %s%n", indent, parser.aritySatisfiedByAttachedOptionParam()); | ||
pw.printf("%scaseInsensitiveEnumValuesAllowed: %s%n", indent, parser.caseInsensitiveEnumValuesAllowed()); | ||
pw.printf("%scollectErrors: %s%n", indent, parser.collectErrors()); | ||
pw.printf("%slimitSplit: %s%n", indent, parser.limitSplit()); | ||
pw.printf("%stoggleBooleanFlags: %s%n", indent, parser.toggleBooleanFlags()); | ||
} | ||
|
||
private void printUsageMessage(UsageMessageSpec usageMessage, PrintWriter pw, String indent) { | ||
pw.printf("%sUsageMessageSpec:%n", indent); | ||
indent += " "; | ||
pw.printf("%swidth: %s%n", indent, usageMessage.width()); | ||
pw.printf("%sabbreviateSynopsis: %s%n", indent, usageMessage.abbreviateSynopsis()); | ||
pw.printf("%shidden: %s%n", indent, usageMessage.hidden()); | ||
pw.printf("%sshowDefaultValues: %s%n", indent, usageMessage.showDefaultValues()); | ||
pw.printf("%ssortOptions: %s%n", indent, usageMessage.sortOptions()); | ||
pw.printf("%srequiredOptionMarker: '%s'%n", indent, usageMessage.requiredOptionMarker()); | ||
pw.printf("%sheaderHeading: '%s'%n", indent, usageMessage.headerHeading()); | ||
pw.printf("%sheader: %s%n", indent, Arrays.toString(usageMessage.header())); | ||
pw.printf("%ssynopsisHeading: '%s'%n", indent, usageMessage.synopsisHeading()); | ||
pw.printf("%scustomSynopsis: %s%n", indent, Arrays.toString(usageMessage.customSynopsis())); | ||
pw.printf("%sdescriptionHeading: '%s'%n", indent, usageMessage.descriptionHeading()); | ||
pw.printf("%sdescription: %s%n", indent, Arrays.toString(usageMessage.description())); | ||
pw.printf("%sparameterListHeading: '%s'%n", indent, usageMessage.parameterListHeading()); | ||
pw.printf("%soptionListHeading: '%s'%n", indent, usageMessage.optionListHeading()); | ||
pw.printf("%scommandListHeading: '%s'%n", indent, usageMessage.commandListHeading()); | ||
pw.printf("%sfooterHeading: '%s'%n", indent, usageMessage.footerHeading()); | ||
pw.printf("%sfooter: %s%n", indent, Arrays.toString(usageMessage.footer())); | ||
} | ||
|
||
|
||
private void printUnmatchedArgsBindingList(List<UnmatchedArgsBinding> unmatchedArgsBindings, PrintWriter pw, String indent) { | ||
pw.printf("%sUnmatchedArgsBindings:", indent); | ||
pw.println(unmatchedArgsBindings.isEmpty() ? " []" : ""); | ||
for (UnmatchedArgsBinding unmatched : unmatchedArgsBindings) { | ||
pw.printf("%sgetter: %s%n", indent + "- ", unmatched.getter()); | ||
pw.printf("%ssetter: %s%n", indent + " ", unmatched.setter()); | ||
} | ||
} | ||
|
||
private void printMixinList(Map<String, CommandSpec> mixins, PrintWriter pw, String indent) { | ||
pw.printf("%sMixins:", indent); | ||
pw.println(mixins.isEmpty() ? " []" : ""); | ||
for (Map.Entry<String, CommandSpec> entry : mixins.entrySet()) { | ||
printCommandSpec(entry.getValue(), indent + "# " + entry.getKey(), pw, indent + "- ", indent + " "); | ||
} | ||
} | ||
|
||
private void printSubcommandList(Map<String, CommandLine> subcommands, PrintWriter pw, String indent) { | ||
pw.printf("%sSubcommands:", indent); | ||
pw.println(subcommands.isEmpty() ? " []" : ""); | ||
for (Map.Entry<String, CommandLine> entry : subcommands.entrySet()) { | ||
printCommandSpec(entry.getValue().getCommandSpec(), | ||
indent + "# " + entry.getKey(), pw, indent + "- ", indent + " "); | ||
} | ||
} | ||
|
||
private void printOptionList(List<OptionSpec> options, PrintWriter pw, String indent) { | ||
pw.printf("%sOptions:", indent); | ||
pw.println(options.isEmpty() ? " []" : ""); | ||
for (OptionSpec option : options) { | ||
printOption(option, pw, indent); | ||
} | ||
} | ||
private void printOption(OptionSpec option, PrintWriter pw, String indent) { | ||
pw.printf("%snames: %s%n", indent + "- ", Arrays.toString(option.names())); | ||
indent += " "; | ||
pw.printf("%susageHelp: %s%n", indent, option.usageHelp()); | ||
pw.printf("%sversionHelp: %s%n", indent, option.versionHelp()); | ||
printArg(option, pw, indent); | ||
} | ||
|
||
private void printPositionalList(List<PositionalParamSpec> positionals, PrintWriter pw, String indent) { | ||
pw.printf("%sPositionalParams:", indent); | ||
pw.println(positionals.isEmpty() ? " []" : ""); | ||
for (PositionalParamSpec positional : positionals) { | ||
printPositional(positional, pw, indent); | ||
} | ||
} | ||
private void printPositional(PositionalParamSpec positional, PrintWriter pw, String indent) { | ||
pw.printf("%sindex: %s%n", indent + "- ", positional.index()); | ||
indent += " "; | ||
printArg(positional, pw, indent); | ||
} | ||
private void printArg(ArgSpec arg, PrintWriter pw, String indent) { | ||
pw.printf("%sdescription: %s%n", indent, Arrays.toString(arg.description())); | ||
pw.printf("%sdescriptionKey: '%s'%n", indent, arg.descriptionKey()); | ||
pw.printf("%stypeInfo: %s%n", indent, arg.typeInfo()); | ||
pw.printf("%sarity: %s%n", indent, arg.arity()); | ||
pw.printf("%ssplitRegex: '%s'%n", indent, arg.splitRegex()); | ||
pw.printf("%sinteractive: %s%n", indent, arg.interactive()); | ||
pw.printf("%srequired: %s%n", indent, arg.required()); | ||
pw.printf("%shidden: %s%n", indent, arg.hidden()); | ||
pw.printf("%shideParamSyntax: %s%n", indent, arg.hideParamSyntax()); | ||
pw.printf("%sdefaultValue: '%s'%n", indent, arg.defaultValue()); | ||
pw.printf("%sshowDefaultValue: %s%n", indent, arg.showDefaultValue()); | ||
pw.printf("%shasInitialValue: %s%n", indent, arg.hasInitialValue()); | ||
pw.printf("%sinitialValue: '%s'%n", indent, arg.initialValue()); | ||
pw.printf("%sparamLabel: '%s'%n", indent, arg.paramLabel()); | ||
pw.printf("%sconverters: %s%n", indent, Arrays.toString(arg.converters())); | ||
pw.printf("%scompletionCandidates: %s%n", indent, iter(arg.completionCandidates())); | ||
pw.printf("%sgetter: %s%n", indent, arg.getter()); | ||
pw.printf("%ssetter: %s%n", indent, arg.setter()); | ||
} | ||
|
||
private String iter(Iterable<String> 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(); | ||
} | ||
|
||
@Command(name = "CommandSpecYamlPrinter", mixinStandardHelpOptions = true, | ||
description = "Prints details of a CommandSpec") | ||
private static class App implements Runnable { | ||
|
||
@Parameters(arity = "1..*") | ||
Class<?>[] classes = new Class[0]; | ||
|
||
// @Override (requires Java 6) | ||
public void run() { | ||
for (Class<?> cls : classes) { | ||
StringWriter sw = new StringWriter(); | ||
new CommandSpecYamlPrinter().print(CommandSpec.forAnnotatedObject(cls), new PrintWriter(sw)); | ||
System.out.println(sw); | ||
} | ||
} | ||
} | ||
} |
1 change: 1 addition & 0 deletions
1
...ocessing-tests/src/main/resources/META-INF/services/javax.annotation.processing.Processor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
picocli.annotation.processing.tests.CommandSpec2YamlProcessor |
Oops, something went wrong.