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 12:16:44 UTC

[isis] branch master updated: ISIS-2270: redesign FactoryService:

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 ab64454  ISIS-2270: redesign FactoryService:
ab64454 is described below

commit ab644549f3cba64cfa03e516085a13d3c79af4b7
Author: Andi Huber <ah...@apache.org>
AuthorDate: Tue Jan 21 13:16:31 2020 +0100

    ISIS-2270: redesign FactoryService:
    
    - add #get(Class)
    - deprecate #instantiate(Class)
    
    also adding scope meta annot. to @DomainObject @Mixin @ViewModel
---
 .../examples/services/factory/FactoryService.java  | 72 ++++++++++++--------
 .../isis/applib/annotation/DomainObject.java       |  3 +-
 .../org/apache/isis/applib/annotation/Mixin.java   |  3 +-
 .../apache/isis/applib/annotation/ViewModel.java   |  3 +-
 .../applib/services/factory/FactoryService.java    | 77 ++++++++++++++--------
 .../apache/isis/core/commons/collections/Can.java  | 10 +--
 .../commons/internal/exceptions/_Exceptions.java   |  8 ++-
 .../factory/FactoryServiceDefault.java             | 20 ++++--
 8 files changed, 123 insertions(+), 73 deletions(-)

diff --git a/api/applib/src/main/adoc/modules/applib-svc/examples/services/factory/FactoryService.java b/api/applib/src/main/adoc/modules/applib-svc/examples/services/factory/FactoryService.java
index 07a904f..2b2fa70 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/examples/services/factory/FactoryService.java
+++ b/api/applib/src/main/adoc/modules/applib-svc/examples/services/factory/FactoryService.java
@@ -24,36 +24,17 @@ import javax.annotation.Nullable;
 import org.apache.isis.applib.services.repository.RepositoryService;
 
 public interface FactoryService {
-
+    
     /**
-     * Creates a new instance of the specified class, but does not persist it.
-     *
-     * <p>
-     * It is recommended that the object be initially instantiated using
-     * this method, though the framework will also handle the case when
-     * the object is simply <i>new()</i>ed up.  The benefits of using
-     * {@link #instantiate(Class)} are:
-     * </p>
-     *
-     * <ul>
-     * <li>any services will be injected into the object immediately
-     *     (otherwise they will not be injected until the framework
-     *     becomes aware of the object, typically when it is
-     *     {@link RepositoryService#persist(Object) persist}ed</li>
-     * <li>the default value for any properties (usually as specified by
-     *     <tt>default<i>Xxx</i>()</tt> supporting methods) will not be
-     *     used</li>
-     * <li>the <tt>created()</tt> callback will not be called.
-     * </ul>
-     *
-     * <p>
-     * The corollary is: if your code never uses <tt>default<i>Xxx</i>()</tt>
-     * supporting methods or the <tt>created()</tt> callback, then you can
-     * alternatively just <i>new()</i> up the object rather than call this
-     * method.
-     * </p>
+     * Gets an instance of the specified type, with injection points resolved 
+     * and life-cycle callbacks processed.
+     * 
+     * @param <T>
+     * @param type
+     * @return
+     * @since 2.0
      */
-    <T> T instantiate(Class<T> domainClass);
+    <T> T get(Class<T> type);
 
     /**
      * Creates a new Mixin instance.
@@ -83,5 +64,38 @@ public interface FactoryService {
         return viewModel(viewModelClass, /*mementoStr*/null);
     }
 
