[ https://issues.apache.org/jira/browse/IGNITE-19535?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]
Vyacheslav Koptilin updated IGNITE-19535: ----------------------------------------- Description: For now, it is required that all public exceptions have to have a constructor which accepts trace identifier, error code, error message, and cause: {code:java} InternalException(UUID traceId, int code, String message, Throwable cause) {code} Initially, this requirement came from the following considerations: if you trying to implement sync API over async: {code:java} /** * Returns a future that can be used to extract a result of async computation. * This future can be completed with a {@code CustomException} if computation failed. */ public CompletableFuture<Result> asyncApiCall() {...} /** * Returns a result of sync computation. * @throws CustomException if computation failed. */ public Result syncApiCall() throws CustomException { try { return asyncApiCall().join(); catch (CompletionException e) { throw e.getCause(); // simple solution that is not correct } }{code} Obviously, the user does not expect that `syncApiCall` can throw CompletionException instead of CustomException. The simplest option is throwing `e.getCause()`, but in that case, the end-user will lose a part of the stack trace representing CompletionException (path to the syncApiCall), and he/she will only stay with the `remote` stack trace. So, the implementation should create a new exception that has the same type as `e.getCause` and should throw it. One of the possible solutions is to write a util method that iterates over all predefined constructor signatures, starting from the most specific signature, and tries to create the required type of the exception: {noformat} Exception(UUID traceId, int code, String message, Throwable cause) Exception(UUID traceId, int code, String message) Exception(UUID traceId, int code, Throwable cause) Exception(int code, String message, Throwable cause) Exception(int code, String message) Exception(int code, Throwable cause) Exception(UUID traceId, int code) Exception(String msg, Throwable cause) Exception(int code) Exception(String msg) Exception(Throwable cause) Exception(){noformat} In that case, our example can be modified as follows: {code:java} /** * Returns a result of sync computation. * @throws CustomException if computation failed. */ public Result syncApiCall() throws CustomException { try { return asyncApiCall().join(); catch (CompletionException e) { throw sneakyThrow(createCopyExceptionWithCause(e)); // here we will throw a new exception with the same type } } {code} It seems to me, that this approach should resolve the vast majority of use cases. Unfortunately, both solutions fail when the CustomException does not have any of mentioned constructor signatures: {noformat} public class CustomException extends IgniteException { int[] partitionIds; public CustomException(int[] patrIds) { super(SPECIFICE_ERR, "Failed to map an operation for partitions [partIds=" + partIds + ']); } }{noformat} Such cases should be handled differently. This case will be addressed by a separate ticket. was: For now, it is required that all public exceptions should have a constructor with the following parameters: {code:java} InternalException(UUID traceId, int code, String message, Throwable cause) {code} This requirement looks a bit restrictive. Need to find a way to improve implementation in order to avoid this. > Removing the constraint that all public exceptions should implement the > mandatory constructor Exception(UUID, int, String, Throwable) > ------------------------------------------------------------------------------------------------------------------------------------- > > Key: IGNITE-19535 > URL: https://issues.apache.org/jira/browse/IGNITE-19535 > Project: Ignite > Issue Type: Improvement > Reporter: Vyacheslav Koptilin > Assignee: Vyacheslav Koptilin > Priority: Major > Labels: iep-84, ignite-3 > Fix For: 3.0.0-beta2 > > Time Spent: 10m > Remaining Estimate: 0h > > For now, it is required that all public exceptions have to have a constructor > which accepts trace identifier, error code, error message, and cause: > {code:java} > InternalException(UUID traceId, int code, String message, Throwable cause) > {code} > Initially, this requirement came from the following considerations: if you > trying to implement sync API over async: > {code:java} > /** > * Returns a future that can be used to extract a result of async computation. > * This future can be completed with a {@code CustomException} if computation > failed. > */ > public CompletableFuture<Result> asyncApiCall() {...} > /** > * Returns a result of sync computation. > * @throws CustomException if computation failed. > */ > public Result syncApiCall() throws CustomException { > try { > return asyncApiCall().join(); > catch (CompletionException e) { > throw e.getCause(); // simple solution that is not correct > } > }{code} > Obviously, the user does not expect that `syncApiCall` can throw > CompletionException instead of CustomException. The simplest option is > throwing `e.getCause()`, but in that case, the end-user will lose a part of > the stack trace representing CompletionException (path to the syncApiCall), > and he/she will only stay with the `remote` stack trace. So, the > implementation should create a new exception that has the same type as > `e.getCause` and should throw it. > One of the possible solutions is to write a util method that iterates over > all predefined constructor signatures, starting from the most specific > signature, and tries to create the required type of the exception: > {noformat} > Exception(UUID traceId, int code, String message, Throwable cause) > Exception(UUID traceId, int code, String message) > Exception(UUID traceId, int code, Throwable cause) > Exception(int code, String message, Throwable cause) > Exception(int code, String message) > Exception(int code, Throwable cause) > Exception(UUID traceId, int code) > Exception(String msg, Throwable cause) > Exception(int code) > Exception(String msg) > Exception(Throwable cause) > Exception(){noformat} > In that case, our example can be modified as follows: > {code:java} > /** > * Returns a result of sync computation. > * @throws CustomException if computation failed. > */ > public Result syncApiCall() throws CustomException { > try { > return asyncApiCall().join(); > catch (CompletionException e) { > throw sneakyThrow(createCopyExceptionWithCause(e)); // here we will > throw a new exception with the same type > } > } {code} > > It seems to me, that this approach should resolve the vast majority of use > cases. Unfortunately, both solutions fail when the CustomException does not > have any of mentioned constructor signatures: > {noformat} > public class CustomException extends IgniteException { > int[] partitionIds; > public CustomException(int[] patrIds) { > super(SPECIFICE_ERR, "Failed to map an operation for partitions > [partIds=" + partIds + ']); > } > }{noformat} > Such cases should be handled differently. This case will be addressed by a > separate ticket. -- This message was sent by Atlassian Jira (v8.20.10#820010)