feat(commons): more tools to meth with checked exceptions

This commit is contained in:
Johannes Frohnmeyer 2024-04-13 13:22:38 +02:00
parent 00d403a3cf
commit 19cf847382
Signed by: Johannes
GPG Key ID: E76429612C2929F4
11 changed files with 133 additions and 32 deletions

View File

@ -0,0 +1,95 @@
package io.gitlab.jfronny.commons.throwable;
import java.util.function.Supplier;
/**
* A utility class to hide checked exceptions from the java compiler.
*/
public class Assume {
/**
* Hides an exception from the java compiler, effectively making it unchecked.
* Wraps the runnable in a runnable not marked to throw the checked exception.
*
* @param runnable the runnable to wrap
* @param <TEx> the exception the runnable might throw
* @return a runnable not marked to throw the checked exception
*/
public static <TEx extends Throwable> Runnable isSafe(ThrowingRunnable<TEx> runnable) {
var rn = (ThrowingRunnable<RuntimeException>) (ThrowingRunnable) runnable;
return rn::run;
}
/**
* Hides an exception from the java compiler, effectively making it unchecked.
* Wraps the supplier in a supplier not marked to throw the checked exception.
*
* @param supplier the supplier to wrap
* @param <T> the return type of the supplier
* @param <TEx> the exception the supplier might throw
* @return a supplier not marked to throw the checked exception
*/
public static <T, TEx extends Throwable> Supplier<T> isSafe(ThrowingSupplier<T, TEx> supplier) {
var rn = (ThrowingSupplier<T, RuntimeException>) (ThrowingSupplier) supplier;
return rn::get;
}
/**
* Hides an exception from the java compiler, effectively making it unchecked.
* Runs a runnable.
*
* @param runnable the runnable to run
* @param <TEx> the exception the runnable might throw
*/
public static <TEx extends Throwable> void sneaky(ThrowingRunnable<TEx> runnable) {
isSafe(runnable).run();
}
/**
* Hides an exception from the java compiler, effectively making it unchecked.
* Runs a supplier and returns the result.
*
* @param supplier the supplier to run
* @param <T> the return type of the supplier
* @param <TEx> the exception the supplier might throw
* @return the result of the supplier
*/
public static <T, TEx extends Throwable> T sneaky(ThrowingSupplier<T, TEx> supplier) {
return isSafe(supplier).get();
}
/**
* Reintroduces an exception previously made sneaky, allowing you to catch it.
* The call does nothing except tricking the compiler into thinking that the exception is thrown.
*
* @param <TEx> the exception to reintroduce into the set of possible exceptions
* @throws TEx the introduced exception
*/
public static <TEx extends Throwable> void reintroduce() throws TEx {
}
/**
* Reintroduces an exception previously made sneaky, allowing you to catch it.
* Simply runs the runnable.
*
* @param runnable the runnable to run
* @param <TEx> the exception to reintroduce into the set of possible exceptions
* @throws TEx the exception that was thrown by the runnable
*/
public static <TEx extends Throwable> void reintroduce(Runnable runnable) throws TEx {
runnable.run();
}
/**
* Reintroduces an exception previously made sneaky, allowing you to catch it.
* Simply runs the supplier and returns the result.
*
* @param supplier the supplier to run
* @param <T> the return type of the supplier
* @param <TEx> the exception to reintroduce into the set of possible exceptions
* @return the result of the supplier
* @throws TEx the exception that was thrown by the supplier
*/
public static <T, TEx extends Throwable> T reintroduce(Supplier<T> supplier) throws TEx {
return supplier.get();
}
}

View File

@ -0,0 +1,22 @@
package io.gitlab.jfronny.commons.throwable;
import java.util.Objects;
public class ExceptionWrapper extends RuntimeException {
public ExceptionWrapper(Throwable e) {
super(e);
if (e instanceof RuntimeException) {
throw new IllegalArgumentException("ExceptionWrapper cannot wrap RuntimeExceptions");
}
}
public static RuntimeException wrap(Throwable t) {
Objects.requireNonNull(t);
return t instanceof RuntimeException r ? r : new ExceptionWrapper(t);
}
public static Throwable unwrap(Throwable t) {
Objects.requireNonNull(t);
return t instanceof ExceptionWrapper w ? w.getCause() : t;
}
}

View File

