diff --git a/build.sh b/build.sh
index da1d0bd..e326905 100755
--- a/build.sh
+++ b/build.sh
@@ -18,7 +18,7 @@ compile() {
}
format() {
- mvn formatter:format
+ mvn spotless:apply
errcheck $?
}
diff --git a/pom.xml b/pom.xml
index 871bcbc..7b7cb94 100644
--- a/pom.xml
+++ b/pom.xml
@@ -157,9 +157,14 @@
- * This class has a field which indicates a reason for this exception. Typically the type of this field is - * {@link Record}. In this case, the class name of this record represents the reason, and the fields of the record hold - * the situation where the exception occurred. - *
- * Optionally, this exception class can notify its instance creation to pre-registered exception handlers. This - * notification feature can be enabled by specifying the system property {@code -Dgithub.sttk.errs.notify=true} when the - * JVM is started. - *
- * The example code of creating and throwing an excepton is as follows: + * + *
This class has a field which indicates a reason for this exception. Typically the type of this + * field is {@link Record}. In this case, the class name of this record represents the reason, and + * the fields of the record hold the situation where the exception occurred. + * + *
Optionally, this exception class can notify its instance creation to pre-registered exception + * handlers. This notification feature can be enabled by specifying the system property {@code + * -Dgithub.sttk.errs.notify=true} when the JVM is started. + * + *
The example code of creating and throwing an excepton is as follows: * *
{@code
* public record FailToDoSomething(String name, int value) {
@@ -41,273 +41,261 @@
*/
public final class Exc extends Exception {
- /** The serial version UID. */
- private static final long serialVersionUID = 260427082865587554L;
-
- /** The reason for this exception. */
- private transient Object reason;
+ /** The serial version UID. */
+ private static final long serialVersionUID = 260427082865587554L;
- /** The stack trace for the location of occurrence. */
- private StackTraceElement trace;
+ /** The reason for this exception. */
+ private transient Object reason;
- /**
- * Is the constructor which takes an object indicating the reason for this exception.
- *
- * @param reason
- * A reason for this exception.
- */
- public Exc(final Object reason) {
- if (reason == null) {
- throw new IllegalArgumentException("reason is null");
- }
- this.reason = reason;
+ /** The stack trace for the location of occurrence. */
+ private StackTraceElement trace;
- this.trace = getStackTrace()[0];
-
- notifyExc(this);
+ /**
+ * Is the constructor which takes an object indicating the reason for this exception.
+ *
+ * @param reason A reason for this exception.
+ */
+ public Exc(final Object reason) {
+ if (reason == null) {
+ throw new IllegalArgumentException("reason is null");
}
-
- /**
- * Is the constructor which takes an object indicating the reason and {@link Throwable} object indicating the cause
- * for this exception.
- *
- * @param reason
- * A reason for this exception.
- * @param cause
- * A cause for this exception.
- */
- @SuppressWarnings("this-escape")
- public Exc(final Object reason, final Throwable cause) {
- super(cause);
-
- if (reason == null) {
- throw new IllegalArgumentException("reason is null");
- }
- this.reason = reason;
-
- this.trace = getStackTrace()[0];
-
- notifyExc(this);
+ this.reason = reason;
+
+ this.trace = getStackTrace()[0];
+
+ notifyExc(this);
+ }
+
+ /**
+ * Is the constructor which takes an object indicating the reason and {@link Throwable} object
+ * indicating the cause for this exception.
+ *
+ * @param reason A reason for this exception.
+ * @param cause A cause for this exception.
+ */
+ @SuppressWarnings("this-escape")
+ public Exc(final Object reason, final Throwable cause) {
+ super(cause);
+
+ if (reason == null) {
+ throw new IllegalArgumentException("reason is null");
}
-
- /**
- * Gets the reason for this exception. The type of the reason.
- *
- * @return The reason for this exception.
- */
- public Object getReason() {
- return this.reason;
+ this.reason = reason;
+
+ this.trace = getStackTrace()[0];
+
+ notifyExc(this);
+ }
+
+ /**
+ * Gets the reason for this exception. The type of the reason.
+ *
+ * @return The reason for this exception.
+ */
+ public Object getReason() {
+ return this.reason;
+ }
+
+ /**
+ * Returns the message of this exception, that is the reason.
+ *
+ * @return The message of this exception.
+ */
+ @Override
+ public String getMessage() {
+ return reason.toString();
+ }
+
+ /**
+ * Returns the detail message of this exception, that contains the reason, source file name, line
+ * number, and the cause if provided.
+ *
+ * @return The message of this exception.
+ */
+ @Override
+ public String toString() {
+ var buf = new StringBuilder(getClass().getName());
+ buf.append(" { reason = ")
+ .append(reason.getClass().getName())
+ .append(" ")
+ .append(reason.toString());
+ buf.append(", file = ").append(this.trace.getFileName());
+ buf.append(", line = ").append(this.trace.getLineNumber());
+ if (getCause() != null) {
+ buf.append(", cause = ").append(getCause().toString());
}
-
- /**
- * Returns the message of this exception, that is the reason.
- *
- * @return The message of this exception.
- */
- @Override
- public String getMessage() {
- return reason.toString();
+ return buf.append(" }").toString();
+ }
+
+ /**
+ * Returns the name of the source file of this exception occurrance.
+ *
+ * This method can return null if this information is unavailable.
+ *
+ * @return The name of the source file of this error occurrence.
+ */
+ public String getFile() {
+ return this.trace.getFileName();
+ }
+
+ /**
+ * Returns the line number of this exception occurrance in the source file.
+ *
+ *
This method can return a negative number if this information is unavailable.
+ *
+ * @return The line number of this exception occurrance in the source file.
+ */
+ public int getLine() {
+ return this.trace.getLineNumber();
+ }
+
+ /**
+ * Creates a {@link RuntimeException} object for methods that cannot throw a {@link Exc}.
+ *
+ * @return A {@link RuntimeException} object.
+ */
+ public RuntimeException toRuntimeException() {
+ return new RuntimeExc(this);
+ }
+
+ /**
+ * Writes a serial data of this exception to a stream.
+ *
+ *
Since a reason object is not necessarily serializable, this method will throw a {@link
+ * NotSerializableException} if the {@code reason} field does not inherit {@link Serializable}.
+ *
+ * @param out An {@link ObjectOutputStream} to which data is written.
+ * @throws IOException if an I/O error occurs.
+ */
+ private void writeObject(ObjectOutputStream out) throws IOException {
+ if (!(this.reason instanceof Serializable)) {
+ throw new NotSerializableException(this.reason.getClass().getName());
}
-
- /**
- * Returns the detail message of this exception, that contains the reason, source file name, line number, and the
- * cause if provided.
- *
- * @return The message of this exception.
- */
- @Override
- public String toString() {
- var buf = new StringBuilder(getClass().getName());
- buf.append(" { reason = ").append(reason.getClass().getName()).append(" ").append(reason.toString());
- buf.append(", file = ").append(this.trace.getFileName());
- buf.append(", line = ").append(this.trace.getLineNumber());
- if (getCause() != null) {
- buf.append(", cause = ").append(getCause().toString());
- }
- return buf.append(" }").toString();
+ out.defaultWriteObject();
+ out.writeObject(this.reason);
+ }
+
+ /**
+ * Reconstitutes the {@code Exc} instance from a stream and initialize the reason and cause
+ * properties when deserializing. If the reason by deserialization is null, this method throws
+ * {@link InvalidObjectException}.
+ *
+ * @param in An {@link ObjectInputStream} from which data is read.
+ * @throws IOException if an I/O error occurs.
+ * @throws ClassNotFoundException if a serialized class cannot be loaded.
+ */
+ private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException {
+ in.defaultReadObject();
+ this.reason = in.readObject();
+
+ if (this.reason == null) {
+ throw new InvalidObjectException("reason is null or invalid.");
}
+ }
- /**
- * Returns the name of the source file of this exception occurrance.
- *
- * This method can return null if this information is unavailable.
- *
- * @return The name of the source file of this error occurrence.
- */
- public String getFile() {
- return this.trace.getFileName();
- }
+ //// Notification ////
- /**
- * Returns the line number of this exception occurrance in the source file.
- *
- * This method can return a negative number if this information is unavailable.
- *
- * @return The line number of this exception occurrance in the source file.
- */
- public int getLine() {
- return this.trace.getLineNumber();
- }
+ private static final boolean useNotification;
- /**
- * Creates a {@link RuntimeException} object for methods that cannot throw a {@link Exc}.
- *
- * @return A {@link RuntimeException} object.
- */
- public RuntimeException toRuntimeException() {
- return new RuntimeExc(this);
+ static {
+ boolean b = false;
+ for (String arg : ManagementFactory.getRuntimeMXBean().getInputArguments()) {
+ if ("-Dgithub.sttk.errs.notify=true".equals(arg)) {
+ b = true;
+ break;
+ }
}
-
- /**
- * Writes a serial data of this exception to a stream.
- *
- * Since a reason object is not necessarily serializable, this method will throw a {@link NotSerializableException}
- * if the {@code reason} field does not inherit {@link Serializable}.
- *
- * @param out
- * An {@link ObjectOutputStream} to which data is written.
- *
- * @throws IOException
- * if an I/O error occurs.
- */
- private void writeObject(ObjectOutputStream out) throws IOException {
- if (!(this.reason instanceof Serializable)) {
- throw new NotSerializableException(this.reason.getClass().getName());
- }
- out.defaultWriteObject();
- out.writeObject(this.reason);
+ useNotification = b;
+ }
+
+ private static boolean isHandlersFixed = false;
+ private static final List syncExcHandlers = new LinkedList<>();
+ private static final List asyncExcHandlers = new LinkedList<>();
+
+ /**
+ * Adds an {@link ExcHandler} object which is executed synchronously just after an {@link Exc} is
+ * created. Handlers added with this method are executed in the order of addition and stop if one
+ * of the handlers throws a {@link RuntimeException} or an {@link Error}. NOTE: This feature is
+ * enabled via the system property: {@code github.sttk.errs.notify=true}
+ *
+ * @param handler An {@link ExcHandler} object.
+ */
+ public static void addSyncHandler(final ExcHandler handler) {
+ if (!useNotification) return;
+ if (isHandlersFixed) return;
+ syncExcHandlers.add(handler);
+ }
+
+ /**
+ * Adds an {@link ExcHandler} object which is executed asynchronously just after an {@link Exc} is
+ * created. Handlers don't stop even if one of the handlers throw a {@link RuntimeException} or an
+ * {@link Error}. NOTE: This feature is enabled via the system property: {@code
+ * github.sttk.errs.notify=true}
+ *
+ * @param handler An {@link ExcHandler} object.
+ */
+ public static void addAsyncHandler(final ExcHandler handler) {
+ if (!useNotification) return;
+ if (isHandlersFixed) return;
+ asyncExcHandlers.add(handler);
+ }
+
+ /**
+ * Prevents further addition of {@link ExcHandler} objects to synchronous and asynchronous
+ * exception handler lists. Before this is called, no {@code Exc} is notified to the handlers.
+ * After this is called, no new handlers can be added, and {@code Exc}(s) is notified to the
+ * handlers. NOTE: This feature is enabled via the system property: {@code
+ * github.sttk.errs.notify=true}
+ */
+ public static void fixHandlers() {
+ if (!useNotification) return;
+ if (isHandlersFixed) return;
+ isHandlersFixed = true;
+ }
+
+ private static void notifyExc(Exc exc) {
+ if (!useNotification) return;
+ if (!isHandlersFixed) return;
+
+ if (syncExcHandlers.isEmpty() && asyncExcHandlers.isEmpty()) {
+ return;
}
- /**
- * Reconstitutes the {@code Exc} instance from a stream and initialize the reason and cause properties when
- * deserializing. If the reason by deserialization is null, this method throws {@link InvalidObjectException}.
- *
- * @param in
- * An {@link ObjectInputStream} from which data is read.
- *
- * @throws IOException
- * if an I/O error occurs.
- * @throws ClassNotFoundException
- * if a serialized class cannot be loaded.
- */
- private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException {
- in.defaultReadObject();
- this.reason = in.readObject();
-
- if (this.reason == null) {
- throw new InvalidObjectException("reason is null or invalid.");
- }
- }
-
- //// Notification ////
-
- private static final boolean useNotification;
+ final var tm = OffsetDateTime.now();
- static {
- boolean b = false;
- for (String arg : ManagementFactory.getRuntimeMXBean().getInputArguments()) {
- if ("-Dgithub.sttk.errs.notify=true".equals(arg)) {
- b = true;
- break;
- }
- }
- useNotification = b;
+ for (var handler : syncExcHandlers) {
+ handler.handle(exc, tm);
}
- private static boolean isHandlersFixed = false;
- private static final List syncExcHandlers = new LinkedList<>();
- private static final List asyncExcHandlers = new LinkedList<>();
-
- /**
- * Adds an {@link ExcHandler} object which is executed synchronously just after an {@link Exc} is created. Handlers
- * added with this method are executed in the order of addition and stop if one of the handlers throws a
- * {@link RuntimeException} or an {@link Error}. NOTE: This feature is enabled via the system property:
- * {@code github.sttk.errs.notify=true}
- *
- * @param handler
- * An {@link ExcHandler} object.
- */
- public static void addSyncHandler(final ExcHandler handler) {
- if (!useNotification)
- return;
- if (isHandlersFixed)
- return;
- syncExcHandlers.add(handler);
- }
-
- /**
- * Adds an {@link ExcHandler} object which is executed asynchronously just after an {@link Exc} is created. Handlers
- * don't stop even if one of the handlers throw a {@link RuntimeException} or an {@link Error}. NOTE: This feature
- * is enabled via the system property: {@code github.sttk.errs.notify=true}
- *
- * @param handler
- * An {@link ExcHandler} object.
- */
- public static void addAsyncHandler(final ExcHandler handler) {
- if (!useNotification)
- return;
- if (isHandlersFixed)
- return;
- asyncExcHandlers.add(handler);
- }
-
- /**
- * Prevents further addition of {@link ExcHandler} objects to synchronous and asynchronous exception handler lists.
- * Before this is called, no {@code Exc} is notified to the handlers. After this is called, no new handlers can be
- * added, and {@code Exc}(s) is notified to the handlers. NOTE: This feature is enabled via the system property:
- * {@code github.sttk.errs.notify=true}
- */
- public static void fixHandlers() {
- if (!useNotification)
- return;
- if (isHandlersFixed)
- return;
- isHandlersFixed = true;
- }
-
- private static void notifyExc(Exc exc) {
- if (!useNotification)
- return;
- if (!isHandlersFixed)
- return;
-
- if (syncExcHandlers.isEmpty() && asyncExcHandlers.isEmpty()) {
- return;
- }
-
- final var tm = OffsetDateTime.now();
-
- for (var handler : syncExcHandlers) {
- handler.handle(exc, tm);
- }
-
- for (var handler : asyncExcHandlers) {
- Thread.ofVirtual().start(() -> {
+ for (var handler : asyncExcHandlers) {
+ Thread.ofVirtual()
+ .start(
+ () -> {
handler.handle(exc, tm);
- });
- }
+ });
}
+ }
}
final class RuntimeExc extends RuntimeException {
- private static final long serialVersionUID = 4664405757902479929L;
-
- RuntimeExc(Exc exc) {
- super(exc);
- }
-
- @Override
- public String getMessage() {
- return getCause().getMessage();
- }
-
- @Override
- public String toString() {
- return getClass().getName() + ": " + getCause().toString();
- }
-
- @Override
- public Throwable fillInStackTrace() {
- return null;
- }
+ private static final long serialVersionUID = 4664405757902479929L;
+
+ RuntimeExc(Exc exc) {
+ super(exc);
+ }
+
+ @Override
+ public String getMessage() {
+ return getCause().getMessage();
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getName() + ": " + getCause().toString();
+ }
+
+ @Override
+ public Throwable fillInStackTrace() {
+ return null;
+ }
}
diff --git a/src/main/java/com/github/sttk/errs/ExcHandler.java b/src/main/java/com/github/sttk/errs/ExcHandler.java
index e3e5278..8d7c3e8 100644
--- a/src/main/java/com/github/sttk/errs/ExcHandler.java
+++ b/src/main/java/com/github/sttk/errs/ExcHandler.java
@@ -6,19 +6,15 @@
import java.time.OffsetDateTime;
-/**
- * {@code ExcHandler} is a handler of an {@link Exc} object creation.
- */
+/** {@code ExcHandler} is a handler of an {@link Exc} object creation. */
@FunctionalInterface
public interface ExcHandler {
- /**
- * Handles an {@link Exc} object creation.
- *
- * @param exc
- * The {@link Exc} object.
- * @param tm
- * The creation time of the {@link Exc} object.
- */
- void handle(Exc exc, OffsetDateTime tm);
+ /**
+ * Handles an {@link Exc} object creation.
+ *
+ * @param exc The {@link Exc} object.
+ * @param tm The creation time of the {@link Exc} object.
+ */
+ void handle(Exc exc, OffsetDateTime tm);
}
diff --git a/src/main/java/com/github/sttk/errs/package-info.java b/src/main/java/com/github/sttk/errs/package-info.java
index 4e00300..31e64b3 100644
--- a/src/main/java/com/github/sttk/errs/package-info.java
+++ b/src/main/java/com/github/sttk/errs/package-info.java
@@ -7,8 +7,9 @@
/**
* Provides classes for handling an exception with a reason.
- *
- * This package contains the {@code Exc} class which has a record field indicates the reason for the exception.
+ *
+ *
This package contains the {@code Exc} class which has a record field indicates the reason for
+ * the exception.
*
* @version 0.1
*/
diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java
index c6c6ade..40cdcbf 100644
--- a/src/main/java/module-info.java
+++ b/src/main/java/module-info.java
@@ -12,5 +12,6 @@
*/
module com.github.sttk.errs {
exports com.github.sttk.errs;
+
requires java.management;
}
diff --git a/src/test/java/com/github/sttk/errs/ExcHandlerTest.java b/src/test/java/com/github/sttk/errs/ExcHandlerTest.java
index ac1ec98..a888606 100644
--- a/src/test/java/com/github/sttk/errs/ExcHandlerTest.java
+++ b/src/test/java/com/github/sttk/errs/ExcHandlerTest.java
@@ -1,140 +1,142 @@
package com.github.sttk.errs;
+import static java.time.format.DateTimeFormatter.ISO_INSTANT;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.jupiter.api.Assertions.fail;
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.BeforeEach;
-import static java.time.format.DateTimeFormatter.ISO_INSTANT;
-import java.util.List;
import java.util.LinkedList;
+import java.util.List;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
public class ExcHandlerTest {
- private ExcHandlerTest() {
- }
-
- @BeforeEach
- void reset() throws Exception {
- var f = Exc.class.getDeclaredField("isHandlersFixed");
- f.setAccessible(true);
- f.setBoolean(null, false);
-
- f = Exc.class.getDeclaredField("syncExcHandlers");
- f.setAccessible(true);
- var o = f.get(null);
- var m = LinkedList.class.getMethod("clear");
- m.invoke(o);
-
- f = Exc.class.getDeclaredField("asyncExcHandlers");
- f.setAccessible(true);
- o = f.get(null);
- m = LinkedList.class.getMethod("clear");
- m.invoke(o);
- }
-
- @SuppressWarnings("unchecked")
- List getSyncExcHandlers() throws Exception {
- var f = Exc.class.getDeclaredField("syncExcHandlers");
- f.setAccessible(true);
- var o = f.get(null);
- return (List) o;
- }
-
- @SuppressWarnings("unchecked")
- List getAsyncExcHandlers() throws Exception {
- var f = Exc.class.getDeclaredField("asyncExcHandlers");
- f.setAccessible(true);
- var o = f.get(null);
- return (List) o;
- }
-
- @Test
- void should_add_sync_handlers_and_fix() throws Exception {
- var handlers = getSyncExcHandlers();
- assertThat(handlers).isEmpty();
-
- ExcHandler handler1 = (exc, tm) -> {
- };
- Exc.addSyncHandler(handler1);
-
- handlers = getSyncExcHandlers();
- assertThat(handlers).containsExactly(handler1);
-
- ExcHandler handler2 = (exc, tm) -> {
- };
- Exc.addSyncHandler(handler2);
-
- handlers = getSyncExcHandlers();
- assertThat(handlers).containsExactly(handler1, handler2);
-
- Exc.fixHandlers();
-
- ExcHandler handler3 = (exc, tm) -> {
- };
- Exc.addSyncHandler(handler3);
-
- handlers = getSyncExcHandlers();
- assertThat(handlers).containsExactly(handler1, handler2);
- }
-
- @Test
- void should_add_async_handlers_and_fix() throws Exception {
- var handlers = getAsyncExcHandlers();
- assertThat(handlers).isEmpty();
-
- ExcHandler handler1 = (exc, tm) -> {
- };
- Exc.addAsyncHandler(handler1);
-
- handlers = getAsyncExcHandlers();
- assertThat(handlers).containsExactly(handler1);
-
- ExcHandler handler2 = (exc, tm) -> {
- };
- Exc.addAsyncHandler(handler2);
-
- handlers = getAsyncExcHandlers();
- assertThat(handlers).containsExactly(handler1, handler2);
-
- Exc.fixHandlers();
-
- ExcHandler handler3 = (exc, tm) -> {
- };
- Exc.addAsyncHandler(handler3);
-
- handlers = getAsyncExcHandlers();
- assertThat(handlers).containsExactly(handler1, handler2);
- }
-
- @Test
- void should_notify_exception() throws Exception {
- final List syncLogs = new LinkedList<>();
- final List asyncLogs = new LinkedList<>();
-
- Exc.addSyncHandler((exc, tm) -> {
- syncLogs.add(String.format("%s:%s(%d):%s", tm.format(ISO_INSTANT), exc.getFile(), exc.getLine(),
- exc.getReason().toString()));
+ private ExcHandlerTest() {}
+
+ @BeforeEach
+ void reset() throws Exception {
+ var f = Exc.class.getDeclaredField("isHandlersFixed");
+ f.setAccessible(true);
+ f.setBoolean(null, false);
+
+ f = Exc.class.getDeclaredField("syncExcHandlers");
+ f.setAccessible(true);
+ var o = f.get(null);
+ var m = LinkedList.class.getMethod("clear");
+ m.invoke(o);
+
+ f = Exc.class.getDeclaredField("asyncExcHandlers");
+ f.setAccessible(true);
+ o = f.get(null);
+ m = LinkedList.class.getMethod("clear");
+ m.invoke(o);
+ }
+
+ @SuppressWarnings("unchecked")
+ List getSyncExcHandlers() throws Exception {
+ var f = Exc.class.getDeclaredField("syncExcHandlers");
+ f.setAccessible(true);
+ var o = f.get(null);
+ return (List) o;
+ }
+
+ @SuppressWarnings("unchecked")
+ List getAsyncExcHandlers() throws Exception {
+ var f = Exc.class.getDeclaredField("asyncExcHandlers");
+ f.setAccessible(true);
+ var o = f.get(null);
+ return (List) o;
+ }
+
+ @Test
+ void should_add_sync_handlers_and_fix() throws Exception {
+ var handlers = getSyncExcHandlers();
+ assertThat(handlers).isEmpty();
+
+ ExcHandler handler1 = (exc, tm) -> {};
+ Exc.addSyncHandler(handler1);
+
+ handlers = getSyncExcHandlers();
+ assertThat(handlers).containsExactly(handler1);
+
+ ExcHandler handler2 = (exc, tm) -> {};
+ Exc.addSyncHandler(handler2);
+
+ handlers = getSyncExcHandlers();
+ assertThat(handlers).containsExactly(handler1, handler2);
+
+ Exc.fixHandlers();
+
+ ExcHandler handler3 = (exc, tm) -> {};
+ Exc.addSyncHandler(handler3);
+
+ handlers = getSyncExcHandlers();
+ assertThat(handlers).containsExactly(handler1, handler2);
+ }
+
+ @Test
+ void should_add_async_handlers_and_fix() throws Exception {
+ var handlers = getAsyncExcHandlers();
+ assertThat(handlers).isEmpty();
+
+ ExcHandler handler1 = (exc, tm) -> {};
+ Exc.addAsyncHandler(handler1);
+
+ handlers = getAsyncExcHandlers();
+ assertThat(handlers).containsExactly(handler1);
+
+ ExcHandler handler2 = (exc, tm) -> {};
+ Exc.addAsyncHandler(handler2);
+
+ handlers = getAsyncExcHandlers();
+ assertThat(handlers).containsExactly(handler1, handler2);
+
+ Exc.fixHandlers();
+
+ ExcHandler handler3 = (exc, tm) -> {};
+ Exc.addAsyncHandler(handler3);
+
+ handlers = getAsyncExcHandlers();
+ assertThat(handlers).containsExactly(handler1, handler2);
+ }
+
+ @Test
+ void should_notify_exception() throws Exception {
+ final List syncLogs = new LinkedList<>();
+ final List asyncLogs = new LinkedList<>();
+
+ Exc.addSyncHandler(
+ (exc, tm) -> {
+ syncLogs.add(
+ String.format(
+ "%s:%s(%d):%s",
+ tm.format(ISO_INSTANT),
+ exc.getFile(),
+ exc.getLine(),
+ exc.getReason().toString()));
});
- Exc.addAsyncHandler((exc, tm) -> {
- asyncLogs.add(String.format("%s:%s(%d):%s", tm.format(ISO_INSTANT), exc.getFile(), exc.getLine(),
- exc.getReason().toString()));
+ Exc.addAsyncHandler(
+ (exc, tm) -> {
+ asyncLogs.add(
+ String.format(
+ "%s:%s(%d):%s",
+ tm.format(ISO_INSTANT),
+ exc.getFile(),
+ exc.getLine(),
+ exc.getReason().toString()));
});
- record FailToDoSomething(String name) {
- }
+ record FailToDoSomething(String name) {}
- new Exc(new FailToDoSomething("abc"));
+ new Exc(new FailToDoSomething("abc"));
- assertThat(syncLogs).isEmpty();
- assertThat(asyncLogs).isEmpty();
+ assertThat(syncLogs).isEmpty();
+ assertThat(asyncLogs).isEmpty();
- Exc.fixHandlers();
+ Exc.fixHandlers();
- new Exc(new FailToDoSomething("abc"));
- assertThat(syncLogs.get(0)).endsWith(":ExcHandlerTest.java(134):FailToDoSomething[name=abc]");
+ new Exc(new FailToDoSomething("abc"));
+ assertThat(syncLogs.get(0)).endsWith(":ExcHandlerTest.java(136):FailToDoSomething[name=abc]");
- Thread.sleep(100);
- assertThat(asyncLogs.get(0)).endsWith(":ExcHandlerTest.java(134):FailToDoSomething[name=abc]");
- }
+ Thread.sleep(100);
+ assertThat(asyncLogs.get(0)).endsWith(":ExcHandlerTest.java(136):FailToDoSomething[name=abc]");
+ }
}
diff --git a/src/test/java/com/github/sttk/errs/ExcTest.java b/src/test/java/com/github/sttk/errs/ExcTest.java
index 6718740..468f890 100644
--- a/src/test/java/com/github/sttk/errs/ExcTest.java
+++ b/src/test/java/com/github/sttk/errs/ExcTest.java
@@ -2,352 +2,351 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.fail;
-import org.junit.jupiter.api.Disabled;
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
+import java.io.NotSerializableException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
-import java.io.Serializable;
-import java.io.NotSerializableException;
-import java.io.InvalidObjectException;
import java.io.PrintWriter;
+import java.io.Serializable;
import java.io.StringWriter;
-import java.io.IOException;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
public class ExcTest {
- private ExcTest() {
- }
+ private ExcTest() {}
- /// exception reasons ///
+ /// exception reasons ///
- record IndexOutOfRange(String name, int index, int min, int max) {
- }
+ record IndexOutOfRange(String name, int index, int min, int max) {}
- record SerializableReason(String name, int index, int min, int max) implements Serializable {
- }
+ record SerializableReason(String name, int index, int min, int max) implements Serializable {}
- @Nested
- class TestConstructor {
- @Test
- void with_Record_reason() {
- var exc = new Exc(new IndexOutOfRange("data", 4, 0, 3));
- var reason = IndexOutOfRange.class.cast(exc.getReason());
- assertThat(reason.name()).isEqualTo("data");
- assertThat(reason.index()).isEqualTo(4);
- assertThat(reason.min()).isEqualTo(0);
- assertThat(reason.max()).isEqualTo(3);
- assertThat(exc.getCause()).isNull();
-
- // exc.printStackTrace();
- }
+ @Nested
+ class TestConstructor {
+ @Test
+ void with_Record_reason() {
+ var exc = new Exc(new IndexOutOfRange("data", 4, 0, 3));
+ var reason = IndexOutOfRange.class.cast(exc.getReason());
+ assertThat(reason.name()).isEqualTo("data");
+ assertThat(reason.index()).isEqualTo(4);
+ assertThat(reason.min()).isEqualTo(0);
+ assertThat(reason.max()).isEqualTo(3);
+ assertThat(exc.getCause()).isNull();
- @Test
- void with_enum_reason() {
- enum Reasons {
- FailToDoSomething,
- }
+ // exc.printStackTrace();
+ }
- var exc = new Exc(Reasons.FailToDoSomething);
- var reason = Reasons.class.cast(exc.getReason());
- assertThat(reason.name()).isEqualTo("FailToDoSomething");
- assertThat(exc.getCause()).isNull();
+ @Test
+ void with_enum_reason() {
+ enum Reasons {
+ FailToDoSomething,
+ }
- // exc.printStackTrace();
- }
+ var exc = new Exc(Reasons.FailToDoSomething);
+ var reason = Reasons.class.cast(exc.getReason());
+ assertThat(reason.name()).isEqualTo("FailToDoSomething");
+ assertThat(exc.getCause()).isNull();
- @Test
- void with_String_reason() {
- var exc = new Exc("FailToDoSomething");
- var reason = String.class.cast(exc.getReason());
- assertThat(reason).isEqualTo("FailToDoSomething");
- assertThat(exc.getCause()).isNull();
- }
+ // exc.printStackTrace();
+ }
- @Test
- void with_reason_but_reason_is_null() {
- try {
- new Exc(null);
- } catch (IllegalArgumentException e) {
- assertThat(e.getMessage()).isEqualTo("reason is null");
- }
- }
+ @Test
+ void with_String_reason() {
+ var exc = new Exc("FailToDoSomething");
+ var reason = String.class.cast(exc.getReason());
+ assertThat(reason).isEqualTo("FailToDoSomething");
+ assertThat(exc.getCause()).isNull();
+ }
- @Test
- void with_reason_and_cause() {
- var cause = new IndexOutOfBoundsException(4);
- var exc = new Exc(new IndexOutOfRange("data", 4, 0, 3), cause);
- var reason = IndexOutOfRange.class.cast(exc.getReason());
- assertThat(reason.name()).isEqualTo("data");
- assertThat(reason.index()).isEqualTo(4);
- assertThat(reason.min()).isEqualTo(0);
- assertThat(reason.max()).isEqualTo(3);
- assertThat(exc.getCause()).isEqualTo(cause);
-
- // exc.printStackTrace();
- }
+ @Test
+ void with_reason_but_reason_is_null() {
+ try {
+ new Exc(null);
+ } catch (IllegalArgumentException e) {
+ assertThat(e.getMessage()).isEqualTo("reason is null");
+ }
+ }
- @Test
- void with_reason_and_cause_but_reason_is_null() {
- var cause = new IndexOutOfBoundsException(4);
- try {
- new Exc(null, cause);
- } catch (IllegalArgumentException e) {
- assertThat(e.getMessage()).isEqualTo("reason is null");
- }
- }
+ @Test
+ void with_reason_and_cause() {
+ var cause = new IndexOutOfBoundsException(4);
+ var exc = new Exc(new IndexOutOfRange("data", 4, 0, 3), cause);
+ var reason = IndexOutOfRange.class.cast(exc.getReason());
+ assertThat(reason.name()).isEqualTo("data");
+ assertThat(reason.index()).isEqualTo(4);
+ assertThat(reason.min()).isEqualTo(0);
+ assertThat(reason.max()).isEqualTo(3);
+ assertThat(exc.getCause()).isEqualTo(cause);
+
+ // exc.printStackTrace();
+ }
- @Test
- void with_reason_and_cause_but_cause_is_null() {
- var exc = new Exc(new IndexOutOfRange("data", 4, 0, 3), null);
- var reason = IndexOutOfRange.class.cast(exc.getReason());
- assertThat(reason.name()).isEqualTo("data");
- assertThat(reason.index()).isEqualTo(4);
- assertThat(reason.min()).isEqualTo(0);
- assertThat(reason.max()).isEqualTo(3);
- assertThat(exc.getCause()).isNull();
-
- // exc.printStackTrace();
- }
+ @Test
+ void with_reason_and_cause_but_reason_is_null() {
+ var cause = new IndexOutOfBoundsException(4);
+ try {
+ new Exc(null, cause);
+ } catch (IllegalArgumentException e) {
+ assertThat(e.getMessage()).isEqualTo("reason is null");
+ }
}
- @Nested
- class TestThrow {
- @Test
- void identify_reason_with_instanceOf() {
- var exc = new Exc(new IndexOutOfRange("data", 4, 0, 3));
- if (exc.getReason() instanceof IndexOutOfRange reason) {
- assertThat(reason.name()).isEqualTo("data");
- assertThat(reason.index()).isEqualTo(4);
- assertThat(reason.min()).isEqualTo(0);
- assertThat(reason.max()).isEqualTo(3);
- }
- }
+ @Test
+ void with_reason_and_cause_but_cause_is_null() {
+ var exc = new Exc(new IndexOutOfRange("data", 4, 0, 3), null);
+ var reason = IndexOutOfRange.class.cast(exc.getReason());
+ assertThat(reason.name()).isEqualTo("data");
+ assertThat(reason.index()).isEqualTo(4);
+ assertThat(reason.min()).isEqualTo(0);
+ assertThat(reason.max()).isEqualTo(3);
+ assertThat(exc.getCause()).isNull();
+
+ // exc.printStackTrace();
+ }
+ }
+
+ @Nested
+ class TestThrow {
+ @Test
+ void identify_reason_with_instanceOf() {
+ var exc = new Exc(new IndexOutOfRange("data", 4, 0, 3));
+ if (exc.getReason() instanceof IndexOutOfRange reason) {
+ assertThat(reason.name()).isEqualTo("data");
+ assertThat(reason.index()).isEqualTo(4);
+ assertThat(reason.min()).isEqualTo(0);
+ assertThat(reason.max()).isEqualTo(3);
+ }
+ }
- @Test
- void identify_Record_reason_with_switch_expression() {
- var exc = new Exc(new IndexOutOfRange("data", 4, 0, 3));
- switch (exc.getReason()) {
- case IndexOutOfRange reason -> {
- assertThat(reason.name()).isEqualTo("data");
- assertThat(reason.index()).isEqualTo(4);
- assertThat(reason.min()).isEqualTo(0);
- assertThat(reason.max()).isEqualTo(3);
- }
- default -> fail();
- }
+ @Test
+ void identify_Record_reason_with_switch_expression() {
+ var exc = new Exc(new IndexOutOfRange("data", 4, 0, 3));
+ switch (exc.getReason()) {
+ case IndexOutOfRange reason -> {
+ assertThat(reason.name()).isEqualTo("data");
+ assertThat(reason.index()).isEqualTo(4);
+ assertThat(reason.min()).isEqualTo(0);
+ assertThat(reason.max()).isEqualTo(3);
}
+ default -> fail();
+ }
+ }
- @Test
- void identify_Enum_reason_with_switch_expression() {
- enum Reasons {
- FailToDoSomething, InvalidValue,
- }
-
- var exc = new Exc(Reasons.FailToDoSomething);
-
- var s = switch (exc.getReason()) {
- case Reasons enm -> switch (enm) {
- case FailToDoSomething -> "fail to do something";
- case InvalidValue -> "invalid value";
+ @Test
+ void identify_Enum_reason_with_switch_expression() {
+ enum Reasons {
+ FailToDoSomething,
+ InvalidValue,
+ }
+
+ var exc = new Exc(Reasons.FailToDoSomething);
+
+ var s =
+ switch (exc.getReason()) {
+ case Reasons enm ->
+ switch (enm) {
+ case FailToDoSomething -> "fail to do something";
+ case InvalidValue -> "invalid value";
};
- default -> "unknown";
- };
- assertThat(s).isEqualTo("fail to do something");
- }
+ default -> "unknown";
+ };
+ assertThat(s).isEqualTo("fail to do something");
}
-
- @Nested
- class TestGetter {
- @Test
- void getReason() {
- var exc = new Exc(new IndexOutOfRange("data", 4, 0, 3));
- assertThat(exc.getReason()).isInstanceOf(IndexOutOfRange.class);
-
- var reason = IndexOutOfRange.class.cast(exc.getReason());
- assertThat(reason.name()).isEqualTo("data");
- assertThat(reason.index()).isEqualTo(4);
- assertThat(reason.min()).isEqualTo(0);
- assertThat(reason.max()).isEqualTo(3);
- }
-
- @Test
- void getCause() {
- var exc = new Exc(new IndexOutOfRange("data", 4, 0, 3));
- assertThat(exc.getCause()).isNull();
-
- var cause = new IndexOutOfBoundsException(4);
- exc = new Exc(new IndexOutOfRange("data", 4, 0, 3), cause);
- assertThat(exc.getCause()).isEqualTo(cause);
- }
-
- @Test
- void getFile() {
- var exc = new Exc(new IndexOutOfRange("data", 4, 0, 3));
- assertThat(exc.getFile()).isEqualTo("ExcTest.java");
- }
-
- @Test
- void getLine() {
- var exc = new Exc(new IndexOutOfRange("data", 4, 0, 3));
- assertThat(exc.getLine()).isEqualTo(194);
- }
+ }
+
+ @Nested
+ class TestGetter {
+ @Test
+ void getReason() {
+ var exc = new Exc(new IndexOutOfRange("data", 4, 0, 3));
+ assertThat(exc.getReason()).isInstanceOf(IndexOutOfRange.class);
+
+ var reason = IndexOutOfRange.class.cast(exc.getReason());
+ assertThat(reason.name()).isEqualTo("data");
+ assertThat(reason.index()).isEqualTo(4);
+ assertThat(reason.min()).isEqualTo(0);
+ assertThat(reason.max()).isEqualTo(3);
}
- @Nested
- class TestGetMessage {
- @Test
- void with_cause() {
- var exc = new Exc(new IndexOutOfRange("data", 4, 0, 3));
- assertThat(exc.getMessage()).isEqualTo("IndexOutOfRange[name=data, index=4, min=0, max=3]");
- }
+ @Test
+ void getCause() {
+ var exc = new Exc(new IndexOutOfRange("data", 4, 0, 3));
+ assertThat(exc.getCause()).isNull();
- @Test
- void with_no_cause() {
- var cause = new IndexOutOfBoundsException(4);
- var exc = new Exc(new IndexOutOfRange("data", 4, 0, 3), cause);
- assertThat(exc.getMessage()).isEqualTo("IndexOutOfRange[name=data, index=4, min=0, max=3]");
- }
+ var cause = new IndexOutOfBoundsException(4);
+ exc = new Exc(new IndexOutOfRange("data", 4, 0, 3), cause);
+ assertThat(exc.getCause()).isEqualTo(cause);
}
- @Nested
- class TestToString {
- @Test
- void with_reason() {
- var exc = new Exc(new IndexOutOfRange("data", 4, 0, 3));
- assertThat(exc.toString()).isEqualTo(
- "com.github.sttk.errs.Exc { reason = com.github.sttk.errs.ExcTest$IndexOutOfRange IndexOutOfRange[name=data, index=4, min=0, max=3], file = ExcTest.java, line = 219 }");
- }
+ @Test
+ void getFile() {
+ var exc = new Exc(new IndexOutOfRange("data", 4, 0, 3));
+ assertThat(exc.getFile()).isEqualTo("ExcTest.java");
+ }
- @Test
- void with_reason_and_cause() {
- var cause = new IndexOutOfBoundsException(4);
- var exc = new Exc(new IndexOutOfRange("data", 4, 0, 3), cause);
- assertThat(exc.toString()).isEqualTo(
- "com.github.sttk.errs.Exc { reason = com.github.sttk.errs.ExcTest$IndexOutOfRange IndexOutOfRange[name=data, index=4, min=0, max=3], file = ExcTest.java, line = 227, cause = java.lang.IndexOutOfBoundsException: Index out of range: 4 }");
- }
+ @Test
+ void getLine() {
+ var exc = new Exc(new IndexOutOfRange("data", 4, 0, 3));
+ assertThat(exc.getLine()).isEqualTo(191);
+ }
+ }
+
+ @Nested
+ class TestGetMessage {
+ @Test
+ void with_cause() {
+ var exc = new Exc(new IndexOutOfRange("data", 4, 0, 3));
+ assertThat(exc.getMessage()).isEqualTo("IndexOutOfRange[name=data, index=4, min=0, max=3]");
}
- @Nested
- class TestToRuntimeException {
- @Test
- void getMessage() {
- var exc = new Exc(new IndexOutOfRange("data", 4, 0, 3));
- var rtExc = exc.toRuntimeException();
- assertThat(rtExc.getMessage()).isEqualTo("IndexOutOfRange[name=data, index=4, min=0, max=3]");
- }
+ @Test
+ void with_no_cause() {
+ var cause = new IndexOutOfBoundsException(4);
+ var exc = new Exc(new IndexOutOfRange("data", 4, 0, 3), cause);
+ assertThat(exc.getMessage()).isEqualTo("IndexOutOfRange[name=data, index=4, min=0, max=3]");
+ }
+ }
+
+ @Nested
+ class TestToString {
+ @Test
+ void with_reason() {
+ var exc = new Exc(new IndexOutOfRange("data", 4, 0, 3));
+ assertThat(exc.toString())
+ .isEqualTo(
+ "com.github.sttk.errs.Exc { reason = com.github.sttk.errs.ExcTest$IndexOutOfRange IndexOutOfRange[name=data, index=4, min=0, max=3], file = ExcTest.java, line = 216 }");
+ }
- @Test
- void getCause() {
- var exc = new Exc(new IndexOutOfRange("data", 4, 0, 3));
- var rtExc = exc.toRuntimeException();
- assertThat(rtExc.getCause()).isEqualTo(exc);
- }
+ @Test
+ void with_reason_and_cause() {
+ var cause = new IndexOutOfBoundsException(4);
+ var exc = new Exc(new IndexOutOfRange("data", 4, 0, 3), cause);
+ assertThat(exc.toString())
+ .isEqualTo(
+ "com.github.sttk.errs.Exc { reason = com.github.sttk.errs.ExcTest$IndexOutOfRange IndexOutOfRange[name=data, index=4, min=0, max=3], file = ExcTest.java, line = 225, cause = java.lang.IndexOutOfBoundsException: Index out of range: 4 }");
+ }
+ }
+
+ @Nested
+ class TestToRuntimeException {
+ @Test
+ void getMessage() {
+ var exc = new Exc(new IndexOutOfRange("data", 4, 0, 3));
+ var rtExc = exc.toRuntimeException();
+ assertThat(rtExc.getMessage()).isEqualTo("IndexOutOfRange[name=data, index=4, min=0, max=3]");
+ }
- @Test
- void printStackTrace() {
- var exc = new Exc(new IndexOutOfRange("data", 4, 0, 3));
- var rtExc = exc.toRuntimeException();
-
- var swOfExc = new StringWriter();
- try (var pwOfExc = new PrintWriter(swOfExc)) {
- exc.printStackTrace(pwOfExc);
- }
- var swOfRtExc = new StringWriter();
- try (var pwOfRtExc = new PrintWriter(swOfRtExc)) {
- rtExc.printStackTrace(pwOfRtExc);
- }
-
- var isWindows = System.getProperty("os.name").toLowerCase().startsWith("windows");
- var prefix = "com.github.sttk.errs.RuntimeExc: " + exc.toString();
- if (isWindows) {
- prefix += System.lineSeparator();
- } else {
- prefix += System.lineSeparator();
- }
- prefix += "Caused by: ";
-
- assertThat(swOfRtExc.toString()).isEqualTo(prefix + swOfExc.toString());
-
- // rtExc.printStackTrace();
- }
+ @Test
+ void getCause() {
+ var exc = new Exc(new IndexOutOfRange("data", 4, 0, 3));
+ var rtExc = exc.toRuntimeException();
+ assertThat(rtExc.getCause()).isEqualTo(exc);
}
- @Nested
- class TestSerialize {
- @Test
- void reason_is_serializable_and_has_no_cause() throws Exception {
- var bos = new ByteArrayOutputStream();
- var oos = new ObjectOutputStream(bos);
- try (oos) {
- var exc = new Exc(new SerializableReason("data", 4, 0, 3));
- oos.writeObject(exc);
- }
-
- var bytes = bos.toByteArray();
- var ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
- try (ois) {
- var obj = ois.readObject();
- assertThat(obj).isInstanceOf(Exc.class);
-
- var exc = Exc.class.cast(obj);
- var cause = exc.getCause();
- assertThat(cause).isNull();
-
- var robj = exc.getReason();
- assertThat(robj).isInstanceOf(SerializableReason.class);
- var reason = SerializableReason.class.cast(robj);
- assertThat(reason.name()).isEqualTo("data");
- assertThat(reason.index()).isEqualTo(4);
- assertThat(reason.min()).isEqualTo(0);
- assertThat(reason.max()).isEqualTo(3);
- }
- }
+ @Test
+ void printStackTrace() {
+ var exc = new Exc(new IndexOutOfRange("data", 4, 0, 3));
+ var rtExc = exc.toRuntimeException();
+
+ var swOfExc = new StringWriter();
+ try (var pwOfExc = new PrintWriter(swOfExc)) {
+ exc.printStackTrace(pwOfExc);
+ }
+ var swOfRtExc = new StringWriter();
+ try (var pwOfRtExc = new PrintWriter(swOfRtExc)) {
+ rtExc.printStackTrace(pwOfRtExc);
+ }
+
+ var isWindows = System.getProperty("os.name").toLowerCase().startsWith("windows");
+ var prefix = "com.github.sttk.errs.RuntimeExc: " + exc.toString();
+ if (isWindows) {
+ prefix += System.lineSeparator();
+ } else {
+ prefix += System.lineSeparator();
+ }
+ prefix += "Caused by: ";
+
+ assertThat(swOfRtExc.toString()).isEqualTo(prefix + swOfExc.toString());
+
+ // rtExc.printStackTrace();
+ }
+ }
+
+ @Nested
+ class TestSerialize {
+ @Test
+ void reason_is_serializable_and_has_no_cause() throws Exception {
+ var bos = new ByteArrayOutputStream();
+ var oos = new ObjectOutputStream(bos);
+ try (oos) {
+ var exc = new Exc(new SerializableReason("data", 4, 0, 3));
+ oos.writeObject(exc);
+ }
+
+ var bytes = bos.toByteArray();
+ var ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
+ try (ois) {
+ var obj = ois.readObject();
+ assertThat(obj).isInstanceOf(Exc.class);
+
+ var exc = Exc.class.cast(obj);
+ var cause = exc.getCause();
+ assertThat(cause).isNull();
+
+ var robj = exc.getReason();
+ assertThat(robj).isInstanceOf(SerializableReason.class);
+ var reason = SerializableReason.class.cast(robj);
+ assertThat(reason.name()).isEqualTo("data");
+ assertThat(reason.index()).isEqualTo(4);
+ assertThat(reason.min()).isEqualTo(0);
+ assertThat(reason.max()).isEqualTo(3);
+ }
+ }
- @Test
- void reason_is_serializable_and_has_cause() throws Exception {
- var bos = new ByteArrayOutputStream();
- var oos = new ObjectOutputStream(bos);
- try (oos) {
- var cause = new IndexOutOfBoundsException(4);
- var exc = new Exc(new SerializableReason("data", 4, 0, 3), cause);
- oos.writeObject(exc);
- }
-
- var bytes = bos.toByteArray();
- var ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
- try (ois) {
- var obj = ois.readObject();
- assertThat(obj).isInstanceOf(Exc.class);
-
- var exc = Exc.class.cast(obj);
- var cause = exc.getCause();
- assertThat(cause).isInstanceOf(IndexOutOfBoundsException.class);
- assertThat(cause.getMessage()).isEqualTo("Index out of range: 4");
-
- var robj = exc.getReason();
- assertThat(robj).isInstanceOf(SerializableReason.class);
- var reason = SerializableReason.class.cast(robj);
- assertThat(reason.name()).isEqualTo("data");
- assertThat(reason.index()).isEqualTo(4);
- assertThat(reason.min()).isEqualTo(0);
- assertThat(reason.max()).isEqualTo(3);
- }
- }
+ @Test
+ void reason_is_serializable_and_has_cause() throws Exception {
+ var bos = new ByteArrayOutputStream();
+ var oos = new ObjectOutputStream(bos);
+ try (oos) {
+ var cause = new IndexOutOfBoundsException(4);
+ var exc = new Exc(new SerializableReason("data", 4, 0, 3), cause);
+ oos.writeObject(exc);
+ }
+
+ var bytes = bos.toByteArray();
+ var ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
+ try (ois) {
+ var obj = ois.readObject();
+ assertThat(obj).isInstanceOf(Exc.class);
+
+ var exc = Exc.class.cast(obj);
+ var cause = exc.getCause();
+ assertThat(cause).isInstanceOf(IndexOutOfBoundsException.class);
+ assertThat(cause.getMessage()).isEqualTo("Index out of range: 4");
+
+ var robj = exc.getReason();
+ assertThat(robj).isInstanceOf(SerializableReason.class);
+ var reason = SerializableReason.class.cast(robj);
+ assertThat(reason.name()).isEqualTo("data");
+ assertThat(reason.index()).isEqualTo(4);
+ assertThat(reason.min()).isEqualTo(0);
+ assertThat(reason.max()).isEqualTo(3);
+ }
+ }
- @Test
- void reason_is_not_serializable() throws Exception {
- var bos = new ByteArrayOutputStream();
- var oos = new ObjectOutputStream(bos);
- try (oos) {
- var exc = new Exc(new IndexOutOfRange("data", 4, 0, 3));
- oos.writeObject(exc);
- fail();
- } catch (NotSerializableException e) {
- assertThat(e.getMessage()).isEqualTo(IndexOutOfRange.class.getName());
- }
- }
+ @Test
+ void reason_is_not_serializable() throws Exception {
+ var bos = new ByteArrayOutputStream();
+ var oos = new ObjectOutputStream(bos);
+ try (oos) {
+ var exc = new Exc(new IndexOutOfRange("data", 4, 0, 3));
+ oos.writeObject(exc);
+ fail();
+ } catch (NotSerializableException e) {
+ assertThat(e.getMessage()).isEqualTo(IndexOutOfRange.class.getName());
+ }
}
+ }
}