CmdLineParser: Replace PrefixedOption with AutoAnnotation
This annotation implementation was not following the contract of
Annotation in at least a few ways:
* hashCode and equals were not implemented properly[1]
* null values are not allowed[2]
AutoAnnotation ensures that the implementation meets the contract, and
reduces boilerplate.
(Other Annotation implementations in this class will require further
untangling and are split into separate changes.)
[1] https://docs.oracle.com/javase/8/docs/api/java/lang/annotation/Annotation.html#hashCode--
[2] https://docs.oracle.com/javase/specs/jls/se8/html/jls-9.html#jls-9.7.1
Change-Id: If7b0ddc86f4acd238bf968ce84bfc96fdff09dbb
diff --git a/java/com/google/gerrit/util/cli/BUILD b/java/com/google/gerrit/util/cli/BUILD
index c94fc1d..b9b9bba 100644
--- a/java/com/google/gerrit/util/cli/BUILD
+++ b/java/com/google/gerrit/util/cli/BUILD
@@ -7,6 +7,7 @@
"//java/com/google/gerrit/common:server",
"//lib:args4j",
"//lib:guava",
+ "//lib/auto:auto-value-annotations",
"//lib/flogger:api",
"//lib/guice",
"//lib/guice:guice-assistedinject",
diff --git a/java/com/google/gerrit/util/cli/CmdLineParser.java b/java/com/google/gerrit/util/cli/CmdLineParser.java
index 771451f..73e8d16 100644
--- a/java/com/google/gerrit/util/cli/CmdLineParser.java
+++ b/java/com/google/gerrit/util/cli/CmdLineParser.java
@@ -36,7 +36,9 @@
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.gerrit.util.cli.Localizable.localizable;
+import static java.util.Objects.requireNonNull;
+import com.google.auto.value.AutoAnnotation;
import com.google.common.base.Strings;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
@@ -421,79 +423,37 @@
throw new CmdLineException(parser, localizable("invalid boolean \"%s=%s\""), name, value);
}
- private static class PrefixedOption implements Option {
- private final String prefix;
- private final Option o;
+ private static Option newPrefixedOption(String prefix, Option o) {
+ requireNonNull(prefix);
+ checkArgument(o.name().startsWith("-"), "Option name must start with '-': %s", o);
+ String[] aliases = Arrays.stream(o.aliases()).map(prefix::concat).toArray(String[]::new);
+ return newOption(
+ prefix + o.name(),
+ aliases,
+ o.usage(),
+ o.metaVar(),
+ o.required(),
+ false,
+ o.hidden(),
+ o.handler(),
+ o.depends(),
+ new String[0]);
+ }
- PrefixedOption(String prefix, Option o) {
- this.prefix = prefix;
- checkArgument(o.name().startsWith("-"), "Option name must start with '-': %s", o);
- this.o = o;
- }
-
- @Override
- public String name() {
- return getPrefixedName(prefix, o.name());
- }
-
- @Override
- public String[] aliases() {
- String[] prefixedAliases = new String[o.aliases().length];
- for (int i = 0; i < prefixedAliases.length; i++) {
- prefixedAliases[i] = getPrefixedName(prefix, o.aliases()[i]);
- }
- return prefixedAliases;
- }
-
- @Override
- public String usage() {
- return o.usage();
- }
-
- @Override
- public String metaVar() {
- return o.metaVar();
- }
-
- @Override
- public boolean required() {
- return o.required();
- }
-
- @Override
- public boolean hidden() {
- return o.hidden();
- }
-
- @SuppressWarnings("rawtypes")
- @Override
- public Class<? extends OptionHandler> handler() {
- return o.handler();
- }
-
- @Override
- public String[] depends() {
- return o.depends();
- }
-
- @Override
- public String[] forbids() {
- return null;
- }
-
- @Override
- public boolean help() {
- return false;
- }
-
- @Override
- public Class<? extends Annotation> annotationType() {
- return o.annotationType();
- }
-
- private static String getPrefixedName(String prefix, String name) {
- return prefix + name;
- }
+ @AutoAnnotation
+ private static Option newOption(
+ String name,
+ String[] aliases,
+ String usage,
+ String metaVar,
+ boolean required,
+ boolean help,
+ boolean hidden,
+ Class<? extends OptionHandler> handler,
+ String[] depends,
+ String[] forbids) {
+ return new AutoAnnotation_CmdLineParser_newOption(
+ name, aliases, usage, metaVar, required, help, hidden, handler, depends, forbids);
}
public class MyParser extends org.kohsuke.args4j.CmdLineParser {
@@ -569,7 +529,7 @@
Option o = m.getAnnotation(Option.class);
if (o != null) {
queueOption(
- new PrefixedOption(prefix, o),
+ newPrefixedOption(prefix, o),
new MethodSetter(this, bean, m),
m.getAnnotation(RequiresOptions.class));
}
@@ -578,7 +538,7 @@
Option o = f.getAnnotation(Option.class);
if (o != null) {
queueOption(
- new PrefixedOption(prefix, o),
+ newPrefixedOption(prefix, o),
Setters.create(f, bean),
f.getAnnotation(RequiresOptions.class));
}