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 297899cae9 ISIS-3084: Wrapper: refactors proxied methods for 
Map/Collection/List into ProgrammingModelConstants
297899cae9 is described below

commit 297899cae9a25c3dc32e61836d5dd05a264d9460
Author: Andi Huber <ahu...@apache.org>
AuthorDate: Thu Jun 30 10:29:02 2022 +0200

    ISIS-3084: Wrapper: refactors proxied methods for Map/Collection/List
    into ProgrammingModelConstants
---
 .../isis/commons/internal/collections/_Lists.java  | 27 +++++++++-
 .../progmodel/ProgrammingModelConstants.java       | 58 ++++++++++++++++++++++
 .../handlers/CollectionInvocationHandler.java      | 40 +++++++--------
 .../wrapper/handlers/MapInvocationHandler.java     | 39 +++++++--------
 ...ava => NonScalarInvocationHandlerAbstract.java} | 42 +++++++++++++---
 5 files changed, 155 insertions(+), 51 deletions(-)

diff --git 
a/commons/src/main/java/org/apache/isis/commons/internal/collections/_Lists.java
 
b/commons/src/main/java/org/apache/isis/commons/internal/collections/_Lists.java
index 1dec99f051..2d5ed27a6d 100644
--- 
a/commons/src/main/java/org/apache/isis/commons/internal/collections/_Lists.java
+++ 
b/commons/src/main/java/org/apache/isis/commons/internal/collections/_Lists.java
@@ -37,6 +37,7 @@ import org.springframework.lang.Nullable;
 import org.apache.isis.commons.internal.base._NullSafe;
 
 import lombok.NonNull;
