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/24 10:22:00 UTC
[isis] 02/02: ISIS-2158: adds general purpose
FactoryService.getOrCreate(requiredType)
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 a9675c8945038d8ffcbdeaeeb28b4f256da4dbf4
Author: Andi Huber <ah...@apache.org>
AuthorDate: Fri Jan 24 11:21:47 2020 +0100
ISIS-2158: adds general purpose FactoryService.getOrCreate(requiredType)
- fixes the tree demo
---
.../applib/services/factory/FactoryService.java | 77 ++++++++++------------
.../ApplicationFeatureRepositoryDefaultTest.java | 22 +++----
.../factory/FactoryServiceDefault.java | 30 +++++++--
.../subdomains/excel/testing/ExcelFixture2.java | 6 +-
.../components/tree/IsisToWicketTreeAdapter.java | 2 +-
5 files changed, 77 insertions(+), 60 deletions(-)
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 4214b3f..fab230d 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
@@ -23,18 +23,31 @@ import java.util.NoSuchElementException;
import javax.annotation.Nullable;
-import org.apache.isis.applib.services.repository.RepositoryService;
import org.apache.isis.core.commons.exceptions.IsisException;
public interface FactoryService {
/**
+ * Carefree general purpose factory method, to automatically get or create an instance of
+ * {@code requiredType}.
+ * <p>
+ * Maps onto one of the specialized factory methods {@link #get(Class)} or {@link #create(Class)}
+ * based on the type's meta-data.
+ * @param <T>
+ * @param requiredType
+ * @return
+ * @throws NoSuchElementException if result is empty
+ * @throws IsisException if instance creation failed
+ */
+ <T> T getOrCreate(Class<T> requiredType);
+
+ /**
* Gets an instance (possibly shared or independent) of the specified {@code requiredType},
* with injection points resolved
* and any life-cycle callback processed.
*
* @param <T>
- * @param requiredType
+ * @param requiredType - only applicable to IoC container managed types
* @return (non-null), an instance of {@code requiredType}, if available and unique
* (i.e. not multiple candidates found with none marked as primary)
*
@@ -48,36 +61,44 @@ public interface FactoryService {
<T> T get(Class<T> requiredType);
/**
- * Creates a new detached entity instance, with injection points resolved.
+ * Creates a new detached entity instance, with injection points resolved
+ * and defaults applied.
* @param <T>
- * @param domainClass
+ * @param domainClass - only applicable to entity types
* @return
+ * @throws IllegalArgumentException if domainClass is not an entity type
* @apiNote forces the domainClass to be added to the meta-model if not already
*/
<T> T detachedEntity(Class<T> domainClass);
/**
- * Creates a new Mixin instance.
+ * Creates a new Mixin instance, with injection points resolved.
* @param <T>
* @param mixinClass
* @param mixedIn
* @return
+ * @throws IllegalArgumentException if mixinClass is not a mixin type
* @apiNote forces the mixinClass to be added to the meta-model if not already
*/
<T> T mixin(Class<T> mixinClass, Object mixedIn);
/**
- * Creates a new ViewModel instance, and initializes according to the given {@code mementoStr}
+ * Creates a new ViewModel instance, with injection points resolved,
+ * and initialized according to the given {@code mementoStr}
* @param viewModelClass
* @param mementoStr - ignored if {@code null}
+ * @throws IllegalArgumentException if viewModelClass is not a viewmodel type
* @apiNote forces the viewModelClass to be added to the meta-model if not already
* @since 2.0
*/
<T> T viewModel(Class<T> viewModelClass, @Nullable String mementoStr);
/**
- * Creates a new ViewModel instance
+ * Creates a new ViewModel instance,
+ * with injection points resolved
+ * and defaults applied.
* @param viewModelClass
+ * @throws IllegalArgumentException if viewModelClass is not a viewmodel type
* @apiNote forces the viewModelClass to be added to the meta-model if not already
* @since 2.0
*/
@@ -85,42 +106,16 @@ 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 #detachedEntity(Class)} if applicable
+ * Creates a new instance of the specified class,
+ * with injection points resolved
+ * and defaults applied.
+ * @param domainClass - not applicable to IoC container managed types
+ * @throws IllegalArgumentException if domainClass is not an IoC container managed type
+ * @apiNote forces the domainClass to be added to the meta-model if not already
+ * @since 2.0
*/
- @Deprecated
- default <T> T instantiate(Class<T> domainClass) {
- return detachedEntity(domainClass);
- }
+ <T> T create(Class<T> domainClass);
}
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/appfeat/ApplicationFeatureRepositoryDefaultTest.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/appfeat/ApplicationFeatureRepositoryDefaultTest.java
index 9d66edf..9f93871 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/appfeat/ApplicationFeatureRepositoryDefaultTest.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/appfeat/ApplicationFeatureRepositoryDefaultTest.java
@@ -180,43 +180,43 @@ public class ApplicationFeatureRepositoryDefaultTest {
// then
final Sequence sequence = context.sequence("loadSequence");
context.checking(new Expectations() {{
- oneOf(mockFactoryService).instantiate(ApplicationFeature.class);
+ oneOf(mockFactoryService).create(ApplicationFeature.class);
inSequence(sequence);
will(returnValue(new ApplicationFeature(ApplicationFeatureId.newClass(Bar.class.getName()))));
- oneOf(mockFactoryService).instantiate(ApplicationFeature.class);
+ oneOf(mockFactoryService).create(ApplicationFeature.class);
inSequence(sequence);
will(returnValue(new ApplicationFeature(ApplicationFeatureId.newMember(Bar.class.getName(), "someProperty"))));
- oneOf(mockFactoryService).instantiate(ApplicationFeature.class);
+ oneOf(mockFactoryService).create(ApplicationFeature.class);
inSequence(sequence);
will(returnValue(new ApplicationFeature(ApplicationFeatureId.newMember(Bar.class.getName(), "someCollection"))));
- oneOf(mockFactoryService).instantiate(ApplicationFeature.class);
+ oneOf(mockFactoryService).create(ApplicationFeature.class);
inSequence(sequence);
will(returnValue(new ApplicationFeature(ApplicationFeatureId.newMember(Bar.class.getName(), "someAction"))));
- oneOf(mockFactoryService).instantiate(ApplicationFeature.class);
+ oneOf(mockFactoryService).create(ApplicationFeature.class);
inSequence(sequence);
will(returnValue(new ApplicationFeature(ApplicationFeatureId.newPackage("org.isisaddons.module.security.dom.feature"))));
- oneOf(mockFactoryService).instantiate(ApplicationFeature.class);
+ oneOf(mockFactoryService).create(ApplicationFeature.class);
inSequence(sequence);
will(returnValue(new ApplicationFeature(ApplicationFeatureId.newPackage("org.isisaddons.module.security.dom"))));
- oneOf(mockFactoryService).instantiate(ApplicationFeature.class);
+ oneOf(mockFactoryService).create(ApplicationFeature.class);
inSequence(sequence);
will(returnValue(new ApplicationFeature(ApplicationFeatureId.newPackage("org.isisaddons.module.security"))));
- oneOf(mockFactoryService).instantiate(ApplicationFeature.class);
+ oneOf(mockFactoryService).create(ApplicationFeature.class);
inSequence(sequence);
will(returnValue(new ApplicationFeature(ApplicationFeatureId.newPackage("org.isisaddons.module"))));
- oneOf(mockFactoryService).instantiate(ApplicationFeature.class);
+ oneOf(mockFactoryService).create(ApplicationFeature.class);
inSequence(sequence);
will(returnValue(new ApplicationFeature(ApplicationFeatureId.newPackage("org.isisaddons"))));
- oneOf(mockFactoryService).instantiate(ApplicationFeature.class);
+ oneOf(mockFactoryService).create(ApplicationFeature.class);
inSequence(sequence);
will(returnValue(new ApplicationFeature(ApplicationFeatureId.newPackage("org"))));
}});
@@ -285,7 +285,7 @@ public class ApplicationFeatureRepositoryDefaultTest {
final ApplicationFeature newlyCreatedParent = new ApplicationFeature();
context.checking(new Expectations() {{
- allowing(mockFactoryService).instantiate(ApplicationFeature.class);
+ allowing(mockFactoryService).create(ApplicationFeature.class);
will(returnValue(newlyCreatedParent));
}});
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 8450470..8c54b3d 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
@@ -48,6 +48,7 @@ import static org.apache.isis.core.commons.internal.base._With.requires;
import static org.apache.isis.core.commons.internal.reflection._Reflect.Filter.paramAssignableFrom;
import static org.apache.isis.core.commons.internal.reflection._Reflect.Filter.paramCount;
+import lombok.NonNull;
import lombok.val;
@Service
@@ -64,14 +65,23 @@ public class FactoryServiceDefault implements FactoryService {
@Inject private ObjectManager objectManager;
@Override
- public <T> T get(final Class<T> requiredType) {
+ public <T> T getOrCreate(@NonNull Class<T> requiredType) {
+ val spec = specificationLoader.loadSpecification(requiredType);
+ if(spec.isManagedBean()) {
+ return get(requiredType);
+ }
+ return create(requiredType);
+ }
+
+ @Override
+ public <T> T get(@NonNull Class<T> requiredType) {
return isisSystemEnvironment.getIocContainer()
.get(requiredType)
.orElseThrow(_Exceptions::noSuchElement);
}
@Override
- public <T> T detachedEntity(final Class<T> domainClass) {
+ public <T> T detachedEntity(@NonNull Class<T> domainClass) {
val spec = specificationLoader.loadSpecification(domainClass);
if(!spec.isEntity()) {
throw _Exceptions.illegalArgument("Class '%s' is not an entity", domainClass.getName());
@@ -80,7 +90,7 @@ public class FactoryServiceDefault implements FactoryService {
}
@Override
- public <T> T mixin(final Class<T> mixinClass, final Object mixedIn) {
+ public <T> T mixin(@NonNull Class<T> mixinClass, @NonNull Object mixedIn) {
val objectSpec = specificationLoader.loadSpecification(mixinClass);
val mixinFacet = objectSpec.getFacet(MixinFacet.class);
if(mixinFacet == null) {
@@ -109,7 +119,7 @@ public class FactoryServiceDefault implements FactoryService {
}
@Override
- public <T> T viewModel(Class<T> viewModelClass, String mementoStr) {
+ public <T> T viewModel(@NonNull Class<T> viewModelClass, String mementoStr) {
requires(viewModelClass, "viewModelClass");
val spec = specificationLoader.loadSpecification(viewModelClass);
@@ -125,6 +135,16 @@ public class FactoryServiceDefault implements FactoryService {
return _Casts.uncheckedCast(viewModel);
}
+ @Override
+ public <T> T create(@NonNull Class<T> domainClass) {
+ val spec = specificationLoader.loadSpecification(domainClass);
+ if(spec.isManagedBean()) {
+ throw _Exceptions.illegalArgument(
+ "Class '%s' is managed by IoC container, use get() instead", domainClass.getName());
+ }
+ return _Casts.uncheckedCast(createObject(spec));
+ }
+
// -- HELEPR
private Object createObject(ObjectSpecification spec) {
@@ -134,4 +154,6 @@ public class FactoryServiceDefault implements FactoryService {
}
+
+
}
diff --git a/subdomains/excel/testing/src/main/java/org/apache/isis/subdomains/excel/testing/ExcelFixture2.java b/subdomains/excel/testing/src/main/java/org/apache/isis/subdomains/excel/testing/ExcelFixture2.java
index e6b6aa0..0afed88 100644
--- a/subdomains/excel/testing/src/main/java/org/apache/isis/subdomains/excel/testing/ExcelFixture2.java
+++ b/subdomains/excel/testing/src/main/java/org/apache/isis/subdomains/excel/testing/ExcelFixture2.java
@@ -16,10 +16,10 @@ import org.apache.isis.applib.services.factory.FactoryService;
import org.apache.isis.applib.services.registry.ServiceRegistry;
import org.apache.isis.applib.services.repository.RepositoryService;
import org.apache.isis.applib.value.Blob;
-import org.apache.isis.testing.fixtures.applib.fixturescripts.FixtureScript;
-import org.apache.isis.testing.fixtures.applib.fixturescripts.FixtureScripts;
import org.apache.isis.subdomains.excel.applib.dom.ExcelService;
import org.apache.isis.subdomains.excel.applib.dom.WorksheetSpec;
+import org.apache.isis.testing.fixtures.applib.fixturescripts.FixtureScript;
+import org.apache.isis.testing.fixtures.applib.fixturescripts.FixtureScripts;
import lombok.Getter;
import lombok.Setter;
@@ -121,7 +121,7 @@ public class ExcelFixture2 extends FixtureScript {
@Override
public T create() {
final T importLine =
- factoryService.instantiate(rowClass);
+ factoryService.getOrCreate(rowClass);
// allow the line to interact with the calling fixture
if(importLine instanceof FixtureAwareRowHandler<?>) {
final FixtureAwareRowHandler<?> farh = (FixtureAwareRowHandler<?>) importLine;
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/tree/IsisToWicketTreeAdapter.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/tree/IsisToWicketTreeAdapter.java
index 34b1ab4..63093e6 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/tree/IsisToWicketTreeAdapter.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/tree/IsisToWicketTreeAdapter.java
@@ -261,7 +261,7 @@ class IsisToWicketTreeAdapter {
}
try {
ensureInit(); // in case we were de-serialzed
- return wrappedTreeAdapter = factoryService.instantiate(treeAdapterClass);
+ return wrappedTreeAdapter = factoryService.getOrCreate(treeAdapterClass);
} catch (Exception e) {
throw new RuntimeException("failed to instantiate tree adapter", e);
}