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 16:57:16 UTC

[isis] branch master updated: ISIS-2158: introduces a new DomainObject nature (experimental)

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 a751eaa  ISIS-2158: introduces a new DomainObject nature (experimental)
a751eaa is described below

commit a751eaa6e632daeb5892d3d2ebef05af38a18178
Author: Andi Huber <ah...@apache.org>
AuthorDate: Tue Jan 21 17:57:04 2020 +0100

    ISIS-2158: introduces a new DomainObject nature (experimental)
    
    - Nature.BEAN to enable an object's lifecycle to entirely be managed by
    Spring
---
 .../org/apache/isis/applib/annotation/Nature.java  | 11 ++-
 .../core/config/beans/IsisBeanTypeRegistry.java    | 96 ++++++++++++++--------
 ...atableObjectFacetForDomainObjectAnnotation.java |  1 +
 .../specloader/SpecificationLoaderDefault.java     |  3 +-
 .../demoapp/dom/events/DemoEventSubscriber.java    |  7 +-
 5 files changed, 81 insertions(+), 37 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 fcb6fc1..df64918 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
@@ -103,10 +103,17 @@ public enum Nature {
     VIEW_MODEL,
 
     /**
-     * An object that acts as a mix-in to some other object, contributing behaviour and/or derived state based on the
+     * An object that acts as a mix-in to some other object, contributing behavior and/or derived state based on the
      * domain object.
      *
      * @see Mixin
      */
-    MIXIN
+    MIXIN,
+    
+    /**
+     * An object that is entirely managed by the underlying IoC container. 
+     * @apiNote EXPERIMENTAL
+     */
+    BEAN,
+    
 }
diff --git a/core/config/src/main/java/org/apache/isis/core/config/beans/IsisBeanTypeRegistry.java b/core/config/src/main/java/org/apache/isis/core/config/beans/IsisBeanTypeRegistry.java
index 6d63f0d..973e458 100644
--- a/core/config/src/main/java/org/apache/isis/core/config/beans/IsisBeanTypeRegistry.java
+++ b/core/config/src/main/java/org/apache/isis/core/config/beans/IsisBeanTypeRegistry.java
@@ -46,6 +46,7 @@ import static org.apache.isis.core.commons.internal.reflection._Annotations.find
 
 import lombok.Getter;
 import lombok.NoArgsConstructor;
+import lombok.Value;
 import lombok.val;
 import lombok.extern.log4j.Log4j2;
 
@@ -112,18 +113,15 @@ public final class IsisBeanTypeRegistry implements IsisComponentScanInterceptor,
         
         val type = typeMeta.getUnderlyingClass();
 
-        if(findNearestAnnotation(type, DomainObject.class).isPresent() ||
-                findNearestAnnotation(type, ViewModel.class).isPresent() ||
-                findNearestAnnotation(type, Mixin.class).isPresent() ||
-                findNearestAnnotation(type, Vetoed.class).isPresent()) {
-            
-            typeMeta.setInjectable(false); // reject
-            
-        } else {
-            typeMeta.setBeanNameOverride(extractObjectType(type).orElse(null));
+        val classification = quickClassify(type);
+        
+        val delegated = classification.isDelegateLifecycleManagement();
+        typeMeta.setInjectable(delegated);
+        if(delegated) {
+            typeMeta.setBeanNameOverride(classification.getExplicitObjectType());    
         }
         
-        val beanSort = quickClassify(type);
+        val beanSort = classification.getBeanSort();
         
         if(beanSort.isToBeIntrospected()) {
             addIntrospectableType(beanSort, typeMeta);
@@ -194,82 +192,114 @@ public final class IsisBeanTypeRegistry implements IsisComponentScanInterceptor,
         }
     }
     
