com.adgear.anoa.AnoaHandler Maven / Gradle / Ivy
package com.adgear.anoa;
import com.adgear.anoa.write.WriteConsumer;
import org.jooq.lambda.fi.util.function.CheckedBiConsumer;
import org.jooq.lambda.fi.util.function.CheckedBiFunction;
import org.jooq.lambda.fi.util.function.CheckedConsumer;
import org.jooq.lambda.fi.util.function.CheckedFunction;
import org.jooq.lambda.fi.util.function.CheckedPredicate;
import org.jooq.lambda.fi.util.function.CheckedSupplier;
import java.util.Objects;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;
import java.util.stream.Stream;
/**
* A factory object for generating {@code Anoa} container objects, either directly or via interfaces
* in {@link java.util.function}, and also {@link org.jooq.lambda.fi.util.function} for checked
* equivalents.
*
* @param Metadata type
* @see Anoa
*/
final public class AnoaHandler {
/**
* An AnoaHandler which discards everything. Resulting {@code Anoa} containers have no value and
* no metadata.
*/
static public final AnoaHandler> DISCARD_HANDLER
= new AnoaHandler<>(__ -> Anoa.EMPTY.meta);
/**
* An AnoaHandler which generates {@code Anoa} containers with the exception thrown as metadata,
* if any.
*/
static public final AnoaHandler NO_OP_HANDLER
= new AnoaHandler<>(AnoaHandler::arraySize1);
/**
* Exception handlers
*/
final Handler0 handler0;
final Handler1 handler1;
final Handler2 handler2;
/**
* Construct an instance with a context-independent exception handler. This means that the
* supplied handler's output depends solely on the handled exception, and not on the context
* within which the exception was thrown, such as a functional interface's arguments, etc.
*
* @param handler0 context-independent exception handler
*/
public AnoaHandler(
Handler0 handler0) {
this(handler0, ((t, __) -> handler0.apply(t)), ((t, _1, _2) -> handler0.apply(t)));
}
/**
* Construct an instance with full exception handling.
*
* @param handler0 context-independent exception handler used for suppliers
* @param handler1 exception handler used for functions and consumers
* @param handler2 exception handler used for bifunctions and biconsumers
*/
public AnoaHandler(
Handler0 handler0,
Handler1 handler1,
Handler2 handler2) {
Objects.requireNonNull(handler0);
Objects.requireNonNull(handler1);
Objects.requireNonNull(handler2);
this.handler0 = handler0;
this.handler1 = handler1;
this.handler2 = handler2;
}
/**
* Convenience factory method for constructing from a simple exception handler.
*
* @param Metadata type
*/
static public AnoaHandler withFn(
Function mapToMetaDatum) {
return new AnoaHandler<>(Handler0.of(mapToMetaDatum));
}
@SuppressWarnings("unchecked")
static M[] arraySize1(M metadatum) {
final M[] meta = (M[]) new Object[1];
meta[0] = metadatum;
return meta;
}
/**
* Wraps {@link Supplier} into another which returns: - an {@code Anoa} container with the
* value returned by {@link Function#apply(Object)}, or else
- if an exception was thrown, a
* valueless container with metadata generated by {@link #handle(Throwable, Object)}.
*/
public Supplier> supplier(
Supplier extends T> supplier) {
Objects.requireNonNull(supplier);
return () -> {
try {
return Anoa.ofNullable(supplier.get());
} catch (Throwable throwable) {
return Anoa.empty(handle(throwable));
}
};
}
/**
* @see #supplier(Supplier)
*/
public Supplier> supplierChecked(
CheckedSupplier extends T> supplier) {
Objects.requireNonNull(supplier);
return () -> {
try {
return Anoa.ofNullable(supplier.get());
} catch (Throwable throwable) {
return Anoa.empty(handle(throwable));
}
};
}
/**
* Wraps {@link Function} into another which returns: - the {@code Anoa} input container if
* it is valueless, or else
- a copy of the input container with the value replaced by the value
* returned by {@link Function#apply(Object)}, or else
- if an exception was thrown: a valueless
* copy of the input container with additional metadata generated by {@link #handle(Throwable,
* Object)}.
*/
public Function, Anoa> function(
Function super U, ? extends T> function) {
Objects.requireNonNull(function);
return (Anoa uWrapped) -> (
uWrapped.flatMap((U u) -> {
try {
return Anoa.ofNullable(function.apply(u));
} catch (Throwable throwable) {
return Anoa.empty(handle(throwable, u));
}
}));
}
/**
* @see #function(Function)
*/
public Function, Anoa> functionChecked(
CheckedFunction super U, ? extends T> function) {
Objects.requireNonNull(function);
return (Anoa uWrapped) -> (
uWrapped.flatMap((U u) -> {
try {
return Anoa.ofNullable(function.apply(u));
} catch (Throwable throwable) {
return Anoa.empty(handle(throwable, u));
}
}));
}
/**
* Wraps {@link BiFunction} into another which returns: - the {@code Anoa} input container
* if it is valueless, or else
- a copy of the input container with the value replaced by the
* value returned by {@link BiFunction#apply(Object, Object)}, or else
- if an exception was
* thrown: a valueless copy of the input container with additional metadata generated by {@link
* #handle(Throwable, Object, Object)}.
*/
public BiFunction, V, Anoa> biFunction(
BiFunction super U, ? super V, ? extends T> biFunction) {
Objects.requireNonNull(biFunction);
return (Anoa uWrapped, V v) -> (
uWrapped.flatMap((U u) -> {
try {
return Anoa.ofNullable(biFunction.apply(u, v));
} catch (Throwable throwable) {
return Anoa.empty(handle(throwable, u, v));
}
}));
}
/**
* @see #biFunction(BiFunction)
*/
public BiFunction, V, Anoa> biFunctionChecked(
CheckedBiFunction super U, ? super V, ? extends T> biFunction) {
Objects.requireNonNull(biFunction);
return (Anoa uWrapped, V v) -> (
uWrapped.flatMap((U u) -> {
try {
return Anoa.ofNullable(biFunction.apply(u, v));
} catch (Throwable throwable) {
return Anoa.empty(handle(throwable, u, v));
}
}));
}
/**
* Wraps {@link Predicate} into a function which returns: - the {@code Anoa} input
* container if it is valueless or if the predicate test on the value succeeds, or else
- a
* valueless copy of the input container if the test fails, or else
- if an exception was
* thrown: a valueless copy of the input container with additional metadata generated by {@link
* #handle(Throwable, Object)}.
*/
public UnaryOperator> predicate(
Predicate super T> predicate) {
return predicate(predicate, __ -> Stream.empty());
}
/**
* @see #predicate(Predicate)
*/
public UnaryOperator> predicateChecked(
CheckedPredicate super T> predicate) {
return predicateChecked(predicate, __ -> Stream.empty());
}
/**
* Wraps {@link Predicate} into a function which returns: - the {@code Anoa} input
* container if it is valueless or if the predicate test on the value succeeds, or else
- a
* valueless copy of the input container with additional metadata generated by {@code failHandler}
* applied to the value, if the predicate test on the value fails, or else
- if an exception was
* thrown: a valueless copy of the input container with additional metadata generated by {@link
* #handle(Throwable, Object)}.
*/
public UnaryOperator> predicate(
Predicate super T> predicate,
Function super T, Stream> failHandler) {
Objects.requireNonNull(predicate);
Objects.requireNonNull(failHandler);
return (Anoa tWrapped) -> (
tWrapped.flatMap((T t) -> {
final boolean testResult;
try {
testResult = predicate.test(t);
} catch (Throwable throwable) {
return Anoa.empty(handle(throwable, t));
}
return testResult
? Anoa.of(t)
: Anoa.empty(failHandler.apply(t));
}));
}
/**
* @see #predicate(Predicate, Function)
*/
public UnaryOperator> predicateChecked(
CheckedPredicate super T> predicate,
Function super T, Stream> failHandler) {
Objects.requireNonNull(predicate);
Objects.requireNonNull(failHandler);
return (Anoa tWrapped) -> (
tWrapped.flatMap((T t) -> {
final boolean testResult;
try {
testResult = predicate.test(t);
} catch (Throwable throwable) {
return Anoa.empty(handle(throwable, t));
}
return testResult
? Anoa.of(t)
: Anoa.empty(failHandler.apply(t));
}));
}
/**
* Wraps {@link Consumer} into a function which applies {@code consumer} to the input container's
* value as a side effect, if present, and then returns: - the {@code Anoa} input
* container, or else
- if an exception was thrown: a valueless copy of the input container with
* additional metadata generated by {@link #handle(Throwable, Object)}.
*/
public UnaryOperator> consumer(
Consumer consumer) {
Objects.requireNonNull(consumer);
return (Anoa tWrapped) -> (
tWrapped.flatMap((T t) -> {
try {
consumer.accept(t);
} catch (Throwable throwable) {
return Anoa.empty(handle(throwable, t));
}
return Anoa.of(t);
}));
}
/**
* @see #consumer(Consumer)
*/
public UnaryOperator> consumerChecked(
CheckedConsumer super T> consumer) {
Objects.requireNonNull(consumer);
return (Anoa tWrapped) -> (
tWrapped.flatMap((T t) -> {
try {
consumer.accept(t);
} catch (Throwable throwable) {
return Anoa.empty(handle(throwable, t));
}
return Anoa.of(t);
}));
}
/**
* @see #consumer(Consumer)
*/
public UnaryOperator> writeConsumer(
WriteConsumer super T> writeConsumer) {
Objects.requireNonNull(writeConsumer);
return (Anoa tWrapped) -> (
tWrapped.flatMap((T t) -> {
try {
writeConsumer.acceptChecked(t);
} catch (Throwable throwable) {
return Anoa.empty(handle(throwable, t));
}
return Anoa.of(t);
}));
}
/**
* Wraps {@link BiConsumer} into a function which applies {@code biConsumer} to the input
* container's value as a side effect, if present, and then returns: - the {@code Anoa}
* input container, or else
- if an exception was thrown: a valueless copy of the input
* container with additional metadata generated by {@link #handle(Throwable, Object, Object)}.
*
*/
public BiFunction, U, Anoa> biConsumer(
BiConsumer super T, ? super U> biConsumer) {
Objects.requireNonNull(biConsumer);
return (Anoa tWrapped, U u) -> (
tWrapped.flatMap((T t) -> {
try {
biConsumer.accept(t, u);
} catch (Throwable throwable) {
return Anoa.empty(handle(throwable, t, u));
}
return Anoa.of(t);
}));
}
/**
* @see #biConsumer(BiConsumer)
*/
public BiFunction, U, Anoa> biConsumerChecked(
CheckedBiConsumer super T, ? super U> biConsumer) {
Objects.requireNonNull(biConsumer);
return (Anoa tWrapped, U u) -> (
tWrapped.flatMap((T t) -> {
try {
biConsumer.accept(t, u);
} catch (Throwable throwable) {
return Anoa.empty(handle(throwable, t, u));
}
return Anoa.of(t);
}));
}
/**
* @see Anoa#empty()
*/
public Anoa empty() {
return Anoa.empty();
}
/**
* @see Anoa#empty(Stream)
*/
public Anoa empty(Stream metadata) {
return Anoa.empty(metadata);
}
/**
* @see Anoa#of(Object)
*/
public Anoa of(T value) {
return Anoa.of(value);
}
/**
* @see Anoa#of(Object, Stream)
*/
public Anoa of(T value, Stream metadata) {
return Anoa.of(value, metadata);
}
/**
* @see Anoa#ofNullable(Object)
*/
public Anoa ofNullable(T value) {
return Anoa.ofNullable(value);
}
/**
* @see Anoa#ofNullable(Object, Stream)
*/
public Anoa ofNullable(T value, Stream metadata) {
return Anoa.ofNullable(value, metadata);
}
/**
* Generates a stream of metadata from the appropriate exception handler
*
* @param throwable Exception to handle
* @return metadata
*/
public Stream handle(
Throwable throwable) {
return Stream.of(handler0.apply(throwable));
}
/**
* Generates a stream of metadata from the appropriate exception handler
*
* @param throwable Exception to handle
* @param value The input value for which {@code throwable} was thrown
* @param Input value type
* @return metadata
*/
public Stream handle(
Throwable throwable,
U value) {
return Stream.of(handler1.apply(throwable, value));
}
/**
* Generates a stream of metadata from the appropriate exception handler
*
* @param throwable Exception to handle
* @param value The input value for which {@code throwable} was thrown
* @param other Additional input value for which {@code throwable} was thrown
* @param Input value type
* @param Additional input value type
* @return metadata
*/
public Stream handle(
Throwable throwable,
U value,
V other) {
return Stream.of(handler2.apply(throwable, value, other));
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy