-
Notifications
You must be signed in to change notification settings - Fork 440
Description
The annotation processor implemented in #500 can create a CommandSpec
model at compile time.
One use case for an annotation processor like this is to generate source code at compile time that would allow picocli-based applications to run without runtime reflection.
This ticket is to explore some ideas for achieving that.
One idea is to generate code (actually modify an existing annotated class) to implement an interface, where a method in this interface generates a CommandSpec
model. Picocli needs to be modified to not perform reflection when the user object implements this interface, and instead call the interface method to obtain the CommandSpec
.
Example input:
@picocli.codegen.GenerateModel
class App {
@Option(names = "-x")
private int x;
public static void main(String[] args) {
CommandLine cmd = new CommandLine(new App());
cmd.parseArgs(args);
}
}
Example output of annotation processor:
// after annotation processing:
class App implements picocli.CommandLine.Model.ICommandSpecFactory {
@Option(names = "-x")
private int x;
public static void main(String[] args) {
CommandLine cmd = new CommandLine(new AppV1());
cmd.parseArgs(args);
}
// ICommandSpecFactory implementation (generated)
public CommandSpec getCommandSpec() {
CommandSpec result = CommandSpec.wrapWithoutInspection(this);
result.addOption(OptionSpec.builder("-x").type(int.class)
.getter(new IGetter() {
public Object get() {
return App.this.x;
}
})
.setter(new ISetter() {
public Object set(Object newValue) {
Object old = App.this.x;
App.this.x = (Integer) newValue;
return old;
}
})
.build());
// other options
return result;
}
}
Lombok does something similar: it inserts accessor code into an existing class for fields annotated with @Getter
and @Setter
.
The way Lombok does this is by using internal APIs from Javac and the Eclipse compiler.