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 7638af5646 ISIS-3232: fail MM validation, if viewmodels have no 
recreation strategy
7638af5646 is described below

commit 7638af5646de3e9d7250302fdffe5f87c8e04fc5
Author: Andi Huber <[email protected]>
AuthorDate: Thu Oct 6 07:52:42 2022 +0200

    ISIS-3232: fail MM validation, if viewmodels have no recreation strategy
---
 .../progmodel/ProgrammingModelConstants.java       | 10 ++++++
 .../facets/HasPostConstructMethodCache.java        |  4 +--
 .../object/viewmodel/ViewModelFacetAbstract.java   |  2 +-
 .../object/viewmodel/ViewModelFacetFactory.java    | 39 +++++++++++++---------
 .../metamodel/facets/MethodFinderUtilsTest.java    | 11 ++----
 5 files changed, 40 insertions(+), 26 deletions(-)

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 22b2ac0b67..3975086aea 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
@@ -478,9 +478,19 @@ public final class ProgrammingModelConstants {
         UNSATISFIED_DOMAIN_INCLUDE_SEMANTICS("${type}#${member}: "
                 + "has synthesized (effective) annotation @Domain.Include, "
                 + "is assumed to represent or support a property, collection 
or action."),
+        VIEWMODEL_CONFLICTING_SERIALIZATION_STRATEGIES(
+                "${type}: has multiple incompatible annotations/interfaces 
indicating that "
+                + "it is a recreatable object of some sort (${facetA} and 
${facetB})"),
         VIEWMODEL_MISSING_DESERIALIZING_CONSTRUCTOR(
                 "${type}: ViewModel contract violation: missing single 
(String) arg constructor "
                 + "(for de-serialization from memento string)."),
+        VIEWMODEL_MISSING_SERIALIZATION_STRATEGY( // draft: not used yet
+                "${type}: Missing ViewModel serialization strategy 
encountered; "
+                + "for ViewModels one of those must be true: "
+                + "(1) implements the ViewModel interface, "
+                + "(2) implements Serializable, "
+                + "(3) uses JAXB semantics, "
+                + "(4) has explicit VIEW_MODEL nature via DomainObject 
annotation."),
         DOMAIN_OBJECT_INVALID_NAVIGABLE_PARENT("${type}: the object's 
navigable parent must no be void, "
                 + "plural, vetoed or a value-type; "
                 + "yet the parent type '${parentType}' as discovered was 
${parentTypeDeficiency}; "),
diff --git 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/HasPostConstructMethodCache.java
 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/HasPostConstructMethodCache.java
index 5e0555595e..3d6389cacf 100644
--- 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/HasPostConstructMethodCache.java
+++ 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/HasPostConstructMethodCache.java
@@ -35,10 +35,10 @@ public interface HasPostConstructMethodCache {
 
     MethodByClassMap getPostConstructMethodsCache();
 
-    default Method postConstructMethodFor(final Object pojo) {
+    default Method postConstructMethodFor(final Class<?> domainObjectClass) {
         return findAnnotatedMethod(
                 // @PostConstruct is allowed to appear on non-public methods
-                MethodFinder.notNecessarilyPublic(pojo.getClass(), 
MethodFinder.ANY_NAME)
+                MethodFinder.notNecessarilyPublic(domainObjectClass, 
MethodFinder.ANY_NAME)
                 .withRequiredReturnType(void.class),
                 PostConstruct.class,
                 getPostConstructMethodsCache());
diff --git 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/viewmodel/ViewModelFacetAbstract.java
 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/viewmodel/ViewModelFacetAbstract.java
index 9776e8ca8d..08770e07ff 100644
--- 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/viewmodel/ViewModelFacetAbstract.java
+++ 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/viewmodel/ViewModelFacetAbstract.java
@@ -95,7 +95,7 @@ implements ViewModelFacet {
             @NonNull Bookmark bookmark);
 
     private void invokePostConstructMethod(final Object viewModel) {
-        final Method postConstructMethod = 
postConstructMethodCache.postConstructMethodFor(viewModel);
+        final Method postConstructMethod = 
postConstructMethodCache.postConstructMethodFor(viewModel.getClass());
         if (postConstructMethod != null) {
             CanonicalInvoker.invoke(postConstructMethod, viewModel);
         }
diff --git 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/viewmodel/ViewModelFacetFactory.java
 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/viewmodel/ViewModelFacetFactory.java
index e1462fecba..bb935d73df 100644
--- 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/viewmodel/ViewModelFacetFactory.java
+++ 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/viewmodel/ViewModelFacetFactory.java
@@ -18,9 +18,12 @@
  */
 package org.apache.isis.core.metamodel.facets.object.viewmodel;
 
+import java.util.Map;
+
 import javax.inject.Inject;
 import javax.xml.bind.annotation.XmlRootElement;
 
+import org.apache.isis.core.config.progmodel.ProgrammingModelConstants;
 import org.apache.isis.core.metamodel.context.MetaModelContext;
 import org.apache.isis.core.metamodel.facetapi.FacetUtil;
 import org.apache.isis.core.metamodel.facetapi.FeatureType;
@@ -90,22 +93,28 @@ implements
 
         programmingModel.addVisitingValidatorSkipManagedBeans(objectSpec -> {
 
-            objectSpec.lookupFacet(ViewModelFacet.class)
-            .map(ViewModelFacet::getSharedFacetRankingElseFail)
-            .ifPresent(facetRanking->facetRanking
-                    .visitTopRankPairsSemanticDiffering(ViewModelFacet.class, 
(a, b)->{
-
-                            ValidationFailure.raiseFormatted(
-                                    objectSpec,
-                                    "%s: has multiple incompatible 
annotations/interfaces indicating that " +
-                                            "it is a recreatable object of 
some sort (%s and %s)",
-                                            objectSpec.getFullIdentifier(),
-                                            a.getClass().getSimpleName(),
-                                            b.getClass().getSimpleName());
-
-
-                    }));
+            // ensure concrete viewmodel types have a ViewModelFacet
+            if(!objectSpec.isAbstract()
+                    && objectSpec.getBeanSort().isViewModel()
+                    && !objectSpec.viewmodelFacet().isPresent()) {
+                ValidationFailure.raiseFormatted(objectSpec,
+                        
ProgrammingModelConstants.Validation.VIEWMODEL_MISSING_SERIALIZATION_STRATEGY
+                            
.getMessageForType(objectSpec.getCorrespondingClass().getName()));
+            }
 
+            objectSpec.viewmodelFacet()
+            .map(ViewModelFacet::getSharedFacetRankingElseFail)
+            .ifPresent(facetRanking->{
+                facetRanking
+                .visitTopRankPairsSemanticDiffering(ViewModelFacet.class, (a, 
b)->{
+                    ValidationFailure.raiseFormatted(objectSpec,
+                            
ProgrammingModelConstants.Validation.VIEWMODEL_CONFLICTING_SERIALIZATION_STRATEGIES
+                                .getMessage(Map.of(
+                                        "type", objectSpec.getFullIdentifier(),
+                                        "facetA", a.getClass().getSimpleName(),
+                                        "facetB", 
b.getClass().getSimpleName())));
+                });
+            });
         });
     }
 
diff --git 
a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/MethodFinderUtilsTest.java
 
b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/MethodFinderUtilsTest.java
index 9fc9c43bcc..eb28b10a68 100644
--- 
a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/MethodFinderUtilsTest.java
+++ 
b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/MethodFinderUtilsTest.java
@@ -45,19 +45,14 @@ class MethodFinderUtilsTest {
     @BeforeEach
     public void setup() {
         val methodByClassMap = new MethodByClassMap();
-        this.hasPostConstructMethodCache = new HasPostConstructMethodCache() {
-            @Override
-            public MethodByClassMap getPostConstructMethodsCache() {
-                return methodByClassMap;
-            }
-        };
+        this.hasPostConstructMethodCache = () -> methodByClassMap;
     }
 
     @Test
     public void whenExists() throws Exception {
 
         val cache = hasPostConstructMethodCache.getPostConstructMethodsCache();
-        val method = hasPostConstructMethodCache.postConstructMethodFor(new 
_TestDummies.WithPostConstruct());
+        val method = 
hasPostConstructMethodCache.postConstructMethodFor(_TestDummies.WithPostConstruct.class);
 
         assertThat(method, is(not(nullValue())));
         final Optional<Method> actual = 
cache.get(_TestDummies.WithPostConstruct.class);
@@ -70,7 +65,7 @@ class MethodFinderUtilsTest {
     public void whenDoesNotExist() throws Exception {
 
         val cache = hasPostConstructMethodCache.getPostConstructMethodsCache();
-        val method = hasPostConstructMethodCache.postConstructMethodFor(new 
NoPostConstruct());
+        val method = 
hasPostConstructMethodCache.postConstructMethodFor(NoPostConstruct.class);
 
         assertThat(method, is(nullValue()));
         final Optional<Method> actual = cache.get(NoPostConstruct.class);

Reply via email to