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/01/19 09:55:59 UTC

[isis] branch master updated: ISIS-2158: polishing class-substitutor API

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 6f8dc36  ISIS-2158: polishing class-substitutor API
6f8dc36 is described below

commit 6f8dc368e06129d5fb8edce9c056d67fcc7c1fd5
Author: Andi Huber <ah...@apache.org>
AuthorDate: Sun Jan 19 10:55:49 2020 +0100

    ISIS-2158: polishing class-substitutor API
---
 ...jectSpecIdFacetDerivedFromClassNameFactory.java |  4 +-
 .../classsubstitutor/ClassSubstitutor.java         | 70 +++++++++++++++-------
 .../classsubstitutor/ClassSubstitutorAbstract.java | 10 ++--
 .../ClassSubstitutorForCollections.java            | 12 ++--
 .../classsubstitutor/ClassSubstitutorRegistry.java | 31 ++++++++--
 .../specloader/SpecificationLoaderDefault.java     | 10 ++--
 .../specloader/specimpl/FacetedMethodsBuilder.java |  4 +-
 .../ClassSubstitutorTest_getClass.java             |  6 +-
 .../JdoDiscriminatorAnnotationFacetFactory.java    |  4 +-
 9 files changed, 98 insertions(+), 53 deletions(-)

diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/objectspecid/classname/ObjectSpecIdFacetDerivedFromClassNameFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/objectspecid/classname/ObjectSpecIdFacetDerivedFromClassNameFactory.java
index 4d9c8b3..2e2eaae 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/objectspecid/classname/ObjectSpecIdFacetDerivedFromClassNameFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/objectspecid/classname/ObjectSpecIdFacetDerivedFromClassNameFactory.java
@@ -72,10 +72,10 @@ implements MetaModelRefiner, ObjectSpecIdFacetFactory {
         }
         val cls = processClassContext.getCls();
         val substitute = classSubstitutorRegistry.getSubstitution(cls);
-        if(substitute.isIgnore()) {
+        if(substitute.isNeverIntrospect()) {
             return;
         }
-        val objectSpecIdFacet = createObjectSpecIdFacet(facetHolder, substitute.replace(cls));
+        val objectSpecIdFacet = createObjectSpecIdFacet(facetHolder, substitute.apply(cls));
         FacetUtil.addFacet(objectSpecIdFacet);
     }
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/classsubstitutor/ClassSubstitutor.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/classsubstitutor/ClassSubstitutor.java
index 9253fb4..99f2145 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/classsubstitutor/ClassSubstitutor.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/classsubstitutor/ClassSubstitutor.java
@@ -20,6 +20,7 @@
 package org.apache.isis.core.metamodel.services.classsubstitutor;
 
 import java.io.Serializable;
+import java.util.function.UnaryOperator;
 
 import javax.annotation.Nullable;
 
