Copilot commented on code in PR #7943:
URL: https://github.com/apache/ignite-3/pull/7943#discussion_r3045872255
##########
modules/core/src/main/java/org/apache/ignite/internal/util/ExceptionUtils.java:
##########
@@ -57,284 +52,17 @@
* Exception utils.
*/
public final class ExceptionUtils {
- /**
- * The names of methods commonly used to access a wrapped exception.
- */
- private static final String[] CAUSE_METHOD_NAMES = {
- "getCause",
- "getNextException",
- "getTargetException",
- "getException",
- "getSourceException",
- "getRootCause",
- "getCausedByException",
- "getNested",
- "getLinkedException",
- "getNestedException",
- "getLinkedCause",
- "getThrowable"
- };
-
- /**
- * The Method object for Java 1.4 getCause.
- */
- private static final Method THROWABLE_CAUSE_METHOD;
-
- static {
- Method causeMtd;
-
- try {
- causeMtd = Throwable.class.getMethod("getCause", (Class<?>) null);
- } catch (Exception ignored) {
- causeMtd = null;
- }
-
- THROWABLE_CAUSE_METHOD = causeMtd;
- }
-
- /**
- * Introspects the {@code Throwable} to obtain the cause.
- *
- * @param throwable The exception to examine.
- * @return The wrapped exception, or {@code null} if not found.
- */
- @Nullable
- private static Throwable getCauseUsingWellKnownTypes(Throwable throwable) {
- if (throwable instanceof SQLException) {
- return ((SQLException) throwable).getNextException();
- }
-
- if (throwable instanceof InvocationTargetException) {
- return ((InvocationTargetException)
throwable).getTargetException();
- }
-
- return null;
- }
-
- /**
- * Finds a {@code Throwable} by method name.
- *
- * @param throwable The exception to examine.
- * @param mtdName The name of the method to find and invoke.
- * @return The wrapped exception, or {@code null} if not found.
- */
- private static @Nullable Throwable getCauseUsingMethodName(Throwable
throwable, String mtdName) {
- Method mtd = null;
-
- try {
- mtd = throwable.getClass().getMethod(mtdName, (Class<?>) null);
- } catch (NoSuchMethodException | SecurityException ignored) {
- // exception ignored
- }
-
- if (mtd != null &&
Throwable.class.isAssignableFrom(mtd.getReturnType())) {
- try {
- return (Throwable) mtd.invoke(throwable,
ArrayUtils.OBJECT_EMPTY_ARRAY);
- } catch (IllegalAccessException | IllegalArgumentException |
InvocationTargetException ignored) {
- // exception ignored
- }
- }
-
- return null;
- }
-
- /**
- * Finds a {@code Throwable} by field name.
- *
- * @param throwable The exception to examine.
- * @param fieldName The name of the attribute to examine.
- * @return The wrapped exception, or {@code null} if not found.
- */
- private static @Nullable Throwable getCauseUsingFieldName(Throwable
throwable, String fieldName) {
- Field field = null;
-
- try {
- field = throwable.getClass().getField(fieldName);
- } catch (NoSuchFieldException | SecurityException ignored) {
- // exception ignored
- }
-
- if (field != null &&
Throwable.class.isAssignableFrom(field.getType())) {
- try {
- return (Throwable) field.get(throwable);
- } catch (IllegalAccessException | IllegalArgumentException
ignored) {
- // exception ignored
- }
- }
-
- return null;
- }
-
- /**
- * Checks if the Throwable class has a {@code getCause} method.
- *
- * @return True if Throwable is nestable.
- */
- public static boolean isThrowableNested() {
- return THROWABLE_CAUSE_METHOD != null;
- }
-
- /**
- * Checks whether this {@code Throwable} class can store a cause.
- *
- * @param throwable The {@code Throwable} to examine, may be null.
- * @return Boolean {@code true} if nested otherwise {@code false}.
- */
- public static boolean isNestedThrowable(Throwable throwable) {
- if (throwable == null) {
- return false;
- }
-
- if (throwable instanceof SQLException || throwable instanceof
InvocationTargetException) {
- return true;
- }
-
- if (isThrowableNested()) {
- return true;
- }
-
- Class<?> cls = throwable.getClass();
- for (String methodName : CAUSE_METHOD_NAMES) {
- try {
- Method mtd = cls.getMethod(methodName, (Class<?>) null);
-
- if (Throwable.class.isAssignableFrom(mtd.getReturnType())) {
- return true;
- }
- } catch (NoSuchMethodException | SecurityException ignored) {
- // exception ignored
- }
- }
-
- try {
- cls.getField("detail");
-
- return true;
- } catch (NoSuchFieldException | SecurityException ignored) {
- // exception ignored
- }
-
- return false;
- }
-
- /**
- * Introspects the {@code Throwable} to obtain the cause.
- *
- * @param throwable The throwable to introspect for a cause, may be null.
- * @return The cause of the {@code Throwable}, {@code null} if none found
or null throwable input.
- */
- public static @Nullable Throwable getCause(Throwable throwable) {
- return getCause(throwable, CAUSE_METHOD_NAMES);
- }
-
- /**
- * Introspects the {@code Throwable} to obtain the cause.
- *
- * @param throwable The throwable to introspect for a cause, may be null.
- * @param mtdNames The method names, null treated as default set.
- * @return The cause of the {@code Throwable}, {@code null} if none found
or null throwable input.
- */
- @Nullable
- public static Throwable getCause(@Nullable Throwable throwable, String[]
mtdNames) {
- if (throwable == null) {
- return null;
- }
-
- Throwable cause = getCauseUsingWellKnownTypes(throwable);
-
- if (cause == null) {
- if (mtdNames == null) {
- mtdNames = CAUSE_METHOD_NAMES;
- }
-
- for (String mtdName : mtdNames) {
- if (mtdName != null) {
- cause = getCauseUsingMethodName(throwable, mtdName);
-
- if (cause != null) {
- break;
- }
- }
- }
-
- if (cause == null) {
- cause = getCauseUsingFieldName(throwable, "detail");
- }
- }
-
- return cause;
- }
-
- /**
- * Returns the list of {@code Throwable} objects in the exception chain.
- *
- * <p>A throwable without cause will return a list containing one element
- the input throwable. A throwable with one cause
- * will return a list containing two elements - the input throwable and
the cause throwable. A {@code null} throwable will return a list
- * of size zero.
- *
- * <p>This method handles recursive cause structures that might otherwise
cause infinite loops. The cause chain is processed until
- * the end is reached, or until the next item in the chain is already in
the result set.
- *
- * @param throwable The throwable to inspect, may be null.
- * @return The list of throwables, never null.
- */
- public static List<Throwable> getThrowableList(Throwable throwable) {
- List<Throwable> list = new ArrayList<>();
-
- // TODO: https://issues.apache.org/jira/browse/IGNITE-28026
- while (throwable != null && !list.contains(throwable)) {
- list.add(throwable);
- throwable = getCause(throwable);
- }
-
- return list;
- }
-
- /**
- * Collects suppressed exceptions from throwable and all it causes.
- *
- * @param t Throwable.
- * @return List of suppressed throwables.
- */
- public static List<Throwable> getSuppressedList(@Nullable Throwable t) {
- List<Throwable> result = new ArrayList<>();
-
- if (t == null) {
- return result;
- }
-
- // TODO: https://issues.apache.org/jira/browse/IGNITE-28026
- do {
- for (Throwable suppressed : t.getSuppressed()) {
- result.add(suppressed);
-
- result.addAll(getSuppressedList(suppressed));
- }
- } while ((t = t.getCause()) != null);
-
- return result;
- }
-
/**
* A way to get the entire nested stack-trace of an throwable.
Review Comment:
Minor grammar nit in the updated Javadoc: "stack-trace of an throwable"
should be "stack trace of a throwable".
```suggestion
* A way to get the entire nested stack trace of a throwable.
```
##########
modules/core/src/main/java/org/apache/ignite/internal/util/ExceptionUtils.java:
##########
@@ -57,284 +52,17 @@
* Exception utils.
*/
public final class ExceptionUtils {
- /**
- * The names of methods commonly used to access a wrapped exception.
- */
- private static final String[] CAUSE_METHOD_NAMES = {
- "getCause",
- "getNextException",
- "getTargetException",
- "getException",
- "getSourceException",
- "getRootCause",
- "getCausedByException",
- "getNested",
- "getLinkedException",
- "getNestedException",
- "getLinkedCause",
- "getThrowable"
- };
-
- /**
- * The Method object for Java 1.4 getCause.
- */
- private static final Method THROWABLE_CAUSE_METHOD;
-
- static {
- Method causeMtd;
-
- try {
- causeMtd = Throwable.class.getMethod("getCause", (Class<?>) null);
- } catch (Exception ignored) {
- causeMtd = null;
- }
-
- THROWABLE_CAUSE_METHOD = causeMtd;
- }
-
- /**
- * Introspects the {@code Throwable} to obtain the cause.
- *
- * @param throwable The exception to examine.
- * @return The wrapped exception, or {@code null} if not found.
- */
- @Nullable
- private static Throwable getCauseUsingWellKnownTypes(Throwable throwable) {
- if (throwable instanceof SQLException) {
- return ((SQLException) throwable).getNextException();
- }
-
- if (throwable instanceof InvocationTargetException) {
- return ((InvocationTargetException)
throwable).getTargetException();
- }
-
- return null;
- }
-
- /**
- * Finds a {@code Throwable} by method name.
- *
- * @param throwable The exception to examine.
- * @param mtdName The name of the method to find and invoke.
- * @return The wrapped exception, or {@code null} if not found.
- */
- private static @Nullable Throwable getCauseUsingMethodName(Throwable
throwable, String mtdName) {
- Method mtd = null;
-
- try {
- mtd = throwable.getClass().getMethod(mtdName, (Class<?>) null);
- } catch (NoSuchMethodException | SecurityException ignored) {
- // exception ignored
- }
-
- if (mtd != null &&
Throwable.class.isAssignableFrom(mtd.getReturnType())) {
- try {
- return (Throwable) mtd.invoke(throwable,
ArrayUtils.OBJECT_EMPTY_ARRAY);
- } catch (IllegalAccessException | IllegalArgumentException |
InvocationTargetException ignored) {
- // exception ignored
- }
- }
-
- return null;
- }
-
- /**
- * Finds a {@code Throwable} by field name.
- *
- * @param throwable The exception to examine.
- * @param fieldName The name of the attribute to examine.
- * @return The wrapped exception, or {@code null} if not found.
- */
- private static @Nullable Throwable getCauseUsingFieldName(Throwable
throwable, String fieldName) {
- Field field = null;
-
- try {
- field = throwable.getClass().getField(fieldName);
- } catch (NoSuchFieldException | SecurityException ignored) {
- // exception ignored
- }
-
- if (field != null &&
Throwable.class.isAssignableFrom(field.getType())) {
- try {
- return (Throwable) field.get(throwable);
- } catch (IllegalAccessException | IllegalArgumentException
ignored) {
- // exception ignored
- }
- }
-
- return null;
- }
-
- /**
- * Checks if the Throwable class has a {@code getCause} method.
- *
- * @return True if Throwable is nestable.
- */
- public static boolean isThrowableNested() {
- return THROWABLE_CAUSE_METHOD != null;
- }
-
- /**
- * Checks whether this {@code Throwable} class can store a cause.
- *
- * @param throwable The {@code Throwable} to examine, may be null.
- * @return Boolean {@code true} if nested otherwise {@code false}.
- */
- public static boolean isNestedThrowable(Throwable throwable) {
- if (throwable == null) {
- return false;
- }
-
- if (throwable instanceof SQLException || throwable instanceof
InvocationTargetException) {
- return true;
- }
-
- if (isThrowableNested()) {
- return true;
- }
-
- Class<?> cls = throwable.getClass();
- for (String methodName : CAUSE_METHOD_NAMES) {
- try {
- Method mtd = cls.getMethod(methodName, (Class<?>) null);
-
- if (Throwable.class.isAssignableFrom(mtd.getReturnType())) {
- return true;
- }
- } catch (NoSuchMethodException | SecurityException ignored) {
- // exception ignored
- }
- }
-
- try {
- cls.getField("detail");
-
- return true;
- } catch (NoSuchFieldException | SecurityException ignored) {
- // exception ignored
- }
-
- return false;
- }
-
- /**
- * Introspects the {@code Throwable} to obtain the cause.
- *
- * @param throwable The throwable to introspect for a cause, may be null.
- * @return The cause of the {@code Throwable}, {@code null} if none found
or null throwable input.
- */
- public static @Nullable Throwable getCause(Throwable throwable) {
- return getCause(throwable, CAUSE_METHOD_NAMES);
- }
-
- /**
- * Introspects the {@code Throwable} to obtain the cause.
- *
- * @param throwable The throwable to introspect for a cause, may be null.
- * @param mtdNames The method names, null treated as default set.
- * @return The cause of the {@code Throwable}, {@code null} if none found
or null throwable input.
- */
- @Nullable
- public static Throwable getCause(@Nullable Throwable throwable, String[]
mtdNames) {
- if (throwable == null) {
- return null;
- }
-
- Throwable cause = getCauseUsingWellKnownTypes(throwable);
-
- if (cause == null) {
- if (mtdNames == null) {
- mtdNames = CAUSE_METHOD_NAMES;
- }
-
- for (String mtdName : mtdNames) {
- if (mtdName != null) {
- cause = getCauseUsingMethodName(throwable, mtdName);
-
- if (cause != null) {
- break;
- }
- }
- }
-
- if (cause == null) {
- cause = getCauseUsingFieldName(throwable, "detail");
- }
- }
-
- return cause;
- }
-
- /**
- * Returns the list of {@code Throwable} objects in the exception chain.
- *
- * <p>A throwable without cause will return a list containing one element
- the input throwable. A throwable with one cause
- * will return a list containing two elements - the input throwable and
the cause throwable. A {@code null} throwable will return a list
- * of size zero.
- *
- * <p>This method handles recursive cause structures that might otherwise
cause infinite loops. The cause chain is processed until
- * the end is reached, or until the next item in the chain is already in
the result set.
- *
- * @param throwable The throwable to inspect, may be null.
- * @return The list of throwables, never null.
- */
- public static List<Throwable> getThrowableList(Throwable throwable) {
- List<Throwable> list = new ArrayList<>();
-
- // TODO: https://issues.apache.org/jira/browse/IGNITE-28026
- while (throwable != null && !list.contains(throwable)) {
- list.add(throwable);
- throwable = getCause(throwable);
- }
-
- return list;
- }
-
- /**
- * Collects suppressed exceptions from throwable and all it causes.
- *
- * @param t Throwable.
- * @return List of suppressed throwables.
- */
- public static List<Throwable> getSuppressedList(@Nullable Throwable t) {
- List<Throwable> result = new ArrayList<>();
-
- if (t == null) {
- return result;
- }
-
- // TODO: https://issues.apache.org/jira/browse/IGNITE-28026
- do {
- for (Throwable suppressed : t.getSuppressed()) {
- result.add(suppressed);
-
- result.addAll(getSuppressedList(suppressed));
- }
- } while ((t = t.getCause()) != null);
-
- return result;
- }
-
/**
* A way to get the entire nested stack-trace of an throwable.
*
* @param throwable The {@code Throwable} to be examined.
* @return The nested stack trace, with the root cause first.
*/
- public static String getFullStackTrace(Throwable throwable) {
+ public static CharSequence getFullStackTrace(Throwable throwable) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw, true);
- var ts = getThrowableList(throwable);
-
- for (Throwable t : ts) {
- t.printStackTrace(pw);
-
- if (isNestedThrowable(t)) {
- break;
- }
- }
-
- return sw.getBuffer().toString();
+ throwable.printStackTrace(pw);
+ return sw.getBuffer();
Review Comment:
`getFullStackTrace` now returns `sw.getBuffer()` which exposes a mutable
`StringBuffer` to callers. If callers retain the returned `CharSequence`, they
can observe or introduce later mutations; consider returning an immutable
snapshot (e.g., `sw.toString()`) or documenting the mutability contract
explicitly.
```suggestion
return sw.toString();
```
##########
modules/core/src/main/java/org/apache/ignite/internal/util/ExceptionUtils.java:
##########
@@ -57,284 +52,17 @@
* Exception utils.
*/
public final class ExceptionUtils {
- /**
- * The names of methods commonly used to access a wrapped exception.
- */
- private static final String[] CAUSE_METHOD_NAMES = {
- "getCause",
- "getNextException",
- "getTargetException",
- "getException",
- "getSourceException",
- "getRootCause",
- "getCausedByException",
- "getNested",
- "getLinkedException",
- "getNestedException",
- "getLinkedCause",
- "getThrowable"
- };
-
- /**
- * The Method object for Java 1.4 getCause.
- */
- private static final Method THROWABLE_CAUSE_METHOD;
-
- static {
- Method causeMtd;
-
- try {
- causeMtd = Throwable.class.getMethod("getCause", (Class<?>) null);
- } catch (Exception ignored) {
- causeMtd = null;
- }
-
- THROWABLE_CAUSE_METHOD = causeMtd;
- }
-
- /**
- * Introspects the {@code Throwable} to obtain the cause.
- *
- * @param throwable The exception to examine.
- * @return The wrapped exception, or {@code null} if not found.
- */
- @Nullable
- private static Throwable getCauseUsingWellKnownTypes(Throwable throwable) {
- if (throwable instanceof SQLException) {
- return ((SQLException) throwable).getNextException();
- }
-
- if (throwable instanceof InvocationTargetException) {
- return ((InvocationTargetException)
throwable).getTargetException();
- }
-
- return null;
- }
-
- /**
- * Finds a {@code Throwable} by method name.
- *
- * @param throwable The exception to examine.
- * @param mtdName The name of the method to find and invoke.
- * @return The wrapped exception, or {@code null} if not found.
- */
- private static @Nullable Throwable getCauseUsingMethodName(Throwable
throwable, String mtdName) {
- Method mtd = null;
-
- try {
- mtd = throwable.getClass().getMethod(mtdName, (Class<?>) null);
- } catch (NoSuchMethodException | SecurityException ignored) {
- // exception ignored
- }
-
- if (mtd != null &&
Throwable.class.isAssignableFrom(mtd.getReturnType())) {
- try {
- return (Throwable) mtd.invoke(throwable,
ArrayUtils.OBJECT_EMPTY_ARRAY);
- } catch (IllegalAccessException | IllegalArgumentException |
InvocationTargetException ignored) {
- // exception ignored
- }
- }
-
- return null;
- }
-
- /**
- * Finds a {@code Throwable} by field name.
- *
- * @param throwable The exception to examine.
- * @param fieldName The name of the attribute to examine.
- * @return The wrapped exception, or {@code null} if not found.
- */
- private static @Nullable Throwable getCauseUsingFieldName(Throwable
throwable, String fieldName) {
- Field field = null;
-
- try {
- field = throwable.getClass().getField(fieldName);
- } catch (NoSuchFieldException | SecurityException ignored) {
- // exception ignored
- }
-
- if (field != null &&
Throwable.class.isAssignableFrom(field.getType())) {
- try {
- return (Throwable) field.get(throwable);
- } catch (IllegalAccessException | IllegalArgumentException
ignored) {
- // exception ignored
- }
- }
-
- return null;
- }
-
- /**
- * Checks if the Throwable class has a {@code getCause} method.
- *
- * @return True if Throwable is nestable.
- */
- public static boolean isThrowableNested() {
- return THROWABLE_CAUSE_METHOD != null;
- }
-
- /**
- * Checks whether this {@code Throwable} class can store a cause.
- *
- * @param throwable The {@code Throwable} to examine, may be null.
- * @return Boolean {@code true} if nested otherwise {@code false}.
- */
- public static boolean isNestedThrowable(Throwable throwable) {
- if (throwable == null) {
- return false;
- }
-
- if (throwable instanceof SQLException || throwable instanceof
InvocationTargetException) {
- return true;
- }
-
- if (isThrowableNested()) {
- return true;
- }
-
- Class<?> cls = throwable.getClass();
- for (String methodName : CAUSE_METHOD_NAMES) {
- try {
- Method mtd = cls.getMethod(methodName, (Class<?>) null);
-
- if (Throwable.class.isAssignableFrom(mtd.getReturnType())) {
- return true;
- }
- } catch (NoSuchMethodException | SecurityException ignored) {
- // exception ignored
- }
- }
-
- try {
- cls.getField("detail");
-
- return true;
- } catch (NoSuchFieldException | SecurityException ignored) {
- // exception ignored
- }
-
- return false;
- }
-
- /**
- * Introspects the {@code Throwable} to obtain the cause.
- *
- * @param throwable The throwable to introspect for a cause, may be null.
- * @return The cause of the {@code Throwable}, {@code null} if none found
or null throwable input.
- */
- public static @Nullable Throwable getCause(Throwable throwable) {
- return getCause(throwable, CAUSE_METHOD_NAMES);
- }
-
- /**
- * Introspects the {@code Throwable} to obtain the cause.
- *
- * @param throwable The throwable to introspect for a cause, may be null.
- * @param mtdNames The method names, null treated as default set.
- * @return The cause of the {@code Throwable}, {@code null} if none found
or null throwable input.
- */
- @Nullable
- public static Throwable getCause(@Nullable Throwable throwable, String[]
mtdNames) {
- if (throwable == null) {
- return null;
- }
-
- Throwable cause = getCauseUsingWellKnownTypes(throwable);
-
- if (cause == null) {
- if (mtdNames == null) {
- mtdNames = CAUSE_METHOD_NAMES;
- }
-
- for (String mtdName : mtdNames) {
- if (mtdName != null) {
- cause = getCauseUsingMethodName(throwable, mtdName);
-
- if (cause != null) {
- break;
- }
- }
- }
-
- if (cause == null) {
- cause = getCauseUsingFieldName(throwable, "detail");
- }
- }
-
- return cause;
- }
-
- /**
- * Returns the list of {@code Throwable} objects in the exception chain.
- *
- * <p>A throwable without cause will return a list containing one element
- the input throwable. A throwable with one cause
- * will return a list containing two elements - the input throwable and
the cause throwable. A {@code null} throwable will return a list
- * of size zero.
- *
- * <p>This method handles recursive cause structures that might otherwise
cause infinite loops. The cause chain is processed until
- * the end is reached, or until the next item in the chain is already in
the result set.
- *
- * @param throwable The throwable to inspect, may be null.
- * @return The list of throwables, never null.
- */
- public static List<Throwable> getThrowableList(Throwable throwable) {
- List<Throwable> list = new ArrayList<>();
-
- // TODO: https://issues.apache.org/jira/browse/IGNITE-28026
- while (throwable != null && !list.contains(throwable)) {
- list.add(throwable);
- throwable = getCause(throwable);
- }
-
- return list;
- }
-
- /**
- * Collects suppressed exceptions from throwable and all it causes.
- *
- * @param t Throwable.
- * @return List of suppressed throwables.
- */
- public static List<Throwable> getSuppressedList(@Nullable Throwable t) {
- List<Throwable> result = new ArrayList<>();
-
- if (t == null) {
- return result;
- }
-
- // TODO: https://issues.apache.org/jira/browse/IGNITE-28026
- do {
- for (Throwable suppressed : t.getSuppressed()) {
- result.add(suppressed);
-
- result.addAll(getSuppressedList(suppressed));
- }
- } while ((t = t.getCause()) != null);
-
- return result;
- }
-
/**
* A way to get the entire nested stack-trace of an throwable.
*
* @param throwable The {@code Throwable} to be examined.
* @return The nested stack trace, with the root cause first.
*/
- public static String getFullStackTrace(Throwable throwable) {
+ public static CharSequence getFullStackTrace(Throwable throwable) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw, true);
- var ts = getThrowableList(throwable);
-
- for (Throwable t : ts) {
- t.printStackTrace(pw);
-
- if (isNestedThrowable(t)) {
- break;
- }
- }
-
- return sw.getBuffer().toString();
+ throwable.printStackTrace(pw);
+ return sw.getBuffer();
Review Comment:
The Javadoc says the returned stack trace is "with the root cause first",
but `Throwable#printStackTrace` prints the top-level exception first and the
root cause last. Please update the Javadoc to match the actual ordering (or
adjust the implementation if root-cause-first output is required).
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]