diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index 02fb09eff..219cd2dde 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -39,6 +39,7 @@ Artifacts in this release are signed by Remko Popma (6601 E5C0 8DCC BB96). * [#2053] [#2175] CLEAN: Remove unused extra format arguments. Thanks to [Michael Vorburger](https://github.com/vorburger) for the pull request. * [#2171] DOC: Fix a few typos in CommandLine's JavaDoc. Thanks to [Michael Vorburger](https://github.com/vorburger) for the pull request. * [#2217] DOC: Clarify documentation for negatable options. Thanks to [dbear496](https://github.com/dbear496) for raising this. +* [#2228] DOC: Clarify that `ParseResult` passed to `IExecutionExceptionHandler` is the top-level parse result, not the parse result of the subcommand that failed. Thanks to [Abel Salgado Romero](https://github.com/abelsromero) for raising this. * [#2047] DEP: Bump andymckay/append-gist-action from 1fbfbbce708a39bd45846f0955ed5521f2099c6d to 6e8d64427fe47cbacf4ab6b890411f1d67c07f3e * [#2091] DEP: Bump actions/checkout from 3.5.2 to 3.6.0 * [#2108] DEP: Bump actions/checkout from 3.6.0 to 4.0.0 diff --git a/src/main/java/picocli/CommandLine.java b/src/main/java/picocli/CommandLine.java index 4b814b64f..1b440895f 100644 --- a/src/main/java/picocli/CommandLine.java +++ b/src/main/java/picocli/CommandLine.java @@ -1775,10 +1775,14 @@ public interface IExecutionExceptionHandler { * {@code Callable} command and returns an exit code suitable for returning from {@link #execute(String...)}. * @param ex the Exception thrown by the {@code Runnable}, {@code Callable} or {@code Method} user object of the command * @param commandLine the CommandLine representing the command or subcommand where the exception occurred - * @param parseResult the result of parsing the command line arguments + * @param fullParseResult the result of parsing the command line arguments. + * This is the ParseResult of the top-level command. + * Note that if the exception occurred in a subcommand, you may want to inspect the ParseResult of + * the subcommand that threw the exception, which can be obtained by calling {@code commandLine.getParseResult()} + * on the CommandLine object passed to this method. * @return an exit code */ - int handleExecutionException(Exception ex, CommandLine commandLine, ParseResult parseResult) throws Exception; + int handleExecutionException(Exception ex, CommandLine commandLine, ParseResult fullParseResult) throws Exception; } /** Abstract superclass for {@link IParseResultHandler2} and {@link IExceptionHandler2} implementations. diff --git a/src/test/java/picocli/Issue2228.java b/src/test/java/picocli/Issue2228.java index 65ce0936e..6942b6d77 100644 --- a/src/test/java/picocli/Issue2228.java +++ b/src/test/java/picocli/Issue2228.java @@ -9,14 +9,18 @@ public class Issue2228 { - @Command - static class TestCommand implements Runnable { + @Command(subcommands = Issue2228.SubCommand.class) + static class TestCommand { + } + + @Command(name = "subsub") + static class SubCommand implements Runnable { - @Option(names = "-x") - public boolean x; + @Option(names = "-y") + public boolean y; public void run() { - throw new IllegalStateException("failing, just for fun"); + throw new IllegalStateException("Y failing, just for fun"); } } @@ -25,23 +29,25 @@ public void testParseResult() { final CommandLine commandLine = new CommandLine(new Issue2228.TestCommand()); final boolean[] handled = new boolean[] {false}; commandLine.setExecutionExceptionHandler(new CommandLine.IExecutionExceptionHandler() { - public int handleExecutionException(Exception ex, CommandLine exCmdLine, ParseResult parseResult) throws Exception { + public int handleExecutionException(Exception ex, CommandLine exCmdLine, ParseResult fullParseResult) throws Exception { handled[0] = true; - assertSame(commandLine, exCmdLine); - ParseResult after = commandLine.getParseResult(); - printParseResult(after, "commandLine.getParseResult()"); - assertFalse(after.matchedArgs().isEmpty()); - assertFalse(after.matchedOptions().isEmpty()); + ParseResult subResult = commandLine.getSubcommands().get("subsub").getParseResult(); + //printParseResult(subResult, "subsub subcommand"); + assertFalse(subResult.matchedArgs().isEmpty()); + assertFalse(subResult.matchedOptions().isEmpty()); + + //printParseResult(fullParseResult, "ExecutionExceptionHandler method arg"); + assertNotNull(fullParseResult); + assertFalse(fullParseResult.subcommand().matchedArgs().isEmpty()); + assertFalse(fullParseResult.subcommand().matchedOptions().isEmpty()); - printParseResult(parseResult, "ExecutionExceptionHandler method arg"); - assertNotNull(parseResult); - assertFalse(parseResult.matchedArgs().isEmpty()); - assertFalse(parseResult.matchedOptions().isEmpty()); + assertTrue(fullParseResult.matchedArgs().isEmpty()); + assertTrue(fullParseResult.matchedOptions().isEmpty()); return 0; } }); - commandLine.execute("-x"); + commandLine.execute("subsub", "-y"); assertTrue("ExecutionExceptionHandler tests were executed", handled[0]); }