-    public BeanSort quickClassify(Class<?> type) {
+    @Value(staticConstructor = "of")
+    public static class BeanClassification {
+        
+        BeanSort beanSort;
+        String explicitObjectType;
+        boolean delegateLifecycleManagement;
+        
+        public static BeanClassification delegated(BeanSort beanSort, String explicitObjectType) {
+            return of(beanSort, explicitObjectType, true);
+        }
+        
+        public static BeanClassification delegated(BeanSort beanSort) {
+            return delegated(beanSort, null);
+        }
+        
+        public static BeanClassification selfManaged(BeanSort beanSort, String explicitObjectType) {
+            return of(beanSort, explicitObjectType, false);
+        }
+        
+        public static BeanClassification selfManaged(BeanSort beanSort) {
+            return selfManaged(beanSort, null);
+        }
+        
+    }
+    
+    public BeanClassification quickClassify(Class<?> type) {
 
         requires(type, "type");
         
         if(findNearestAnnotation(type, Vetoed.class).isPresent()) {
-            return BeanSort.UNKNOWN; // reject
+            return BeanClassification.selfManaged(BeanSort.UNKNOWN); // reject
         }
 
         val aDomainService = findNearestAnnotation(type, DomainService.class);
         if(aDomainService.isPresent()) {
-            return BeanSort.MANAGED_BEAN_CONTRIBUTING;
+            return BeanClassification
+                    .delegated(BeanSort.MANAGED_BEAN_CONTRIBUTING, objectType(aDomainService.get()));
         }
 
         //this takes precedence over whatever @DomainObject has to say
         if(_Reflect.containsAnnotation(type, "javax.jdo.annotations.PersistenceCapable")) {
-            return BeanSort.ENTITY;
+            return BeanClassification.selfManaged(BeanSort.ENTITY);
         }
 
         if(findNearestAnnotation(type, Mixin.class).isPresent()) {
-            return BeanSort.MIXIN;
+            return BeanClassification.selfManaged(BeanSort.MIXIN);
         }
 
         if(findNearestAnnotation(type, ViewModel.class).isPresent()) {
-            return BeanSort.VIEW_MODEL;
+            return BeanClassification.selfManaged(BeanSort.VIEW_MODEL);
         }
 
         if(org.apache.isis.applib.ViewModel.class.isAssignableFrom(type)) {
-            return BeanSort.VIEW_MODEL;
+            return BeanClassification.selfManaged(BeanSort.VIEW_MODEL);
         }
 
         val aDomainObject = findNearestAnnotation(type, DomainObject.class).orElse(null);
         if(aDomainObject!=null) {
             switch (aDomainObject.nature()) {
+            case BEAN:
+                return BeanClassification.delegated(BeanSort.MANAGED_BEAN_CONTRIBUTING, objectType(aDomainObject));
             case MIXIN:
-                return BeanSort.MIXIN;
+                return BeanClassification.selfManaged(BeanSort.MIXIN);
             case JDO_ENTITY:
-                return BeanSort.ENTITY;
+                return BeanClassification.selfManaged(BeanSort.ENTITY);
             case EXTERNAL_ENTITY:
             case INMEMORY_ENTITY:
             case VIEW_MODEL:
             case NOT_SPECIFIED:
-                return BeanSort.VIEW_MODEL; //because object is not associated with a persistence context unless discovered above
+                //because object is not associated with a persistence context unless discovered above
+                return BeanClassification.selfManaged(BeanSort.VIEW_MODEL);
             } 
         }
 
         if(findNearestAnnotation(type, Component.class).isPresent()) {
-            return BeanSort.MANAGED_BEAN_NOT_CONTRIBUTING;
+            return BeanClassification.delegated(BeanSort.MANAGED_BEAN_NOT_CONTRIBUTING);
         }
         
         if(Collection.class.isAssignableFrom(type)) {
-            return BeanSort.COLLECTION;
+            return BeanClassification.selfManaged(BeanSort.COLLECTION);
         }
 
         if(Serializable.class.isAssignableFrom(type)) {
-            return BeanSort.VALUE;
+            return BeanClassification.delegated(BeanSort.VALUE);
         }
 
-        return BeanSort.UNKNOWN;
+        return BeanClassification.delegated(BeanSort.UNKNOWN);
     }
 
-    private Optional<String> extractObjectType(Class<?> type) {
-
-        val aDomainService = _Reflect.getAnnotation(type, DomainService.class);
+    private String objectType(DomainService aDomainService) {
         if(aDomainService!=null) {
             val objectType = aDomainService.objectType();
             if(_Strings.isNotEmpty(objectType)) {
-                return Optional.of(objectType); 
+                return objectType; 
             }
-            return Optional.empty(); // stop processing
         }
-
-        return Optional.empty();
-
+        return null;
     }
 
-
+    private String objectType(DomainObject aDomainObject) {
+        if(aDomainObject!=null) {
+            val objectType = aDomainObject.objectType();
+            if(_Strings.isNotEmpty(objectType)) {
+                return objectType; 
+            }
+        }
+        return null;
+    }
 
 
 }
\ No newline at end of file
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 764e0de..d1d0c3b 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
@@ -41,6 +41,7 @@ extends RecreatableObjectFacetDeclarativeInitializingAbstract {
                 .map(nature -> {
                     switch (nature) {
                     case NOT_SPECIFIED:
+                    case BEAN:
                     case JDO_ENTITY:
                     case MIXIN:
                         // not a recreatable object, so no facet
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 494d43c..6ff6be8 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
@@ -448,7 +448,8 @@ public class SpecificationLoaderDefault implements SpecificationLoader {
                 && isisConfiguration.getCore().getMetaModel().getIntrospector().isLockAfterFullIntrospection()) {
 
             val typeRegistry = isisBeanTypeRegistryHolder.getIsisBeanTypeRegistry();
-            val sort = typeRegistry.quickClassify(cls);
+            val category = typeRegistry.quickClassify(cls);
+            val sort = category.getBeanSort();
 
 //          ISIS-2256:
 //            throw _Exceptions.illegalState(
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 d16c0a9..a24e314 100644
--- a/examples/demo/src/main/java/demoapp/dom/events/DemoEventSubscriber.java
+++ b/examples/demo/src/main/java/demoapp/dom/events/DemoEventSubscriber.java
@@ -22,6 +22,7 @@ import javax.inject.Inject;
 import javax.inject.Named;
 
 import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.context.annotation.Import;
 import org.springframework.context.event.EventListener;
 import org.springframework.stereotype.Service;
 
@@ -34,6 +35,7 @@ import org.apache.isis.applib.services.wrapper.WrapperFactory;
 import lombok.val;
 import lombok.extern.log4j.Log4j2;
 
+import demoapp.dom.events.DemoEventSubscriber.EventLogWriter;
 import demoapp.dom.events.EventsDemo.UiButtonEvent;
 
 import static demoapp.utils.DemoUtils.emphasize;
@@ -41,6 +43,9 @@ import static demoapp.utils.DemoUtils.emphasize;
 @Service
 @Named("demoapp.eventSubscriber")
 @Qualifier("demo")
+@Import({
+    EventLogWriter.class
+})
 @Log4j2
 public class DemoEventSubscriber {
 
@@ -60,7 +65,7 @@ public class DemoEventSubscriber {
     }
 
     @DomainObject(
-            nature = Nature.INMEMORY_ENTITY, 
+            nature = Nature.BEAN, 
             objectType = "demoapp.eventLogWriter")
     public static class EventLogWriter {