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/16 12:01:14 UTC

[isis] branch master updated: ISIS-2158: refactoring all reflective constructor usages

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 3e5b4c8  ISIS-2158: refactoring all reflective constructor usages
3e5b4c8 is described below

commit 3e5b4c83d4b29da61de083b5bf5ecced47e4cb89
Author: Andi Huber <ah...@apache.org>
AuthorDate: Thu Jan 16 13:01:00 2020 +0100

    ISIS-2158: refactoring all reflective constructor usages
---
 .../core/commons/internal/reflection/_Reflect.java |  62 +++---
 .../core/metamodel/facets/DomainEventHelper.java   | 222 +++++++++------------
 .../metamodel/facets/jaxb/JaxbFacetFactory.java    |  52 +++--
 .../mixin/MetaModelValidatorForMixinTypes.java     |  34 +++-
 .../mixin/MixinFacetForDomainObjectAnnotation.java |  10 +-
 .../object/mixin/MixinFacetForMixinAnnotation.java |   9 +-
 .../objectmanager/create/ObjectCreator.java        |   2 +-
 .../create/ObjectCreator_builtinHandlers.java      |   5 -
 .../identify/ObjectIdentifier_builtinHandlers.java |   6 +-
 .../factory/FactoryServiceDefault.java             |  62 +++---
 10 files changed, 232 insertions(+), 232 deletions(-)

diff --git a/core/commons/src/main/java/org/apache/isis/core/commons/internal/reflection/_Reflect.java b/core/commons/src/main/java/org/apache/isis/core/commons/internal/reflection/_Reflect.java
index f37e801..b29c378 100644
--- a/core/commons/src/main/java/org/apache/isis/core/commons/internal/reflection/_Reflect.java
+++ b/core/commons/src/main/java/org/apache/isis/core/commons/internal/reflection/_Reflect.java
@@ -27,11 +27,11 @@ import java.lang.annotation.Annotation;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.reflect.Constructor;
+import java.lang.reflect.Executable;
 import java.lang.reflect.Field;
 import java.lang.reflect.Member;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
-import java.util.Optional;
 import java.util.Spliterator;
 import java.util.Spliterators;
 import java.util.function.Consumer;
@@ -43,14 +43,15 @@ import javax.annotation.Nullable;
 
 import org.springframework.core.annotation.AnnotationUtils;
 
-import org.apache.isis.core.commons.internal.base._Strings;
-import org.apache.isis.core.commons.internal.collections._Arrays;
+import org.apache.isis.core.commons.collections.Can;
 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 static org.apache.isis.core.commons.internal.base._NullSafe.stream;
+import org.apache.isis.core.commons.internal.collections._Arrays;
+import org.apache.isis.core.commons.internal.functions._Predicates;
 
 import lombok.val;
