All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.artkonr.result.BaseResult Maven / Gradle / Ivy

package io.github.artkonr.result;

import lombok.NonNull;

import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

/**
 * An abstract result container that suggests that there
 *  is an operation that concludes OK or with an error. Suited
 *  for catching and propagating errors in a functional style.
 * 

Two principal states are managed by this entity: *

    *
  1. {@code OK} - stands for a successful completion;
  2. *
  3. {@code ERR} - stands for an errored completion.
  4. *
*

Implementations decide what constitutes an {@code OK} result, * but the {@code ERR} result is enforced by this class: an error * result is always backed by a generified {@link Exception}. * @param type of exception held by the ERR result. */ public abstract class BaseResult { /** * Contained error state. *

Internal implementation detail: following the previous point, * this class and subclasses decide if an instance stands for * {@code OK} or {@code ERR} based */ protected final E error; /** * Checks if {@code this} instance is {@code OK}. * @return {@code true} if {@code this} is an {@code OK} result */ public final boolean isOk() { return error == null; } /** * Checks if {@code this} instance is {@code ERR}. * @return {@code true} if {@code this} is an {@code ERR} result */ public final boolean isErr() { return error != null; } /** * Checks if {@code this} instance is {@code ERR} * and the underlying error is of the specified * type or its subclass. * @param type expected type * @return {@code true} if {@code this} is an {@code ERR} * result and the predicate holds * @throws IllegalArgumentException if no argument provided */ public final boolean isErrAnd(@NonNull Class type) { return isErr() && type.isAssignableFrom(error.getClass()); } /** * Checks if {@code this} instance is {@code ERR} * and the specified predicate holds. * @param predicate predicate * @return {@code true} if {@code this} is an {@code ERR} * result and the predicate holds * @throws IllegalArgumentException if no argument provided */ public final boolean isErrAnd(@NonNull Predicate predicate) { return isErr() && predicate.test(error); } /** * Attempts to get container {@code ERR} state. * @return internal {@code ERR} state * @throws IllegalStateException if {@code this} instance is not an {@code ERR} result. */ public final E getErr() { if (isErr()) { return error; } else { throw new IllegalStateException("not an ERR result"); } } /** * Applies a callback function to convert the internal * error state if {@code this} instance is {@code ERR}; * returns a recreated {@code OK} otherwise. * @param remap callback * @return mapped result * @param new error type * @throws IllegalArgumentException if no argument provided or * if the callback function returns {@code null} */ public abstract BaseResult mapErr(@NonNull Function remap); /** * Erases the {@code ERR} type information of * {@code this} result. * @return result with broadened */ public abstract BaseResult upcast(); /** * Converts an {@code OK} result into {@code ERR} * using the specified factory if {@code this} * instance is {@code OK}. Recreates {@code this} * with its internal error state otherwise. *

Note: the resulting type parameter is up-cast * to the most generic type supported: {@link Exception}. * @param factory exception factory * @return converted result * @throws IllegalArgumentException if no argument provided * or if the factory returns a {@code null} */ public abstract BaseResult taint(@NonNull Supplier factory); /** * Converts an {@code OK} result into {@code ERR} * using the specified factory if {@code this} * instance is {@code OK}. Recreates {@code this} * with its internal error state otherwise. *

Contrary to {@link BaseResult#taint(Supplier) tainting}, * this method implies that the type of the error * created by the factory matches the type of * {@code this} instance. * @param factory exception factory * @return converted result * @throws IllegalArgumentException if no argument provided * or if the factory returns a {@code null} */ public abstract BaseResult fork(@NonNull Supplier factory); /** * Performs the specified callback if {@code this} * instance is {@code ERR} or does nothing otherwise. * @param action callback * @throws IllegalArgumentException if the argument is null */ public void ifOk(@NonNull Runnable action) { if (isOk()) { action.run(); } } /** * Performs the specified callback if {@code this} * instance is {@code ERR} or does nothing otherwise. * @param action callback * @throws IllegalArgumentException if the argument is null */ public void ifErr(@NonNull Runnable action) { if (isErr()) { action.run(); } } /** * Performs the specified callback if {@code this} * instance is {@code ERR} or does nothing otherwise. * @param action callback * @throws IllegalArgumentException if the argument is null */ public void ifErr(@NonNull Consumer action) { if (isErr()) { action.accept(error); } } /** * Exception factory: creates an exception that notifies of * an unexpected exception during wrapping. * @param expected expected type * @param err actual error caught * @return created exception */ protected static IllegalStateException unexpectedWrappedException(Class expected, Exception err) { return new IllegalStateException(String.format( "unexpected wrapped exception: expected=%s actual=%s", expected.getName(), err )); } /** * Internal constructor. *

Setting the argument to {@code null} must * follow the class contract. * @param error nullable error value */ protected BaseResult(E error) { this.error = error; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy