functionalj.result.Result Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of functionalj-core Show documentation
Show all versions of functionalj-core Show documentation
The module for FunctionalJ Core.
// ============================================================================
// Copyright (c) 2017-2021 Nawapunth Manusitthipol (NawaMan - http://nawaman.net).
// ----------------------------------------------------------------------------
// MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// ============================================================================
package functionalj.result;
import static functionalj.function.Func.f;
import static java.util.Arrays.asList;
import static java.util.Objects.requireNonNull;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
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 functionalj.function.Func;
import functionalj.function.Func0;
import functionalj.function.Func1;
import functionalj.function.Func2;
import functionalj.function.Func3;
import functionalj.function.Func4;
import functionalj.function.Func5;
import functionalj.function.Func6;
import functionalj.function.FunctionInvocationException;
import functionalj.list.FuncList;
import functionalj.pipeable.Pipeable;
import functionalj.promise.HasPromise;
import functionalj.promise.Promise;
import functionalj.tuple.Tuple;
import functionalj.tuple.Tuple2;
import functionalj.validator.SimpleValidator;
import functionalj.validator.Validator;
import lombok.val;
import nullablej.nullable.Nullable;
// TODO - Make Result lazy.
public abstract class Result
implements
AsResult,
Pipeable>,
HasPromise,
ResultMapAddOn,
ResultChainAddOn,
ResultFilterAddOn ,
ResultPeekAddOn,
ResultStatusAddOn {
protected static Func1 throwException() {
return e -> { throw e; };
}
protected static Func1 throwRuntimeException() {
return e -> {
if (e instanceof RuntimeException)
throw e;
throw new RuntimeException(e);
};
}
protected static Func1 returnException() {
return e -> e;
}
protected Func1> returnValueException() {
return e -> newException(e);
}
protected static Func1> returnValueNull() {
return e -> Result.ofNull();
}
protected static Func1 returnNull() {
return e -> null;
}
protected static Func1 returnFalse() {
return e -> false;
}
protected static Func1 returnTrue() {
return e -> false;
}
@SuppressWarnings("rawtypes")
private static final Result NULL = new Value<>(null);
/**
* Returns the Null result.
*
* @param the data type of the result.
* @return the Result containing null value.
*/
public static Result ofNull() {
@SuppressWarnings("unchecked")
val nullResult = (Result)NULL;
return nullResult;
}
/**
* Returns the NotExist result.
*
* @param the data type of the result.
* @return the Result that is the result does not exist.
*/
public static Result ofNotExist() {
@SuppressWarnings("unchecked")
val notAvailableResult = (Result)Result.ofException(new ResultNotExistException());
return notAvailableResult;
}
/**
* Returns the NotExist result with message.
*
* @param message the exception message.
* @param the data type of the result.
* @return the Result that is the result is not available.
*/
public static Result ofNotExist(String message) {
@SuppressWarnings("unchecked")
val exceptionResult = (Result)Result.ofException(new ResultNotExistException(message, null));
return exceptionResult;
}
/**
* Returns the NotExist result with message and cause.
*
* @param message the exception message.
* @param cause the exception cause.
* @param the data type of the result.
* @return the Result that is the result is not available.
*/
public static Result ofNotExist(String message, Exception cause) {
@SuppressWarnings("unchecked")
val exceptionResult = (Result)Result.ofException(new ResultNotExistException(message, cause));
return exceptionResult;
}
/**
* Returns the NoMore result.
*
* @param the data type of the result.
* @return the Result that is the result does not exist.
*/
public static Result ofNoMore() {
@SuppressWarnings("unchecked")
val notAvailableResult = (Result)Result.ofException(new NoMoreResultException());
return notAvailableResult;
}
/**
* Returns the NoMore result with message.
*
* @param message the exception message.
* @param the data type of the result.
* @return the Result that is the result is not available.
*/
public static Result ofNoMore(String message) {
@SuppressWarnings("unchecked")
val exceptionResult = (Result)Result.ofException(new NoMoreResultException(message, null));
return exceptionResult;
}
/**
* Returns the NoMore result with message and cause.
*
* @param message the exception message.
* @param cause the exception cause.
* @param the data type of the result.
* @return the Result that is the result is not available.
*/
public static Result ofNoMore(String message, Exception cause) {
@SuppressWarnings("unchecked")
val exceptionResult = (Result)Result.ofException(new NoMoreResultException(message, cause));
return exceptionResult;
}
/**
* Returns the NotReady result.
*
* @param the data type of the result.
* @return the Result that is the result is not ready.
*/
public static Result ofNotReady() {
@SuppressWarnings("unchecked")
val notReady = (Result)Result.ofException(new ResultNotReadyException());
return notReady;
}
/**
* Returns the NotReady result with message.
*
* @param message the exception message.
* @param the data type of the result.
* @return the Result that is the result is not ready.
*/
public static Result ofNotReady(String message) {
@SuppressWarnings("unchecked")
val exceptionResult = (Result)Result.ofException(new ResultNotReadyException(message, null));
return exceptionResult;
}
/**
* Returns the NotReady result with message.
*
* @param message the exception message.
* @param cause the exception cause.
* @param the data type of the result.
* @return the Result that is the result is not ready.
*/
public static Result ofNotReady(String message, Exception cause) {
@SuppressWarnings("unchecked")
val exceptionResult = (Result)Result.ofException(new ResultNotReadyException(message, cause));
return exceptionResult;
}
/**
* Returns the Cancelled result.
*
* @param the data type of the result.
* @return the Result that is the result is cancelled.
*/
public static Result ofCancelled() {
@SuppressWarnings("unchecked")
val cancelledResult = (Result)Result.ofException(new ResultCancelledException());
return cancelledResult;
}
/**
* Returns the Cancelled result with message.
*
* @param message the exception message.
* @param the data type of the result.
* @return the Result that is the result is cancelled.
*/
public static Result ofCancelled(String message) {
@SuppressWarnings("unchecked")
val cancelledResult = (Result)Result.ofException(new ResultCancelledException(message, null));
return cancelledResult;
}
/**
* Returns the Cancelled result with message.
*
* @param message the exception message.
* @param cause the exception cause.
* @param the data type of the result.
* @return the Result that is the result is cancelled.
*/
public static Result ofCancelled(String message, Exception cause) {
@SuppressWarnings("unchecked")
val cancelledResult = (Result)Result.ofException(new ResultCancelledException(message, cause));
return cancelledResult;
}
/**
* Returns the Invalid result with message.
*
* @param message the exception message.
* @param the data type of the result.
* @return the Result that is the result is invalid.
*/
public static Result ofInvalid(String message) {
@SuppressWarnings("unchecked")
val invalidResult = (Result)Result.ofException(new ValidationException(message, null));
return invalidResult;
}
/**
* Returns the Invalid result with message.
*
* @param message the exception message.
* @param cause the exception cause.
* @param the data type of the result.
* @return the Result that is the result is invalid.
*/
public static Result ofInvalid(String message, Exception cause) {
@SuppressWarnings("unchecked")
val invalidResult = (Result)Result.ofException(new ValidationException(message, cause));
return invalidResult;
}
public static Value Value(D data) {
return new Value(data);
}
public static Result ofValue(D value) {
return valueOf(value);
}
public static Result valueOf(D value) {
if (value == null)
return Result.ofNull();
return new Value(value, (Exception)null);
}
public static Result from(Supplier extends D> supplier) {
return of(Func0.of(supplier::get));
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public static Result of(Func0 extends D> supplier) {
try {
return Result.valueOf((D)((Func0)supplier).applyUnsafe());
} catch (FunctionInvocationException e) {
val cause = e.getCause();
if (cause instanceof Exception)
return Result.ofException((Exception)cause);
else return Result.ofException(e);
} catch (Exception e) {
return Result.ofException(e);
}
}
public static Result Try(Func0 extends D> supplier) {
return of(supplier);
}
public static Result ofException(String exceptionMsg) {
return new Value((D)null, new FunctionInvocationException(exceptionMsg));
}
public static Result ofException(Exception exception) {
return new Value(null, (exception != null) ? exception : new FunctionInvocationException("Unknown reason."));
}
public static Result ofResult(Result result) {
if (result == null)
return Result.ofNotExist();
if (result instanceof Result)
return (Result)result;
val data = result.__valueData();
@SuppressWarnings("unchecked")
val value = (data instanceof ExceptionHolder) ? null : (D)data;
val exception = (data instanceof ExceptionHolder) ? ((ExceptionHolder)data).getException() : null;
if (exception != null)
return Result.ofException(exception);
return Result.valueOf(value);
}
public static Result of(
T1 value1,
T2 value2,
BiFunction merger) {
return Result.of(Func0.of(()->{
val value = Func.applyUnsafe(merger, value1, value2);
return value;
}));
}
public static Result of(
T1 value1,
T2 value2,
T3 value3,
Func3 merger) {
return Result.of(Func0.of(()->{
val value = merger.applyUnsafe(value1, value2, value3);
return value;
}));
}
public static Result of(
T1 value1,
T2 value2,
T3 value3,
T4 value4,
Func4 merger) {
return Result.of(Func0.of(()->{
val value = merger.applyUnsafe(value1, value2, value3, value4);
return value;
}));
}
public static Result of(
T1 value1,
T2 value2,
T3 value3,
T4 value4,
T5 value5,
Func5 merger) {
return Result.of(Func0.of(()->{
val value = merger.applyUnsafe(value1, value2, value3, value4, value5);
return value;
}));
}
public static Result of(
T1 value1,
T2 value2,
T3 value3,
T4 value4,
T5 value5,
T6 value6,
Func6 merger) {
return Result.of(Func0.of(()->{
val value = merger.applyUnsafe(value1, value2, value3, value4, value5, value6);
return value;
}));
}
public static Result Do(Func0 extends D> supplier) {
try {
return Result.valueOf((D)supplier.applyUnsafe());
} catch (Exception e) {
return Result.ofException(e);
}
}
public static Result Do(
Func0 supplier1,
Func0 supplier2,
Func2 merger) {
return Result.ofResults(
Try(supplier1),
Try(supplier2),
merger
);
}
public static Result Do(
Func0 supplier1,
Func0 supplier2,
Func0 supplier3,
Func3 merger) {
return Result.ofResults(
Try(supplier1),
Try(supplier2),
Try(supplier3),
merger
);
}
public static Result Do(
Func0 supplier1,
Func0 supplier2,
Func0 supplier3,
Func0 supplier4,
Func4 merger) {
return Result.ofResults(
Try(supplier1),
Try(supplier2),
Try(supplier3),
Try(supplier4),
merger
);
}
public static Result Do(
Func0 supplier1,
Func0 supplier2,
Func0 supplier3,
Func0 supplier4,
Func0 supplier5,
Func5 merger) {
return Result.ofResults(
Try(supplier1),
Try(supplier2),
Try(supplier3),
Try(supplier4),
Try(supplier5),
merger
);
}
public static Result Do(
Func0 supplier1,
Func0 supplier2,
Func0 supplier3,
Func0 supplier4,
Func0 supplier5,
Func0 supplier6,
Func6 merger) {
return Result.ofResults(
Try(supplier1),
Try(supplier2),
Try(supplier3),
Try(supplier4),
Try(supplier5),
Try(supplier6),
merger
);
}
public static Result ofResults(
HasResult result1,
HasResult result2,
BiFunction merger) {
return Result.of(Func0.of(()->{
val value1 = result1.getResult().orThrow();
val value2 = result2.getResult().orThrow();
val value = Func.applyUnsafe(merger, value1, value2);
return value;
}));
}
public static Result ofResults(
HasResult result1,
HasResult result2,
HasResult result3,
Func3 merger) {
return Result.of(Func0.of(()->{
val value1 = result1.getResult().orThrow();
val value2 = result2.getResult().orThrow();
val value3 = result3.getResult().orThrow();
val value = merger.applyUnsafe(value1, value2, value3);
return value;
}));
}
public static Result ofResults(
HasResult result1,
HasResult result2,
HasResult result3,
HasResult result4,
Func4 merger) {
return Result.of(Func0.of(()->{
val value1 = result1.getResult().orThrow();
val value2 = result2.getResult().orThrow();
val value3 = result3.getResult().orThrow();
val value4 = result4.getResult().orThrow();
val value = merger.applyUnsafe(value1, value2, value3, value4);
return value;
}));
}
public static Result ofResults(
HasResult result1,
HasResult result2,
HasResult result3,
HasResult result4,
HasResult result5,
Func5 merger) {
return Result.of(Func0.of(()->{
val value1 = result1.getResult().orThrow();
val value2 = result2.getResult().orThrow();
val value3 = result3.getResult().orThrow();
val value4 = result4.getResult().orThrow();
val value5 = result5.getResult().orThrow();
val value = merger.applyUnsafe(value1, value2, value3, value4, value5);
return value;
}));
}
public static Result ofResults(
HasResult result1,
HasResult result2,
HasResult result3,
HasResult result4,
HasResult result5,
HasResult result6,
Func6 merger) {
return Result.of(Func0.of(()->{
val value1 = result1.getResult().orThrow();
val value2 = result2.getResult().orThrow();
val value3 = result3.getResult().orThrow();
val value4 = result4.getResult().orThrow();
val value5 = result5.getResult().orThrow();
val value6 = result6.getResult().orThrow();
val value = merger.applyUnsafe(value1, value2, value3, value4, value5, value6);
return value;
}));
}
abstract Object __valueData();
public Result or(Result anotherResult) {
if (this.isPresent())
return this;
if (anotherResult.isPresent())
return anotherResult;
return this;
}
@SuppressWarnings("unchecked")
protected Result newException(Exception exception) {
return (Result)Result.ofException(exception);
}
@SuppressWarnings("unchecked")
public T mapData(Func1 exceptionGet, Func2 processor) {
try {
val data = __valueData();
val isValue = ((data == null) || !(data instanceof ExceptionHolder));
val value = isValue ? (DATA)data : null;
val exception = isValue ? null : ((ExceptionHolder)data).getException();
assert !((value != null) && (exception != null));
return processor.applyUnsafe(value, exception);
} catch (Exception cause) {
return exceptionGet.apply(cause);
}
}
@SuppressWarnings("unchecked")
public Result mapValue(BiFunction> processor) {
return new DerivedResult(this, org-> {
try {
val data = org.__valueData();
val isValue = ((data == null) || !(data instanceof ExceptionHolder));
val value = isValue ? (DATA)data : null;
val exception = isValue ? null : ((ExceptionHolder)data).getException();
assert !((value != null) && (exception != null));
val newValue = Func.from(processor).applyUnsafe(value, exception);
return newValue;
} catch (Exception cause) {
return newException(cause);
}
});
}
public final DATA get() {
return value();
}
public final DATA value() {
return mapData(
throwRuntimeException(),
(value, exception) -> {
if (exception != null)
throw exception;
return value;
}
);
}
public final DATA getValue() {
return value();
}
public final Exception exception() {
return mapData(
returnNull(),
(value, exception) -> {
if (exception != null)
return exception;
return null;
}
);
}
public final Exception getException() {
return exception();
}
public final > T castTo(Class clzz) {
return clzz.cast(this);
}
@Override
public Result asResult() {
return this;
}
public final Tuple2 toTuple() {
return new Tuple2() {
@Override public final DATA _1() { return getValue(); }
@Override public final Exception _2() { return getException(); }
};
}
public final Optional toOptional() {
return Optional.ofNullable(this.get());
}
public final Nullable toNullable() {
return Nullable.of(this.get());
}
public final FuncList toList() {
return FuncList.of(this.get());
}
public final Func0 toSupplier() {
return ()->get();
}
@Override
public Promise getPromise() {
return mapData(
Promise::ofException,
(value, exception) -> {
return (exception == null)
? Promise.ofValue(value)
: Promise.ofException(exception);
}
);
}
@Override
public final Result __data() throws Exception {
return this;
}
@SuppressWarnings("unchecked")
public final Result map(Function super DATA, ? extends TARGET> mapper) {
return mapValue(
f((value, exception) -> {
if (value == null)
return (Result)this;
val newValue = Func.from(mapper).applyUnsafe(value);
return Result.valueOf(newValue);
})
);
}
public final Result as(Class onlyClass) {
return filter(onlyClass::isInstance)
.map (onlyClass::cast);
}
public final Result mapException(Function super Exception, ? extends Exception> mapper) {
return mapValue(
f((value, exception) -> {
if (exception == null)
return this;
val newException = Func.from(mapper).applyUnsafe(exception);
return newException(newException);
})
);
}
public final Result mapWith(
Func2 super DATA, ? super OPERANT, ? extends TARGET> func,
Result operantResult) {
return flatMap(data -> {
return operantResult.map(operant -> {
return func.apply(data, operant);
});
});
}
@SuppressWarnings("unchecked")
public final Result flatMap(Function super DATA, ? extends Result> mapper) {
return mapValue(
f((value, exception) -> {
if (value == null)
return (Result)this;
val monad = (Result)Func.from(mapper).applyUnsafe(value);
return monad;
})
);
}
public final Result filter(Predicate super DATA> theCondition) {
return mapValue(
(value, exception) -> {
if (value != null) {
val isPass = theCondition.test(value);
if (!isPass)
return Result.ofNull();
}
return this;
}
);
}
public final Result peek(Consumer super DATA> theConsumer) {
return mapValue((value, exception) -> {
if (value != null)
theConsumer.accept(value);
return this;
});
}
public final Result forValue(Consumer super DATA> theConsumer) {
mapData(throwException(),
(value, exception) -> {
if (value != null)
theConsumer.accept(value);
return null;
});
return this;
}
//== Status and check
public ResultStatus getStatus() {
return mapData(
returnNull(),
(value, exception) -> {
return ResultStatus.getStatus(value, exception);
});
}
//== Validation ==
//== TODO - Validate then accumulate.
public final Result validateNotNull() {
return mapData(
returnValueException(),
(value, exception)->{
if ((value == null) && (exception == null))
return newException(
new ValidationException(
new NullPointerException()));
return this;
});
}
public final Result validateNotNull(String message) {
return mapData(
returnValueException(),
(value, exception)->{
if ((value == null) && (exception == null))
return newException(
new ValidationException(message));
return this;
}
);
}
public final Result validateUnavailable() {
return mapData(
returnValueException(),
(value, exception)->{
if (exception instanceof ResultNotAvailableException)
return newException(new ValidationException(exception));
return this;
}
);
}
public final Result validateNotReady() {
return mapData(
returnValueException(),
(value, exception)->{
if ((exception instanceof ResultNotAvailableException)
|| (exception instanceof ResultNotReadyException))
return newException(new ValidationException(exception));
return this;
}
);
}
public final Result validateResultCancelled() {
return mapData(
returnValueException(),
(value, exception)->{
if (exception instanceof ResultCancelledException)
return newException(new ValidationException(exception));
return this;
}
);
}
public final Result validateResultNotExist() {
return mapData(
returnValueException(),
(value, exception)->{
if (exception instanceof ResultNotExistException)
return newException(new ValidationException(exception));
return this;
}
);
}
public final Result validateNoMoreResult() {
return mapData(
returnValueException(),
(value, exception)->{
if (exception instanceof NoMoreResultException)
return newException(new ValidationException(exception));
return this;
}
);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public final Result validate(String stringFormat, Predicate super DATA> validChecker) {
return mapData(
returnValueException(),
(value, exception)->{
if (value == null)
return this;
try {
if (validChecker.test(value))
return this;
val validationException = SimpleValidator.exceptionFor(stringFormat).apply(value, (Predicate)validChecker);
return (Result)newException(validationException);
} catch (Exception cause) {
val validationException = SimpleValidator.exceptionFor(stringFormat, cause).apply(value, (Predicate)validChecker);
return (Result)newException(validationException);
}
}
);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public final Result validate(String stringFormat, Func1 super DATA, T> mapper, Predicate super T> validChecker) {
return mapData(
returnValueException(),
(value, exception)->{
if (value == null)
return this;
try {
val target = mapper.applyUnsafe(value);
if (validChecker.test(target))
return this;
val validationException = SimpleValidator.exceptionFor(stringFormat).apply(value, (Predicate)validChecker);
return (Result)newException(validationException);
} catch (Exception cause) {
val validationException = SimpleValidator.exceptionFor(stringFormat, cause).apply(value, (Predicate)validChecker);
return (Result)newException(validationException);
}
});
}
public final Result