+import lombok.experimental.UtilityClass;
 
 /**
  * <h1>- internal use only -</h1>
@@ -407,29 +408,42 @@ public final class _Reflect {
         return null;
     }
     
+    
     // -- COMMON CONSTRUCTOR IDIOMS
-
-    public static boolean hasPublic1ArgConstructor(Class<?> cls) {
-        val constructors = cls.getConstructors();
-        for (val constructor : constructors) {
-            if(constructor.getParameterCount()==1 && 
-                    Modifier.isPublic(constructor.getModifiers())) {
-                return true;
-            }
-        }
-        return false;
+    
+    public static Can<Constructor<?>> getDeclaredConstructors(Class<?> cls) {
+        return Can.ofArray(cls.getDeclaredConstructors());
     }
-
-    public static Optional<Constructor<?>> getPublic1ArgConstructor(Class<?> cls) {
-        val constructors = cls.getConstructors();
-        for (val constructor : constructors) {
-            if(constructor.getParameterCount()==1 && 
-                    Modifier.isPublic(constructor.getModifiers())) {
-                return Optional.of(constructor);
+    
+    public static Can<Constructor<?>> getPublicConstructors(Class<?> cls) {
+        return Can.ofArray(cls.getConstructors());
+    }
+    
+    // -- FILTER
+    
+    @UtilityClass
+    public static class Filter {
+        
+        public static Predicate<Executable> isPublic() {
+            return ex->Modifier.isPublic(ex.getModifiers());
+        }
+        
+        public static Predicate<Executable> paramCount(int paramCount) {
+            return ex->ex.getParameterCount() == paramCount;
+        }
+        
+        public static Predicate<Executable> paramAssignableFrom(int paramIndex, Class<?> paramType) {
+            return ex->ex.getParameterTypes()[paramIndex].isAssignableFrom(paramType);
+        }
+        
+        public static Predicate<Executable> paramAssignableFromValue(int paramIndex, @Nullable Object value) {
+            if(value==null) {
+                return _Predicates.alwaysTrue();
             }
+            return ex->ex.getParameterTypes()[paramIndex].isAssignableFrom(value.getClass());
         }
-        return Optional.empty();
+        
     }
-
+    
 
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/DomainEventHelper.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/DomainEventHelper.java
index 6c6f1b4..21bcd3e 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/DomainEventHelper.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/DomainEventHelper.java
@@ -19,7 +19,6 @@
 
 package org.apache.isis.core.metamodel.facets;
 
-import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.util.Arrays;
 import java.util.Collections;
@@ -34,6 +33,7 @@ import org.apache.isis.applib.events.domain.PropertyDomainEvent;
 import org.apache.isis.applib.services.registry.ServiceRegistry;
 import org.apache.isis.core.commons.internal.assertions._Assert;
 import org.apache.isis.core.commons.internal.collections._Lists;
+import org.apache.isis.core.commons.internal.reflection._Reflect;
 import org.apache.isis.core.metamodel.facetapi.IdentifiedHolder;
 import org.apache.isis.core.metamodel.services.events.MetamodelEventService;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
@@ -42,6 +42,9 @@ import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.core.metamodel.spec.feature.ObjectActionParameter;
 
 import static org.apache.isis.core.commons.internal.base._Casts.uncheckedCast;
+import static org.apache.isis.core.commons.internal.reflection._Reflect.Filter.paramAssignableFrom;
+import static org.apache.isis.core.commons.internal.reflection._Reflect.Filter.paramAssignableFromValue;
+import static org.apache.isis.core.commons.internal.reflection._Reflect.Filter.paramCount;
 
 import lombok.NonNull;
 import lombok.RequiredArgsConstructor;
@@ -161,40 +164,36 @@ public class DomainEventHelper {
             final Object... arguments) 
         throws InstantiationException, IllegalAccessException, IllegalArgumentException, 
         InvocationTargetException, NoSuchMethodException, SecurityException {
+
+        val constructors = _Reflect.getPublicConstructors(type);
+
+        val noArgConstructors = constructors.filter(paramCount(0));
         
-        final Constructor<?>[] constructors = type.getConstructors();
-
-        // no-arg constructor
-        for (final Constructor<?> constructor : type.getConstructors()) {
-            if(constructor.getParameterCount() == 0) {
-                final Object event = constructor.newInstance();
-                final ActionDomainEvent<S> ade = uncheckedCast(event);
-                
-                ade.initSource(source);
-                ade.setIdentifier(identifier);
-                ade.setArguments(asList(arguments));
-                return ade;
-            }
+        for (val constructor : noArgConstructors) {
+            
+            final Object event = constructor.newInstance();
+            final ActionDomainEvent<S> ade = uncheckedCast(event);
+            
+            ade.initSource(source);
+            ade.setIdentifier(identifier);
+            ade.setArguments(asList(arguments));
+            return ade;
         }
 
-
-        for (final Constructor<?> constructor : constructors) {
-            final Class<?>[] parameterTypes = constructor.getParameterTypes();
-            if(parameterTypes.length != 3) {
-                continue;
-            }
-            if(!parameterTypes[0].isAssignableFrom(source.getClass())) {
-                continue;
-            }
-            if(!parameterTypes[1].isAssignableFrom(Identifier.class)) {
-                continue;
-            }
-            if(!parameterTypes[2].isAssignableFrom(Object[].class)) {
-                continue;
-            }
-            final Object event = constructor.newInstance(source, identifier, arguments);
+        // else
+        
+        val updateEventConstructors = constructors
+                .filter(paramCount(3)
+                        .and(paramAssignableFrom(0, source.getClass()))
+                        .and(paramAssignableFrom(1, Identifier.class))
+                        .and(paramAssignableFrom(2, Object[].class))
+                        );
+        
+        for (val constructor : updateEventConstructors) {
+            val event = constructor.newInstance(source, identifier, arguments);
             return uncheckedCast(event);
         }
+        
         throw new NoSuchMethodException(type.getName()+".<init>(? super " + source.getClass().getName() + ", " + Identifier.class.getName() + ", [Ljava.lang.Object;)");
     }
 
@@ -261,43 +260,35 @@ public class DomainEventHelper {
                     final T oldValue,
                     final T newValue) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException  {
 
-        final Constructor<?>[] constructors = type.getConstructors();
-
-        // no-arg constructor
-        for (final Constructor<?> constructor : constructors) {
-            if(constructor.getParameterCount() == 0) {
-                final Object event = constructor.newInstance();
-                final PropertyDomainEvent<S, T> pde = uncheckedCast(event);
-                pde.initSource(source);
-                pde.setIdentifier(identifier);
-                pde.setOldValue(oldValue);
-                pde.setNewValue(newValue);
-                return pde;
-            }
+        val constructors = _Reflect.getPublicConstructors(type);
+
+        val noArgConstructors = constructors.filter(paramCount(0));
+        
+        for (val constructor : noArgConstructors) {
+            final Object event = constructor.newInstance();
+            final PropertyDomainEvent<S, T> pde = uncheckedCast(event);
+            pde.initSource(source);
+            pde.setIdentifier(identifier);
+            pde.setOldValue(oldValue);
+            pde.setNewValue(newValue);
+            return pde;
         }
 
         // else
-        for (final Constructor<?> constructor : constructors) {
-            final Class<?>[] parameterTypes = constructor.getParameterTypes();
-            if(parameterTypes.length != 4) {
-                continue;
-            }
-            if(!parameterTypes[0].isAssignableFrom(source.getClass())) {
-                continue;
-            }
-            if(!parameterTypes[1].isAssignableFrom(Identifier.class)) {
-                continue;
-            }
-            if(oldValue != null && !parameterTypes[2].isAssignableFrom(oldValue.getClass())) {
-                continue;
-            }
-            if(newValue != null && !parameterTypes[3].isAssignableFrom(newValue.getClass())) {
-                continue;
-            }
-            final Object event = constructor.newInstance(source, identifier, oldValue, newValue);
+        val updateEventConstructors = constructors
+                .filter(paramCount(4)
+                        .and(paramAssignableFrom(0, source.getClass()))
+                        .and(paramAssignableFrom(1, Identifier.class))
+                        .and(paramAssignableFromValue(2, oldValue))
+                        .and(paramAssignableFromValue(3, newValue))
+                        );
+        
+        for (val constructor : updateEventConstructors) {
+            val event = constructor.newInstance(source, identifier, oldValue, newValue);
             return uncheckedCast(event);
         }
 
+        // else
         throw new NoSuchMethodException(type.getName()+".<init>(? super " + source.getClass().getName() + ", " + Identifier.class.getName() + ", java.lang.Object, java.lang.Object)");
     }
 
@@ -352,88 +343,57 @@ public class DomainEventHelper {
                             throws NoSuchMethodException, SecurityException, InstantiationException,
                             IllegalAccessException, IllegalArgumentException, InvocationTargetException {
 
-        final Constructor<?>[] constructors = type.getConstructors();
-
-        // no-arg constructor
-        for (final Constructor<?> constructor : constructors) {
-            if(constructor.getParameterCount() == 0) {
-                final Object event = constructor.newInstance();
-                final CollectionDomainEvent<S, T> cde = uncheckedCast(event);
+        val constructors = _Reflect.getPublicConstructors(type);
 
-                cde.initSource(source);
-                cde.setIdentifier(identifier);
-                cde.setOf(of);
-                cde.setValue(value);
-                return cde;
-            }
+        val noArgConstructors = constructors.filter(paramCount(0));
+        
+        for (val constructor : noArgConstructors) {
+            final Object event = constructor.newInstance();
+            final CollectionDomainEvent<S, T> cde = uncheckedCast(event);
+
+            cde.initSource(source);
+            cde.setIdentifier(identifier);
+            cde.setOf(of);
+            cde.setValue(value);
+            return cde;
         }
-
+        
+        // else
         // search for constructor accepting source, identifier, type, value
-        for (final Constructor<?> constructor : constructors) {
-            final Class<?>[] parameterTypes = constructor.getParameterTypes();
-            if(parameterTypes.length != 4) {
-                continue;
-            }
-            if(!parameterTypes[0].isAssignableFrom(source.getClass())) {
-                continue;
-            }
-            if(!parameterTypes[1].isAssignableFrom(Identifier.class)) {
-                continue;
-            }
-            if(!parameterTypes[2].isAssignableFrom(CollectionDomainEvent.Of.class)) {
-                continue;
-            }
-            if(value != null && !parameterTypes[3].isAssignableFrom(value.getClass())) {
-                continue;
-            }
-            final Object event = constructor.newInstance(source, identifier, of, value);
+        val updateEventConstructors = constructors
+                .filter(paramCount(4)
+                        .and(paramAssignableFrom(0, source.getClass()))
+                        .and(paramAssignableFrom(1, Identifier.class))
+                        .and(paramAssignableFrom(2, CollectionDomainEvent.Of.class))
+                        .and(paramAssignableFromValue(3, value))
+                        );
+        
+        for (val constructor : updateEventConstructors) {
+            val event = constructor.newInstance(source, identifier, of, value);
             return uncheckedCast(event);
         }
+        
+        // else
 
         if(phase == AbstractDomainEvent.Phase.EXECUTED) {
-            if(of == CollectionDomainEvent.Of.ADD_TO) {
-                // support for @PostsCollectionAddedTo annotation:
+            if(of == CollectionDomainEvent.Of.ADD_TO 
+                    || of == CollectionDomainEvent.Of.REMOVE_FROM) {
+                // support for annotations @PostsCollectionAddedTo and @PostsCollectionRemovedFrom:
                 // search for constructor accepting source, identifier, value
-                for (final Constructor<?> constructor : constructors) {
-                    final Class<?>[] parameterTypes = constructor.getParameterTypes();
-                    if(parameterTypes.length != 3) {
-                        continue;
-                    }
-                    if(!parameterTypes[0].isAssignableFrom(source.getClass())) {
-                        continue;
-                    }
-                    if(!parameterTypes[1].isAssignableFrom(Identifier.class)) {
-                        continue;
-                    }
-                    if(value != null && !parameterTypes[2].isAssignableFrom(value.getClass())) {
-                        continue;
-                    }
-                    final Object event = constructor.newInstance(source, identifier, value);
-                    return uncheckedCast(event);
-                }
-            } else if(of == CollectionDomainEvent.Of.REMOVE_FROM) {
-                // support for @PostsCollectionRemovedFrom annotation:
-                // search for constructor accepting source, identifier, value
-                for (final Constructor<?> constructor : constructors) {
-                    final Class<?>[] parameterTypes = constructor.getParameterTypes();
-                    if(parameterTypes.length != 3) {
-                        continue;
-                    }
-                    if(!parameterTypes[0].isAssignableFrom(source.getClass())) {
-                        continue;
-                    }
-                    if(!parameterTypes[1].isAssignableFrom(Identifier.class)) {
-                        continue;
-                    }
-                    if(value != null && !parameterTypes[2].isAssignableFrom(value.getClass())) {
-                        continue;
-                    }
-                    final Object event = constructor.newInstance(
-                            source, identifier, value);
+                val eventConstructors = constructors
+                        .filter(paramCount(3)
+                                .and(paramAssignableFrom(0, source.getClass()))
+                                .and(paramAssignableFrom(1, Identifier.class))
+                                .and(paramAssignableFromValue(2, value))
+                                );
+                for (val constructor : eventConstructors) {
+                    val event = constructor.newInstance(source, identifier, of, value);
                     return uncheckedCast(event);
                 }
             }
         }
+        
+        // else
         throw new NoSuchMethodException(type.getName()+".<init>(? super " + source.getClass().getName() + ", " + Identifier.class.getName() + ", java.lang.Object)");
     }
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/jaxb/JaxbFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/jaxb/JaxbFacetFactory.java
index ba17599..bdbd35a 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/jaxb/JaxbFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/jaxb/JaxbFacetFactory.java
@@ -19,7 +19,6 @@
 
 package org.apache.isis.core.metamodel.facets.jaxb;
 
-import java.lang.reflect.Constructor;
 import java.lang.reflect.Modifier;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
@@ -36,8 +35,8 @@ import javax.xml.bind.annotation.XmlTransient;
 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 
 import org.apache.isis.core.commons.internal.collections._Lists;
+import org.apache.isis.core.commons.internal.reflection._Reflect;
 import org.apache.isis.core.config.IsisConfiguration;
-import org.apache.isis.core.metamodel.commons.MethodUtil;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facetapi.FeatureType;
 import org.apache.isis.core.metamodel.facetapi.MetaModelRefiner;
@@ -53,6 +52,11 @@ import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
 import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidator;
 import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorVisiting;
 
+import static org.apache.isis.core.commons.internal.reflection._Reflect.Filter.isPublic;
+import static org.apache.isis.core.commons.internal.reflection._Reflect.Filter.paramCount;
+
+import lombok.val;
+
 /**
  * just adds a validator
  */
@@ -385,25 +389,33 @@ implements MetaModelRefiner {
                 final ObjectSpecification objectSpec,
                 final MetaModelValidator validator) {
 
-            final Class<?> correspondingClass = objectSpec.getCorrespondingClass();
-            final Constructor<?>[] constructors = correspondingClass.getDeclaredConstructors();
-            for (Constructor<?> constructor : constructors) {
-                if(constructor.getParameterCount() == 0) {
-                    if (!MethodUtil.isPublic(constructor)) {
-                        validator.onFailure(
-                                objectSpec,
-                                objectSpec.getIdentifier(),
-                                "JAXB view model '%s' has a no-arg constructor, however it is not public",
-                                objectSpec.getFullIdentifier());
-                    }
-                    return;
-                }
+            val correspondingClass = objectSpec.getCorrespondingClass();
+            
+            val publicNoArgConstructors = _Reflect
+                    .getPublicConstructors(correspondingClass)
+                    .filter(paramCount(0));
+            
+            if(publicNoArgConstructors.getCardinality().isOne()) {
+                return; // happy case
+            }
+            
+            val privateNoArgConstructors = _Reflect
+                    .getDeclaredConstructors(correspondingClass)
+                    .filter(paramCount(0).and(isPublic().negate()));
+            
+            if(privateNoArgConstructors.isNotEmpty()) {
+                validator.onFailure(
+                        objectSpec,
+                        objectSpec.getIdentifier(),
+                        "JAXB view model '%s' has a no-arg constructor, however it is not public",
+                        objectSpec.getFullIdentifier());
+            } else {
+                validator.onFailure(
+                        objectSpec,
+                        objectSpec.getIdentifier(),
+                        "JAXB view model '%s' does not have a public no-arg constructor", 
+                        objectSpec.getFullIdentifier());
             }
-            validator.onFailure(
-                    objectSpec,
-                    objectSpec.getIdentifier(),
-                    "JAXB view model '%s' does not have a public no-arg constructor", 
-                    objectSpec.getFullIdentifier());
         }
     }
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MetaModelValidatorForMixinTypes.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MetaModelValidatorForMixinTypes.java
index 834115f..683dfb5 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MetaModelValidatorForMixinTypes.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MetaModelValidatorForMixinTypes.java
@@ -23,7 +23,10 @@ import org.apache.isis.core.commons.internal.reflection._Reflect;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorForValidationFailures;
 
+import static org.apache.isis.core.commons.internal.reflection._Reflect.Filter.paramCount;
+
 import lombok.NonNull;
+import lombok.val;
 
 public class MetaModelValidatorForMixinTypes extends MetaModelValidatorForValidationFailures {
 
@@ -37,17 +40,30 @@ public class MetaModelValidatorForMixinTypes extends MetaModelValidatorForValida
             @NonNull FacetHolder facetHolder,
             final Class<?> candidateMixinType) {
 
-        if (_Reflect.hasPublic1ArgConstructor(candidateMixinType)) {
-            return true;
-        }
+        val mixinContructors = _Reflect
+                .getPublicConstructors(candidateMixinType)
+                .filter(paramCount(1));
         
-        onFailure(
-                facetHolder,
-                Identifier.classIdentifier(candidateMixinType),
-                "%s: annotated with %s annotation but does not have a public 1-arg constructor",
-                candidateMixinType.getName(), 
-                annotation);
+        if(mixinContructors.getCardinality().isOne()) {
+            return true; // happy case
+        }
         
+        if(mixinContructors.getCardinality().isZero()) {
+            onFailure(
+                    facetHolder,
+                    Identifier.classIdentifier(candidateMixinType),
+                    "%s: annotated with %s annotation but does not have a public 1-arg constructor",
+                    candidateMixinType.getName(), 
+                    annotation);
+        } else {
+            onFailure(
+                    facetHolder,
+                    Identifier.classIdentifier(candidateMixinType),
+                    "%s: annotated with %s annotation needs a single public 1-arg constructor but has %d",
+                    candidateMixinType.getName(), 
+                    annotation,
+                    mixinContructors.size());
+        }
         return false;
     }
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacetForDomainObjectAnnotation.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacetForDomainObjectAnnotation.java
index fed0b78..ecc9c0a 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacetForDomainObjectAnnotation.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacetForDomainObjectAnnotation.java
@@ -29,7 +29,9 @@ import org.apache.isis.core.commons.internal.reflection._Reflect;
 import org.apache.isis.core.metamodel.facetapi.Facet;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 
