|
|
@@ -0,0 +1,174 @@
|
|
|
+/*
|
|
|
+ * @author Ranides Atterwim <ranides@gmail.com>
|
|
|
+ * @copyright Ranides Atterwim
|
|
|
+ * @license WTFPL
|
|
|
+ * @url http://ranides.net/projects/assira
|
|
|
+ */
|
|
|
+package net.ranides.assira.trace;
|
|
|
+
|
|
|
+import java.io.PrintWriter;
|
|
|
+import java.io.StringWriter;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Optional;
|
|
|
+import java.util.function.Consumer;
|
|
|
+import java.util.function.Supplier;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+import java.util.stream.Stream;
|
|
|
+import java.util.stream.StreamSupport;
|
|
|
+import net.ranides.assira.collection.iterators.ForwardSpliterator;
|
|
|
+import net.ranides.assira.events.EventListener;
|
|
|
+import net.ranides.assira.events.Events;
|
|
|
+import net.ranides.assira.functional.CheckedRunnable;
|
|
|
+
|
|
|
+/**
|
|
|
+ *
|
|
|
+ * @author ranides
|
|
|
+ */
|
|
|
+public final class ExceptionUtils {
|
|
|
+
|
|
|
+ private ExceptionUtils() { }
|
|
|
+
|
|
|
+ public static String toString(Throwable cause) {
|
|
|
+ StringWriter out = new StringWriter();
|
|
|
+ cause.printStackTrace(new PrintWriter(out));
|
|
|
+ return out.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ public static Stream<Throwable> getCauseStream(Throwable cause) {
|
|
|
+ return StreamSupport.stream(new CauseSpliterator(cause), false);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static List<Throwable> getCauseList(Throwable cause) {
|
|
|
+ return getCauseStream(cause).collect(Collectors.toList());
|
|
|
+ }
|
|
|
+
|
|
|
+ public static String getStackTrace(Throwable cause) {
|
|
|
+ StringWriter result = new StringWriter();
|
|
|
+ PrintWriter writer = new PrintWriter(result);
|
|
|
+ cause.printStackTrace(writer);
|
|
|
+ writer.flush();
|
|
|
+ return result.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ public static RuntimeException rethrow(Throwable cause) {
|
|
|
+ new ExceptionErasure<RuntimeException>().rethrow(cause);
|
|
|
+
|
|
|
+ // not reachable, wyjątek bez wrappowania leci linię wyżej
|
|
|
+ throw new RuntimeException(cause); // NOPMD
|
|
|
+ }
|
|
|
+
|
|
|
+ private static class ExceptionErasure<T extends Throwable> { // NOPMD
|
|
|
+
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
+ private void rethrow(Throwable exception) throws T {
|
|
|
+ throw (T) exception;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ private static final class CauseSpliterator extends ForwardSpliterator<Throwable> {
|
|
|
+
|
|
|
+ private Throwable current;
|
|
|
+
|
|
|
+ public CauseSpliterator(Throwable current) {
|
|
|
+ this.current = current;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean tryAdvance(Consumer<? super Throwable> action) {
|
|
|
+ if(null == current) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ action.accept(current);
|
|
|
+ current = current.getCause();
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ public static <E extends Exception> GroupExceptions<E> group(Supplier<E> supplier) {
|
|
|
+ return new GroupExceptions<>(supplier);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static <E extends Exception> ConsumeExceptions<E> consume(Consumer<E> consumer) {
|
|
|
+ return new ConsumeExceptions<>(consumer);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static <E extends Exception> ObserveExceptions observe(EventListener<? super Events.Failure> listener) {
|
|
|
+ return new ObserveExceptions(listener);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static class ObserveExceptions {
|
|
|
+
|
|
|
+ private final EventListener<? super Events.Failure> listener;
|
|
|
+
|
|
|
+ ObserveExceptions(EventListener<? super Events.Failure> listener) {
|
|
|
+ this.listener = listener;
|
|
|
+ }
|
|
|
+
|
|
|
+ public <T extends Exception> ObserveExceptions run(CheckedRunnable<T> action) {
|
|
|
+ try {
|
|
|
+ action.run();
|
|
|
+ } catch(Exception cause) {
|
|
|
+ listener.handleEvent(Events.failure(cause));
|
|
|
+ }
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ public static class ConsumeExceptions<E extends Exception> {
|
|
|
+
|
|
|
+ private final Consumer<E> consumer;
|
|
|
+
|
|
|
+ ConsumeExceptions(Consumer<E> consumer) {
|
|
|
+ this.consumer = consumer;
|
|
|
+ }
|
|
|
+
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
+ public ConsumeExceptions<E> run(CheckedRunnable<E> action) {
|
|
|
+ try {
|
|
|
+ action.run();
|
|
|
+ } catch(Exception cause) {
|
|
|
+ consumer.accept((E)cause);
|
|
|
+ }
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ public static class GroupExceptions<E extends Exception> {
|
|
|
+
|
|
|
+ private final Supplier<E> supplier;
|
|
|
+
|
|
|
+ private E exception;
|
|
|
+
|
|
|
+ GroupExceptions(Supplier<E> supplier) {
|
|
|
+ this.supplier = supplier;
|
|
|
+ }
|
|
|
+
|
|
|
+ public <T extends Exception> GroupExceptions<E> run(CheckedRunnable<T> action) {
|
|
|
+ try {
|
|
|
+ action.run();
|
|
|
+ } catch(Exception cause) {
|
|
|
+ if(exception == null) {
|
|
|
+ exception = supplier.get();
|
|
|
+ }
|
|
|
+ exception.addSuppressed(cause);
|
|
|
+ }
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ public Optional<E> cause() {
|
|
|
+ return Optional.ofNullable(exception);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void rethrow() throws E {
|
|
|
+ if(null != exception) {
|
|
|
+ throw exception;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+}
|