You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2020/12/19 07:16:26 UTC

[isis] branch master updated: ISIS-2033: commons: promote _Result from internal to public

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/isis.git


The following commit(s) were added to refs/heads/master by this push:
     new 332211d  ISIS-2033: commons: promote _Result from internal to public
332211d is described below

commit 332211d2701818fc75881bbfe638fd6b8ee71c9f
Author: Andi Huber <ah...@apache.org>
AuthorDate: Sat Dec 19 08:16:08 2020 +0100

    ISIS-2033: commons: promote _Result from internal to public
    
    also use commons' Result for the JpaSupportService
---
 .../base/_Result.java => functional/Result.java}   | 104 +++++++++++++--------
 .../isis/commons/internal/reflection/_Reflect.java |  10 +-
 .../isis/commons/internal/resources/_Json.java     |  42 ++++-----
 .../isis/commons/internal/resources/_Yaml.java     |  18 ++--
 .../metamodel/commons/CanonicalParameterUtil.java  |   8 +-
 .../autocomplete/AutoCompleteFacetAbstract.java    |   4 +-
 .../jpa/applib/services/JpaSupportService.java     |  33 ++++---
 .../services/JpaSupportServiceUsingSpring.java     |   9 +-
 .../apache/isis/testdomain/jpa/JpaQueryTest.java   |  66 ++++++-------
 .../viewer/resources/ObjectActionArgHelper.java    |   4 +-
 10 files changed, 167 insertions(+), 131 deletions(-)

diff --git a/commons/src/main/java/org/apache/isis/commons/internal/base/_Result.java b/commons/src/main/java/org/apache/isis/commons/functional/Result.java
similarity index 57%
rename from commons/src/main/java/org/apache/isis/commons/internal/base/_Result.java
rename to commons/src/main/java/org/apache/isis/commons/functional/Result.java
index f1fd629..27e3234 100644
--- a/commons/src/main/java/org/apache/isis/commons/internal/base/_Result.java
+++ b/commons/src/main/java/org/apache/isis/commons/functional/Result.java
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.commons.internal.base;
+package org.apache.isis.commons.functional;
 
 import java.util.NoSuchElementException;
 import java.util.Optional;
@@ -37,26 +37,23 @@ import lombok.ToString;
 import lombok.val;
 
 /**
- * <h1>- internal use only -</h1>
- * <p>
- * A specialization of the {@link _Either} monad.
- * <p>
- * <b>WARNING</b>: Do <b>NOT</b> use any of the classes provided by this package! <br/>
- * These may be changed or removed without notice!
- *
- * @since 2.0
+ * The {@link Result} type represents a value of one of two possible types (a disjoint union). 
+ * The data constructors {@link Result#success(Object)} and {@link Result#failure(Throwable)}
+ * represent the two possible values.
+ * 
+ * @since 2.0 {@index}
  */
 @RequiredArgsConstructor(access=AccessLevel.PRIVATE, staticName="of")
 @ToString @EqualsAndHashCode
