You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@causeway.apache.org by ah...@apache.org on 2023/02/26 20:54:13 UTC
[causeway] branch master updated: CAUSEWAY-3304: Try: reworking some of the problematic methods
This is an automated email from the ASF dual-hosted git repository.
ahuber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/causeway.git
The following commit(s) were added to refs/heads/master by this push:
new a387ad2094 CAUSEWAY-3304: Try: reworking some of the problematic methods
a387ad2094 is described below
commit a387ad2094a4fd5830aba594479f1f7871746acb
Author: Andi Huber <ah...@apache.org>
AuthorDate: Sun Feb 26 21:54:06 2023 +0100
CAUSEWAY-3304: Try: reworking some of the problematic methods
- also adding todo markers for more work
---
.../apache/causeway/commons/functional/Try.java | 151 ++++++++++++++++++---
.../org/apache/causeway/commons/io/DataSource.java | 3 +-
.../restfulobjects/client/RestfulClient.java | 3 +-
.../viewer/resources/ObjectActionArgHelper.java | 4 +-
4 files changed, 135 insertions(+), 26 deletions(-)
diff --git a/commons/src/main/java/org/apache/causeway/commons/functional/Try.java b/commons/src/main/java/org/apache/causeway/commons/functional/Try.java
index ec6774c23e..2a8ab52cf2 100644
--- a/commons/src/main/java/org/apache/causeway/commons/functional/Try.java
+++ b/commons/src/main/java/org/apache/causeway/commons/functional/Try.java
@@ -24,6 +24,7 @@ import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.function.Consumer;
import java.util.function.Function;
+import java.util.function.Supplier;
import java.util.function.UnaryOperator;
import org.springframework.lang.Nullable;
@@ -101,13 +102,17 @@ public interface Try<T> {
// -- PEEKING
/**
- * Peeks into the {@code value} if this is a {@link Success}.
+ * If this is a {@link Success}, peeks into the {@code value} wrapped in an {@link Optional}.
*/
- Try<T> ifSuccess(final @NonNull Consumer<Optional<T>> valueConsumer);
+ Try<T> ifSuccess(final @NonNull Consumer<Optional<T>> valueConsumer); //TODO use ThrowingConsumer instead
/**
- * Peeks into the {@code failure} if this is a {@link Failure}.
+ * If this is a {@link Success} with a present {@code value}, peeks into the {@code value}.
*/
- Try<T> ifFailure(final @NonNull Consumer<Throwable> exceptionConsumer);
+ Try<T> ifSuccessAsNullable(final @NonNull ThrowingConsumer<T> valueConsumer);
+ /**
+ * If this is a {@link Failure}, peeks into the {@code failure}.
+ */
+ Try<T> ifFailure(final @NonNull Consumer<Throwable> exceptionConsumer); //TODO use ThrowingConsumer instead
// -- FAIL EARLY
@@ -118,16 +123,29 @@ public interface Try<T> {
// -- MAPPING
+ /**
+ * Maps this {@link Try} to another if this is a {@link Success},
+ * passing the {@code value} wrapped in an {@link Optional}.
+ * Otherwise if this is a {@link Failure} acts as identity operator.
+ */
+ <R> Try<R> mapSuccess(@NonNull ThrowingFunction<Optional<T>, R> successMapper);
/**
* Maps this {@link Try} to another if this is a {@link Success}.
* Otherwise if this is a {@link Failure} acts as identity operator.
+ * @apiNote If preceded with a call to {@link #mapEmptyToFailure()},
+ * the success value - as passed over to the successMapper - is guaranteed non-null.
+ */
+ <R> Try<R> mapSuccessAsNullable(@NonNull ThrowingFunction<T, R> successMapper);
+ /**
+ * Maps this {@link Try} to another if this is a {@link Failure}.
+ * Otherwise if this is a {@link Success} acts as identity operator.
*/
- <R> Try<R> mapSuccess(final @NonNull Function<T, R> successMapper);
+ Try<T> mapFailure(@NonNull UnaryOperator<Throwable> failureMapper); //TODO use ThrowingFunction instead
/**
- * Maps this {@link Try} to another if its a {@link Failure}.
+ * Recovers from a failed {@link Try} if its a {@link Failure}.
* Otherwise if this is a {@link Success} acts as identity operator.
*/
- Try<T> mapFailure(final @NonNull UnaryOperator<Throwable> failureMapper);
+ Try<T> mapFailureToSuccess(@NonNull ThrowingFunction<Throwable, T> recoveryMapper);
/**
* Maps this {@link Try} to {@link Failure} if this is a {@link Success} with an empty {@code value}.
* Otherwise acts as identity operator.
@@ -138,17 +156,20 @@ public interface Try<T> {
* using according mapping function {@code successMapper} or {@code failureMapper}.
* @apiNote It is a common functional programming convention, to map the success value <i>right</i>.
*/
- <L, R> Either<L, R> map(
+ <L, R> Either<L, R> mapToEither(
final @NonNull Function<Throwable, L> failureMapper,
final @NonNull Function<Optional<T>, R> successMapper);
- // -- TERMINATE
+ // -- ACCEPT
/**
* Either consumes the success or the failure.
- * @apiNote Order of arguments conforms to {@link #map(Function, Function)}
+ * <p>
+ * If any of the {@link Consumer} arguments throw exceptions, those are not catched by this {@link Try}.
+ * In other words: this method always acts as an identity operator
+ * @apiNote Order of arguments conforms to {@link #mapToEither(Function, Function)}
*/
- void accept(
+ Try<T> accept(
final @NonNull Consumer<Throwable> failureConsumer,
final @NonNull Consumer<Optional<T>> successConsumer);
@@ -157,7 +178,7 @@ public interface Try<T> {
/**
* Maps the contained {@code value} or {@code failure} to a new value of type {@code R}
* using according mapping function {@code successMapper} or {@code failureMapper}.
- * @apiNote Order of arguments conforms to {@link #map(Function, Function)}
+ * @apiNote Order of arguments conforms to {@link #mapToEither(Function, Function)}
*/
<R> R fold(
final @NonNull Function<Throwable, R> failureMapper,
@@ -167,14 +188,48 @@ public interface Try<T> {
/**
* If this is a {@link Success}, maps it to a new {@link Try} based on given {@link Callable}.
- * Otherwise if its a {@link Failure} acts as identity operator.
+ * Otherwise if its a {@link Failure}, acts as identity operator.
*/
<R> Try<R> thenCall(final @NonNull Callable<R> callable);
/**
- * If this is a {@link Success}, maps it to new {@link Try} based on given {@link ThrowingRunnable}.
- * Otherwise if its a {@link Failure} acts as identity operator.
+ * If this is a {@link Success}, maps it to a new {@link Try} based on given {@link ThrowingRunnable}.
+ * Otherwise if this is a {@link Failure}, acts as identity operator.
*/
Try<Void> thenRun(final @NonNull ThrowingRunnable runnable);
+ /**
+ * If this is a {@link Success}, maps it to a new {@link Try} based on given {@link Supplier}.
+ * Otherwise if this is a {@link Failure}, acts as identity operator.
+ */
+ <R> Try<R> then(final @NonNull Callable<? extends Try<R>> next);
+
+ /**
+ * If this is a {@link Failure}, maps it to a new {@link Try} based on given {@link Callable}.
+ * Otherwise if this is a {@link Success}, acts as identity operator.
+ */
+ Try<T> orCall(final @NonNull Callable<T> fallback);
+
+ // -- SHORTCUTS
+
+ /**
+ * If this is a {@link Failure} throws the contained failure,
+ * otherwise if this is a {@link Success}, returns the success value as null-able.
+ */
+ @Nullable
+ default T valueAsNullableElseFail() {
+ ifFailureFail();
+ return getValue().orElse(null);
+ }
+
+ /**
+ * If this is a {@link Failure} throws the contained failure,
+ * otherwise if this is a {@link Success},
+ * either returns the success value if it is NOT <code>null</code>
+ * or throws a {@link NoSuchElementException}.
+ */
+ default T valueAsNonNullElseFail() {
+ ifFailureFail();
+ return getValue().orElseThrow();
+ }
// -- SUCCESS
@@ -196,6 +251,11 @@ public interface Try<T> {
valueConsumer.accept(getValue());
return this;
}
+ @Override
+ public Try<T> ifSuccessAsNullable(final @NonNull ThrowingConsumer<T> valueConsumer) {
+ valueConsumer.accept(getValue().orElse(null));
+ return this;
+ }
@Override
public Success<T> ifFailure(final @NonNull Consumer<Throwable> exceptionConsumer) {
@@ -214,14 +274,22 @@ public interface Try<T> {
}
@Override
- public <R> Try<R> mapSuccess(final @NonNull Function<T, R> successMapper){
- return Try.call(()->successMapper.apply(value));
+ public <R> Try<R> mapSuccess(final @NonNull ThrowingFunction<Optional<T>, R> successMapper) {
+ return Try.call(()->successMapper.apply(getValue()));
+ }
+ @Override
+ public <R> Try<R> mapSuccessAsNullable(final @NonNull ThrowingFunction<T, R> successMapper) {
+ return Try.call(()->successMapper.apply(getValue().orElse(null)));
}
@Override
public Success<T> mapFailure(final @NonNull UnaryOperator<Throwable> failureMapper){
return this;
}
+ @Override
+ public Try<T> mapFailureToSuccess(final @NonNull ThrowingFunction<Throwable, T> recoveryMapper) {
+ return this;
+ }
@Override
public Try<T> mapEmptyToFailure() {
@@ -241,10 +309,25 @@ public interface Try<T> {
}
@Override
- public void accept(
+ public <R> Try<R> then(final @NonNull Callable<? extends Try<R>> next) {
+ try {
+ return next.call();
+ } catch (Throwable e) {
+ return Try.failure(e);
+ }
+ }
+
+ @Override
+ public Try<T> orCall(@NonNull final Callable<T> fallback) {
+ return this;
+ }
+
+ @Override
+ public Try<T> accept(
final @NonNull Consumer<Throwable> failureConsumer,
final @NonNull Consumer<Optional<T>> successConsumer) {
successConsumer.accept(getValue());
+ return this;
}
@Override
@@ -255,7 +338,7 @@ public interface Try<T> {
}
@Override
- public <L, R> Either<L, R> map(
+ public <L, R> Either<L, R> mapToEither(
final @NonNull Function<Throwable, L> failureMapper,
final @NonNull Function<Optional<T>, R> successMapper) {
return Either.right(successMapper.apply(getValue()));
@@ -282,6 +365,11 @@ public interface Try<T> {
public Failure<T> ifSuccess(final @NonNull Consumer<Optional<T>> valueConsumer) {
return this;
}
+ @Override
+ public Failure<T> ifSuccessAsNullable(final @NonNull ThrowingConsumer<T> valueConsumer) {
+ return this;
+ }
+
@Override
public Failure<T> ifFailure(final @NonNull Consumer<Throwable> exceptionConsumer) {
@@ -300,7 +388,11 @@ public interface Try<T> {
}
@Override
- public <R> Failure<R> mapSuccess(final @NonNull Function<T, R> successMapper){
+ public <R> Failure<R> mapSuccess(final @NonNull ThrowingFunction<Optional<T>, R> successMapper) {
+ return new Failure<>(throwable);
+ }
+ @Override
+ public <R> Failure<R> mapSuccessAsNullable(final @NonNull ThrowingFunction<T, R> successMapper) {
return new Failure<>(throwable);
}
@@ -312,6 +404,10 @@ public interface Try<T> {
return failure(e);
}
}
+ @Override
+ public Try<T> mapFailureToSuccess(final @NonNull ThrowingFunction<Throwable, T> recoveryMapper) {
+ return Try.call(()->recoveryMapper.apply(throwable));
+ }
@Override
public Try<T> mapEmptyToFailure() {
@@ -329,10 +425,21 @@ public interface Try<T> {
}
@Override
- public void accept(
+ public <R> Try<R> then(final @NonNull Callable<? extends Try<R>> next) {
+ return new Failure<>(throwable);
+ }
+
+ @Override
+ public Try<T> orCall(@NonNull final Callable<T> fallback) {
+ return Try.call(fallback);
+ }
+
+ @Override
+ public Try<T> accept(
final @NonNull Consumer<Throwable> failureConsumer,
final @NonNull Consumer<Optional<T>> successConsumer) {
failureConsumer.accept(throwable);
+ return this;
}
@Override
@@ -343,7 +450,7 @@ public interface Try<T> {
}
@Override
- public <L, R> Either<L, R> map(
+ public <L, R> Either<L, R> mapToEither(
final @NonNull Function<Throwable, L> failureMapper,
final @NonNull Function<Optional<T>, R> successMapper) {
return Either.left(failureMapper.apply(throwable));
diff --git a/commons/src/main/java/org/apache/causeway/commons/io/DataSource.java b/commons/src/main/java/org/apache/causeway/commons/io/DataSource.java
index ff5f206d5f..b9ac147cae 100644
--- a/commons/src/main/java/org/apache/causeway/commons/io/DataSource.java
+++ b/commons/src/main/java/org/apache/causeway/commons/io/DataSource.java
@@ -96,7 +96,8 @@ public interface DataSource {
}
})
// unwrap the inner try
- .mapSuccess(wrappedTry->wrappedTry.getValue().get());
+ .mapEmptyToFailure()
+ .mapSuccessAsNullable(wrappedTry->wrappedTry.valueAsNonNullElseFail());
}
};
}
diff --git a/viewers/restfulobjects/client/src/main/java/org/apache/causeway/viewer/restfulobjects/client/RestfulClient.java b/viewers/restfulobjects/client/src/main/java/org/apache/causeway/viewer/restfulobjects/client/RestfulClient.java
index 7e7c608f8a..a12e8402dc 100644
--- a/viewers/restfulobjects/client/src/main/java/org/apache/causeway/viewer/restfulobjects/client/RestfulClient.java
+++ b/viewers/restfulobjects/client/src/main/java/org/apache/causeway/viewer/restfulobjects/client/RestfulClient.java
@@ -176,7 +176,8 @@ public class RestfulClient implements AutoCloseable {
*/
public <T> Try<T> digestValue(final Response response, final ValueSemanticsProvider<T> valSemantics) {
return digest(response, ValueDecomposition.class)
- .mapSuccess(valDecomposition->valSemantics.compose(valDecomposition));
+ .mapEmptyToFailure()
+ .mapSuccessAsNullable(valDecomposition->valSemantics.compose(valDecomposition));
}
// -- UTILITY
diff --git a/viewers/restfulobjects/viewer/src/main/java/org/apache/causeway/viewer/restfulobjects/viewer/resources/ObjectActionArgHelper.java b/viewers/restfulobjects/viewer/src/main/java/org/apache/causeway/viewer/restfulobjects/viewer/resources/ObjectActionArgHelper.java
index aa10b96e68..384823065b 100644
--- a/viewers/restfulobjects/viewer/src/main/java/org/apache/causeway/viewer/restfulobjects/viewer/resources/ObjectActionArgHelper.java
+++ b/viewers/restfulobjects/viewer/src/main/java/org/apache/causeway/viewer/restfulobjects/viewer/resources/ObjectActionArgHelper.java
@@ -59,13 +59,13 @@ public class ObjectActionArgHelper {
val paramMeta = parameters.getElseFail(argIndex);
val paramSpec = paramMeta.getElementType();
- val tryArgument = (paramMeta.isOptional()
+ final Try<ManagedObject> tryArgument = (paramMeta.isOptional()
&& argRepr == null)
? Try.success(ManagedObject.empty(paramSpec))
: Try.call(()->
new JsonParserHelper(resourceContext, paramSpec)
.objectAdapterFor(argRepr))
- .mapSuccess(success->success!=null
+ .mapSuccessAsNullable(success->success!=null
? success
: ManagedObject.empty(paramSpec));