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 2022/05/14 14:51:20 UTC

[isis] 01/01: ISIS-3051: remove mixin facet copy around hackery

This is an automated email from the ASF dual-hosted git repository.

ahuber pushed a commit to branch 3051-mm-regression
in repository https://gitbox.apache.org/repos/asf/isis.git

commit c70ddc1f25deb2a99b3027317a45c8ceb22435c5
Author: Andi Huber <ah...@apache.org>
AuthorDate: Sat May 14 12:52:15 2022 +0200

    ISIS-3051: remove mixin facet copy around hackery
---
 .../metamodel/facetapi/FacetHolderAbstract.java    | 116 +++++++++++++++++++++
 .../isis/core/metamodel/facetapi/FacetUtil.java    |  19 ++--
 ...ctionParameterChoicesFacetViaMethodFactory.java |  10 ++
 .../ParameterNameFacetFactoryUsingReflection.java  |   7 +-
 .../param/ChoicesAndDefaultsPostProcessor.java     |   8 ++
 .../isis/core/metamodel/spec/Specification.java    |   5 +-
 .../specloader/specimpl/ObjectActionMixedIn.java   |  10 +-
 .../specimpl/OneToManyAssociationMixedIn.java      |  13 +--
 .../specimpl/OneToOneAssociationMixedIn.java       |  14 +--
 9 files changed, 160 insertions(+), 42 deletions(-)

diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetapi/FacetHolderAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetapi/FacetHolderAbstract.java
index 044b6ec801..a5f2045c4f 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetapi/FacetHolderAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetapi/FacetHolderAbstract.java
@@ -18,6 +18,7 @@
  */
 package org.apache.isis.core.metamodel.facetapi;
 
+import java.util.HashSet;
 import java.util.Map;
 import java.util.Optional;
 import java.util.stream.Stream;
@@ -53,6 +54,119 @@ implements FacetHolder {
         return facetHolder;
     }
 
+    public static FacetHolder wrapped(
+            final @NonNull MetaModelContext mmc,
+            final @NonNull Identifier featureIdentifier,
+            final @NonNull FacetHolder delegate) {
+        return new WrappedFacetHolder(mmc, featureIdentifier, delegate);
+    }
+
+    /**
+     * @see FacetHolderAbstract#wrapped(MetaModelContext, Identifier, FacetHolder)
+     */
+    @RequiredArgsConstructor
+    static class WrappedFacetHolder implements FacetHolder {
+
+        @Getter(onMethod_ = {@Override})
+        private final @NonNull MetaModelContext metaModelContext;
+        private final @NonNull Identifier featureIdentifierOverride;
+        private final @NonNull FacetHolder delegate;
+
+        @Override public Identifier getFeatureIdentifier() {
+            return featureIdentifierOverride; }
+        @Override public int getFacetCount() {
+            return delegate.getFacetCount(); }
+        @Override public <T extends Facet> T getFacet(final Class<T> facetType) {
+            return delegate.getFacet(facetType); }
+        @Override public boolean containsFacet(final Class<? extends Facet> facetType) {
+            return delegate.containsFacet(facetType); }
+        @Override public Stream<Facet> streamFacets() {
+            return delegate.streamFacets(); }
+        @Override public Stream<FacetRanking> streamFacetRankings() {
+            return delegate.streamFacetRankings(); }
+        @Override public Optional<FacetRanking> getFacetRanking(final Class<? extends Facet> facetType) {
+            return delegate.getFacetRanking(facetType); }
+        @Override public void addFacet(final @NonNull Facet facet) {
+            delegate.addFacet(facet);
+        }
+
+    }
+
+    /**
+     * @see FacetHolderAbstract#layered(MetaModelContext, Identifier, FacetHolder)
+     */
+    static class LayeredFacetHolder extends FacetHolderAbstract {
+
+        private final @NonNull FacetHolder parentLayer;
+
+        private LayeredFacetHolder(final MetaModelContext metaModelContext, final FacetHolder parentLayer) {
+            super(metaModelContext);
+            this.parentLayer = parentLayer;
+        }
+
+        @Override
+        public int getFacetCount() {
+            // cannot simply add up this and parent
+            return (int)streamFacets().count();
+        }
+
+        @Override
+        public <T extends Facet> T getFacet(final Class<T> facetType) {
+            return Optional.ofNullable(super.getFacet(facetType))
+                    .orElse(parentLayer.getFacet(facetType));
+        }
+
+        @Override
+        public boolean containsFacet(final Class<? extends Facet> facetType) {
+            return super.containsFacet(facetType)
+                    || parentLayer.containsFacet(facetType);
+        }
+
+        @Override
+        public Stream<Facet> streamFacets() {
+            val localFacetTypes = new HashSet<Class<? extends Facet>>();
+            return Stream.concat(
+                    super.streamFacets()
+                    .peek(facet->localFacetTypes.add(facet.facetType()))
+                    ,
+                    parentLayer.streamFacets()
+                    .filter(facet->!localFacetTypes.contains(facet.facetType())));
+        }
+
+        @Override
+        public Stream<FacetRanking> streamFacetRankings() {
+            val localFacetTypes = new HashSet<Class<? extends Facet>>();
+            return Stream.concat(
+                    super.streamFacetRankings()
+                    .peek(ranking->localFacetTypes.add(ranking.facetType()))
+                    ,
+                    parentLayer.streamFacetRankings()
+                    .filter(ranking->!localFacetTypes.contains(ranking.facetType())));
+        }
+
+        @Override
+        public Optional<FacetRanking> getFacetRanking(final Class<? extends Facet> facetType) {
+            return Optional.ofNullable(super.getFacetRanking(facetType))
+                    .orElse(parentLayer.getFacetRanking(facetType));
+        }
+
+    }
+
+    /**
+     * Adds a new (transparent) layer on top of the {@code parentLayer}.
+     * <p>
+     * Facets can be added to this holder, while not affecting its parent.
+     * However, the parent acts as a fallback for {@link Facet} lookups.
+     */
+    private static FacetHolder layered(
+            final @NonNull MetaModelContext mmc,
+            final @NonNull Identifier featureIdentifier,
+            final @NonNull FacetHolder parentLayer) {
+        val facetHolder = new LayeredFacetHolder(mmc, parentLayer);
+        facetHolder.featureIdentifier = featureIdentifier;
+        return facetHolder;
+    }
+
     // -- FIELDS
 
     @Getter(onMethod_ = {@Override}) private final @NonNull MetaModelContext metaModelContext;
