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());
+ }
}