|
@@ -6,6 +6,7 @@
|
|
|
*/
|
|
*/
|
|
|
package net.ranides.assira.trace;
|
|
package net.ranides.assira.trace;
|
|
|
|
|
|
|
|
|
|
+import lombok.experimental.UtilityClass;
|
|
|
import net.ranides.assira.collection.iterators.ForwardSpliterator;
|
|
import net.ranides.assira.collection.iterators.ForwardSpliterator;
|
|
|
import net.ranides.assira.events.EventListener;
|
|
import net.ranides.assira.events.EventListener;
|
|
|
import net.ranides.assira.events.Events;
|
|
import net.ranides.assira.events.Events;
|
|
@@ -22,27 +23,52 @@ import java.util.stream.Stream;
|
|
|
import java.util.stream.StreamSupport;
|
|
import java.util.stream.StreamSupport;
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
|
|
+ * Utility methods for Exception objects.
|
|
|
*
|
|
*
|
|
|
* @author ranides
|
|
* @author ranides
|
|
|
*/
|
|
*/
|
|
|
-public final class ExceptionUtils {
|
|
|
|
|
|
|
+@UtilityClass
|
|
|
|
|
+public class ExceptionUtils {
|
|
|
|
|
|
|
|
- private ExceptionUtils() { }
|
|
|
|
|
-
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Converts exception to String.
|
|
|
|
|
+ *
|
|
|
|
|
+ * It returns formatted stacktrace, but exact format is undefined.
|
|
|
|
|
+ * The point of the method is to return readable and meaningful description of exception.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param cause cause
|
|
|
|
|
+ * @return String
|
|
|
|
|
+ */
|
|
|
public static String toString(Throwable cause) {
|
|
public static String toString(Throwable cause) {
|
|
|
- StringWriter out = new StringWriter();
|
|
|
|
|
- cause.printStackTrace(new PrintWriter(out));
|
|
|
|
|
- return out.toString();
|
|
|
|
|
|
|
+ return getStackTrace(cause);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Returns stream with chain of cause exceptions.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param cause cause
|
|
|
|
|
+ * @return stream
|
|
|
|
|
+ */
|
|
|
public static Stream<Throwable> getCauseStream(Throwable cause) {
|
|
public static Stream<Throwable> getCauseStream(Throwable cause) {
|
|
|
return StreamSupport.stream(new CauseSpliterator(cause), false);
|
|
return StreamSupport.stream(new CauseSpliterator(cause), false);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Returns list with chain of cause exceptions.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param cause cause
|
|
|
|
|
+ * @return list
|
|
|
|
|
+ */
|
|
|
public static List<Throwable> getCauseList(Throwable cause) {
|
|
public static List<Throwable> getCauseList(Throwable cause) {
|
|
|
return getCauseStream(cause).collect(Collectors.toList());
|
|
return getCauseStream(cause).collect(Collectors.toList());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Returns formatted stacktrace as String
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param cause cause
|
|
|
|
|
+ * @return string
|
|
|
|
|
+ */
|
|
|
public static String getStackTrace(Throwable cause) {
|
|
public static String getStackTrace(Throwable cause) {
|
|
|
StringWriter result = new StringWriter();
|
|
StringWriter result = new StringWriter();
|
|
|
PrintWriter writer = new PrintWriter(result);
|
|
PrintWriter writer = new PrintWriter(result);
|
|
@@ -51,6 +77,22 @@ public final class ExceptionUtils {
|
|
|
return result.toString();
|
|
return result.toString();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * It is sneaky throw.
|
|
|
|
|
+ * It throws any passed exception, without declaring it, even check one.
|
|
|
|
|
+ *
|
|
|
|
|
+ * It can be used by simple call:
|
|
|
|
|
+ * ExceptionUtils.rethrow(new IOException(...))
|
|
|
|
|
+ *
|
|
|
|
|
+ * But preferred way is to write:
|
|
|
|
|
+ * throw ExceptionUtils.rethrow(new IOException(...))
|
|
|
|
|
+ *
|
|
|
|
|
+ * Second form tells the compiler, that we throw unconditionally,
|
|
|
|
|
+ * so flow analysis will work correctly.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param cause cause
|
|
|
|
|
+ * @return should be ingored
|
|
|
|
|
+ */
|
|
|
public static RuntimeException rethrow(Throwable cause) {
|
|
public static RuntimeException rethrow(Throwable cause) {
|
|
|
new ExceptionErasure<RuntimeException>().rethrow(cause);
|
|
new ExceptionErasure<RuntimeException>().rethrow(cause);
|
|
|
|
|
|
|
@@ -86,19 +128,52 @@ public final class ExceptionUtils {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * It creates executor, which will collect all thrown exceptions as
|
|
|
|
|
+ * suppressed objects inside "E" created by provided supplier.
|
|
|
|
|
+ * Supplier will be called by executor only if some exception is thrown at least once.
|
|
|
|
|
+ *
|
|
|
|
|
+ * Returned executor allows to run any code by calling {@link GroupExceptions#run(CheckedRunnable)}
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param supplier supplier
|
|
|
|
|
+ * @param <E> E
|
|
|
|
|
+ * @return executor
|
|
|
|
|
+ */
|
|
|
public static <E extends Exception> GroupExceptions<E> group(Supplier<E> supplier) {
|
|
public static <E extends Exception> GroupExceptions<E> group(Supplier<E> supplier) {
|
|
|
return new GroupExceptions<>(supplier);
|
|
return new GroupExceptions<>(supplier);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * It creates executor, which will send all thrown exceptions to consumer.
|
|
|
|
|
+ *
|
|
|
|
|
+ * Returned executor allows to run any code by calling {@link ConsumeExceptions#run(CheckedRunnable)}
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param consumer consumer
|
|
|
|
|
+ * @param <E> E
|
|
|
|
|
+ * @return executor
|
|
|
|
|
+ */
|
|
|
public static <E extends Exception> ConsumeExceptions<E> consume(Consumer<E> consumer) {
|
|
public static <E extends Exception> ConsumeExceptions<E> consume(Consumer<E> consumer) {
|
|
|
return new ConsumeExceptions<>(consumer);
|
|
return new ConsumeExceptions<>(consumer);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * It creates executor, which will send all thrown exceptions to event listener.
|
|
|
|
|
+ * Type of generated event is: {@link Events.Failure}.
|
|
|
|
|
+ *
|
|
|
|
|
+ * Returned executor allows to run any code by calling {@link ConsumeExceptions#run(CheckedRunnable)}
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param listener listener
|
|
|
|
|
+ * @param <E> E
|
|
|
|
|
+ * @return executor
|
|
|
|
|
+ */
|
|
|
public static <E extends Exception> ObserveExceptions observe(EventListener<? super Events.Failure> listener) {
|
|
public static <E extends Exception> ObserveExceptions observe(EventListener<? super Events.Failure> listener) {
|
|
|
return new ObserveExceptions(listener);
|
|
return new ObserveExceptions(listener);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Executor which allows execution of arbitrary code and sends events about thrown exceptions.
|
|
|
|
|
+ */
|
|
|
public static class ObserveExceptions {
|
|
public static class ObserveExceptions {
|
|
|
|
|
|
|
|
private final EventListener<? super Events.Failure> listener;
|
|
private final EventListener<? super Events.Failure> listener;
|
|
@@ -106,7 +181,15 @@ public final class ExceptionUtils {
|
|
|
ObserveExceptions(EventListener<? super Events.Failure> listener) {
|
|
ObserveExceptions(EventListener<? super Events.Failure> listener) {
|
|
|
this.listener = listener;
|
|
this.listener = listener;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Executes code and catches thrown exceptions.
|
|
|
|
|
+ * You can chain calls to this method.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param action action
|
|
|
|
|
+ * @param <T> T
|
|
|
|
|
+ * @return this
|
|
|
|
|
+ */
|
|
|
public <T extends Exception> ObserveExceptions run(CheckedRunnable<T> action) {
|
|
public <T extends Exception> ObserveExceptions run(CheckedRunnable<T> action) {
|
|
|
try {
|
|
try {
|
|
|
action.run();
|
|
action.run();
|
|
@@ -117,7 +200,12 @@ public final class ExceptionUtils {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Executor which allows execution of arbitrary code and sends thrown exceptions to consumer.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param <E> E
|
|
|
|
|
+ */
|
|
|
public static class ConsumeExceptions<E extends Exception> {
|
|
public static class ConsumeExceptions<E extends Exception> {
|
|
|
|
|
|
|
|
private final Consumer<E> consumer;
|
|
private final Consumer<E> consumer;
|
|
@@ -126,6 +214,13 @@ public final class ExceptionUtils {
|
|
|
this.consumer = consumer;
|
|
this.consumer = consumer;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Executes code and catches thrown exceptions.
|
|
|
|
|
+ * You can chain calls to this method.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param action action
|
|
|
|
|
+ * @return this
|
|
|
|
|
+ */
|
|
|
@SuppressWarnings("unchecked")
|
|
@SuppressWarnings("unchecked")
|
|
|
public ConsumeExceptions<E> run(CheckedRunnable<E> action) {
|
|
public ConsumeExceptions<E> run(CheckedRunnable<E> action) {
|
|
|
try {
|
|
try {
|
|
@@ -137,7 +232,16 @@ public final class ExceptionUtils {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Executor which allows execution of arbitrary code and collects thrown exceptions.
|
|
|
|
|
+ *
|
|
|
|
|
+ * Exceptions are collected as "suppressed" inside parent exception created by "supplier".
|
|
|
|
|
+ *
|
|
|
|
|
+ * Parent exception is created only if at least one exception is thrown.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param <E>
|
|
|
|
|
+ */
|
|
|
public static class GroupExceptions<E extends Exception> {
|
|
public static class GroupExceptions<E extends Exception> {
|
|
|
|
|
|
|
|
private final Supplier<E> supplier;
|
|
private final Supplier<E> supplier;
|
|
@@ -147,7 +251,15 @@ public final class ExceptionUtils {
|
|
|
GroupExceptions(Supplier<E> supplier) {
|
|
GroupExceptions(Supplier<E> supplier) {
|
|
|
this.supplier = supplier;
|
|
this.supplier = supplier;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Executes code and catches thrown exceptions.
|
|
|
|
|
+ * You can chain calls to this method.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param action action
|
|
|
|
|
+ * @param <T> T
|
|
|
|
|
+ * @return this
|
|
|
|
|
+ */
|
|
|
public <T extends Exception> GroupExceptions<E> run(CheckedRunnable<T> action) {
|
|
public <T extends Exception> GroupExceptions<E> run(CheckedRunnable<T> action) {
|
|
|
try {
|
|
try {
|
|
|
action.run();
|
|
action.run();
|
|
@@ -159,15 +271,29 @@ public final class ExceptionUtils {
|
|
|
}
|
|
}
|
|
|
return this;
|
|
return this;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- public Optional<E> cause() {
|
|
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Returns "container exception" with cause exceptions added as "suppressed"
|
|
|
|
|
+ * If there was no error then it returns none
|
|
|
|
|
+ *
|
|
|
|
|
+ * @return optional
|
|
|
|
|
+ */
|
|
|
|
|
+ public Optional<E> exception() {
|
|
|
return Optional.ofNullable(exception);
|
|
return Optional.ofNullable(exception);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- public void rethrow() throws E {
|
|
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Throws "container exception" if there was any error at execution time.
|
|
|
|
|
+ * If there was no error then it returns "false".
|
|
|
|
|
+ *
|
|
|
|
|
+ * @throws E E
|
|
|
|
|
+ * @return boolean
|
|
|
|
|
+ */
|
|
|
|
|
+ public boolean rethrow() throws E {
|
|
|
if(null != exception) {
|
|
if(null != exception) {
|
|
|
throw exception;
|
|
throw exception;
|
|
|
}
|
|
}
|
|
|
|
|
+ return false;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
}
|
|
}
|