-
+    // -- DEPRECATIONS
+    
+    /**
+     * Creates a new instance of the specified class, but does not persist it.
+     *
+     * <p>
+     * It is recommended that the object be initially instantiated using
+     * this method, though the framework will also handle the case when
+     * the object is simply <i>new()</i>ed up.  The benefits of using
+     * {@link #instantiate(Class)} are:
+     * </p>
+     *
+     * <ul>
+     * <li>any services will be injected into the object immediately
+     *     (otherwise they will not be injected until the framework
+     *     becomes aware of the object, typically when it is
+     *     {@link RepositoryService#persist(Object) persist}ed</li>
+     * <li>the default value for any properties (usually as specified by
+     *     <tt>default<i>Xxx</i>()</tt> supporting methods) will (since 2.0) be
+     *     used</li>
+     * <li>the <tt>created()</tt> callback will not be called.
+     * </ul>
+     *
+     * <p>
+     * The corollary is: if your code never uses <tt>default<i>Xxx</i>()</tt>
+     * supporting methods or the <tt>created()</tt> callback, then you can
+     * alternatively just <i>new()</i> up the object rather than call this
+     * method.
+     * </p>
+     * @deprecated with sematic changes since 2.0 previous behavior is no longer guaranteed
+     */
+    @Deprecated
+    <T> T instantiate(Class<T> domainClass);
+    
 }
diff --git a/api/applib/src/main/java/org/apache/isis/applib/annotation/DomainObject.java b/api/applib/src/main/java/org/apache/isis/applib/annotation/DomainObject.java
index 391e992..785446f 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/annotation/DomainObject.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/annotation/DomainObject.java
@@ -24,6 +24,7 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+import org.springframework.context.annotation.Scope;
 import org.springframework.stereotype.Component;
 
 import org.apache.isis.applib.events.domain.ActionDomainEvent;
@@ -47,7 +48,7 @@ import org.apache.isis.applib.events.lifecycle.ObjectUpdatingEvent;
 @Inherited
 @Target({ ElementType.TYPE, ElementType.ANNOTATION_TYPE })
 @Retention(RetentionPolicy.RUNTIME)
-@Component
+@Component @Scope("prototype")
 public @interface DomainObject {
 
     /**
diff --git a/api/applib/src/main/java/org/apache/isis/applib/annotation/Mixin.java b/api/applib/src/main/java/org/apache/isis/applib/annotation/Mixin.java
index 7568045..5e47907 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/annotation/Mixin.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/annotation/Mixin.java
@@ -25,6 +25,7 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+import org.springframework.context.annotation.Scope;
 import org.springframework.stereotype.Component;
 
 /**
@@ -38,7 +39,7 @@ import org.springframework.stereotype.Component;
 @Inherited
 @Target({ ElementType.TYPE })
 @Retention(RetentionPolicy.RUNTIME)
-@Component
+@Component @Scope("prototype")
 public @interface Mixin {
 
     /**
diff --git a/api/applib/src/main/java/org/apache/isis/applib/annotation/ViewModel.java b/api/applib/src/main/java/org/apache/isis/applib/annotation/ViewModel.java
index 3c61bbc..e76c9d2 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/annotation/ViewModel.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/annotation/ViewModel.java
@@ -27,6 +27,7 @@ import java.lang.annotation.Target;
 
 import javax.xml.bind.annotation.XmlRootElement;
 
+import org.springframework.context.annotation.Scope;
 import org.springframework.stereotype.Component;
 
 /**
@@ -56,7 +57,7 @@ import org.springframework.stereotype.Component;
 @Inherited
 @Target({ ElementType.TYPE, ElementType.ANNOTATION_TYPE })
 @Retention(RetentionPolicy.RUNTIME)
-@Component
+@Component @Scope("prototype")
 public @interface ViewModel {
 
 
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/factory/FactoryService.java b/api/applib/src/main/java/org/apache/isis/applib/services/factory/FactoryService.java
index 07a904f..2f4ec09 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/factory/FactoryService.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/factory/FactoryService.java
@@ -19,6 +19,8 @@
 
 package org.apache.isis.applib.services.factory;
 
+import java.util.NoSuchElementException;
+
 import javax.annotation.Nullable;
 
 import org.apache.isis.applib.services.repository.RepositoryService;
@@ -26,34 +28,20 @@ import org.apache.isis.applib.services.repository.RepositoryService;
 public interface FactoryService {
 
     /**
-     * Creates a new instance of the specified class, but does not persist it.
-     *
-     * <p>
-     * It is recommended that the object be initially instantiated using
-     * this method, though the framework will also handle the case when
-     * the object is simply <i>new()</i>ed up.  The benefits of using
-     * {@link #instantiate(Class)} are:
-     * </p>
-     *
-     * <ul>
-     * <li>any services will be injected into the object immediately
-     *     (otherwise they will not be injected until the framework
-     *     becomes aware of the object, typically when it is
-     *     {@link RepositoryService#persist(Object) persist}ed</li>
-     * <li>the default value for any properties (usually as specified by
-     *     <tt>default<i>Xxx</i>()</tt> supporting methods) will not be
-     *     used</li>
-     * <li>the <tt>created()</tt> callback will not be called.
-     * </ul>
-     *
-     * <p>
-     * The corollary is: if your code never uses <tt>default<i>Xxx</i>()</tt>
-     * supporting methods or the <tt>created()</tt> callback, then you can
-     * alternatively just <i>new()</i> up the object rather than call this
-     * method.
-     * </p>
+     * Gets an instance of the specified {@code requiredType}, with injection points resolved 
+     * and any life-cycle callback processed.
+     * 
+     * @param <T>
+     * @param requiredType
+     * @return (non-null), if ambiguous picks the first best matching
+     * 
+     * @throws NoSuchElementException if result is empty
+     * 
+     * @apiNote does not force the requiredType to be added to the meta-model
+     * 
+     * @since 2.0
      */
-    <T> T instantiate(Class<T> domainClass);
+    <T> T get(Class<T> requiredType);
 
     /**
      * Creates a new Mixin instance.
@@ -83,5 +71,40 @@ public interface FactoryService {
         return viewModel(viewModelClass, /*mementoStr*/null);
     }
 
+    // -- DEPRECATIONS
+    
+    /**
+     * Creates a new instance of the specified class, but does not persist it.
+     *
+     * <p>
+     * It is recommended that the object be initially instantiated using
+     * this method, though the framework will also handle the case when
+     * the object is simply <i>new()</i>ed up.  The benefits of using
+     * {@link #instantiate(Class)} are:
+     * </p>
+     *
+     * <ul>
+     * <li>any services will be injected into the object immediately
+     *     (otherwise they will not be injected until the framework
+     *     becomes aware of the object, typically when it is
+     *     {@link RepositoryService#persist(Object) persist}ed</li>
+     * <li>the default value for any properties (usually as specified by
+     *     <tt>default<i>Xxx</i>()</tt> supporting methods) will (since 2.0) be
+     *     used</li>
+     * <li>the <tt>created()</tt> callback will not be called.
+     * </ul>
+     *
+     * <p>
+     * The corollary is: if your code never uses <tt>default<i>Xxx</i>()</tt>
+     * supporting methods or the <tt>created()</tt> callback, then you can
+     * alternatively just <i>new()</i> up the object rather than call this
+     * method.
+     * </p>
+     * @deprecated with semantic changes since 2.0 previous behavior is no longer guaranteed, 
+     * instead consider use of {@link #get(Class)} if applicable
+     */
+    @Deprecated
+    <T> T instantiate(Class<T> domainClass);
+
 
 }
diff --git a/core/commons/src/main/java/org/apache/isis/core/commons/collections/Can.java b/core/commons/src/main/java/org/apache/isis/core/commons/collections/Can.java
index d91e7ab..3ddd8ee 100644
--- a/core/commons/src/main/java/org/apache/isis/core/commons/collections/Can.java
+++ b/core/commons/src/main/java/org/apache/isis/core/commons/collections/Can.java
@@ -100,10 +100,11 @@ public interface Can<T> extends Iterable<T> {
     Optional<T> getFirst();
 
     /**
-     * Shortcut for {@code getFirst().orElseThrow(_Exceptions::unexpectedCodeReach)}
+     * Shortcut for {@code getFirst().orElseThrow(_Exceptions::noSuchElement)}
+     * @throws NoSuchElementException if result is empty
      */
     default T getFirstOrFail() {
-        return getFirst().orElseThrow(_Exceptions::unexpectedCodeReach);
+        return getFirst().orElseThrow(_Exceptions::noSuchElement);
     }
 
     /**
@@ -112,10 +113,11 @@ public interface Can<T> extends Iterable<T> {
     Optional<T> getSingleton();
     
     /**
-     * Shortcut for {@code getSingleton().orElseThrow(_Exceptions::unexpectedCodeReach)}
+     * Shortcut for {@code getSingleton().orElseThrow(_Exceptions::noSuchElement)}
+     * @throws NoSuchElementException if result is empty
      */
     default T getSingletonOrFail() {
-        return getSingleton().orElseThrow(_Exceptions::unexpectedCodeReach);
+        return getSingleton().orElseThrow(_Exceptions::noSuchElement);
     }
 
     // -- FACTORIES
diff --git a/core/commons/src/main/java/org/apache/isis/core/commons/internal/exceptions/_Exceptions.java b/core/commons/src/main/java/org/apache/isis/core/commons/internal/exceptions/_Exceptions.java
index f8ff8e5..2563b62 100644
--- a/core/commons/src/main/java/org/apache/isis/core/commons/internal/exceptions/_Exceptions.java
+++ b/core/commons/src/main/java/org/apache/isis/core/commons/internal/exceptions/_Exceptions.java
@@ -33,11 +33,9 @@ import javax.annotation.Nullable;
 
 import org.apache.isis.core.commons.internal.base._NullSafe;
 import org.apache.isis.core.commons.internal.base._Strings;
+import org.apache.isis.core.commons.internal.base._With;
 import org.apache.isis.core.commons.internal.collections._Lists;
 import org.apache.isis.core.commons.internal.functions._Functions;
-import org.apache.isis.core.commons.internal.base._With;
-
-import static org.apache.isis.core.commons.internal.base._NullSafe.stream;
 
 import lombok.val;
 
@@ -87,6 +85,10 @@ public final class _Exceptions {
         return new IllegalStateException(String.format(format, args));
     }
 
+    public static final NoSuchElementException noSuchElement() {
+        return new NoSuchElementException();
+    }
+    
     public static final NoSuchElementException noSuchElement(String msg) {
         return new NoSuchElementException(msg);
     }
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/factory/FactoryServiceDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/factory/FactoryServiceDefault.java
index 3094598..ec76f6a 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/factory/FactoryServiceDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/factory/FactoryServiceDefault.java
@@ -33,6 +33,7 @@ import org.apache.isis.applib.annotation.OrderPrecedence;
 import org.apache.isis.applib.services.factory.FactoryService;
 import org.apache.isis.applib.services.inject.ServiceInjector;
 import org.apache.isis.core.commons.internal.base._Casts;
+import org.apache.isis.core.commons.internal.environment.IsisSystemEnvironment;
 import org.apache.isis.core.commons.internal.exceptions._Exceptions;
 import org.apache.isis.core.commons.internal.reflection._Reflect;
 import org.apache.isis.core.metamodel.facets.object.mixin.MixinFacet;
@@ -57,12 +58,12 @@ public class FactoryServiceDefault implements FactoryService {
     @Inject IsisSessionFactory isisSessionFactory; // dependsOn
     @Inject private SpecificationLoader specificationLoader;
     @Inject private ServiceInjector serviceInjector;
+    @Inject private IsisSystemEnvironment isisSystemEnvironment; 
 
     @Override
-    public <T> T instantiate(final Class<T> domainClass) {
-        val spec = specificationLoader.loadSpecification(domainClass);
-        val adapter = ManagedObject._newTransientInstance(spec); 
-        return _Casts.uncheckedCast(adapter.getPojo());
+    public <T> T get(final Class<T> requiredType) {
+        val candidates = isisSystemEnvironment.getIocContainer().select(requiredType);
+        return candidates.getFirstOrFail();
     }
 
     @Override
@@ -111,9 +112,14 @@ public class FactoryServiceDefault implements FactoryService {
         return _Casts.uncheckedCast(viewModel);
     }
 
-
-
-
+    // -- DEPRECATIONS
+    
+    @Override
+    public <T> T instantiate(final Class<T> domainClass) {
+        val spec = specificationLoader.loadSpecification(domainClass);
+        val adapter = ManagedObject._newTransientInstance(spec); 
+        return _Casts.uncheckedCast(adapter.getPojo());
+    }
 
 
 }