This is an automated email from the ASF dual-hosted git repository.
ptupitsyn pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
The following commit(s) were added to refs/heads/main by this push:
new a333ed677d8 IGNITE-28310 Optimize
ClientInboundMessageHandler#writeError (#7943)
a333ed677d8 is described below
commit a333ed677d8e03bc734e569399bac1e8485c02f0
Author: Pavel Tupitsyn <[email protected]>
AuthorDate: Wed Apr 8 11:52:25 2026 +0300
IGNITE-28310 Optimize ClientInboundMessageHandler#writeError (#7943)
* Remove legacy stack trace retrieval code, use simple `printStackTrace`
* Remove extra `toString` call, pass `CharSequence` to `ClientMessagePacker`
---
.../internal/client/proto/ClientMessagePacker.java | 2 +-
.../ignite/internal/util/ExceptionUtils.java | 282 +--------------------
.../CompletableFutureExceptionMatcher.java | 2 +-
3 files changed, 7 insertions(+), 279 deletions(-)
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 52ef39b0cbf..539e14a1f11 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 class ClientMessagePacker implements AutoCloseable {
*
* @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 4969432747e..85857fd193e 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.io.StringWriter;
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 @@ import org.jetbrains.annotations.Nullable;
*/
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.
+ * 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 9af26535682..f2e2f7e8e58 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 @@ public class CompletableFutureExceptionMatcher extends
TypeSafeMatcher<Completab
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) {