-import lombok.val;
+import static org.apache.isis.core.commons.internal.reflection._Reflect.Filter.paramCount;
+
+import lombok.val; 
 
 public class MixinFacetForDomainObjectAnnotation extends MixinFacetAbstract {
 
@@ -56,9 +58,11 @@ public class MixinFacetForDomainObjectAnnotation extends MixinFacetAbstract {
                 .filter(domainObject -> domainObject.nature() == Nature.MIXIN)
                 .map(domainObject -> {
                     
-                    val constructorIfAny = _Reflect.getPublic1ArgConstructor(candidateMixinType);
+                    val mixinContructors = _Reflect
+                            .getPublicConstructors(candidateMixinType)
+                            .filter(paramCount(1));
                     
-                    return constructorIfAny
+                    return mixinContructors.getSingleton() // empty if cardinality!=1
                     .map(constructor -> new MixinFacetForDomainObjectAnnotation(
                                 candidateMixinType, 
                                 domainObject.mixinMethod(), 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacetForMixinAnnotation.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacetForMixinAnnotation.java
index 8927cc3..f52fd77 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacetForMixinAnnotation.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacetForMixinAnnotation.java
@@ -27,6 +27,8 @@ import org.apache.isis.core.commons.internal.reflection._Reflect;
 import org.apache.isis.core.metamodel.facetapi.Facet;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 
+import static org.apache.isis.core.commons.internal.reflection._Reflect.Filter.paramCount;
+
 import lombok.val;
 
 public class MixinFacetForMixinAnnotation extends MixinFacetAbstract {
@@ -50,8 +52,11 @@ public class MixinFacetForMixinAnnotation extends MixinFacetAbstract {
             final FacetHolder facetHolder,
             final ServiceInjector servicesInjector) {
         
-        val constructorIfAny = _Reflect.getPublic1ArgConstructor(candidateMixinType);
-        return constructorIfAny
+        val mixinContructors = _Reflect
+                .getPublicConstructors(candidateMixinType)
+                .filter(paramCount(1));
+        
+        return mixinContructors.getSingleton() // empty if cardinality!=1 
                 .map(constructor -> new MixinFacetForMixinAnnotation(
                         candidateMixinType, 
                         mixin.method(), 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/create/ObjectCreator.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/create/ObjectCreator.java
index 7ddd48d..52adc96 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/create/ObjectCreator.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/create/ObjectCreator.java
@@ -75,7 +75,7 @@ public interface ObjectCreator {
         return request -> chainOfRespo
                 .handle(request)
                 .orElseThrow(()->_Exceptions.unrecoverableFormatted(
-                        "ObjectLoader failed to hanlde request %s", request));
+                        "ObjectCreator failed to hanlde request %s", request));
         
     }
     
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/create/ObjectCreator_builtinHandlers.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/create/ObjectCreator_builtinHandlers.java
index 03e1c628..a2bb3ec 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/create/ObjectCreator_builtinHandlers.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/create/ObjectCreator_builtinHandlers.java
@@ -60,8 +60,6 @@ final class ObjectCreator_builtinHandlers {
         @Override
         public ManagedObject handle(ObjectCreator.Request objectCreateRequest) {
             
-            //XXX legacy of objectAdapterContext.objectCreationMixin.newInstance(objectSpec);
-            
             val spec = objectCreateRequest.getObjectSpecification();
             
             if (log.isDebugEnabled()) {
@@ -107,9 +105,6 @@ final class ObjectCreator_builtinHandlers {
             .forEach(field->field.toDefault(adapter));
 
              val pojo = adapter.getPojo();
-            
-            //XXX pojo already got everything injected above
-            //metaModelContext.getServiceInjector().injectServicesInto(pojo);
 
             CallbackFacet.Util.callCallback(adapter, CreatedCallbackFacet.class);
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/identify/ObjectIdentifier_builtinHandlers.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/identify/ObjectIdentifier_builtinHandlers.java
index 28781e7..7df40f0 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/identify/ObjectIdentifier_builtinHandlers.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/identify/ObjectIdentifier_builtinHandlers.java
@@ -61,7 +61,7 @@ class ObjectIdentifier_builtinHandlers {
         @Override
         public RootOid handle(ManagedObject managedObject) {
             final String identifier = SERVICE_IDENTIFIER;
-            return Oid.Factory.persistentOf(managedObject.getSpecification().getSpecId(), identifier);
+            return Oid.Factory.of(managedObject.getSpecification().getSpecId(), identifier);
         }
 
     }
@@ -83,7 +83,7 @@ class ObjectIdentifier_builtinHandlers {
                 throw _Exceptions.unrecoverable(msg);
             }
             val identifier = entityFacet.identifierFor(spec, pojo);
-            return Oid.Factory.persistentOf(spec.getSpecId(), identifier);
+            return Oid.Factory.of(spec.getSpecId(), identifier);
         }
 
     }
@@ -130,7 +130,7 @@ class ObjectIdentifier_builtinHandlers {
         public RootOid handle(ManagedObject managedObject) {
             val spec = managedObject.getSpecification();
             val identifier = UUID.randomUUID().toString();
-            return Oid.Factory.transientOf(spec.getSpecId(), identifier);
+            return Oid.Factory.of(spec.getSpecId(), identifier);
         }
 
     }
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 c5a1506..3094598 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
@@ -19,7 +19,6 @@
 
 package org.apache.isis.core.runtimeservices.factory;
 
-import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 
 import javax.inject.Inject;
@@ -30,20 +29,21 @@ import org.springframework.context.annotation.Primary;
 import org.springframework.core.annotation.Order;
 import org.springframework.stereotype.Service;
 
-import org.apache.isis.applib.NonRecoverableException;
-import org.apache.isis.applib.ViewModel;
 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.exceptions._Exceptions;
+import org.apache.isis.core.commons.internal.reflection._Reflect;
 import org.apache.isis.core.metamodel.facets.object.mixin.MixinFacet;
 import org.apache.isis.core.metamodel.facets.object.viewmodel.ViewModelFacet;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
-import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
 import org.apache.isis.core.runtime.session.IsisSessionFactory;
 
 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.val;
 
@@ -60,37 +60,38 @@ public class FactoryServiceDefault implements FactoryService {
 
     @Override
     public <T> T instantiate(final Class<T> domainClass) {
-        final ObjectSpecification spec = specificationLoader.loadSpecification(domainClass);
-        final ManagedObject adapter = ManagedObject._newTransientInstance(spec); 
+        val spec = specificationLoader.loadSpecification(domainClass);
+        val adapter = ManagedObject._newTransientInstance(spec); 
         return _Casts.uncheckedCast(adapter.getPojo());
     }
 
     @Override
     public <T> T mixin(final Class<T> mixinClass, final Object mixedIn) {
-        final ObjectSpecification objectSpec = specificationLoader.loadSpecification(mixinClass);
-        final MixinFacet mixinFacet = objectSpec.getFacet(MixinFacet.class);
+        val objectSpec = specificationLoader.loadSpecification(mixinClass);
+        val mixinFacet = objectSpec.getFacet(MixinFacet.class);
         if(mixinFacet == null) {
-            throw new NonRecoverableException("Class '" + mixinClass.getName() + " is not a mixin");
+            throw _Exceptions.illegalArgument("Class '%s'  is not a mixin", mixinClass.getName());
         }
         if(!mixinFacet.isMixinFor(mixedIn.getClass())) {
-            throw new NonRecoverableException("Mixin class '" + mixinClass.getName() + " is not a mixin for supplied object '" + mixedIn + "'");
+            throw _Exceptions.illegalArgument("Mixin class '%s' is not a mixin for supplied object '%s'",
+                    mixinClass.getName(), mixedIn);
         }
-        final Constructor<?>[] constructors = mixinClass.getConstructors();
-        for (Constructor<?> constructor : constructors) {
-            if(constructor.getParameterTypes().length == 1 &&
-                    constructor.getParameterTypes()[0].isAssignableFrom(mixedIn.getClass())) {
-                final Object mixin;
-                try {
-                    mixin = constructor.newInstance(mixedIn);
-                    return _Casts.uncheckedCast(serviceInjector.injectServicesInto(mixin));
-                } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
-                    throw new NonRecoverableException(e);
-                }
-            }
+        val mixinConstructor = _Reflect
+                .getPublicConstructors(mixinClass) 
+                        .filter(paramCount(1).and(paramAssignableFrom(0, mixedIn.getClass())))
+                .getSingleton()
+                .orElseThrow(()->_Exceptions.illegalArgument(
+                        "Failed to locate constructor in '%s' to instantiate using '%s'", 
+                        mixinClass.getName(), mixedIn));
+        
+        try {
+            val mixin = mixinConstructor.newInstance(mixedIn);
+            return _Casts.uncheckedCast(serviceInjector.injectServicesInto(mixin));
+        } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
+            throw _Exceptions.illegalArgument(
+                    "Failed to invoke constructor of '%s' using single argument '%s'", 
+                    mixinClass.getName(), mixedIn);
         }
-        // should never get here because of previous guards
-        throw new NonRecoverableException( String.format(
-                "Failed to locate constructor in %s to instantiate using %s", mixinClass.getName(), mixedIn));
     }
 
     @Override
@@ -99,16 +100,9 @@ public class FactoryServiceDefault implements FactoryService {
 
         val spec = specificationLoader.loadSpecification(viewModelClass);
         if (!spec.containsFacet(ViewModelFacet.class)) {
-            val msg = String.format("Type '%s' must be recogniced as a ViewModel, that is the type's meta-model "
+            throw _Exceptions.illegalArgument("Type '%s' must be recogniced as a ViewModel, "
+                    + "that is the type's meta-model "
                     + "must have an associated ViewModelFacet: ", viewModelClass.getName());
-            throw new IllegalArgumentException(msg);
-        }
-
-        if(ViewModel.class.isAssignableFrom(viewModelClass)) {
-            //FIXME[2152] is this execution branch required, or does the below code suffice for all cases?
-            val viewModel = (ViewModel) instantiate(viewModelClass);
-            viewModel.viewModelInit(mementoStr);
-            return _Casts.uncheckedCast(viewModel);
         }
 
         val viewModelFacet = spec.getFacet(ViewModelFacet.class);