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 2019/09/23 12:44:22 UTC

[isis] branch v2 updated: ISIS-2161: adds a new annotation: Model

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

ahuber pushed a commit to branch v2
in repository https://gitbox.apache.org/repos/asf/isis.git


The following commit(s) were added to refs/heads/v2 by this push:
     new 89b4981  ISIS-2161: adds a new annotation: Model
89b4981 is described below

commit 89b49816894a1a92f12259215c3fb97e974b180c
Author: Andi Huber <ah...@apache.org>
AuthorDate: Mon Sep 23 14:44:13 2019 +0200

    ISIS-2161: adds a new annotation: Model
    
    - new validation: SupportingMethodValidatorRefinerFactory
    - replaces validation via MethodPrefixBasedFacetFactoryAbstract
---
 .../applib/annotation/{Support.java => Model.java} |   8 +-
 .../isis/metamodel/consent/InteractionAdvisor.java |  49 +++++++-
 .../MethodPrefixBasedFacetFactoryAbstract.java     |  22 +---
 .../SupportingMethodValidatorRefinerFactory.java   | 134 +++++++++++++++++++++
 .../interactions/InteractionAdvisorFacet.java      |  51 --------
 .../dflt/ProgrammingModelFacetsJava8.java          |   5 +
 .../isis/metamodel/spec/ObjectSpecification.java   |  24 +++-
 ...encedAction.java => OrphanedActionSupport.java} |  12 +-
 ...dAction.java => OrphanedCollectionSupport.java} |  12 +-
 ...cedAction.java => OrphanedPropertySupport.java} |  12 +-
 .../ProperActionSupport.java}                      |  20 ++-
 .../ProperCollectionSupport.java}                  |  22 +++-
 .../ProperPrefixedAction.java}                     |  17 ++-
 ...efixedMember.java => ProperPrefixedMember.java} |   4 +-
 .../ProperPropertySupport.java}                    |  20 ++-
 .../DomainModelTest_usingBadDomain.java            |  42 ++++++-
 .../DomainModelTest_usingGoodDomain.java           |  68 +++--------
 17 files changed, 351 insertions(+), 171 deletions(-)

diff --git a/core/applib/src/main/java/org/apache/isis/applib/annotation/Support.java b/core/applib/src/main/java/org/apache/isis/applib/annotation/Model.java
similarity index 85%
rename from core/applib/src/main/java/org/apache/isis/applib/annotation/Support.java
rename to core/applib/src/main/java/org/apache/isis/applib/annotation/Model.java
index b872fc1..1cdcd75 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/annotation/Support.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/annotation/Model.java
@@ -27,16 +27,16 @@ import java.lang.annotation.Target;
 
 /**
  * Indicates that a method is a supporting-method, one that contributes (hide, validate, ...) 
- * to an <em>Action</em>.
+ * to an <em>Action/</em>.
  * <p>
- * While optional, it marks a clear intent by the programmer and allows for the metamodel to enforce 
- * validation rules.
+ * By placing the {@link Model} annotation on a method, a contract with the metamodel is enforced, 
+ * such that this method must be recognized and can not be be ignored.
  *
  * @since 2.0
  */
 @Inherited
 @Target({ ElementType.METHOD })
 @Retention(RetentionPolicy.RUNTIME)
