/** Sets the CommandLine constructed with this {@code CommandSpec} model. */ protected CommandSpec commandLine(CommandLine commandLine) { this.commandLine = commandLine; for (CommandSpec mixedInSpec : mixins.values()) { mixedInSpec.commandLine(commandLine); } for (CommandLine sub : commands.values()) { sub.getCommandSpec().parent(this); } return this; }
/** Returns this {@code ParseResult} as a list of {@code CommandLine} objects, one for each matched command/subcommand. * For backwards compatibility with pre-3.0 methods. */ public List<CommandLine> asCommandLineList() { List<CommandLine> result = new ArrayList<CommandLine>(); ParseResult pr = this; while (pr != null) { result.add(pr.commandSpec().commandLine()); pr = pr.hasSubcommand() ? pr.subcommand() : null; } return result; } }
/** Executes the top-level {@code Runnable} or {@code Callable} subcommand. * If the top-level command does not implement either {@code Runnable} or {@code Callable}, an {@code ExecutionException} * is thrown detailing the problem and capturing the offending {@code CommandLine} object. * * @param parseResult the {@code ParseResult} that resulted from successfully parsing the command line arguments * @return an empty list if help was requested, or a list containing a single element: the result of calling the * {@code Callable}, or a {@code null} element if the last (sub)command was a {@code Runnable} * @throws ExecutionException if a problem occurred while processing the parse results; use * {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed * @since 3.0 */ protected List<Object> handle(ParseResult parseResult) throws ExecutionException { return execute(parseResult.commandSpec().commandLine(), new ArrayList<Object>()); // first } @Override protected RunFirst self() { return this; }
/** Registers the specified subcommand with this Help. * @param commandName the name of the subcommand to display in the usage message * @param command the {@code CommandSpec} or {@code @Command} annotated object to get more information from * @return this Help instance (for method chaining) * @deprecated */ @Deprecated public Help addSubcommand(String commandName, Object command) { commands.put(commandName, getHelpFactory().create(CommandSpec.forAnnotatedObject(command, commandSpec.commandLine().factory), defaultColorScheme(Ansi.AUTO))); return this; }
/** Sets the CommandLine constructed with this {@code CommandSpec} model. */ protected CommandSpec commandLine(CommandLine commandLine) { this.commandLine = commandLine; for (CommandSpec mixedInSpec : mixins.values()) { mixedInSpec.commandLine(commandLine); } for (CommandLine sub : commands.values()) { sub.getCommandSpec().parent(this); } return this; }
/** Returns this {@code ParseResult} as a list of {@code CommandLine} objects, one for each matched command/subcommand. * For backwards compatibility with pre-3.0 methods. */ public List<CommandLine> asCommandLineList() { List<CommandLine> result = new ArrayList<CommandLine>(); ParseResult pr = this; while (pr != null) { result.add(pr.commandSpec().commandLine()); pr = pr.hasSubcommand() ? pr.subcommand() : null; } return result; } }
private ParameterException createParameterException(Object value, Throwable t) { CommandLine cmd = spec.commandLine() == null ? new CommandLine(spec) : spec.commandLine(); return new ParameterException(cmd, "Could not invoke " + method + " with " + value, t); } }
/** * Constructs a new {@code CommandLine} interpreter with the specified object (which may be an annotated user object or a {@link CommandSpec CommandSpec}) and object factory. * <p>The specified object may be a {@link CommandSpec CommandSpec} object, or it may be a {@code @Command}-annotated * user object with {@code @Option} and {@code @Parameters}-annotated fields, in which case picocli automatically * constructs a {@code CommandSpec} from this user object. * </p><p> If the specified command object is an interface {@code Class} with {@code @Option} and {@code @Parameters}-annotated methods, * picocli creates a {@link java.lang.reflect.Proxy Proxy} whose methods return the matched command line values. * If the specified command object is a concrete {@code Class}, picocli delegates to the {@linkplain IFactory factory} to get an instance. * </p><p> * When the {@link #parse(String...)} method is called, the {@link CommandSpec CommandSpec} object will be * initialized based on command line arguments. If the commandSpec is created from an annotated user object, this * user object will be initialized based on the command line arguments.</p> * @param command an annotated user object or a {@code CommandSpec} object to initialize from the command line arguments * @param factory the factory used to create instances of {@linkplain Command#subcommands() subcommands}, {@linkplain Option#converter() converters}, etc., that are registered declaratively with annotation attributes * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation * @since 2.2 */ public CommandLine(Object command, IFactory factory) { this.factory = Assert.notNull(factory, "factory"); interpreter = new Interpreter(); commandSpec = CommandSpec.forAnnotatedObject(command, factory); commandSpec.commandLine(this); commandSpec.validate(); if (commandSpec.unmatchedArgsBindings().size() > 0) { setUnmatchedArgumentsAllowed(true); } }
/** Executes the top-level command and all subcommands as {@code Runnable} or {@code Callable}. * If any of the {@code CommandLine} commands does not implement either {@code Runnable} or {@code Callable}, an {@code ExecutionException} * is thrown detailing the problem and capturing the offending {@code CommandLine} object. * * @param parseResult the {@code ParseResult} that resulted from successfully parsing the command line arguments * @return an empty list if help was requested, or a list containing the result of executing all commands: * the return values from calling the {@code Callable} commands, {@code null} elements for commands that implement {@code Runnable} * @throws ExecutionException if a problem occurred while processing the parse results; use * {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed * @since 3.0 */ protected List<Object> handle(ParseResult parseResult) throws ExecutionException { List<Object> result = new ArrayList<Object>(); execute(parseResult.commandSpec().commandLine(), result); while (parseResult.hasSubcommand()) { parseResult = parseResult.subcommand(); execute(parseResult.commandSpec().commandLine(), result); } return returnResultOrExit(result); } @Override protected RunAll self() { return this; }
@Test public void testExceptionHandlingCreatesCommandLineIfNecessary() throws Exception { Method setX = ModelMethodBindingBean.class.getDeclaredMethod("setX", int.class); setX.setAccessible(true); CommandSpec spec = CommandSpec.create(); assertNull(spec.commandLine()); MethodBinding binding = new MethodBinding(null, setX, spec); try { binding.set(41); fail("Expect exception"); } catch (Exception ex) { assertNotNull(spec.commandLine()); // has been set ParameterException pex = (ParameterException) ex; assertSame(pex.getCommandLine(), spec.commandLine()); assertSame(spec, pex.getCommandLine().getCommandSpec()); } } }
@Test public void testExceptionHandlingUsesCommandLineIfAvailable() throws Exception { Method setX = ModelMethodBindingBean.class.getDeclaredMethod("setX", int.class); setX.setAccessible(true); CommandSpec spec = CommandSpec.create(); CommandLine cmd = new CommandLine(spec); spec.commandLine(cmd); MethodBinding binding = new MethodBinding(null, setX, spec); try { binding.set(41); fail("Expect exception"); } catch (Exception ex) { ParameterException pex = (ParameterException) ex; assertSame(cmd, pex.getCommandLine()); } }
public <T> T set(T value) { throw new ParameterException(commandSpec.commandLine(), "RAPTOR error"); } };
public <T> T set(T value) { throw new ParameterException(mixinSpec.commandLine(), "TREX error"); } };
/** * Returns the command that this is a subcommand of, or {@code null} if this is a top-level command. * @return the command that this is a subcommand of, or {@code null} if this is a top-level command * @see #addSubcommand(String, Object) * @see Command#subcommands() * @since 0.9.8 */ public CommandLine getParent() { CommandSpec parent = getCommandSpec().parent(); return parent == null ? null : parent.commandLine(); }
/** Registers the specified subcommand with this Help. * @param commandName the name of the subcommand to display in the usage message * @param command the {@code CommandSpec} or {@code @Command} annotated object to get more information from * @return this Help instance (for method chaining) * @deprecated */ @Deprecated public Help addSubcommand(String commandName, Object command) { commands.put(commandName, getHelpFactory().create(CommandSpec.forAnnotatedObject(command, commandSpec.commandLine().factory), defaultColorScheme(Ansi.AUTO))); return this; }
private ParameterException createParameterException(Object value, Throwable t) { CommandLine cmd = spec.commandLine() == null ? new CommandLine(spec) : spec.commandLine(); return new ParameterException(cmd, "Could not invoke " + method + " with " + value, t); } public String toString() {
@Option(names = "--raptor") void setRaptorFences(final String value) { throw new ParameterException(spec.commandLine(), "RAPTOR error"); } }
@Parameters(index = "1..*") public void setOtherFiles(List<File> otherFiles) { for (File f : otherFiles) { if (!f.exists()) { throw new ParameterException(spec.commandLine(), "File " + f.getAbsolutePath() + " must exist"); } } this.otherFiles = otherFiles; }
@Option(names = "--trex") void setTRexFences(final String value) { throw new ParameterException(spec.commandLine(), "TREX error"); } }
@Option(names = "--minimum") public void setMinimum(int min) { if (min < 0) { throw new ParameterException(spec.commandLine(), "Minimum must be a positive integer"); } minimum = min; }