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 <[email protected]>
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;