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/21 15:15:23 UTC

[isis] 02/02: ISIS-2158: have @XmlRootElement win over any other RecreatableObjectFacet providing strategy

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

commit fff71c540413525a8bc5a1d5fb0a6609ee38b51f
Author: Andi Huber <ah...@apache.org>
AuthorDate: Tue Jan 21 16:15:10 2020 +0100

    ISIS-2158: have @XmlRootElement win over any other
    RecreatableObjectFacet providing strategy
---
 .../org/apache/isis/applib/annotation/Nature.java  |  6 +--
 .../isis/core/metamodel/facetapi/FacetUtil.java    | 21 ++++++++++
 .../DomainObjectAnnotationFacetFactory.java        |  4 +-
 ...atableObjectFacetForDomainObjectAnnotation.java |  7 ++--
 .../RecreatableObjectFacetAbstract.java            |  4 +-
 .../recreatable/RecreatableObjectFacetFactory.java | 45 ++++++++++++++--------
 ...ableObjectFacetForXmlRootElementAnnotation.java |  3 +-
 .../demoapp/dom/events/DemoEventSubscriber.java    |  2 +-
 8 files changed, 64 insertions(+), 28 deletions(-)

diff --git a/api/applib/src/main/java/org/apache/isis/applib/annotation/Nature.java b/api/applib/src/main/java/org/apache/isis/applib/annotation/Nature.java
index 4ffa704..fcb6fc1 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/annotation/Nature.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/annotation/Nature.java
@@ -70,8 +70,8 @@ public enum Nature {
      * constructed from some sort of internal memory data structure.
      *
      * <p>
-     *     As for a {@link #EXTERNAL_ENTITY}, the identity of a synthetic entity is determined solely by the state of
-     *     object's properties (that have not been set to be ignored using
+     *     As for a {@link #EXTERNAL_ENTITY}, the identity of a synthetic entity is determined solely by the 
+     *     state of object's properties (that have not been set to be ignored using
      *     {@link org.apache.isis.applib.annotation.Property#notPersisted()}).
      * </p>
      *
@@ -82,7 +82,7 @@ public enum Nature {
      */
     INMEMORY_ENTITY,
     /**
-     * An object that is conceptually part of the application layer, and which surfaces behaviour and/or state that
+     * An object that is conceptually part of the application layer, and which surfaces behavior and/or state that
      * is aggregate of one or more domain entity.
      *
      * <p>
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 3a1bd13..db73476 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
@@ -31,6 +31,27 @@ import lombok.val;
 @NoArgsConstructor(access = AccessLevel.PRIVATE)
 public final class FacetUtil {
 
+    public static void addIfNotAlreadyPresent(final Facet facet) {
+        if (facet == null) {
+            return;
+        }
+        val facetHolder = facet.getFacetHolder();
+        if(!facetHolder.containsFacet(facet.facetType())) {
+            facetHolder.addFacet(facet);    
+        }
+    }
+    
+    public static void replaceIfAlreadyPresent(final Facet facet) {
+        if (facet == null) {
+            return;
+        }
+        val facetHolder = facet.getFacetHolder();
+        facetHolder.addOrReplaceFacet(facet);
+        // second call sets the underlying facet as well to this type
+        // hacky, to pass validation
+        facetHolder.addOrReplaceFacet(facet); 
+    }
+    
 
     public static void addOrReplaceFacet(final Facet facet) {
         if (facet == null) {
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobject/DomainObjectAnnotationFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobject/DomainObjectAnnotationFacetFactory.java
index 940e69b..dd5c9d8 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobject/DomainObjectAnnotationFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobject/DomainObjectAnnotationFacetFactory.java
@@ -41,6 +41,7 @@ import org.apache.isis.applib.services.HasUniqueId;
 import org.apache.isis.core.commons.internal.collections._Maps;
 import org.apache.isis.core.metamodel.context.MetaModelContext;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facetapi.FacetUtil;
 import org.apache.isis.core.metamodel.facetapi.FeatureType;
 import org.apache.isis.core.metamodel.facetapi.MetaModelRefiner;
 import org.apache.isis.core.metamodel.facets.FacetFactoryAbstract;
@@ -300,7 +301,8 @@ implements MetaModelRefiner, PostConstructMethodCache, ObjectSpecIdFacetFactory
                     postConstructMethodCache);
 
         if(recreatableObjectFacet != null) {
-            super.addFacet(recreatableObjectFacet);
+            // handle with least priority
+            FacetUtil.addIfNotAlreadyPresent(recreatableObjectFacet);
         } else {
 
             val mixinDomainObjectIfAny =
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobject/recreatable/RecreatableObjectFacetForDomainObjectAnnotation.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobject/recreatable/RecreatableObjectFacetForDomainObjectAnnotation.java
index d978af1..d51408c 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobject/recreatable/RecreatableObjectFacetForDomainObjectAnnotation.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobject/recreatable/RecreatableObjectFacetForDomainObjectAnnotation.java
@@ -28,8 +28,8 @@ import org.apache.isis.core.metamodel.facets.PostConstructMethodCache;
 import org.apache.isis.core.metamodel.facets.object.recreatable.RecreatableObjectFacetDeclarativeInitializingAbstract;
 import org.apache.isis.core.metamodel.facets.object.viewmodel.ViewModelFacet;
 
-public class RecreatableObjectFacetForDomainObjectAnnotation extends
-RecreatableObjectFacetDeclarativeInitializingAbstract {
+public class RecreatableObjectFacetForDomainObjectAnnotation 
+extends RecreatableObjectFacetDeclarativeInitializingAbstract {
 
     public static ViewModelFacet create(
             final Optional<DomainObject> domainObjectIfAny,
@@ -49,8 +49,7 @@ RecreatableObjectFacetDeclarativeInitializingAbstract {
                     case VIEW_MODEL:
                     case EXTERNAL_ENTITY:
                     case INMEMORY_ENTITY:
-                        final ViewModelFacet existingFacet = holder.getFacet(ViewModelFacet.class);
-                        if (existingFacet != null) {
+                        if (!holder.containsFacet(ViewModelFacet.class)) {
                             return null;
                         }
                         return new RecreatableObjectFacetForDomainObjectAnnotation(
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/recreatable/RecreatableObjectFacetAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/recreatable/RecreatableObjectFacetAbstract.java
index 70f9758..56b747b 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/recreatable/RecreatableObjectFacetAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/recreatable/RecreatableObjectFacetAbstract.java
@@ -35,7 +35,9 @@ import org.apache.isis.core.metamodel.specloader.specimpl.dflt.ObjectSpecificati
 
 import lombok.val;
 
-public abstract class RecreatableObjectFacetAbstract extends FacetAbstract implements ViewModelFacet {
+public abstract class RecreatableObjectFacetAbstract 
+extends FacetAbstract 
+implements ViewModelFacet {
 
     private final PostConstructMethodCache postConstructMethodCache;
     private final ViewModelFacet.RecreationMechanism recreationMechanism;
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/recreatable/RecreatableObjectFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/recreatable/RecreatableObjectFacetFactory.java
index 718af72..f5b48d5 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/recreatable/RecreatableObjectFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/recreatable/RecreatableObjectFacetFactory.java
@@ -30,7 +30,6 @@ import org.apache.isis.applib.RecreatableDomainObject;
 import org.apache.isis.applib.ViewModel;
 import org.apache.isis.core.commons.internal.collections._Maps;
 import org.apache.isis.core.config.IsisConfiguration;
-import org.apache.isis.core.metamodel.facetapi.Facet;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facetapi.FacetUtil;
 import org.apache.isis.core.metamodel.facetapi.FeatureType;
@@ -42,6 +41,8 @@ import org.apache.isis.core.metamodel.facets.PostConstructMethodCache;
 import org.apache.isis.core.metamodel.facets.object.viewmodel.ViewModelFacet;
 import org.apache.isis.core.metamodel.progmodel.ProgrammingModel;
 
+import lombok.val;
+
 public class RecreatableObjectFacetFactory extends FacetFactoryAbstract
 implements MetaModelRefiner, PostConstructMethodCache {
 
@@ -56,34 +57,41 @@ implements MetaModelRefiner, PostConstructMethodCache {
     @Override
     public void process(final ProcessClassContext processClassContext) {
 
+        val facetHolder = processClassContext.getFacetHolder();
+        val type = processClassContext.getCls();
+        
         // ViewModel interface
         if (ViewModel.class.isAssignableFrom(processClassContext.getCls())) {
             final PostConstructMethodCache postConstructMethodCache = this;
             FacetUtil.addFacet(new RecreatableObjectFacetForRecreatableObjectInterface(
-                    processClassContext.getFacetHolder(), postConstructMethodCache));
+                    facetHolder, postConstructMethodCache));
         }
 
         // ViewModel annotation
-        final org.apache.isis.applib.annotation.ViewModel annotation = Annotations.getAnnotation(processClassContext.getCls(), org.apache.isis.applib.annotation.ViewModel.class);
-        FacetUtil.addFacet(create(annotation, processClassContext.getFacetHolder()));
-
-        // XmlRootElement annotation
-        final XmlRootElement xmlRootElement = Annotations.getAnnotation(processClassContext.getCls(), XmlRootElement.class);
-        FacetUtil.addFacet(create(xmlRootElement, processClassContext.getFacetHolder()));
-
+        final org.apache.isis.applib.annotation.ViewModel annotation = 
+                Annotations.getAnnotation(type, org.apache.isis.applib.annotation.ViewModel.class);
+        FacetUtil.addFacet(create(annotation, facetHolder));
+        
         // RecreatableDomainObject interface
-        if (RecreatableDomainObject.class.isAssignableFrom(processClassContext.getCls())) {
+        if (RecreatableDomainObject.class.isAssignableFrom(type)) {
             final PostConstructMethodCache postConstructMethodCache = this;
             FacetUtil.addFacet(new RecreatableObjectFacetForRecreatableDomainObjectInterface(
-                    processClassContext.getFacetHolder(), postConstructMethodCache));
+                    facetHolder, postConstructMethodCache));
         }
+        
+        // XmlRootElement annotation
+        final XmlRootElement xmlRootElement = Annotations.getAnnotation(type, XmlRootElement.class);
+        // handle with highest precedence
+        FacetUtil.replaceIfAlreadyPresent(create(xmlRootElement, facetHolder));
 
-        // DomainObject(nature=VIEW_MODEL) is managed by the DomainObjectFacetFactory
+        // DomainObject(nature=VIEW_MODEL) is managed by the DomainObjectAnnotationFacetFactory
     }
 
     private ViewModelFacet create(final org.apache.isis.applib.annotation.ViewModel annotation, final FacetHolder holder) {
         final PostConstructMethodCache postConstructMethodCache = this;
-        return annotation != null ? new RecreatableObjectFacetForViewModelAnnotation(holder, postConstructMethodCache) : null;
+        return annotation != null 
+                ? new RecreatableObjectFacetForViewModelAnnotation(holder, postConstructMethodCache) 
+                        : null;
     }
 
     private ViewModelFacet create(final XmlRootElement annotation, final FacetHolder holder) {
@@ -100,16 +108,19 @@ implements MetaModelRefiner, PostConstructMethodCache {
 
         programmingModel.addValidator((objectSpec, validate) -> {
 
-            final ViewModelFacet facet = objectSpec.getFacet(ViewModelFacet.class);
-            final Facet underlyingFacet = facet != null ? facet.getUnderlyingFacet() : null;
-            if(underlyingFacet != null && underlyingFacet.getClass() != facet.getClass()) {
+            val viewModelFacet = objectSpec.getFacet(ViewModelFacet.class);
+            val underlyingFacet = viewModelFacet != null ? viewModelFacet.getUnderlyingFacet() : null;
+            if(underlyingFacet == null) {
+                return true;    
+            }
+            if(underlyingFacet.getClass() != viewModelFacet.getClass()) {
                 validate.onFailure(
                         objectSpec,
                         objectSpec.getIdentifier(),
                         "%s: has multiple incompatible annotations/interfaces indicating that " +
                                 "it is a recreatable object of some sort (%s and %s)",
                                 objectSpec.getFullIdentifier(),
-                                facet.getClass().getSimpleName(),
+                                viewModelFacet.getClass().getSimpleName(),
                                 underlyingFacet.getClass().getSimpleName());
             }
             return true;
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/recreatable/RecreatableObjectFacetForXmlRootElementAnnotation.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/recreatable/RecreatableObjectFacetForXmlRootElementAnnotation.java
index 390dc9f..315be60 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/recreatable/RecreatableObjectFacetForXmlRootElementAnnotation.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/recreatable/RecreatableObjectFacetForXmlRootElementAnnotation.java
@@ -24,7 +24,8 @@ import org.apache.isis.applib.services.urlencoding.UrlEncodingService;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.PostConstructMethodCache;
 
-public class RecreatableObjectFacetForXmlRootElementAnnotation extends RecreatableObjectFacetAbstract {
+public class RecreatableObjectFacetForXmlRootElementAnnotation 
+extends RecreatableObjectFacetAbstract {
 
 
     public RecreatableObjectFacetForXmlRootElementAnnotation(
diff --git a/examples/demo/src/main/java/demoapp/dom/events/DemoEventSubscriber.java b/examples/demo/src/main/java/demoapp/dom/events/DemoEventSubscriber.java
index 039cad9..d16c0a9 100644
--- a/examples/demo/src/main/java/demoapp/dom/events/DemoEventSubscriber.java
+++ b/examples/demo/src/main/java/demoapp/dom/events/DemoEventSubscriber.java
@@ -52,7 +52,7 @@ public class DemoEventSubscriber {
 
         log.info(emphasize("UiButtonEvent")); // <-- log to the console
         
-        val eventLogWriter = factoryService.instantiate(EventLogWriter.class); // <-- get a new writer
+        val eventLogWriter = factoryService.get(EventLogWriter.class); // <-- get a new writer
         
         wrapper.async(eventLogWriter)
             .run(EventLogWriter::storeEvent, event);