-
Notifications
You must be signed in to change notification settings - Fork 431
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to remove stacktraces on error #663
Comments
Two options I can think of: Option 1. Try-catch try {
CommandLine.run(new MyApp(), args);
} catch (ExecutionException ex) {
System.err.println("Error: " + ex.getMessage());
} Option 2. Custom error handler IExceptionHandler2<Void> handler = new DefaultExceptionHandler<Void>() {
public Void handleExecutionException(ExecutionException ex,
ParseResult parseResult) {
System.err.println("Error: " + ex.getMessage());
return null;
}
}
CommandLine cmd = new CommandLine(new MyApp());
cmd.parseWithHandlers(new RunLast(),
handler, args); |
Hi, We were using the first option :
We are using our own functional exceptions, that prints end user specific messages, and using instance of upon the exception was quite strange. |
Okay, so basically you’re asking, is there a way to avoid our business exception being wrapped in an Let me take a look to see what is possible in upcoming 4.0. |
One idea is for picocli to provide API like the below. The CommandLine cmd = new CommandLine(new App());
try {
cmd.tryExecute(MyException.class, args);
} catch (MyException ex) {
// handle...
} If your application potentially throws multiple business exceptions, your code could look like this: CommandLine cmd = new CommandLine(new App());
try {
cmd.tryExecute(MyException1.class, MyException2.class, args);
} catch (MyException1 ex) {
// handle...
} catch (MyException2 ex) {
// handle...
} catch (ExecutionException other) {
// handle...
} Thoughts? |
Disable stacktraces.
Keep original messages
Let throwing original exceptions
https://github.com/remkop/picocli/blob/master/src/main/java/picocli/CommandLine.java#L1201 |
I'm thinking to have two methods: // CommandLine
/**
* Executes the Runnable, Callable or Method that the CommandLine was constructed with,
* and returns an exit code that the application can use to call `System.exit` with.
*
* This method never throws an exception.
*
* Any exception that occurs during parsing or while executing the business logic
* is mapped to an exit code.
*/
public int execute(String... args) { ... }
/**
* Executes the Runnable, Callable or Method that the CommandLine was constructed with,
* and returns an exit code that the application can use to call `System.exit` with.
*
* Any `ParameterException` that occurs while parsing the user input is mapped to an exit code.
* This can be customized with a custom `IParameterExceptionHandler`.
*
* Any `Exception` that occurs while executing the Runnable, Callable or Method is rethrown.
* (The actual business exception is rethrown, not the picocli wrapper `ExecutionException`.)
* This can be customized with a custom `IExecutionExceptionHandler`.
*
* @throws by default, throws any exception that occurs while executing
* the Runnable, Callable or Method that the CommandLine was constructed with
*/
public int tryExecute(String... args) throws Exception { ... } Thoughts? |
…te` and `tryExecute` methods: configurable convenience methods with improved exit code support. * The new `execute` and `tryExecute` methods are similar to the `run`, `call` and `invoke` methods, but are not static, so they allow parser configuration. * In addition, these methods, in combination with the new `IExitCodeGenerator` and `IExitCodeExceptionMapper` interfaces, offer clean exit code support. * Finally, the `tryExecute` method rethrows any exception thrown from the Runnable, Callable or Method, while `execute` is guaranteed to never throw an exception. * Many variants of the previous `run`, `call` and `invoke` convenience methods are now deprecated in favor of the new `execute` methods. * Many methods on `AbstractHandler` are now deprecated. Still TODO: tests and documentation.
An initial implementation just landed in master. Please check it out if you have a chance. |
I put a working prototype of the above API in master, but I am not entirely happy with it. The prototype has both a It seems simpler to have just one If a business exception occurs, the default behaviour will be to print the stack trace of that business exception (not the In your case, your application is using our own functional exceptions, that prints end user specific messages, so you will want to do something different. To customize, applications can configure an IExecutionExceptionHandler handler = new IExecutionExceptionHandler() {
public int handleExecutionException(ExecutionException execEx, ParseResult parseResult) {
try {
execEx.rethrowCauseIf(Throwable.class); // rethrow the wrapped exception
throw execEx; // in case the ExecutionException had no cause Exception
} catch (SGEx sgex) {
System.err.println(sgex.getMessage());
} catch (Exception exception) {
System.err.println("An internal error has occurred, please contact support.");
System.err.println("Error : " + exception.getMessage());
}
return 9876;
}
}
CommandLine cmd = new CommandLine(new MyApp());
cmd.setExecutionExceptionHandler(handler); // install the custom handler
int exitCode = cmd.execute(args);
System.exit(exitCode); |
Reopening since I’m not happy with the solution I proposed above. |
@nicolasmingo @jrevault I pushed a change to master: The Example: IExecutionExceptionHandler errorHandler = new IExecutionExceptionHandler() {
public int handleExecutionException(Exception ex,
CommandLine commandLine,
ParseResult parseResult) {
//ex.printStackTrace(); // no stack trace
commandLine.getErr().println(ex.getMessage());
commandLine.usage(commandLine.getErr());
return commandLine.getCommandSpec().exitCodeOnExecutionException();
}
};
int exitCode = new CommandLine(new App())
.setExecutionExceptionHandler(errorHandler)
.execute(args); This looks quite a bit cleaner to me than the previous attempt. Thoughts? Note that we have a unique window of opportunity during the 4.0-alpha phase to flesh out API design issues. It will be much harder to change the API after the 4.0 GA release. Please give the above a try and provide feedback. |
Closing this ticket. I'm planning to release 4.0-alpha-3 in the next few days. Feedback welcome! :-) |
@nicolasmingo, @jrevault picocli-4.0-alpha-3 has been released with improved exit code support and exception handling. This is the last alpha! Please take a look and provide feedback if you have a chance. |
I'm trying to use picocli, but when I have a business exception, it is encapsulated inside ExecutionException. A stracktrace is printed out, but I need to have a cleaner error message (without stacktrace). How to do it ?
The text was updated successfully, but these errors were encountered: