diff --git a/modules/client-common/src/main/java/org/apache/ignite/internal/client/proto/ClientMessagePacker.java b/modules/client-common/src/main/java/org/apache/ignite/internal/client/proto/ClientMessagePacker.java index 52ef39b0cbfc..539e14a1f119 100644 --- a/modules/client-common/src/main/java/org/apache/ignite/internal/client/proto/ClientMessagePacker.java +++ b/modules/client-common/src/main/java/org/apache/ignite/internal/client/proto/ClientMessagePacker.java @@ -347,7 +347,7 @@ public void packDouble(double v) { * * @param s the value to be written. */ - public void packString(@Nullable String s) { + public void packString(@Nullable CharSequence s) { assert !closed : "Packer is closed"; if (s == null) { diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/ExceptionUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/util/ExceptionUtils.java index 4969432747e5..85857fd193e6 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/util/ExceptionUtils.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/util/ExceptionUtils.java @@ -30,11 +30,6 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodType; import java.lang.invoke.WrongMethodTypeException; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.sql.SQLException; -import java.util.ArrayList; import java.util.IdentityHashMap; import java.util.List; import java.util.Objects; @@ -58,283 +53,16 @@ */ 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. - * - *

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. - * - *

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 getThrowableList(Throwable throwable) { - List 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 getSuppressedList(@Nullable Throwable t) { - List 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. + * Gets the stack trace as a char sequence. * * @param throwable The {@code Throwable} to be examined. - * @return The nested stack trace, with the root cause first. + * @return The stack trace. */ - 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(); } /** diff --git a/modules/core/src/testFixtures/java/org/apache/ignite/internal/testframework/matchers/CompletableFutureExceptionMatcher.java b/modules/core/src/testFixtures/java/org/apache/ignite/internal/testframework/matchers/CompletableFutureExceptionMatcher.java index 9af265356825..f2e2f7e8e584 100644 --- a/modules/core/src/testFixtures/java/org/apache/ignite/internal/testframework/matchers/CompletableFutureExceptionMatcher.java +++ b/modules/core/src/testFixtures/java/org/apache/ignite/internal/testframework/matchers/CompletableFutureExceptionMatcher.java @@ -120,7 +120,7 @@ protected void describeMismatchSafely(CompletableFuture item, Description mis private static void describeThrowable(Throwable throwable, Description mismatchDescription) { mismatchDescription.appendValue(throwable) .appendText(System.lineSeparator()) - .appendText(ExceptionUtils.getFullStackTrace(throwable)); + .appendText(ExceptionUtils.getFullStackTrace(throwable).toString()); } private boolean matchesWithCause(Throwable e) {