diff --git a/src/main/java/picocli/CommandLine.java b/src/main/java/picocli/CommandLine.java index 52db4a8cc..20c529087 100644 --- a/src/main/java/picocli/CommandLine.java +++ b/src/main/java/picocli/CommandLine.java @@ -11447,7 +11447,7 @@ static ArgGroupSpec extractArgGroupSpec(IAnnotatedElement member, IFactory facto boolean hasArgAnnotation = false; while (!hierarchy.isEmpty()) { cls = hierarchy.pop(); - hasArgAnnotation |= initFromAnnotatedFields(scope, cls, commandSpec, builder, factory, null); + hasArgAnnotation |= initFromAnnotatedMembers(scope, cls, commandSpec, builder, factory, null); } ArgGroupSpec result = builder.build(); if (annotationsAreMandatory) {validateArgGroupSpec(result, hasArgAnnotation, cls.getName()); } @@ -11475,20 +11475,19 @@ static CommandSpec extractCommandSpec(Object command, IFactory factory, boolean injectSpecIntoVersionProvider(result, cmd, factory); result.setAddMethodSubcommands(false); // method commands don't have method subcommands hasCommandAnnotation = true; - initSubcommands(cmd, null, result, factory, new Stack>()); // after adding options + initSubcommands(cmd, null, result, factory, Collections.>emptySet()); // after adding options result.mixinStandardHelpOptions(cmd.mixinStandardHelpOptions()); // do this last initFromMethodParameters(userObject, method, result, null, factory); // set command name to method name, unless @Command#name is set result.initName(((Method)command).getName()); } else { - Stack> hierarchy = new Stack>(); Class cls = userObject.getType(); + Stack> hierarchy = new Stack>(); while (cls != null) { hierarchy.add(cls); cls = cls.getSuperclass(); } - @SuppressWarnings("unchecked") - Stack> originalHierarchy = (Stack>) hierarchy.clone(); + Set> fullHierarchySet = new HashSet>(hierarchy); boolean mixinStandardHelpOptions = false; while (!hierarchy.isEmpty()) { cls = hierarchy.pop(); @@ -11499,9 +11498,9 @@ static CommandSpec extractCommandSpec(Object command, IFactory factory, boolean hasCommandAnnotation = true; mixinStandardHelpOptions |= cmd.mixinStandardHelpOptions(); } - initSubcommands(cmd, cls, result, factory, originalHierarchy); // after adding options + initSubcommands(cmd, cls, result, factory, fullHierarchySet); // after adding options initMethodSubcommands(cls, result, factory); // regardless of @Command annotation. NOTE: after adding options - hasCommandAnnotation |= initFromAnnotatedFields(userObject, cls, result, null, factory, null); + hasCommandAnnotation |= initFromAnnotatedMembers(userObject, cls, result, null, factory, null); } result.mixinStandardHelpOptions(mixinStandardHelpOptions); //#377 Standard help options should be added last } @@ -11515,14 +11514,14 @@ static CommandSpec extractCommandSpec(Object command, IFactory factory, boolean private static void injectSpecIntoVersionProvider(CommandSpec result, Command cmd, IFactory factory) { if (result.versionProvider() == null) { return; } - CommandReflection.initFromAnnotatedFields(new ObjectScope(result.versionProvider()), cmd.versionProvider(), result, null, factory, new Predicate() { + initFromAnnotatedMembers(new ObjectScope(result.versionProvider()), cmd.versionProvider(), result, null, factory, new Predicate() { public boolean test(TypedMember tm) { return tm.isSpec() && !(tm.isArgGroup() || tm.isUnmatched() || tm.isMixin() || tm.isOption() || tm.isParameter() || tm.isParentCommand()); } }); } - private static void initSubcommands(Command cmd, Class cls, CommandSpec parent, IFactory factory, Stack> hierarchy) { + private static void initSubcommands(Command cmd, Class cls, CommandSpec parent, IFactory factory, Set> hierarchy) { if (cmd == null) { return; } for (Class sub : cmd.subcommands()) { if (sub.equals(cls)) { @@ -11565,7 +11564,7 @@ private static String subcommandName(Class sub) { } return subCommand.name(); } - private static boolean initFromAnnotatedFields(IScope scope, Class cls, CommandSpec receiver, ArgGroupSpec.Builder groupBuilder, IFactory factory, Predicate predicate) { + private static boolean initFromAnnotatedMembers(IScope scope, Class cls, CommandSpec receiver, ArgGroupSpec.Builder groupBuilder, IFactory factory, Predicate predicate) { boolean result = false; for (Field field : cls.getDeclaredFields()) { result |= initFromAnnotatedTypedMembers(TypedMember.createIfAnnotated(field, scope), predicate, receiver, groupBuilder, factory); @@ -11880,13 +11879,14 @@ static class CommandUserObject implements IScope { private CommandUserObject(Object objectOrClass, IFactory factory) { this.factory = Assert.notNull(factory, "factory"); - type = objectOrClass == null ? null : objectOrClass.getClass(); - instance = objectOrClass; if (objectOrClass instanceof Class) { - type = (Class) objectOrClass; instance = null; - } else if (objectOrClass instanceof Method) { - type = null; // don't mix in options/positional params from outer class @Command + type = (Class) objectOrClass; + } else { + instance = objectOrClass; + type = objectOrClass == null || objectOrClass instanceof Method // don't mix in options/positional params from outer class @Command + ? null + : objectOrClass.getClass(); } } @Override public String toString() {