@ -90,7 +90,7 @@ public interface ThrowingBiConsumer<T, U, TEx extends Throwable> {
} catch (Throwable e) {
if (exception.isAssignableFrom(e.getClass()))
handler.accept((TEx) e);
else throw Try.runtimeException(e);
else throw ExceptionWrapper.wrap(e);
}
};
}
@ -98,7 +98,7 @@ public interface ThrowingBiConsumer<T, U, TEx extends Throwable> {
@Contract(value = "-> new", pure = true)
@ApiStatus.NonExtendable
default @NotNull BiConsumer<T, U> orThrow() {
return orThrow(Try::runtimeException)::accept;
return orThrow(t -> ExceptionWrapper.wrap(t))::accept;
}
@Contract(value = "_ -> new", pure = true)

View File

@ -85,7 +85,7 @@ public interface ThrowingBiFunction<T, U, R, TEx extends Throwable> {
} catch (Throwable e) {
if (exception.isAssignableFrom(e.getClass()))
return handler.apply((TEx) e);
else throw Try.runtimeException(e);
else throw ExceptionWrapper.wrap(e);
}
};
}
@ -93,7 +93,7 @@ public interface ThrowingBiFunction<T, U, R, TEx extends Throwable> {
@Contract(value = "-> new", pure = true)
@ApiStatus.NonExtendable
default @NotNull BiFunction<T, U, R> orThrow() {
return orThrow(Try::runtimeException)::apply;
return orThrow(t -> ExceptionWrapper.wrap(t))::apply;
}
@Contract(value = "_ -> new", pure = true)

View File

@ -86,7 +86,7 @@ public interface ThrowingBooleanSupplier<TEx extends Throwable> {
} catch (Throwable e) {
if (exception.isAssignableFrom(e.getClass()))
return handler.test((TEx) e);
else throw Try.runtimeException(e);
else throw ExceptionWrapper.wrap(e);
}
};
}
@ -94,7 +94,7 @@ public interface ThrowingBooleanSupplier<TEx extends Throwable> {
@Contract(value = "-> new", pure = true)
@ApiStatus.NonExtendable
default @NotNull BooleanSupplier orThrow() {
return orThrow(Try::runtimeException)::get;
return orThrow(t -> ExceptionWrapper.wrap(t))::get;
}
@Contract(value = "_ -> new", pure = true)

View File

@ -78,7 +78,7 @@ public interface ThrowingConsumer<T, TEx extends Throwable> {
} catch (Throwable e) {
if (exception.isAssignableFrom(e.getClass()))
handler.accept((TEx) e);
else throw Try.runtimeException(e);
else throw ExceptionWrapper.wrap(e);
}
};
}
@ -86,7 +86,7 @@ public interface ThrowingConsumer<T, TEx extends Throwable> {
@Contract(value = "-> new", pure = true)
@ApiStatus.NonExtendable
default @NotNull Consumer<T> orThrow() {
return orThrow(Try::runtimeException)::accept;
return orThrow(t -> ExceptionWrapper.wrap(t))::accept;
}
@Contract(value = "_ -> new", pure = true)

View File

@ -61,7 +61,7 @@ public interface ThrowingFunction<T, R, TEx extends Throwable> {
} catch (Throwable e) {
if (exception.isAssignableFrom(e.getClass()))
return handler.apply((TEx) e);
else throw Try.runtimeException(e);
else throw ExceptionWrapper.wrap(e);
}
};
}
@ -69,7 +69,7 @@ public interface ThrowingFunction<T, R, TEx extends Throwable> {
@Contract(value = "-> new", pure = true)
@ApiStatus.NonExtendable
default @NotNull Function<T, R> orThrow() {
return orThrow(Try::runtimeException)::apply;
return orThrow(t -> ExceptionWrapper.wrap(t))::apply;
}
@Contract(value = "_ -> new", pure = true)

View File

@ -106,7 +106,7 @@ public interface ThrowingPredicate<T, TEx extends Throwable> {
} catch (Throwable e) {
if (exception.isAssignableFrom(e.getClass()))
return handler.test((TEx) e);
else throw Try.runtimeException(e);
else throw ExceptionWrapper.wrap(e);
}
};
}
@ -114,7 +114,7 @@ public interface ThrowingPredicate<T, TEx extends Throwable> {
@Contract(value = "-> new", pure = true)
@ApiStatus.NonExtendable
default @NotNull Predicate<T> orThrow() {
return orThrow(Try::runtimeException)::test;
return orThrow(t -> ExceptionWrapper.wrap(t))::test;
}
@Contract(value = "_ -> new", pure = true)

View File

@ -54,7 +54,7 @@ public interface ThrowingRunnable<TEx extends Throwable> {
} catch (Throwable e) {
if (exception.isAssignableFrom(e.getClass()))
handler.accept((TEx) e);
else throw Try.runtimeException(e);
else throw ExceptionWrapper.wrap(e);
}
};
}
@ -62,7 +62,7 @@ public interface ThrowingRunnable<TEx extends Throwable> {
@Contract(value = "-> new", pure = true)
@ApiStatus.NonExtendable
default @NotNull Runnable orThrow() {
return orThrow(Try::runtimeException)::run;
return orThrow(t -> ExceptionWrapper.wrap(t))::run;
}
@Contract(value = "_ -> new", pure = true)

View File

@ -48,7 +48,7 @@ public interface ThrowingSupplier<T, TEx extends Throwable> {
} catch (Throwable e) {
if (exception.isAssignableFrom(e.getClass()))
return handler.apply((TEx) e);
else throw Try.runtimeException(e);
else throw ExceptionWrapper.wrap(e);
}
};
}
@ -56,7 +56,7 @@ public interface ThrowingSupplier<T, TEx extends Throwable> {
@Contract(value = "-> new", pure = true)
@ApiStatus.NonExtendable
default @NotNull Supplier<T> orThrow() {
return orThrow(Try::runtimeException)::get;
return orThrow(t -> ExceptionWrapper.wrap(t))::get;
}
@Contract(value = "_ -> new", pure = true)

View File

@ -3,8 +3,6 @@ package io.gitlab.jfronny.commons.throwable;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.Objects;
import java.util.function.*;
@ -121,18 +119,4 @@ public class Try {
public static <T> @NotNull Supplier<T> handle(@NotNull ThrowingSupplier<T, ?> tr, @NotNull Function<Throwable, ? extends T> handler) {
return Objects.requireNonNull(tr).addHandler(handler);
}
/**
* Converts any throwable to a RuntimeException (returns it if it is already one)
*
* @param t A throwable to convert
* @return A runtime exception
*/
@Contract(pure = true)
protected static @NotNull RuntimeException runtimeException(@NotNull Throwable t) {
Objects.requireNonNull(t);
return t instanceof RuntimeException e ? e
: t instanceof IOException e ? new UncheckedIOException(e)
: new RuntimeException(t);
}
}