+import lombok.val;
 
 /**
  * <h1>- internal use only -</h1>
@@ -70,6 +71,30 @@ public final class _Lists {
         return Optional.ofNullable(list.get(list.size()-1));
     }
 
+    // -- LIST CONCATENATION
+
+    /**
+     * Returns an unmodifiable list containing all elements from given list
+     * and the specified element.
+     */
+    public static <T> List<T> append(final List<T> list, final T element) {
+        val resultList = new ArrayList<T>(list.size() + 1);
+        resultList.addAll(list);
+        resultList.add(element);
+        return Collections.unmodifiableList(resultList);
+    }
+
+    /**
+     * Returns an unmodifiable list containing all elements from given lists
+     * list1 and list2.
+     */
+    public static <T> List<T> concat(final List<T> list1, final List<T> list2) 
{
+        val resultList = new ArrayList<T>(list1.size() + list2.size());
+        resultList.addAll(list1);
+        resultList.addAll(list2);
+        return Collections.unmodifiableList(resultList);
+    }
+
     // -- UNMODIFIABLE LIST
 
     /**
@@ -206,6 +231,4 @@ public final class _Lists {
         return toUnmodifiable(ArrayList::new);
     }
 
-
-
 }
diff --git 
a/core/config/src/main/java/org/apache/isis/core/config/progmodel/ProgrammingModelConstants.java
 
b/core/config/src/main/java/org/apache/isis/core/config/progmodel/ProgrammingModelConstants.java
index d93d294b24..ea17f20629 100644
--- 
a/core/config/src/main/java/org/apache/isis/core/config/progmodel/ProgrammingModelConstants.java
+++ 
b/core/config/src/main/java/org/apache/isis/core/config/progmodel/ProgrammingModelConstants.java
@@ -28,6 +28,7 @@ import java.time.OffsetDateTime;
 import java.time.format.DateTimeFormatter;
 import java.time.format.DateTimeFormatterBuilder;
 import java.util.Collection;
+import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Optional;
@@ -52,6 +53,7 @@ import org.apache.isis.commons.functional.Try;
 import org.apache.isis.commons.internal.base._Casts;
 import org.apache.isis.commons.internal.base._Refs;
 import org.apache.isis.commons.internal.base._Strings;
+import org.apache.isis.commons.internal.collections._Lists;
 import org.apache.isis.commons.internal.exceptions._Exceptions;
 import org.apache.isis.commons.internal.reflection._Annotations;
 import org.apache.isis.commons.internal.reflection._Reflect;
@@ -62,6 +64,7 @@ import static 
org.apache.isis.commons.internal.reflection._Reflect.Filter.paramC
 import lombok.Getter;
 import lombok.NonNull;
 import lombok.RequiredArgsConstructor;
+import lombok.SneakyThrows;
 import lombok.val;
 
 public final class ProgrammingModelConstants {
@@ -505,6 +508,61 @@ public final class ProgrammingModelConstants {
 
     }
 
+    //TODO needs an update to reflect Java 7->11 Language changes
+    @RequiredArgsConstructor
+    public static enum WrapperFactoryProxy {
+        COLLECTION(
+                List.of(
+                        getMethod(Collection.class, "contains", Object.class),
+                        getMethod(Collection.class, "size"),
+                        getMethod(Collection.class, "isEmpty")
+                ),
+                List.of(
+                        getMethod(Collection.class, "add", Object.class),
+                        getMethod(Collection.class, "remove", Object.class),
+                        getMethod(Collection.class, "addAll", 
Collection.class),
+                        getMethod(Collection.class, "removeAll", 
Collection.class),
+                        getMethod(Collection.class, "retainAll", 
Collection.class),
+                        getMethod(Collection.class, "clear")
+                )),
+        LIST(
+                _Lists.concat(
+                        WrapperFactoryProxy.COLLECTION.intercepted,
+                        List.of(
+                                getMethod(List.class, "get", int.class)
+                        )
+                ),
+                _Lists.concat(
+                        WrapperFactoryProxy.COLLECTION.vetoed,
+                        List.of(
+                        )
+                )),
+        MAP(
+                List.of(
+                        getMethod(Map.class, "containsKey", Object.class),
+                        getMethod(Map.class, "containsValue", Object.class),
+                        getMethod(Map.class, "size"),
+                        getMethod(Map.class, "isEmpty")
+                ),
+                List.of(
+                        getMethod(Map.class, "put", Object.class, 
Object.class),
+                        getMethod(Map.class, "remove", Object.class),
+                        getMethod(Map.class, "putAll", Map.class),
+                        getMethod(Map.class, "clear")
+                ))
+        ;
+        @Getter private final List<Method> intercepted;
+        @Getter private final List<Method> vetoed;
+        // -- HELPER
+        @SneakyThrows
+        private static Method getMethod(
+                final Class<?> cls,
+                final String methodName,
+                final Class<?>... parameterClass) {
+            return cls.getMethod(methodName, parameterClass);
+        }
+    }
+
     // -- HELPER
 
     private static String getCapitalizedMemberName(final Member member) {
diff --git 
a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/handlers/CollectionInvocationHandler.java
 
b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/handlers/CollectionInvocationHandler.java
index 14fd232dda..6ce0ac9692 100644
--- 
a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/handlers/CollectionInvocationHandler.java
+++ 
b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/handlers/CollectionInvocationHandler.java
@@ -21,36 +21,34 @@ package 
org.apache.isis.core.runtimeservices.wrapper.handlers;
 import java.util.Collection;
 import java.util.List;
 
-import org.apache.isis.core.metamodel.commons.ObjectExtensions;
+import org.apache.isis.commons.internal.assertions._Assert;
+import org.apache.isis.core.config.progmodel.ProgrammingModelConstants;
 import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
 
-class CollectionInvocationHandler<T, R> extends 
AbstractCollectionInvocationHandler<T, R> {
+import lombok.val;
+
+class CollectionInvocationHandler<T, C extends Collection<?>>
+extends NonScalarInvocationHandlerAbstract<T, C> {
 
     public CollectionInvocationHandler(
-            final R collectionToProxy,
+            final C collectionToProxy,
             final DomainObjectInvocationHandler<T> handler,
             final OneToManyAssociation otma) {
 
         super(collectionToProxy, handler, otma);
 
-        try {
-            intercept(ObjectExtensions.getMethod(collectionToProxy, 
"contains", Object.class));
-            intercept(ObjectExtensions.getMethod(collectionToProxy, "size"));
-            intercept(ObjectExtensions.getMethod(collectionToProxy, 
"isEmpty"));
-            if (collectionToProxy instanceof List) {
-                intercept(ObjectExtensions.getMethod(collectionToProxy, "get", 
int.class));
-            }
-            veto(ObjectExtensions.getMethod(collectionToProxy, "add", 
Object.class));
-            veto(ObjectExtensions.getMethod(collectionToProxy, "remove", 
Object.class));
-            veto(ObjectExtensions.getMethod(collectionToProxy, "addAll", 
Collection.class));
-            veto(ObjectExtensions.getMethod(collectionToProxy, "removeAll", 
Collection.class));
-            veto(ObjectExtensions.getMethod(collectionToProxy, "retainAll", 
Collection.class));
-            veto(ObjectExtensions.getMethod(collectionToProxy, "clear"));
-        } catch (final NoSuchMethodException e) {
-            // ///CLOVER:OFF
-            throw new RuntimeException("A Collection method could not be 
found: " + e.getMessage());
-            // ///CLOVER:ON
-        }
+        
_Assert.assertTrue(collectionToProxy.getClass().isAssignableFrom(Collection.class),
+                ()->String.format("Cannot use %s for type %s, these are not 
compatible.",
+                        this.getClass().getName(),
+                        collectionToProxy.getClass()));
+
+        val methodSets = (collectionToProxy instanceof List)
+                ? ProgrammingModelConstants.WrapperFactoryProxy.LIST
+                : ProgrammingModelConstants.WrapperFactoryProxy.COLLECTION;
+
+        methodSets.getIntercepted().forEach(this::intercept);
+        methodSets.getVetoed().forEach(this::veto);
+
     }
 
 }
diff --git 
a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/handlers/MapInvocationHandler.java
 
b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/handlers/MapInvocationHandler.java
index 2ee8c8b2c8..ff22c492ef 100644
--- 
a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/handlers/MapInvocationHandler.java
+++ 
b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/handlers/MapInvocationHandler.java
@@ -20,33 +20,32 @@ package 
org.apache.isis.core.runtimeservices.wrapper.handlers;
 
 import java.util.Map;
 
-import org.apache.isis.core.metamodel.commons.ObjectExtensions;
+import org.apache.isis.commons.internal.assertions._Assert;
+import org.apache.isis.core.config.progmodel.ProgrammingModelConstants;
 import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
 
-class MapInvocationHandler<T, C>
-extends AbstractCollectionInvocationHandler<T, C> {
+class MapInvocationHandler<T, M extends Map<?,?>>
+extends NonScalarInvocationHandlerAbstract<T, M> {
 
     public MapInvocationHandler(
-            final C collectionToProxy,
+            final M mapToProxy,
             final DomainObjectInvocationHandler<T> handler,
             final OneToManyAssociation otma) {
 
-        super(collectionToProxy, handler, otma);
-
-        try {
-            intercept(ObjectExtensions.getMethod(collectionToProxy, 
"containsKey", Object.class));
-            intercept(ObjectExtensions.getMethod(collectionToProxy, 
"containsValue", Object.class));
-            intercept(ObjectExtensions.getMethod(collectionToProxy, "size"));
-            intercept(ObjectExtensions.getMethod(collectionToProxy, 
"isEmpty"));
-            veto(ObjectExtensions.getMethod(collectionToProxy, "put", 
Object.class, Object.class));
-            veto(ObjectExtensions.getMethod(collectionToProxy, "remove", 
Object.class));
-            veto(ObjectExtensions.getMethod(collectionToProxy, "putAll", 
Map.class));
-            veto(ObjectExtensions.getMethod(collectionToProxy, "clear"));
-        } catch (final NoSuchMethodException e) {
-            // ///CLOVER:OFF
-            throw new RuntimeException("A Collection method could not be 
found: " + e.getMessage());
-            // ///CLOVER:ON
-        }
+        super(mapToProxy, handler, otma);
+
+        _Assert.assertTrue(mapToProxy.getClass().isAssignableFrom(Map.class),
+                ()->String.format("Cannot use %s for type %s, these are not 
compatible.",
+                        this.getClass().getName(),
+                        mapToProxy.getClass()));
+
+        ProgrammingModelConstants.WrapperFactoryProxy.MAP
+        .getIntercepted()
+        .forEach(this::intercept);
+
+        ProgrammingModelConstants.WrapperFactoryProxy.MAP
+        .getVetoed()
+        .forEach(this::veto);
     }
 
 }
diff --git 
a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/handlers/AbstractCollectionInvocationHandler.java
 
b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/handlers/NonScalarInvocationHandlerAbstract.java
similarity index 66%
rename from 
core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/handlers/AbstractCollectionInvocationHandler.java
rename to 
core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/handlers/NonScalarInvocationHandlerAbstract.java
index 7048438e52..55ec020e56 100644
--- 
a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/handlers/AbstractCollectionInvocationHandler.java
+++ 
b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/handlers/NonScalarInvocationHandlerAbstract.java
@@ -20,14 +20,22 @@ package 
org.apache.isis.core.runtimeservices.wrapper.handlers;
 
 import java.lang.reflect.Method;
 import java.util.List;
+import java.util.Map;
 
 import org.apache.isis.applib.services.wrapper.events.CollectionMethodEvent;
-import org.apache.isis.applib.services.wrapper.events.InteractionEvent;
 import org.apache.isis.commons.internal.collections._Lists;
 import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
 
-abstract class AbstractCollectionInvocationHandler<T, C>
-extends DelegatingInvocationHandlerDefault<C> {
+import lombok.val;
+
+/**
+ * Base class in support of non-scalar types to be proxied up.
+ *
+ * @param <T> Domain Object type
+ * @param <P> non-scalar type (eg. {@link Collection} or {@link Map}) to be 
proxied
+ */
+abstract class NonScalarInvocationHandlerAbstract<T, P>
+extends DelegatingInvocationHandlerDefault<P> {
 
     private final List<Method> interceptedMethods = _Lists.newArrayList();
     private final List<Method> vetoedMethods = _Lists.newArrayList();
@@ -35,8 +43,8 @@ extends DelegatingInvocationHandlerDefault<C> {
     private final OneToManyAssociation oneToManyAssociation;
     private final T domainObject;
 
-    public AbstractCollectionInvocationHandler(
-            final C collectionOrMapToProxy,
+    protected NonScalarInvocationHandlerAbstract(
+            final P collectionOrMapToProxy,
             final DomainObjectInvocationHandler<T> handler,
             final OneToManyAssociation otma) {
 
@@ -48,11 +56,21 @@ extends DelegatingInvocationHandlerDefault<C> {
         this.domainObject = handler.getDelegate();
     }
 
+    /**
+     * Adds given method to the list of intercepted methods,
+     * those which will trigger {@link CollectionMethodEvent}(s)
+     * on invocation.
+     */
     protected Method intercept(final Method method) {
         this.interceptedMethods.add(method);
         return method;
     }
 
+    /**
+     * Adds given method to the list of vetoed methods,
+     * those which will cause an {@link UnsupportedOperationException}
+     * on invocation.
+     */
     protected Method veto(final Method method) {
         this.vetoedMethods.add(method);
         return method;
@@ -76,13 +94,21 @@ extends DelegatingInvocationHandlerDefault<C> {
 
             resolveIfRequired(domainObject);
 
-            final InteractionEvent ev = new 
CollectionMethodEvent(getDelegate(), getCollection().getFeatureIdentifier(), 
getDomainObject(), method.getName(), args, returnValueObj);
-            notifyListeners(ev);
+            val event =
+                    new CollectionMethodEvent(
+                            getDelegate(),
+                            getCollection().getFeatureIdentifier(),
+                            getDomainObject(),
+                            method.getName(),
+                            args,
+                            returnValueObj);
+            notifyListeners(event);
             return returnValueObj;
         }
 
         if (vetoedMethods.contains(method)) {
-            throw new UnsupportedOperationException(String.format("Method '%s' 
may not be called directly.", method.getName()));
+            throw new UnsupportedOperationException(
+                    String.format("Method '%s' may not be called directly.", 
method.getName()));
         }
 
         return returnValueObj;

Reply via email to