@@ -148,4 +262,6 @@ implements FacetHolder {
     }
 
 
+
+
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetapi/FacetUtil.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetapi/FacetUtil.java
index 014c84572b..3f8a62adce 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetapi/FacetUtil.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetapi/FacetUtil.java
@@ -38,7 +38,7 @@ public final class FacetUtil {
      * @param facet - non-null
      * @return the argument as is
      */
-    public static <F extends Facet> F addFacet(final @NonNull F facet) {
+    public <F extends Facet> F addFacet(final @NonNull F facet) {
         facet.getFacetHolder().addFacet(facet);
         return facet;
     }
@@ -49,7 +49,7 @@ public final class FacetUtil {
      * @param facetIfAny - null-able (for fail-safety)
      * @return the argument as is - or just in case if null converted to an Optional.empty()
      */
-    public static <F extends Facet> Optional<F> addFacetIfPresent(final @Nullable Optional<F> facetIfAny) {
+    public <F extends Facet> Optional<F> addFacetIfPresent(final @Nullable Optional<F> facetIfAny) {
         if (facetIfAny == null) {
             return Optional.empty();
         }
@@ -64,7 +64,7 @@ public final class FacetUtil {
      *
      * @return whether given {@code facetList} contains any non-<tt>null</tt> facets
      */
-    public static boolean addFacets(final @NonNull Iterable<Facet> facetList) {
+    public boolean addFacets(final @NonNull Iterable<Facet> facetList) {
         boolean addedFacets = false;
         for (val facet : facetList) {
             addedFacets = addFacetIfPresent(Optional.ofNullable(facet)).isPresent()
@@ -73,7 +73,7 @@ public final class FacetUtil {
         return addedFacets;
     }
 
-    public static <T extends Facet> XmlSchema.ExtensionData<T> getFacetsByType(final FacetHolder facetHolder) {
+    public <T extends Facet> XmlSchema.ExtensionData<T> getFacetsByType(final FacetHolder facetHolder) {
 
         return new XmlSchema.ExtensionData<T>() {
 
@@ -92,18 +92,13 @@ public final class FacetUtil {
         };
     }
 
-    public static void copyFacetsTo(final FacetHolder source, final FacetHolder target) {
-        source.streamFacets()
-        .forEach(target::addFacet);
-    }
-
     // -- DYNAMIC UPDATE SUPPORT
 
     /**
      * Removes any facet that matches the facet's java class from its FacetHolder,
      * then adds the facet to the facetHolder.
      */
-    public static <F extends Facet> void updateFacet(
+    public <F extends Facet> void updateFacet(
             final @NonNull F facet) {
 
         purgeIf(facet.facetType(), facet.getClass()::isInstance, facet.getFacetHolder());
@@ -114,7 +109,7 @@ public final class FacetUtil {
      * Removes any facet of facet-type from facetHolder if it passes the given filter,
      * then if present adds facetIfAny to the facetHolder.
      */
-    public static <F extends Facet> void updateFacet(
+    public <F extends Facet> void updateFacet(
             final @NonNull Class<F> facetType,
             final @NonNull Predicate<? super F> filter,
             final @NonNull Optional<? extends F> facetIfAny,
@@ -127,7 +122,7 @@ public final class FacetUtil {
     /**
      * Removes any facet of facet-type from facetHolder if it passes the given filter.
      */
-    public static <F extends Facet> void purgeIf(
+    public <F extends Facet> void purgeIf(
             final Class<F> facetType,
             final Predicate<? super F> filter,
             final FacetHolder facetHolder) {
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/choices/methodnum/ActionParameterChoicesFacetViaMethodFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/choices/methodnum/ActionParameterChoicesFacetViaMethodFactory.java
index 480f190f5b..a29bb6e25c 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/choices/methodnum/ActionParameterChoicesFacetViaMethodFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/choices/methodnum/ActionParameterChoicesFacetViaMethodFactory.java
@@ -18,6 +18,8 @@
  */
 package org.apache.isis.core.metamodel.facets.param.choices.methodnum;
 
+import java.util.Optional;
+
 import javax.inject.Inject;
 
 import org.apache.isis.core.config.progmodel.ProgrammingModelConstants.MemberSupportPrefix;
@@ -43,6 +45,14 @@ extends ActionParameterSupportFacetFactoryAbstract {
         val choicesMethod = searchResult.getSupportingMethod();
         val returnType = searchResult.getReturnType();
         val patConstructor = searchResult.getPatConstructor();
+
+        if(Optional.ofNullable(paramAsHolder.getFeatureIdentifier().getClassName()).orElse("")
+                .contains("HasCommunicationChannels_removeCommunicationChannel")) {
+            System.err.println("==ActionParameterChoicesFacetViaMethodFactory");
+            System.err.printf("%s%n", paramAsHolder.getFeatureIdentifier());
+            System.err.printf("\t%d: %s%n", paramAsHolder.getParamIndex(), paramAsHolder.getFeatureIdentifier().toString());
+        }
+
         addFacet(
                 new ActionParameterChoicesFacetViaMethod(
                         choicesMethod, returnType, patConstructor, paramAsHolder));
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/name/ParameterNameFacetFactoryUsingReflection.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/name/ParameterNameFacetFactoryUsingReflection.java
index 62379efdd0..a28203f2e9 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/name/ParameterNameFacetFactoryUsingReflection.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/name/ParameterNameFacetFactoryUsingReflection.java
@@ -68,7 +68,12 @@ extends FacetFactoryAbstract {
         val naturalName = StringExtensions.asNaturalName2(parameterName);
         val facetHolder = processParameterContext.getFacetHolder();
 
-
+        if(Optional.ofNullable(facetHolder.getFeatureIdentifier().getClassName()).orElse("")
+                .contains("HasCommunicationChannels_removeCommunicationChannel")) {
+            System.err.println("==ParameterNameFacetFactoryUsingReflection");
+            System.err.printf("%s%n", facetHolder.getFeatureIdentifier());
+            System.err.printf("\t%d: %s%n", facetHolder.getParamIndex(), facetHolder.getFeatureIdentifier().toString());
+        }
 
         FacetUtil.addFacet(
                 new NamedFacetForParameterUsingReflection(naturalName, facetHolder));
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/postprocessors/param/ChoicesAndDefaultsPostProcessor.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/postprocessors/param/ChoicesAndDefaultsPostProcessor.java
index 6114953025..93473f4828 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/postprocessors/param/ChoicesAndDefaultsPostProcessor.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/postprocessors/param/ChoicesAndDefaultsPostProcessor.java
@@ -67,6 +67,14 @@ extends ObjectSpecificationPostProcessorAbstract {
 
         val paramAsHolder = param;
 
+        if(Optional.ofNullable(paramAsHolder.getFeatureIdentifier().getClassName()).orElse("")
+                .contains("HasCommunicationChannels_removeCommunicationChannel")) {
+            System.err.println("==ChoicesAndDefaultsPostProcessor");
+            System.err.printf("%s%n", paramAsHolder.getFeatureIdentifier());
+            System.err.printf("\t%d: %s%n", paramAsHolder.getParameterIndex(), paramAsHolder.getFeatureIdentifier().toString());
+            System.err.printf("\thasMemberLevelChoices: %b%n", hasMemberLevelChoices(param));
+        }
+
         if(!hasMemberLevelChoices(param)) {
             param.getElementType()
             .lookupNonFallbackFacet(ChoicesFacet.class)
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/Specification.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/Specification.java
index 4adc9b1faa..c905164163 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/Specification.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/Specification.java
@@ -55,8 +55,9 @@ public interface Specification extends HasFacetHolder {
      * </li><li>for a {@link OneToManyAssociation collection} it will be the type of
      * element the collection holds (not the type of collection)
      * </li><li>for an {@link ObjectAction action} will return {@link ObjectAction#getReturnType()}
-     * </li><li>for an {@link ObjectActionParameter action parameter}, will return the type of
-     * the parameter
+     * </li><li>for an {@link ObjectActionParameter action parameter}, will return the element type of
+     * the parameter (this is the parameter type itself if scalar, otherwise the type of
+     * element the collection (non-scalar) parameter holds)
      * </li>
      * </ul>
      * @since 2.0
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedIn.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedIn.java
index 47de4a1e27..c8944e2814 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedIn.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedIn.java
@@ -29,7 +29,6 @@ import org.apache.isis.commons.internal.reflection._Annotations;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facetapi.FacetHolderAbstract;
-import org.apache.isis.core.metamodel.facetapi.FacetUtil;
 import org.apache.isis.core.metamodel.facets.all.named.MemberNamedFacet;
 import org.apache.isis.core.metamodel.facets.all.named.MemberNamedFacetForStaticMemberName;
 import org.apache.isis.core.metamodel.interactions.InteractionHead;
@@ -81,16 +80,15 @@ implements MixedInMember {
                     mixinAction.getFacetedMethod().getFeatureIdentifier().getMemberParameterClassNames()),
                 mixinAction.getFacetedMethod(), false);
 
-        this.facetHolder = FacetHolderAbstract.simple(
+        this.facetHolder = FacetHolderAbstract.wrapped(
                 mixedInType.getMetaModelContext(),
-                super.getFeatureIdentifier());
+                super.getFeatureIdentifier(),
+                mixinAction.getFacetedMethod());
+
         this.mixinType = mixinType;
         this.mixinAction = mixinAction;
         this.mixedInType = mixedInType;
 
-        // copy over facets from mixin action to self
-        FacetUtil.copyFacetsTo(mixinAction.getFacetedMethod(), facetHolder);
-
         // adjust name if necessary
 
         val isExplicitlyNamed = lookupNonFallbackFacet(MemberNamedFacet.class)
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToManyAssociationMixedIn.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToManyAssociationMixedIn.java
index e96f592dd1..837855d20a 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToManyAssociationMixedIn.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToManyAssociationMixedIn.java
@@ -97,9 +97,10 @@ implements MixedInMember {
                     _MixedInMemberNamingStrategy.determineIdFrom(mixinAction)),
                 mixinAction.getFacetedMethod(), typeOfSpec(mixinAction));
 
-        this.facetHolder = FacetHolderAbstract.simple(
+        this.facetHolder = FacetHolderAbstract.wrapped(
                 mixeeSpec.getMetaModelContext(),
-                super.getFeatureIdentifier());
+                super.getFeatureIdentifier(),
+                mixinAction.getFacetedMethod());
 
         this.mixinType = mixinType;
         this.mixinAction = mixinAction;
@@ -112,14 +113,6 @@ implements MixedInMember {
         FacetUtil.addFacet(disabledFacet());
         FacetUtil.addFacet(new TypeOfFacetAbstract(getElementType().getCorrespondingClass(), this) {});
 
-        //
-        // in addition, copy over facets from contributed to own.
-        //
-        // These could include everything under @Collection(...) because the
-        // CollectionAnnotationFacetFactory is also run against actions.
-        //
-        FacetUtil.copyFacetsTo(mixinAction.getFacetedMethod(), facetHolder);
-
         // adjust name if necessary
         val isExplicitlyNamed = lookupNonFallbackFacet(MemberNamedFacet.class)
                 .isPresent();
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToOneAssociationMixedIn.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToOneAssociationMixedIn.java
index 8ee7f5dd91..0d83de2592 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToOneAssociationMixedIn.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToOneAssociationMixedIn.java
@@ -80,9 +80,10 @@ implements MixedInMember {
                     _MixedInMemberNamingStrategy.determineIdFrom(mixinAction)),
                 mixinAction.getFacetedMethod(), mixinAction.getReturnType());
 
-        this.facetHolder = FacetHolderAbstract.simple(
+        this.facetHolder = FacetHolderAbstract.wrapped(
                 mixeeSpec.getMetaModelContext(),
-                super.getFeatureIdentifier());
+                super.getFeatureIdentifier(),
+                mixinAction.getFacetedMethod());
 
         this.mixinType = mixinType;
         this.mixinAction = mixinAction;
@@ -93,15 +94,6 @@ implements MixedInMember {
         //
         FacetUtil.addFacet(disabledFacet());
 
-        //
-        // in addition, copy over facets from contributed to own.
-        //
-        // These could include everything under @Property(...) because the
-        // PropertyAnnotationFacetFactory is also run against actions.
-        //
-
-        FacetUtil.copyFacetsTo(mixinAction.getFacetedMethod(), facetHolder);
-
         // adjust name if necessary
         val isExplicitlyNamed = lookupNonFallbackFacet(MemberNamedFacet.class)
                 .isPresent();