-public final class _Result<L> {
+public final class Result<L> {
 
     private final L value;
-    private final Throwable exception;
+    private final Throwable throwable;
     private final boolean isSuccess;
     
     // -- FACTORIES
 
-    public static <L> _Result<L> of(@NonNull Callable<L> callable) {
+    public static <L> Result<L> of(final @NonNull Callable<L> callable) {
         try {
             return success(callable.call());
         } catch (Throwable e) {
@@ -64,7 +61,7 @@ public final class _Result<L> {
         }
     }
     
-    public static <L> _Result<L> ofNullable(@NonNull Callable<L> callable) {
+    public static <L> Result<L> ofNullable(final @NonNull Callable<L> callable) {
         try {
             return successNullable(callable.call());
         } catch (Throwable e) {
@@ -72,16 +69,26 @@ public final class _Result<L> {
         }
     }
     
-    public static <L> _Result<L> success(@NonNull L value) {
+    public static <L> Result<L> success(final @NonNull L value) {
         return of(value, null, true);
     }
 
-    public static <L> _Result<L> successNullable(@Nullable L value) {
+    public static <L> Result<L> successNullable(final @Nullable L value) {
         return of(value, null, true);
     }
     
-    public static <L> _Result<L> failure(@NonNull Throwable exception) {
-        return of(null, exception, false);
+    public static <L> Result<L> failure(final @NonNull Throwable throwable) {
+        return of(null, throwable, false);
+    }
+    
+    // -- FACTORY SHORTCUTS
+    
+    public static <L> Result<L> failure(final @NonNull String message) {
+        return failure(new Error(message));
+    }
+    
+    public static <L> Result<L> failure(final @NonNull String message, final @NonNull Throwable cause) {
+        return failure(new Error(message, cause));
     }
     
     // -- PREDICATES
@@ -101,7 +108,7 @@ public final class _Result<L> {
     }
 
     public Optional<Throwable> exception() {
-        return Optional.ofNullable(exception); 
+        return Optional.ofNullable(throwable); 
     }
 
 //    public L valueIfAny() {
@@ -114,34 +121,34 @@ public final class _Result<L> {
     
     // -- PEEKING
     
-    public _Result<L> onSuccess(final @NonNull Consumer<L> valueConsumer){
+    public Result<L> ifSuccess(final @NonNull Consumer<L> valueConsumer){
         if(isSuccess()) {
             valueConsumer.accept(value);
         }
         return this;
     }
     
-    public _Result<L> onFailure(final @NonNull Consumer<Throwable> exceptionConsumer){
+    public Result<L> ifFailure(final @NonNull Consumer<Throwable> exceptionConsumer){
         if(isFailure()) {
-            exceptionConsumer.accept(exception);
+            exceptionConsumer.accept(throwable);
         }
         return this;
     }
     
     // -- MAPPING
 
-    public <T> _Result<T> mapValue(final @NonNull Function<L, T> valueMapper){
+    public <T> Result<T> mapSuccess(final @NonNull Function<L, T> successMapper){
         return isSuccess()
-                ? _Result.of(()->valueMapper.apply(value))
-                : _Result.failure(exception);
+                ? Result.of(()->successMapper.apply(value))
+                : Result.failure(throwable);
     }
 
-    public _Result<L> mapException(final @NonNull UnaryOperator<Throwable> exceptionMapper){
+    public Result<L> mapFailure(final @NonNull UnaryOperator<Throwable> failureMapper){
         if (isSuccess()) {
             return this;
         }
         try {
-            return _Result.failure(exceptionMapper.apply(exception));
+            return Result.failure(failureMapper.apply(throwable));
         } catch (Throwable e) {
             return failure(e);
         }
@@ -150,35 +157,54 @@ public final class _Result<L> {
     // -- FOLDING
     
     public <T> T fold(
-            final @NonNull Function<L, T> valueMapper,
-            final @NonNull Function<Throwable, T> exceptionMapper){
+            final @NonNull Function<L, T> successMapper,
+            final @NonNull Function<Throwable, T> failureMapper){
         return isSuccess()
-                ? valueMapper.apply(value)
-                : exceptionMapper.apply(exception);
+                ? successMapper.apply(value)
+                : failureMapper.apply(throwable);
     }
     
-    // -- REDUCTION
+    // -- EXTRACTION
     
     @SneakyThrows
-    public L getOrThrow() {
+    public L orElseFail() {
         if (isSuccess()) {
             if(value==null) {
                 throw new NoSuchElementException();
             }
             return value;
         }
-        throw exception;
+        throw throwable;
+    }
+    
+    @SneakyThrows
+    public @Nullable L nullableOrElseFail() {
+        if (isSuccess()) {
+            return value;
+        }
+        throw throwable;
+    }
+    
+    @SneakyThrows
+    public L orElseThrow(final @NonNull UnaryOperator<Throwable> toThrowable) {
+        if (isSuccess()) {
+            if(value==null) {
+                throw toThrowable.apply(new NoSuchElementException());
+            }
+            return value;
+        }
+        throw toThrowable.apply(throwable);
     }
     
     @SneakyThrows
-    public @Nullable L getNullableOrThrow() {
+    public @Nullable L nullableOrElseThrow(final @NonNull UnaryOperator<Throwable> toThrowable) {
         if (isSuccess()) {
             return value;
         }
-        throw exception;
+        throw toThrowable.apply(throwable);
     }
     
-    public L getOrDefault(final @NonNull L defaultValue) {
+    public L orDefault(final @NonNull L defaultValue) {
         if (isSuccess()) {
             if(value!=null) {
                 return value;
@@ -187,14 +213,14 @@ public final class _Result<L> {
         return defaultValue;
     }
     
-    public @Nullable L getNullableOrDefault(final @Nullable L defaultValue) {
+    public @Nullable L nullableOrDefault(final @Nullable L defaultValue) {
         if (isSuccess()) {
             return value;
         }
         return defaultValue;
     }
     
-    public L getOrElse(final @NonNull Supplier<L> defaultValueSupplier) {
+    public L orElseGet(final @NonNull Supplier<L> defaultValueSupplier) {
         if (isSuccess()) {
             if(value!=null) {
                 return value;
@@ -207,7 +233,7 @@ public final class _Result<L> {
         throw new NoSuchElementException();
     }
     
-    public @Nullable L getNullableOrElse(final @NonNull Supplier<L> defaultValueSupplier) {
+    public @Nullable L nullableOrElseGet(final @NonNull Supplier<L> defaultValueSupplier) {
         if (isSuccess()) {
             return value;
         }
diff --git a/commons/src/main/java/org/apache/isis/commons/internal/reflection/_Reflect.java b/commons/src/main/java/org/apache/isis/commons/internal/reflection/_Reflect.java
index e1d0fd8..de94daa 100644
--- a/commons/src/main/java/org/apache/isis/commons/internal/reflection/_Reflect.java
+++ b/commons/src/main/java/org/apache/isis/commons/internal/reflection/_Reflect.java
@@ -46,8 +46,8 @@ import javax.annotation.Nullable;
 import org.springframework.core.annotation.AnnotationUtils;
 
 import org.apache.isis.commons.collections.Can;
+import org.apache.isis.commons.functional.Result;
 import org.apache.isis.commons.internal.base._NullSafe;
-import org.apache.isis.commons.internal.base._Result;
 import org.apache.isis.commons.internal.base._Strings;
 import org.apache.isis.commons.internal.base._With;
 import org.apache.isis.commons.internal.collections._Arrays;
@@ -470,13 +470,13 @@ public final class _Reflect {
     }
     
     
-    public static _Result<Object> invokeMethodOn(
+    public static Result<Object> invokeMethodOn(
             @NonNull final Method method, 
             @NonNull final Object target, 
             final Object... args) {
         
         /*sonar-ignore-on*/
-        return _Result.ofNullable(()->{
+        return Result.ofNullable(()->{
             if(method.isAccessible()) {
                 return method.invoke(target, args);
             }
@@ -490,12 +490,12 @@ public final class _Reflect {
         /*sonar-ignore-off*/
     }
     
-    public static <T> _Result<T> invokeConstructor(
+    public static <T> Result<T> invokeConstructor(
             @NonNull final Constructor<T> constructor, 
             final Object... args) {
         
         /*sonar-ignore-on*/
-        return _Result.of(()->{
+        return Result.of(()->{
             if(constructor.isAccessible()) {
                 return constructor.newInstance(args);
             }
diff --git a/commons/src/main/java/org/apache/isis/commons/internal/resources/_Json.java b/commons/src/main/java/org/apache/isis/commons/internal/resources/_Json.java
index 5b763f1..7184f93 100644
--- a/commons/src/main/java/org/apache/isis/commons/internal/resources/_Json.java
+++ b/commons/src/main/java/org/apache/isis/commons/internal/resources/_Json.java
@@ -29,7 +29,7 @@ import com.fasterxml.jackson.databind.JsonMappingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.SerializationFeature;
 
-import org.apache.isis.commons.internal.base._Result;
+import org.apache.isis.commons.functional.Result;
 
 import lombok.val;
 
@@ -73,8 +73,8 @@ public class _Json {
      * @param content
      * @return
      */
-    public static <T> _Result<T> tryReadJson(final Class<T> clazz, InputStream content) {
-        return _Result.of(()->readJson(clazz, content));
+    public static <T> Result<T> tryReadJson(final Class<T> clazz, InputStream content) {
+        return Result.of(()->readJson(clazz, content));
     }
 
     /**
@@ -104,8 +104,8 @@ public class _Json {
      * @param content
      * @return
      */
-    public static <T> _Result<List<T>> tryReadJsonList(final Class<T> clazz, InputStream content) {
-        return _Result.of(()->readJsonList(clazz, content));
+    public static <T> Result<List<T>> tryReadJsonList(final Class<T> clazz, InputStream content) {
+        return Result.of(()->readJsonList(clazz, content));
     }
 
 
@@ -136,8 +136,8 @@ public class _Json {
      * @param content
      * @return
      */
-    public static <T> _Result<T> tryReadJson(final Class<T> clazz, String content) {
-        return _Result.of(()->readJson(clazz, content));
+    public static <T> Result<T> tryReadJson(final Class<T> clazz, String content) {
+        return Result.of(()->readJson(clazz, content));
     }
 
     /**
@@ -167,8 +167,8 @@ public class _Json {
      * @param content
      * @return
      */
-    public static <T> _Result<List<T>> tryReadJsonList(final Class<T> clazz, String content) {
-        return _Result.of(()->readJsonList(clazz, content));
+    public static <T> Result<List<T>> tryReadJsonList(final Class<T> clazz, String content) {
+        return Result.of(()->readJsonList(clazz, content));
     }
 
 
@@ -199,8 +199,8 @@ public class _Json {
      * @param content
      * @return
      */
-    public static <T> _Result<T> tryReadJson(final Class<T> clazz, File content) {
-        return _Result.of(()->readJson(clazz, content));
+    public static <T> Result<T> tryReadJson(final Class<T> clazz, File content) {
+        return Result.of(()->readJson(clazz, content));
     }
 
     /**
@@ -230,8 +230,8 @@ public class _Json {
      * @param content
      * @return
      */
-    public static <T> _Result<List<T>> tryReadJsonList(final Class<T> clazz, File content) {
-        return _Result.of(()->readJsonList(clazz, content));
+    public static <T> Result<List<T>> tryReadJsonList(final Class<T> clazz, File content) {
+        return Result.of(()->readJsonList(clazz, content));
     }
 
     // -- BYTE CONTENT
@@ -261,8 +261,8 @@ public class _Json {
      * @param content
      * @return
      */
-    public static <T> _Result<T> tryReadJson(final Class<T> clazz, byte[] content) {
-        return _Result.of(()->readJson(clazz, content));
+    public static <T> Result<T> tryReadJson(final Class<T> clazz, byte[] content) {
+        return Result.of(()->readJson(clazz, content));
     }
 
     /**
@@ -292,8 +292,8 @@ public class _Json {
      * @param content
      * @return
      */
-    public static <T> _Result<List<T>> tryReadJsonList(final Class<T> clazz, byte[] content) {
-        return _Result.of(()->readJsonList(clazz, content));
+    public static <T> Result<List<T>> tryReadJsonList(final Class<T> clazz, byte[] content) {
+        return Result.of(()->readJsonList(clazz, content));
     }
     
     // -- WRITING
@@ -309,12 +309,12 @@ public class _Json {
         return toString(objectMapper, pojo);
     }
     
-    public static <T> _Result<String> tryToString(ObjectMapper objectMapper, Object pojo) {
-        return _Result.of(()->toString(objectMapper, pojo));
+    public static <T> Result<String> tryToString(ObjectMapper objectMapper, Object pojo) {
+        return Result.of(()->toString(objectMapper, pojo));
     }
     
-    public static <T> _Result<String> tryToString(Object pojo) {
-        return _Result.of(()->toString(pojo));
+    public static <T> Result<String> tryToString(Object pojo) {
+        return Result.of(()->toString(pojo));
     }
 
 }
diff --git a/commons/src/main/java/org/apache/isis/commons/internal/resources/_Yaml.java b/commons/src/main/java/org/apache/isis/commons/internal/resources/_Yaml.java
index 9d15e02..e084105 100644
--- a/commons/src/main/java/org/apache/isis/commons/internal/resources/_Yaml.java
+++ b/commons/src/main/java/org/apache/isis/commons/internal/resources/_Yaml.java
@@ -28,7 +28,7 @@ import java.io.InputStream;
 import org.yaml.snakeyaml.Yaml;
 import org.yaml.snakeyaml.constructor.Constructor;
 
-import org.apache.isis.commons.internal.base._Result;
+import org.apache.isis.commons.functional.Result;
 
 import lombok.val;
 
@@ -68,8 +68,8 @@ public class _Yaml {
      * @param content
      * @return
      */
-    public static <T> _Result<T> tryReadYaml(final Class<T> clazz, InputStream content) {
-        return _Result.of(()->readYaml(clazz, content));
+    public static <T> Result<T> tryReadYaml(final Class<T> clazz, InputStream content) {
+        return Result.of(()->readYaml(clazz, content));
     }
     
     // -- FROM STRING
@@ -95,8 +95,8 @@ public class _Yaml {
      * @param content
      * @return
      */
-    public static <T> _Result<T> tryReadYaml(final Class<T> clazz, String content) {
-        return _Result.of(()->readYaml(clazz, content));
+    public static <T> Result<T> tryReadYaml(final Class<T> clazz, String content) {
+        return Result.of(()->readYaml(clazz, content));
     }
     
     // -- FROM FILE
@@ -126,8 +126,8 @@ public class _Yaml {
      * @param content
      * @return
      */
-    public static <T> _Result<T> tryReadYaml(final Class<T> clazz, File content) {
-        return _Result.of(()->readYaml(clazz, content));
+    public static <T> Result<T> tryReadYaml(final Class<T> clazz, File content) {
+        return Result.of(()->readYaml(clazz, content));
     }
     
     // -- FROM BYTE ARRAY
@@ -156,8 +156,8 @@ public class _Yaml {
      * @param content
      * @return
      */
-    public static <T> _Result<T> tryReadYaml(final Class<T> clazz, byte[] content) {
-        return _Result.of(()->readYaml(clazz, content));
+    public static <T> Result<T> tryReadYaml(final Class<T> clazz, byte[] content) {
+        return Result.of(()->readYaml(clazz, content));
     }
     
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/commons/CanonicalParameterUtil.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/commons/CanonicalParameterUtil.java
index 1b2e6bc..3bd36ed 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/commons/CanonicalParameterUtil.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/commons/CanonicalParameterUtil.java
@@ -56,8 +56,8 @@ public final class CanonicalParameterUtil {
         
         // supports effective private constructors as well
         return _Reflect.invokeConstructor(constructor, adaptedExecutionParameters)
-        .mapException(ex->toVerboseException(constructor.getParameterTypes(), adaptedExecutionParameters, ex))
-        .getOrThrow();
+        .mapFailure(ex->toVerboseException(constructor.getParameterTypes(), adaptedExecutionParameters, ex))
+        .orElseFail();
     }
     
     public static Object invoke(Method method, Object targetPojo, Object[] executionParameters)
@@ -67,8 +67,8 @@ public final class CanonicalParameterUtil {
 
         // supports effective private methods as well
         return _Reflect.invokeMethodOn(method, targetPojo, adaptedExecutionParameters)
-        .mapException(ex->toVerboseException(method.getParameterTypes(), adaptedExecutionParameters, ex))
-        .getNullableOrThrow();
+        .mapFailure(ex->toVerboseException(method.getParameterTypes(), adaptedExecutionParameters, ex))
+        .nullableOrElseFail();
     }
     
     private static Object[] preprocess(Executable executable, Object[] executionParameters) {
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/autocomplete/AutoCompleteFacetAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/autocomplete/AutoCompleteFacetAbstract.java
index 606ed71..b70781b 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/autocomplete/AutoCompleteFacetAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/autocomplete/AutoCompleteFacetAbstract.java
@@ -77,8 +77,8 @@ implements AutoCompleteFacet {
         val resultAdapter = getPublisherDispatchService()
         .withPublishingSuppressed(()->{
                 final Object list = _Reflect.invokeMethodOn(repositoryMethod, getRepository(), search)
-                        .onFailure(e->log.warn("failure while executing auto-complete", e))
-                        .getOrElse(Collections::emptyList);
+                        .ifFailure(e->log.warn("failure while executing auto-complete", e))
+                        .orElseGet(Collections::emptyList);
                 return getObjectManager().adapt(list);
         });
 
diff --git a/persistence/jpa/applib/src/main/java/org/apache/isis/persistence/jpa/applib/services/JpaSupportService.java b/persistence/jpa/applib/src/main/java/org/apache/isis/persistence/jpa/applib/services/JpaSupportService.java
index 9b73461..eb658f3 100644
--- a/persistence/jpa/applib/src/main/java/org/apache/isis/persistence/jpa/applib/services/JpaSupportService.java
+++ b/persistence/jpa/applib/src/main/java/org/apache/isis/persistence/jpa/applib/services/JpaSupportService.java
@@ -18,34 +18,45 @@
  */
 package org.apache.isis.persistence.jpa.applib.services;
 
-import java.util.Optional;
-
 import javax.persistence.EntityManager;
 
-import org.apache.isis.commons.internal.exceptions._Exceptions;
+import org.apache.isis.commons.functional.Result;
 
 import lombok.NonNull;
 
 /**
- * Provides access to the current interaction's {@link EntityManager} 
+ * Provides access to the current interaction's {@link EntityManager}(s) 
  * 
  * @since 2.0 {@index}
  */
 public interface JpaSupportService {
 
     /**
-     * Optionally returns the current interaction's {@link EntityManager},
+     * Optionally returns the current interaction's {@link EntityManager}, 
+     * that is bound to given {@code entityClass},
      * based on whether an open interaction is available and a persistence layer 
      * is configured in support of JPA.
+     * @param entityType - (non-null)
+     * @throws NullPointerException when given {@code entityType} is {@code null}
      */
-    Optional<EntityManager> getEntityManager(Class<?> entityClass);
+    Result<EntityManager> getEntityManager(@NonNull Class<?> entityType);
     
-    default EntityManager getEntityManagerElseFail(final @NonNull Class<?> entityClass) {
-        return getEntityManager(entityClass)
-                .orElseThrow(()->_Exceptions.illegalState(
+    /**
+     * Returns the current interaction's {@link EntityManager} that is managing the given domain type 
+     * {@code entityType}.
+     * @param entityType - (non-null)
+     * 
+     * @throws NullPointerException when given {@code entityType} is {@literal null}
+     * @throws IllegalStateException when no open interaction is available or when the given type is not 
+     * JPA managed or no unique {@link EntityManager} managing this type can be resolved.
+     */
+    default EntityManager getEntityManagerElseFail(final @NonNull Class<?> entityType) {
+        
+        return getEntityManager(entityType)
+                .orElseThrow(cause->new IllegalStateException(
+                        String.format(
                         "Current thread either has no open interaction or"
-                        + " no persistence layer "
-                        + " in support of given JPA entity class %s is configured.", entityClass));
+                        + " or no unique EntityManager managing type %s can be resolved.", entityType), cause));
     }
     
 }
diff --git a/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/services/JpaSupportServiceUsingSpring.java b/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/services/JpaSupportServiceUsingSpring.java
index a26e89c..6804835 100644
--- a/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/services/JpaSupportServiceUsingSpring.java
+++ b/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/services/JpaSupportServiceUsingSpring.java
@@ -18,13 +18,12 @@
  */
 package org.apache.isis.persistence.jpa.integration.services;
 
-import java.util.Optional;
-
 import javax.inject.Inject;
 import javax.persistence.EntityManager;
 
 import org.springframework.data.jpa.repository.JpaContext;
 
+import org.apache.isis.commons.functional.Result;
 import org.apache.isis.persistence.jpa.applib.services.JpaSupportService;
 
 import lombok.NonNull;
@@ -38,13 +37,13 @@ public class JpaSupportServiceUsingSpring implements JpaSupportService {
 
     private final JpaContext jpaContextSpring;
     
-    public Optional<EntityManager> getEntityManager(final @NonNull Class<?> entityClass) {
+    public Result<EntityManager> getEntityManager(final @NonNull Class<?> entityClass) {
         try {
             val em = jpaContextSpring.getEntityManagerByManagedType(entityClass);
-            return Optional.ofNullable(em);
+            return Result.success(em);
         } catch (Exception e) {
             log.error("failed to get an EntityManager for entity type %s", entityClass, e);
-            return Optional.empty();
+            return Result.failure(e);
         }
     }
     
diff --git a/regressiontests/stable/src/test/java/org/apache/isis/testdomain/jpa/JpaQueryTest.java b/regressiontests/stable/src/test/java/org/apache/isis/testdomain/jpa/JpaQueryTest.java
index 2b43498..2a57791 100644
--- a/regressiontests/stable/src/test/java/org/apache/isis/testdomain/jpa/JpaQueryTest.java
+++ b/regressiontests/stable/src/test/java/org/apache/isis/testdomain/jpa/JpaQueryTest.java
@@ -25,7 +25,6 @@ import java.util.TreeSet;
 
 import javax.inject.Inject;
 
-import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.MethodOrderer;
@@ -71,38 +70,6 @@ class JpaQueryTest extends IsisIntegrationTestAbstract {
         // Util_H2Console.main(null);
     }
 
-    @AfterAll
-    static void afterAll() throws SQLException {
-    }
-
-    void cleanUp() {
-        repository.allInstances(JpaInventory.class).forEach(repository::remove);
-        repository.allInstances(JpaBook.class).forEach(repository::remove);
-        repository.allInstances(JpaProduct.class).forEach(repository::remove);
-    }
-
-    void setUp3Books() {
-
-        cleanUp();
-        // given - expected pre condition: no inventories
-        assertEquals(0, repository.allInstances(JpaInventory.class).size());
-        
-        // setup sample Inventory with 3 Books
-        SortedSet<JpaProduct> products = new TreeSet<>();
-
-        products.add(JpaBook.of("Sample Book-1", "A sample book for testing.", 39., "Sample Author", "ISBN-A",
-                "Sample Publisher"));
-
-        products.add(JpaBook.of("Sample Book-2", "A sample book for testing.", 29., "Sample Author", "ISBN-B",
-                "Sample Publisher"));
-        
-        products.add(JpaBook.of("Sample Book-3", "A sample book for testing.", 99., "Sample Author", "ISBN-C",
-                "Sample Publisher"));
-        
-        val inventory = new JpaInventory("Sample Inventory", products);
-        repository.persistAndFlush(inventory);
-    }
-
     @Test @Order(1) 
     void sampleInventory_shouldBeSetUpWith3Books() {
 
@@ -186,8 +153,41 @@ class JpaQueryTest extends IsisIntegrationTestAbstract {
         assertInventoryHasBooks(affordableBooks, 1, 2);
     }
     
+    @Test @Order(99) 
+    void previousTest_shouldHaveRolledBack() {
+        assertEquals(0, repository.allInstances(JpaInventory.class).size());
+        assertEquals(0, repository.allInstances(JpaProduct.class).size());
+    }
+    
     // -- HELPER 
     
+    private void cleanUp() {
+        repository.allInstances(JpaInventory.class).forEach(repository::remove);
+        repository.allInstances(JpaProduct.class).forEach(repository::remove);
+    }
+
+    private void setUp3Books() {
+
+        cleanUp();
+        // given - expected pre condition: no inventories
+        assertEquals(0, repository.allInstances(JpaInventory.class).size());
+        
+        // setup sample Inventory with 3 Books
+        SortedSet<JpaProduct> products = new TreeSet<>();
+
+        products.add(JpaBook.of("Sample Book-1", "A sample book for testing.", 39., "Sample Author", "ISBN-A",
+                "Sample Publisher"));
+
+        products.add(JpaBook.of("Sample Book-2", "A sample book for testing.", 29., "Sample Author", "ISBN-B",
+                "Sample Publisher"));
+        
+        products.add(JpaBook.of("Sample Book-3", "A sample book for testing.", 99., "Sample Author", "ISBN-C",
+                "Sample Publisher"));
+        
+        val inventory = new JpaInventory("Sample Inventory", products);
+        repository.persistAndFlush(inventory);
+    }
+    
     private void assertInventoryHasBooks(Collection<? extends JpaProduct> products, int...expectedBookIndices) {
         val actualBookIndices = products.stream()
                 .map(JpaProduct::getName)
diff --git a/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/resources/ObjectActionArgHelper.java b/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/resources/ObjectActionArgHelper.java
index 037791e..7652f4e 100644
--- a/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/resources/ObjectActionArgHelper.java
+++ b/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/resources/ObjectActionArgHelper.java
@@ -22,8 +22,8 @@ import java.util.List;
 import java.util.Map;
 
 import org.apache.isis.commons.collections.Can;
+import org.apache.isis.commons.functional.Result;
 import org.apache.isis.commons.internal.base._Either;
-import org.apache.isis.commons.internal.base._Result;
 import org.apache.isis.commons.internal.collections._Lists;
 import org.apache.isis.core.metamodel.interactions.managed.InteractionVeto;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
@@ -59,7 +59,7 @@ public class ObjectActionArgHelper {
             val paramMeta = parameters.getElseFail(argIndex);
             val paramSpec = paramMeta.getSpecification();
             
-            val objectOrVeto = _Result.of(()->
+            val objectOrVeto = Result.of(()->
                     (paramMeta.isOptional() && argRepr == null) 
                     ? ManagedObject.empty(paramSpec)
                     : new JsonParserHelper(resourceContext, paramSpec)