-public @interface Support {
+public @interface Model {
 
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/consent/InteractionAdvisor.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/consent/InteractionAdvisor.java
index d868f56..60303b4 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/consent/InteractionAdvisor.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/consent/InteractionAdvisor.java
@@ -19,7 +19,11 @@
 
 package org.apache.isis.metamodel.consent;
 
+import java.util.Map;
+
 import org.apache.isis.metamodel.facetapi.Facet;
+import org.apache.isis.metamodel.facetapi.FacetHolder;
+import org.apache.isis.metamodel.interactions.InteractionAdvisorFacet;
 
 /**
  * Marker interface for implementations (specifically, {@link Facet}s) that can
@@ -32,7 +36,50 @@ public interface InteractionAdvisor {
     /**
      * For testing purposes only.
      */
-    public static InteractionAdvisor NOOP = new InteractionAdvisor() {
+    public static InteractionAdvisor NOOP = new InteractionAdvisorFacet() {
+        @Override
+        public void appendAttributesTo(final Map<String, Object> attributeMap) {
+        }
+
+        @Override
+        public boolean alwaysReplace() {
+            return false;
+        }
+
+        @Override
+        public Class<? extends Facet> facetType() {
+            return null;
+        }
+
+        @Override
+        public FacetHolder getFacetHolder() {
+            return null;
+        }
+
+        @Override
+        public boolean isNoop() {
+            return true;
+        }
+
+        @Override
+        public void setFacetHolder(final FacetHolder facetHolder) {
+        }
+
+        @Override
+        public Facet getUnderlyingFacet() {
+            return null;
+        }
+
+        @Override
+        public void setUnderlyingFacet(final Facet underlyingFacet) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean isDerived() {
+            return false;
+        }
+
     };
 
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/MethodPrefixBasedFacetFactoryAbstract.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/MethodPrefixBasedFacetFactoryAbstract.java
index f5dd40e..7b23cfa 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/MethodPrefixBasedFacetFactoryAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/MethodPrefixBasedFacetFactoryAbstract.java
@@ -22,17 +22,9 @@ package org.apache.isis.metamodel.facets;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
-import java.util.Objects;
 
-import org.apache.isis.config.internal._Config;
 import org.apache.isis.metamodel.facetapi.FeatureType;
-import org.apache.isis.metamodel.spec.ObjectSpecification;
-import org.apache.isis.metamodel.spec.feature.Contributed;
 import org.apache.isis.metamodel.specloader.validator.MetaModelValidatorComposite;
-import org.apache.isis.metamodel.specloader.validator.MetaModelValidatorVisiting;
-import org.apache.isis.metamodel.specloader.validator.ValidationFailures;
-
-import lombok.val;
 
 public abstract class MethodPrefixBasedFacetFactoryAbstract
 extends FacetFactoryAbstract
@@ -63,13 +55,12 @@ implements MethodPrefixBasedFacetFactory {
         return prefixes;
     }
 
+ 
     @Override
     public void refineMetaModelValidator(final MetaModelValidatorComposite metaModelValidator) {
-    }
-
-//TODO[2161] remove prefix checks    
-//    @Override
-//    public void refineMetaModelValidator(final MetaModelValidatorComposite metaModelValidator) {
+        
+//XXX[2161] replaced by SupportingMethodValidatorRefinerFactory, which changes behavior!     
+        
 //        if(orphanValidation == OrphanValidation.DONT_VALIDATE) {
 //            return;
 //        }
@@ -78,7 +69,6 @@ implements MethodPrefixBasedFacetFactory {
 //                ISIS_REFLECTOR_VALIDATOR_NO_PARAMS_ONLY_KEY,
 //                ISIS_REFLECTOR_VALIDATOR_NO_PARAMS_ONLY_DEFAULT);
 //
-//        
 //        metaModelValidator.add(new MetaModelValidatorVisiting(new MetaModelValidatorVisiting.Visitor() {
 //
 //            @Override
@@ -93,8 +83,6 @@ implements MethodPrefixBasedFacetFactory {
 //
 //                        if (actionId.startsWith(prefix) && prefix.length() < actionId.length()) {
 //
-//                            System.err.println("self: " + self);
-//                            
 //                            val explanation =
 //                                    objectAction.getParameterCount() > 0 && 
 //                                    noParamsOnly &&
@@ -120,6 +108,6 @@ implements MethodPrefixBasedFacetFactory {
 //                return true;
 //            }
 //        }));
-//    }
+    }
 
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/actions/support/SupportingMethodValidatorRefinerFactory.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/actions/support/SupportingMethodValidatorRefinerFactory.java
new file mode 100644
index 0000000..2fb4c2e
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/actions/support/SupportingMethodValidatorRefinerFactory.java
@@ -0,0 +1,134 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.metamodel.facets.actions.support;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.apache.isis.applib.annotation.Model;
+import org.apache.isis.commons.internal.collections._Lists;
+import org.apache.isis.commons.internal.collections._Sets;
+import org.apache.isis.metamodel.facetapi.FacetHolder;
+import org.apache.isis.metamodel.facetapi.MetaModelValidatorRefiner;
+import org.apache.isis.metamodel.facets.FacetFactoryAbstract;
+import org.apache.isis.metamodel.facets.ImperativeFacet;
+import org.apache.isis.metamodel.spec.ObjectSpecification;
+import org.apache.isis.metamodel.specloader.validator.MetaModelValidatorComposite;
+import org.apache.isis.metamodel.specloader.validator.MetaModelValidatorVisiting;
+import org.apache.isis.metamodel.specloader.validator.ValidationFailures;
+
+import lombok.val;
+
+/**
+ * 
+ * @since 2.0
+ *
+ */
+public class SupportingMethodValidatorRefinerFactory extends FacetFactoryAbstract 
+implements MetaModelValidatorRefiner {
+
+    public SupportingMethodValidatorRefinerFactory() {
+        super(Collections.emptyList()); // does not contribute any facets
+    }
+
+    @Override
+    public void process(ProcessMethodContext processMethodContext) {
+        // does not contribute any facets
+    }
+
+    @Override
+    public void refineMetaModelValidator(final MetaModelValidatorComposite metaModelValidator) {
+
+        metaModelValidator.add(new MetaModelValidatorVisiting(new MetaModelValidatorVisiting.Visitor() {
+
+            @Override
+            public boolean visit(ObjectSpecification spec, ValidationFailures validationFailures) {
+
+                val type = spec.getCorrespondingClass();
+                
+                // methods known to the metamodel
+                val recognizedMethods = spec.streamFacetHolders()
+                .flatMap(FacetHolder::streamFacets)
+                .filter(ImperativeFacet.class::isInstance)
+                .map(ImperativeFacet.class::cast)
+                .map(ImperativeFacet::getMethods)
+                .flatMap(List::stream)
+                .collect(Collectors.toCollection(HashSet::new));
+                
+                // methods intended by the coder to be known to the metamodel
+                val intendedMethods = _Sets.<Method>newHashSet(); 
+                for(val method: type.getDeclaredMethods()) {
+                    if(method.getDeclaredAnnotation(Model.class)!=null) {
+                        intendedMethods.add(method);
+                    }
+                }
+                
+                // methods intended by the coder but not known to the metamodel
+                val notRecognizedMethods =
+                        _Sets.minus(intendedMethods, recognizedMethods);
+
+                // find reasons about why these are not recognized    
+                notRecognizedMethods.forEach(notRecognizedMethod->{
+                    val unmetContraints = unmetContraints(spec, notRecognizedMethod);
+
+                    val messageFormat = "%s#%s: has annotion %s, is assumed to support "
+                            + "a property, collection or action. Unmet constraint(s): %s";
+                    validationFailures.add(
+                            spec.getIdentifier(),
+                            messageFormat,
+                            spec.getIdentifier().getClassName(),
+                            notRecognizedMethod.getName(),
+                            Model.class.getSimpleName(),
+                            unmetContraints.stream()
+                            .collect(Collectors.joining("; ")));
+                });
+                        
+                
+                return true; // continue
+            }
+
+        }));
+
+    }
+    
+    // -- VALIDATION LOGIC
+    
+    private List<String> unmetContraints(
+            ObjectSpecification spec, 
+            Method method) {
+        
+        //val type = spec.getCorrespondingClass();
+        val unmetContraints = _Lists.<String>newArrayList();
+        
+        final int modifiers = method.getModifiers();
+        if (!Modifier.isPublic(modifiers)) {
+            unmetContraints.add("method must be 'public'");
+            return unmetContraints; // don't check any further
+        } 
+        
+        unmetContraints.add("misspelled prefix or unsupported method signature");
+        return unmetContraints;
+        
+    }
+
+}
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/interactions/InteractionAdvisorFacet.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/interactions/InteractionAdvisorFacet.java
index 02bdbe6..59b411e 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/interactions/InteractionAdvisorFacet.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/interactions/InteractionAdvisorFacet.java
@@ -19,14 +19,11 @@
 
 package org.apache.isis.metamodel.interactions;
 
-import java.util.Map;
-
 import org.apache.isis.metamodel.consent.Allow;
 import org.apache.isis.metamodel.consent.Consent;
 import org.apache.isis.metamodel.consent.InteractionAdvisor;
 import org.apache.isis.metamodel.consent.Veto;
 import org.apache.isis.metamodel.facetapi.Facet;
-import org.apache.isis.metamodel.facetapi.FacetHolder;
 
 /**
  * Used by {@link Consent} (specifically the main implementations {@link Allow}
@@ -44,53 +41,5 @@ import org.apache.isis.metamodel.facetapi.FacetHolder;
  */
 public interface InteractionAdvisorFacet extends InteractionAdvisor, Facet {
 
-    /**
-     * For testing purposes only.
-     */
-    public static InteractionAdvisorFacet NOOP = new InteractionAdvisorFacet() {
-        @Override
-        public void appendAttributesTo(final Map<String, Object> attributeMap) {
-        }
-
-        @Override
-        public boolean alwaysReplace() {
-            return false;
-        }
-
-        @Override
-        public Class<? extends Facet> facetType() {
-            return null;
-        }
-
-        @Override
-        public FacetHolder getFacetHolder() {
-            return null;
-        }
-
-        @Override
-        public boolean isNoop() {
-            return true;
-        }
-
-        @Override
-        public void setFacetHolder(final FacetHolder facetHolder) {
-        }
-
-        @Override
-        public Facet getUnderlyingFacet() {
-            return null;
-        }
-
-        @Override
-        public void setUnderlyingFacet(final Facet underlyingFacet) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public boolean isDerived() {
-            return false;
-        }
-
-    };
 
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/progmodels/dflt/ProgrammingModelFacetsJava8.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/progmodels/dflt/ProgrammingModelFacetsJava8.java
index eaa4af7..4940402 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/progmodels/dflt/ProgrammingModelFacetsJava8.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/progmodels/dflt/ProgrammingModelFacetsJava8.java
@@ -30,6 +30,7 @@ import org.apache.isis.metamodel.facets.actions.layout.ActionLayoutFacetFactory;
 import org.apache.isis.metamodel.facets.actions.notcontributed.derived.NotContributedFacetDerivedFromDomainServiceFacetFactory;
 import org.apache.isis.metamodel.facets.actions.notcontributed.derived.NotContributedFacetDerivedFromMixinFacetFactory;
 import org.apache.isis.metamodel.facets.actions.notinservicemenu.derived.NotInServiceMenuFacetDerivedFromDomainServiceFacetFactory;
+import org.apache.isis.metamodel.facets.actions.support.SupportingMethodValidatorRefinerFactory;
 import org.apache.isis.metamodel.facets.actions.validate.method.ActionValidationFacetViaMethodFactory;
 import org.apache.isis.metamodel.facets.all.i18n.TranslationFacetFactory;
 import org.apache.isis.metamodel.facets.collections.accessor.CollectionAccessorFacetViaAccessorFactory;
@@ -409,6 +410,10 @@ public final class ProgrammingModelFacetsJava8 extends ProgrammingModelAbstract
         addFactory(new TranslationFacetFactory());
 
         addFactory(new ViewModelSemanticCheckingFacetFactory());
+        
+        // possibly required at the very end
+        addFactory(new SupportingMethodValidatorRefinerFactory());
+
     }
 
     @Override
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/spec/ObjectSpecification.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/spec/ObjectSpecification.java
index 7504fa7..27f5e1b 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/spec/ObjectSpecification.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/spec/ObjectSpecification.java
@@ -24,14 +24,17 @@ import java.lang.reflect.Modifier;
 import java.util.Comparator;
 import java.util.Optional;
 import java.util.function.Function;
+import java.util.stream.Stream;
 
 import org.apache.isis.applib.annotation.DomainObject;
 import org.apache.isis.commons.exceptions.IsisException;
+import org.apache.isis.commons.internal.collections._Streams;
 import org.apache.isis.commons.internal.ioc.BeanSort;
 import org.apache.isis.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.metamodel.consent.Consent;
 import org.apache.isis.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.metamodel.consent.InteractionResult;
+import org.apache.isis.metamodel.facetapi.FacetHolder;
 import org.apache.isis.metamodel.facets.all.describedas.DescribedAsFacet;
 import org.apache.isis.metamodel.facets.all.help.HelpFacet;
 import org.apache.isis.metamodel.facets.all.hide.HiddenFacet;
@@ -58,7 +61,7 @@ import org.apache.isis.metamodel.specloader.classsubstitutor.ClassSubstitutor;
 import org.apache.isis.metamodel.specloader.specimpl.MixedInMember;
 import org.apache.isis.security.authentication.AuthenticationSession;
 
-import static org.apache.isis.commons.internal.functions._Predicates.instanceOf;
+import lombok.val;
 
 /**
  * Represents an entity or value (cf {@link java.lang.Class}) within the
@@ -101,8 +104,8 @@ ObjectAssociationContainer, Hierarchical,  DefaultProvider {
      */
     public default Optional<MixedInMember> getMixedInMember(ObjectSpecification onType) {
         return streamObjectActions(Contributed.INCLUDED)
-                .filter(instanceOf(MixedInMember.class))
-                .map(member->(MixedInMember) member)
+                .filter(MixedInMember.class::isInstance)
+                .map(MixedInMember.class::cast)
                 .filter(member->member.getMixinType() == onType)
                 .findAny();
     }
@@ -409,5 +412,20 @@ ObjectAssociationContainer, Hierarchical,  DefaultProvider {
         return newInstance; 
     }
 
+    /**
+     * Streams all FacetHolders associated with this spec. 
+     * @since 2.0
+     */
+    default Stream<FacetHolder> streamFacetHolders(){
+        
+        val self = Stream.of(this);
+        val actions = streamObjectActions(Contributed.EXCLUDED);
+        val properties = streamProperties(Contributed.EXCLUDED);
+        val collections = streamCollections(Contributed.EXCLUDED);
+
+        return _Streams.concat(self, actions, properties, collections);
+        
+    }
+
 
 }
diff --git a/examples/smoketests/src/main/java/org/apache/isis/testdomain/model/bad/UnresolvableReferencedAction.java b/examples/smoketests/src/main/java/org/apache/isis/testdomain/model/bad/OrphanedActionSupport.java
similarity index 83%
copy from examples/smoketests/src/main/java/org/apache/isis/testdomain/model/bad/UnresolvableReferencedAction.java
copy to examples/smoketests/src/main/java/org/apache/isis/testdomain/model/bad/OrphanedActionSupport.java
index 7e5c990..cda312f 100644
--- a/examples/smoketests/src/main/java/org/apache/isis/testdomain/model/bad/UnresolvableReferencedAction.java
+++ b/examples/smoketests/src/main/java/org/apache/isis/testdomain/model/bad/OrphanedActionSupport.java
@@ -19,15 +19,15 @@
 package org.apache.isis.testdomain.model.bad;
 
 import org.apache.isis.applib.annotation.DomainObject;
+import org.apache.isis.applib.annotation.Model;
 import org.apache.isis.applib.annotation.Nature;
-import org.apache.isis.applib.annotation.Support;
 
 @DomainObject(nature = Nature.VIEW_MODEL)
-public class UnresolvableReferencedAction {
-    
-    // should fail, because there is no action named 'something'
-    @Support
-    public boolean hideSomething() {
+public class OrphanedActionSupport {
+
+    // should fail
+    @Model
+    public boolean hideOrphaned() {
         return false;
     }
     
diff --git a/examples/smoketests/src/main/java/org/apache/isis/testdomain/model/bad/UnresolvableReferencedAction.java b/examples/smoketests/src/main/java/org/apache/isis/testdomain/model/bad/OrphanedCollectionSupport.java
similarity index 83%
copy from examples/smoketests/src/main/java/org/apache/isis/testdomain/model/bad/UnresolvableReferencedAction.java
copy to examples/smoketests/src/main/java/org/apache/isis/testdomain/model/bad/OrphanedCollectionSupport.java
index 7e5c990..6615f91 100644
--- a/examples/smoketests/src/main/java/org/apache/isis/testdomain/model/bad/UnresolvableReferencedAction.java
+++ b/examples/smoketests/src/main/java/org/apache/isis/testdomain/model/bad/OrphanedCollectionSupport.java
@@ -19,15 +19,15 @@
 package org.apache.isis.testdomain.model.bad;
 
 import org.apache.isis.applib.annotation.DomainObject;
+import org.apache.isis.applib.annotation.Model;
 import org.apache.isis.applib.annotation.Nature;
-import org.apache.isis.applib.annotation.Support;
 
 @DomainObject(nature = Nature.VIEW_MODEL)
-public class UnresolvableReferencedAction {
-    
-    // should fail, because there is no action named 'something'
-    @Support
-    public boolean hideSomething() {
+public class OrphanedCollectionSupport {
+
+    // should fail
+    @Model
+    public boolean hideMyCollection() {
         return false;
     }
     
diff --git a/examples/smoketests/src/main/java/org/apache/isis/testdomain/model/bad/UnresolvableReferencedAction.java b/examples/smoketests/src/main/java/org/apache/isis/testdomain/model/bad/OrphanedPropertySupport.java
similarity index 83%
copy from examples/smoketests/src/main/java/org/apache/isis/testdomain/model/bad/UnresolvableReferencedAction.java
copy to examples/smoketests/src/main/java/org/apache/isis/testdomain/model/bad/OrphanedPropertySupport.java
index 7e5c990..bd579ed 100644
--- a/examples/smoketests/src/main/java/org/apache/isis/testdomain/model/bad/UnresolvableReferencedAction.java
+++ b/examples/smoketests/src/main/java/org/apache/isis/testdomain/model/bad/OrphanedPropertySupport.java
@@ -19,15 +19,15 @@
 package org.apache.isis.testdomain.model.bad;
 
 import org.apache.isis.applib.annotation.DomainObject;
+import org.apache.isis.applib.annotation.Model;
 import org.apache.isis.applib.annotation.Nature;
-import org.apache.isis.applib.annotation.Support;
 
 @DomainObject(nature = Nature.VIEW_MODEL)
-public class UnresolvableReferencedAction {
-    
-    // should fail, because there is no action named 'something'
-    @Support
-    public boolean hideSomething() {
+public class OrphanedPropertySupport {
+
+    // should fail
+    @Model
+    public boolean hideMyProperty() {
         return false;
     }
     
diff --git a/examples/smoketests/src/main/java/org/apache/isis/testdomain/model/bad/UnresolvableReferencedAction.java b/examples/smoketests/src/main/java/org/apache/isis/testdomain/model/good/ProperActionSupport.java
similarity index 76%
copy from examples/smoketests/src/main/java/org/apache/isis/testdomain/model/bad/UnresolvableReferencedAction.java
copy to examples/smoketests/src/main/java/org/apache/isis/testdomain/model/good/ProperActionSupport.java
index 7e5c990..4380ff3 100644
--- a/examples/smoketests/src/main/java/org/apache/isis/testdomain/model/bad/UnresolvableReferencedAction.java
+++ b/examples/smoketests/src/main/java/org/apache/isis/testdomain/model/good/ProperActionSupport.java
@@ -16,19 +16,27 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.testdomain.model.bad;
+package org.apache.isis.testdomain.model.good;
 
+import org.apache.isis.applib.annotation.Action;
 import org.apache.isis.applib.annotation.DomainObject;
 import org.apache.isis.applib.annotation.Nature;
-import org.apache.isis.applib.annotation.Support;
+import org.apache.isis.applib.annotation.Model;
 
 @DomainObject(nature = Nature.VIEW_MODEL)
-public class UnresolvableReferencedAction {
+public class ProperActionSupport {
+
+    // proper action
+    @Action
+    public void myAction() {
+
+    }
     
-    // should fail, because there is no action named 'something'
-    @Support
-    public boolean hideSomething() {
+    // proper support
+    @Model
+    public boolean hideMyAction() {
         return false;
     }
+
     
 }
diff --git a/examples/smoketests/src/main/java/org/apache/isis/testdomain/model/bad/UnresolvableReferencedAction.java b/examples/smoketests/src/main/java/org/apache/isis/testdomain/model/good/ProperCollectionSupport.java
similarity index 70%
copy from examples/smoketests/src/main/java/org/apache/isis/testdomain/model/bad/UnresolvableReferencedAction.java
copy to examples/smoketests/src/main/java/org/apache/isis/testdomain/model/good/ProperCollectionSupport.java
index 7e5c990..c989c36 100644
--- a/examples/smoketests/src/main/java/org/apache/isis/testdomain/model/bad/UnresolvableReferencedAction.java
+++ b/examples/smoketests/src/main/java/org/apache/isis/testdomain/model/good/ProperCollectionSupport.java
@@ -16,18 +16,28 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.testdomain.model.bad;
+package org.apache.isis.testdomain.model.good;
 
+import java.util.List;
+
+import org.apache.isis.applib.annotation.Collection;
 import org.apache.isis.applib.annotation.DomainObject;
+import org.apache.isis.applib.annotation.Model;
 import org.apache.isis.applib.annotation.Nature;
-import org.apache.isis.applib.annotation.Support;
+
+import lombok.Getter;
+import lombok.Setter;
 
 @DomainObject(nature = Nature.VIEW_MODEL)
-public class UnresolvableReferencedAction {
+public class ProperCollectionSupport {
+
+    // proper property
+    @Collection @Getter @Setter
+    private List<String> myCollection;
     
-    // should fail, because there is no action named 'something'
-    @Support
-    public boolean hideSomething() {
+    // proper support
+    @Model
+    public boolean hideMyCollection() {
         return false;
     }
     
diff --git a/examples/smoketests/src/main/java/org/apache/isis/testdomain/model/bad/UnresolvableReferencedAction.java b/examples/smoketests/src/main/java/org/apache/isis/testdomain/model/good/ProperPrefixedAction.java
similarity index 76%
copy from examples/smoketests/src/main/java/org/apache/isis/testdomain/model/bad/UnresolvableReferencedAction.java
copy to examples/smoketests/src/main/java/org/apache/isis/testdomain/model/good/ProperPrefixedAction.java
index 7e5c990..c8117e6 100644
--- a/examples/smoketests/src/main/java/org/apache/isis/testdomain/model/bad/UnresolvableReferencedAction.java
+++ b/examples/smoketests/src/main/java/org/apache/isis/testdomain/model/good/ProperPrefixedAction.java
@@ -16,18 +16,23 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.testdomain.model.bad;
+package org.apache.isis.testdomain.model.good;
 
+import org.apache.isis.applib.annotation.Action;
 import org.apache.isis.applib.annotation.DomainObject;
 import org.apache.isis.applib.annotation.Nature;
-import org.apache.isis.applib.annotation.Support;
 
 @DomainObject(nature = Nature.VIEW_MODEL)
-public class UnresolvableReferencedAction {
+public class ProperPrefixedAction {
+
+    // should not fail since 2.0
+    @Action
+    public boolean hideWhatever() {
+        return false;
+    }
     
-    // should fail, because there is no action named 'something'
-    @Support
-    public boolean hideSomething() {
+    // should not fail since 2.0
+    public boolean hideWhatever2() {
         return false;
     }
     
diff --git a/examples/smoketests/src/main/java/org/apache/isis/testdomain/model/good/ReservedPrefixedMember.java b/examples/smoketests/src/main/java/org/apache/isis/testdomain/model/good/ProperPrefixedMember.java
similarity index 87%
rename from examples/smoketests/src/main/java/org/apache/isis/testdomain/model/good/ReservedPrefixedMember.java
rename to examples/smoketests/src/main/java/org/apache/isis/testdomain/model/good/ProperPrefixedMember.java
index 87f8ff3..4aa3ceb 100644
--- a/examples/smoketests/src/main/java/org/apache/isis/testdomain/model/good/ReservedPrefixedMember.java
+++ b/examples/smoketests/src/main/java/org/apache/isis/testdomain/model/good/ProperPrefixedMember.java
@@ -2,6 +2,7 @@ package org.apache.isis.testdomain.model.good;
 
 import org.apache.isis.applib.annotation.Action;
 import org.apache.isis.applib.annotation.DomainObject;
+import org.apache.isis.applib.annotation.Model;
 import org.apache.isis.applib.annotation.Nature;
 import org.apache.isis.applib.annotation.Property;
 
@@ -9,7 +10,7 @@ import lombok.Getter;
 import lombok.Setter;
 
 @DomainObject(nature = Nature.VIEW_MODEL)
-public class ReservedPrefixedMember {
+public class ProperPrefixedMember {
     
     // should be allowed since 2.0
     @Action 
@@ -18,6 +19,7 @@ public class ReservedPrefixedMember {
     }
     
     // should be identified as support
+    @Model
     public String disableDisableSomething() {
         return null;
     }
diff --git a/examples/smoketests/src/main/java/org/apache/isis/testdomain/model/bad/UnresolvableReferencedAction.java b/examples/smoketests/src/main/java/org/apache/isis/testdomain/model/good/ProperPropertySupport.java
similarity index 72%
rename from examples/smoketests/src/main/java/org/apache/isis/testdomain/model/bad/UnresolvableReferencedAction.java
rename to examples/smoketests/src/main/java/org/apache/isis/testdomain/model/good/ProperPropertySupport.java
index 7e5c990..3c88b22 100644
--- a/examples/smoketests/src/main/java/org/apache/isis/testdomain/model/bad/UnresolvableReferencedAction.java
+++ b/examples/smoketests/src/main/java/org/apache/isis/testdomain/model/good/ProperPropertySupport.java
@@ -16,18 +16,26 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.testdomain.model.bad;
+package org.apache.isis.testdomain.model.good;
 
 import org.apache.isis.applib.annotation.DomainObject;
+import org.apache.isis.applib.annotation.Model;
 import org.apache.isis.applib.annotation.Nature;
-import org.apache.isis.applib.annotation.Support;
+import org.apache.isis.applib.annotation.Property;
+
+import lombok.Getter;
+import lombok.Setter;
 
 @DomainObject(nature = Nature.VIEW_MODEL)
-public class UnresolvableReferencedAction {
+public class ProperPropertySupport {
+
+    // proper property
+    @Property @Getter @Setter
+    private String myProperty;
     
-    // should fail, because there is no action named 'something'
-    @Support
-    public boolean hideSomething() {
+    // proper support
+    @Model
+    public boolean hideMyProperty() {
         return false;
     }
     
diff --git a/examples/smoketests/src/test/java/org/apache/isis/testdomain/domainmodel/DomainModelTest_usingBadDomain.java b/examples/smoketests/src/test/java/org/apache/isis/testdomain/domainmodel/DomainModelTest_usingBadDomain.java
index 7f28cf2..b302e63 100644
--- a/examples/smoketests/src/test/java/org/apache/isis/testdomain/domainmodel/DomainModelTest_usingBadDomain.java
+++ b/examples/smoketests/src/test/java/org/apache/isis/testdomain/domainmodel/DomainModelTest_usingBadDomain.java
@@ -28,7 +28,9 @@ import org.apache.isis.metamodel.spec.DomainModelException;
 import org.apache.isis.testdomain.conf.Configuration_headless;
 import org.apache.isis.testdomain.model.bad.AmbiguousTitle;
 import org.apache.isis.testdomain.model.bad.Configuration_usingInvalidDomain;
-import org.apache.isis.testdomain.model.bad.UnresolvableReferencedAction;
+import org.apache.isis.testdomain.model.bad.OrphanedActionSupport;
+import org.apache.isis.testdomain.model.bad.OrphanedCollectionSupport;
+import org.apache.isis.testdomain.model.bad.OrphanedPropertySupport;
 
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -62,16 +64,48 @@ class DomainModelTest_usingBadDomain {
     }
     
     @Test
-    void unresolvableReferencedAction_shouldFail() {
+    void orphanedActionSupport_shouldFail() {
            
         val validateDomainModel = new ValidateDomainModel();
         
         assertThrows(DomainModelException.class, validateDomainModel::run);
         assertTrue(validateDomainModel.anyMatchesContaining(
-                UnresolvableReferencedAction.class, 
-                " ")); //TODO no validator written yet
+                OrphanedActionSupport.class, 
+                "is assumed to support"));
     }
+    
+//    @Test
+//    void orphanedActionSupportNotEnforced_shouldFail() {
+//           
+//        val validateDomainModel = new ValidateDomainModel();
+//        
+//        assertThrows(DomainModelException.class, validateDomainModel::run);
+//        assertTrue(validateDomainModel.anyMatchesContaining(
+//                OrphanedPrefixedAction.class, 
+//                "is assumed to support"));
+//    }
 
+    @Test
+    void orphanedPropertySupport_shouldFail() {
+           
+        val validateDomainModel = new ValidateDomainModel();
+        
+        assertThrows(DomainModelException.class, validateDomainModel::run);
+        assertTrue(validateDomainModel.anyMatchesContaining(
+                OrphanedPropertySupport.class, 
+                "is assumed to support"));
+    }
+    
+    @Test
+    void orphanedCollectionSupport_shouldFail() {
+           
+        val validateDomainModel = new ValidateDomainModel();
+        
+        assertThrows(DomainModelException.class, validateDomainModel::run);
+        assertTrue(validateDomainModel.anyMatchesContaining(
+                OrphanedCollectionSupport.class, 
+                "is assumed to support"));
+    }
     
     
 
diff --git a/examples/smoketests/src/test/java/org/apache/isis/testdomain/domainmodel/DomainModelTest_usingGoodDomain.java b/examples/smoketests/src/test/java/org/apache/isis/testdomain/domainmodel/DomainModelTest_usingGoodDomain.java
index 5c2e431..0278d03 100644
--- a/examples/smoketests/src/test/java/org/apache/isis/testdomain/domainmodel/DomainModelTest_usingGoodDomain.java
+++ b/examples/smoketests/src/test/java/org/apache/isis/testdomain/domainmodel/DomainModelTest_usingGoodDomain.java
@@ -18,25 +18,15 @@
  */
 package org.apache.isis.testdomain.domainmodel;
 
-import javax.inject.Inject;
-
 import org.junit.jupiter.api.Test;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.test.context.TestPropertySource;
 
-import org.apache.isis.applib.services.jaxb.JaxbService;
-import org.apache.isis.applib.services.metamodel.MetaModelService;
 import org.apache.isis.config.IsisPresets;
 import org.apache.isis.integtestsupport.validate.ValidateDomainModel;
-import org.apache.isis.metamodel.spec.DomainModelException;
-import org.apache.isis.schema.metamodel.v1.DomainClassDto;
 import org.apache.isis.testdomain.conf.Configuration_headless;
-import org.apache.isis.testdomain.model.bad.UnresolvableReferencedAction;
 import org.apache.isis.testdomain.model.good.Configuration_usingValidDomain;
 
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
 import lombok.val;
 
 @SpringBootTest(
@@ -55,52 +45,34 @@ import lombok.val;
 })
 class DomainModelTest_usingGoodDomain {
     
-    @Inject private MetaModelService metaModelService;
-    @Inject private JaxbService jaxbService;
-    
-//    @BeforeAll
-//    static void beforeAll() {
-//        val typeMetaData = TypeMetaData.of(AValidDomainObject.class.getName());
-//        val typeRegistry = IsisBeanTypeRegistry.current();
-//        typeRegistry.isIoCManagedType(typeMetaData); // as a side-effect adds class to the meta model
-//    }
+//    @Inject private MetaModelService metaModelService;
+//    @Inject private JaxbService jaxbService;
 
-    @Test //TODO under construction
+    @Test
     void reservedPrefix_shouldBeAllowedForMembers() {
            
         
-        val config = new MetaModelService.Config()
-//              .withIgnoreNoop()
-//              .withIgnoreAbstractClasses()
-//              .withIgnoreBuiltInValueTypes()
-//              .withIgnoreInterfaces()
-                //.withPackagePrefix("*")
-                .withPackagePrefix("org.apache.isis.testdomain.")
-                ;
-        
-
-        System.out.println("!!! listing MM");
-
-        val metamodelDto = metaModelService.exportMetaModel(config);
-        for (DomainClassDto domainClass : metamodelDto.getDomainClassDto()) {
-            
-            System.out.println("dc: " + domainClass.getId());
-            val xmlString = jaxbService.toXml(domainClass);
-            System.out.println(xmlString);
-            
-            //for(val act : domainClass.getActions().getAct()) {
-            
-            
-        }
-        
-        System.out.println("!!! ---");
+//        val config = new MetaModelService.Config()
+////              .withIgnoreNoop()
+////              .withIgnoreAbstractClasses()
+////              .withIgnoreBuiltInValueTypes()
+////              .withIgnoreInterfaces()
+//                //.withPackagePrefix("*")
+//                .withPackagePrefix("org.apache.isis.testdomain.")
+//                ;
+//
+//        System.out.println("!!! listing MM");
+//        val metamodelDto = metaModelService.exportMetaModel(config);
+//        for (DomainClassDto domainClass : metamodelDto.getDomainClassDto()) {
+//            System.out.println("dc: " + domainClass.getId());
+//            val xmlString = jaxbService.toXml(domainClass);
+//            System.out.println(xmlString);
+//        }
+//        System.out.println("!!! ---");
         
         val validateDomainModel = new ValidateDomainModel();
         validateDomainModel.run(); // should not throw
         
-        //ReservedPrefixedMember
- 
-        
     }