@@ -41,48 +42,71 @@ public interface ClassSubstitutor {
      * @since 2.0
      */
     @Value(staticConstructor = "of")
-    static class Substitution implements Serializable {
+    static class Substitution implements UnaryOperator<Class<?>>, Serializable {
         private static final long serialVersionUID = 1L;
-        private static final Substitution NOP = Substitution.of(Type.DO_NOT_REPLACE, null);
-        private static final Substitution IGNORE = Substitution.of(Type.IGNORE_CLASS, null);
+        private static final Substitution PASSTHROUGH = Substitution.of(Type.PASSTHROUGH, null);
+        private static final Substitution NEVER_REPLACE_CLASS = Substitution.of(Type.NEVER_REPLACE_CLASS, null);
+        private static final Substitution NEVER_INTROSPECT_CLASS = Substitution.of(Type.NEVER_INTROSPECT_CLASS, null);
         
         private static enum Type {
-            DO_NOT_REPLACE,
-            IGNORE_CLASS,
+            PASSTHROUGH,
+            NEVER_REPLACE_CLASS,
+            NEVER_INTROSPECT_CLASS,
             REPLACE_WITH_OTHER_CLASS,
         }
         
         @NonNull Type type;        
         @Nullable Class<?> replacement;
 
+        // -- FACTORIES
+
+        /**
+         * The result type to be used for a ClassSubstitutor that does not feel responsible 
+         * for the (operand-) class, hence acts as a pass-through when aggregating.
+         */
+        public static Substitution passThrough() {
+            return PASSTHROUGH;
+        }
+        
         /**
-         * for framework internal use only, not required for ClassSubstitutor implementations!
-         * (forces a class to be never replaced)
+         * Forces the (operand-) class never to be replaced.
+         * 
+         * @implNote not required for ClassSubstitutor implementations!
+         * (for framework internal use when aggregating)
          */
-        public static Substitution dontReplaceClass() {
-            return NOP;
+        public static Substitution neverReplaceClass() {
+            return NEVER_REPLACE_CLASS;
         }
         
-        public static Substitution ignoreClass() {
-            return IGNORE;
+        public static Substitution neverIntrospect() {
+            return NEVER_INTROSPECT_CLASS;
         }
         
-        public static Substitution replaceClass(@lombok.NonNull @org.springframework.lang.NonNull Class<?> cls) {
+        public static Substitution replaceWith(@lombok.NonNull @org.springframework.lang.NonNull Class<?> cls) {
             return of(Type.REPLACE_WITH_OTHER_CLASS, cls);
         }
         
+        // -- PREDICATES
+        
         /**
-         * @return whether the replacement is an identity operation (do nothing) 
+         *  @return whether to act as a pass-through (indifferent)
          */
-        public boolean isDoNotReplace() {
-            return type == Type.DO_NOT_REPLACE;
+        public boolean isPassThrough() {
+            return type == Type.PASSTHROUGH;
+        }
+        
+        /**
+         * @return whether to not replace the class (do nothing) 
+         */
+        public boolean isNeverReplace() {
+            return type == Type.NEVER_REPLACE_CLASS;
         }
         
         /**
          * @return whether to ignore the class (never introspect)
          */
-        public boolean isIgnore() {
-            return type == Type.IGNORE_CLASS;
+        public boolean isNeverIntrospect() {
+            return type == Type.NEVER_INTROSPECT_CLASS;
         }
 
         /**
@@ -92,8 +116,11 @@ public interface ClassSubstitutor {
             return type == Type.REPLACE_WITH_OTHER_CLASS;            
         }
 
-        public Class<?> replace(Class<?> cls) {
-            if(isIgnore()) {
+        // -- OPERATOR
+        
+        @Override
+        public Class<?> apply(Class<?> cls) {
+            if(isNeverIntrospect()) {
                 return null;
             }
             return isReplace() ? getReplacement() : cls;
@@ -105,12 +132,9 @@ public interface ClassSubstitutor {
     
     /**
      * @param cls
-     * @return Substitution for given {@code cls} if any
-     * or Substitution.ignore(), when {@code cls} shall be ignored 
-     * @implNote most likely do not return Substitution.dontReplaceClass(), return {@code null} instead
+     * @return (non-null) Substitution for given {@code cls} 
      * @since 2.0
      */
-    @Nullable
     Substitution getSubstitution(@lombok.NonNull @org.springframework.lang.NonNull Class<?> cls);
      
     
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/classsubstitutor/ClassSubstitutorAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/classsubstitutor/ClassSubstitutorAbstract.java
index bea06ad..445a094 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/classsubstitutor/ClassSubstitutorAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/classsubstitutor/ClassSubstitutorAbstract.java
@@ -33,18 +33,18 @@ import lombok.val;
 public abstract class ClassSubstitutorAbstract implements ClassSubstitutor {
 
     @Override
-    public Substitution getSubstitution(@NonNull Class<?> cls) {
+    public final Substitution getSubstitution(@NonNull Class<?> cls) {
         val replacement = getReplacement(cls);
         if(replacement==null) {
-            return Substitution.ignoreClass();
+            return Substitution.neverIntrospect();
         }
         if(cls.equals(replacement)) {
-            return null; // NOP
+            return Substitution.passThrough(); // indifferent
         }
-        return Substitution.replaceClass(replacement) ;
+        return Substitution.replaceWith(replacement) ;
     }
     
-    private Class<?> getReplacement(final Class<?> cls) {
+    protected Class<?> getReplacement(final Class<?> cls) {
 
         if(cls == null) {
             return null;
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/classsubstitutor/ClassSubstitutorForCollections.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/classsubstitutor/ClassSubstitutorForCollections.java
index 920e61d..1fe6adf 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/classsubstitutor/ClassSubstitutorForCollections.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/classsubstitutor/ClassSubstitutorForCollections.java
@@ -42,20 +42,20 @@ public class ClassSubstitutorForCollections implements ClassSubstitutor {
     @Override
     public Substitution getSubstitution(@NonNull Class<?> cls) {
         if(Vector.class.isAssignableFrom(cls)) {
-            return Substitution.replaceClass(Vector.class);
+            return Substitution.replaceWith(Vector.class);
         }
         if(List.class.isAssignableFrom(cls)) {
-            return Substitution.replaceClass(List.class);
+            return Substitution.replaceWith(List.class);
         }
         if(SortedSet.class.isAssignableFrom(cls)) {
-            return Substitution.replaceClass(SortedSet.class);
+            return Substitution.replaceWith(SortedSet.class);
         }
         if(Set.class.isAssignableFrom(cls)) {
-            return Substitution.replaceClass(Set.class);
+            return Substitution.replaceWith(Set.class);
         }
         if(Collection.class.isAssignableFrom(cls)) {
-            return Substitution.replaceClass(Collection.class);
+            return Substitution.replaceWith(Collection.class);
         }
-        return null; // NOP
+        return Substitution.passThrough(); // indifferent
     }
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/classsubstitutor/ClassSubstitutorRegistry.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/classsubstitutor/ClassSubstitutorRegistry.java
index c20ba96..1ad7249 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/classsubstitutor/ClassSubstitutorRegistry.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/classsubstitutor/ClassSubstitutorRegistry.java
@@ -30,16 +30,20 @@ import org.springframework.core.annotation.Order;
 import org.springframework.stereotype.Component;
 
 import org.apache.isis.applib.annotation.OrderPrecedence;
-import org.apache.isis.core.commons.internal.base._NullSafe;
 import org.apache.isis.core.commons.internal.collections._Maps;
+import org.apache.isis.core.commons.internal.functions._Predicates;
 import org.apache.isis.core.metamodel.services.classsubstitutor.ClassSubstitutor.Substitution;
 
+import lombok.val;
+import lombok.extern.log4j.Log4j2;
+
 /**
  * Aggregates all {@link ClassSubstitutor}s.
  */
 @Component
 @Named("isisMetaModel.ClassSubstitutorRegistry")
 @Order(OrderPrecedence.MIDPOINT)
+@Log4j2
 public class ClassSubstitutorRegistry {
 
     private final List<ClassSubstitutor> classSubstitutors;
@@ -51,9 +55,13 @@ public class ClassSubstitutorRegistry {
 
     private final Map<Class<?>, Substitution> cache = _Maps.newConcurrentHashMap();
 
+    /**
+     * @param originalClass
+     * @return (non-null) the aggregated Substitution that applies to given originalClass
+     */
     public Substitution getSubstitution(@Nullable final Class<?> originalClass) {
         if(originalClass == null) {
-            return Substitution.dontReplaceClass();
+            return Substitution.neverReplaceClass();
         }
         return cache.computeIfAbsent(originalClass, this::findSubstitutionFor);
     }
@@ -63,11 +71,24 @@ public class ClassSubstitutorRegistry {
     private Substitution findSubstitutionFor(final Class<?> originalClass) {
         
         return classSubstitutors.stream()
-        .map(classSubstitutor->classSubstitutor.getSubstitution(originalClass))
-        .filter(_NullSafe::isPresent)
+        .map(classSubstitutor->getSubstitutionElseWarn(classSubstitutor, originalClass))
+        .filter(_Predicates.not(Substitution::isPassThrough))
         .findFirst()
-        .orElse(Substitution.dontReplaceClass());
+        .orElse(Substitution.neverReplaceClass());
          
     }
     
+    private Substitution getSubstitutionElseWarn(ClassSubstitutor substitutor, Class<?> originalClass) {
+        val substitution = substitutor.getSubstitution(originalClass);
+        if(substitution == null) {
+            log.warn("ClassSubstitutor.getSubstitution(Class) must never return null! "
+                    + "However, substitutor {} just did for class argument {}. "
+                    + "Pass-through was applied instead.", 
+                    substitutor.getClass().getName(),
+                    originalClass.getClass().getName());
+            return Substitution.passThrough();
+        }
+        return substitution;
+    }
+    
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoaderDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoaderDefault.java
index b166bab..a87e03b 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoaderDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoaderDefault.java
@@ -354,7 +354,7 @@ public class SpecificationLoaderDefault implements SpecificationLoader {
         // ensure that all types are loadable
         if (Arrays.stream(domainTypes)
                 .map(classSubstitutorRegistry::getSubstitution)
-                .anyMatch(Substitution::isIgnore)) {
+                .anyMatch(Substitution::isNeverIntrospect)) {
             return false;
         }
         Arrays.stream(domainTypes).forEach(this::loadSpecification);
@@ -373,11 +373,11 @@ public class SpecificationLoaderDefault implements SpecificationLoader {
         requires(upTo, "upTo");
         
         val substitute = classSubstitutorRegistry.getSubstitution(type);
-        if (substitute.isIgnore()) {
+        if (substitute.isNeverIntrospect()) {
             return null; // never inspect
         }
         
-        val substitutedType = substitute.replace(type);
+        val substitutedType = substitute.apply(type);
         
         val typeName = substitutedType.getName();
 
@@ -519,12 +519,12 @@ public class SpecificationLoaderDefault implements SpecificationLoader {
     private void invalidateCache(final Class<?> cls) {
 
         val substitute = classSubstitutorRegistry.getSubstitution(cls);
-        if(substitute.isIgnore()) {
+        if(substitute.isNeverIntrospect()) {
             return;
         }
 
         ObjectSpecification spec = 
-                loadSpecification(substitute.replace(cls), IntrospectionState.TYPE_AND_MEMBERS_INTROSPECTED);
+                loadSpecification(substitute.apply(cls), IntrospectionState.TYPE_AND_MEMBERS_INTROSPECTED);
         
         while(spec != null) {
             val type = spec.getCorrespondingClass();
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/FacetedMethodsBuilder.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/FacetedMethodsBuilder.java
index 8ede154..2ca54c0 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/FacetedMethodsBuilder.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/FacetedMethodsBuilder.java
@@ -315,7 +315,7 @@ public class FacetedMethodsBuilder {
             facetedMethod.setType(elementType);
 
             // skip if class substitutor says so.
-            if (classSubstitutorRegistry.getSubstitution(elementType).isIgnore()) {
+            if (classSubstitutorRegistry.getSubstitution(elementType).isNeverIntrospect()) {
                 continue;
             }
 
@@ -333,7 +333,7 @@ public class FacetedMethodsBuilder {
             final Class<?> returnType = accessorMethod.getReturnType();
 
             // skip if class strategy says so.
-            if (classSubstitutorRegistry.getSubstitution(returnType).isIgnore()) {
+            if (classSubstitutorRegistry.getSubstitution(returnType).isNeverIntrospect()) {
                 continue;
             }
 
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/specloader/classsubstitutor/ClassSubstitutorTest_getClass.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/specloader/classsubstitutor/ClassSubstitutorTest_getClass.java
index 39d7418..8103490 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/specloader/classsubstitutor/ClassSubstitutorTest_getClass.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/specloader/classsubstitutor/ClassSubstitutorTest_getClass.java
@@ -57,21 +57,21 @@ public class ClassSubstitutorTest_getClass {
     @Test
     public void regularDomainObject() throws Exception {
         val input = SomeDomainObject.class;
-        val replacement = classSubstitutorReg.getSubstitution(input).replace(input);
+        val replacement = classSubstitutorReg.getSubstitution(input).apply(input);
         assertEquals(input, replacement);
     }
 
     @Test
     public void someEnum() throws Exception {
         val input = SomeDomainObject.SomeEnum.class;
-        val replacement = classSubstitutorReg.getSubstitution(input).replace(input);
+        val replacement = classSubstitutorReg.getSubstitution(input).apply(input);
         assertEquals(input, replacement);
     }
 
     @Test
     public void someAnonymousSubtypeOfEnum() throws Exception {
         val input = SomeDomainObject.SomeEnum.Foo.getClass();
-        val replacement = classSubstitutorReg.getSubstitution(input).replace(input);
+        val replacement = classSubstitutorReg.getSubstitution(input).apply(input);
         assertEquals(SomeDomainObject.SomeEnum.class, replacement);
     }
 
diff --git a/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/metamodel/facets/object/discriminator/JdoDiscriminatorAnnotationFacetFactory.java b/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/metamodel/facets/object/discriminator/JdoDiscriminatorAnnotationFacetFactory.java
index b869dca..13fa490 100644
--- a/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/metamodel/facets/object/discriminator/JdoDiscriminatorAnnotationFacetFactory.java
+++ b/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/metamodel/facets/object/discriminator/JdoDiscriminatorAnnotationFacetFactory.java
@@ -69,11 +69,11 @@ implements ObjectSpecIdFacetFactory {
                     annotationValue, facetHolder);
         } else {
             val substitute = classSubstitutorRegistry.getSubstitution(cls);
-            if(substitute.isIgnore()) {
+            if(substitute.isNeverIntrospect()) {
                 return;
             }
                    
-            val substituted = substitute.replace(cls);
+            val substituted = substitute.apply(cls);
             facet = new ObjectSpecIdFacetDerivedFromClassName(
                             substituted.getCanonicalName(), 
                             facetHolder);