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 2019/10/15 10:08:29 UTC

[isis] branch v2 updated: ISIS-2158: change naming strategy for managed-beans

This is an automated email from the ASF dual-hosted git repository.

ahuber pushed a commit to branch v2
in repository https://gitbox.apache.org/repos/asf/isis.git


The following commit(s) were added to refs/heads/v2 by this push:
     new e3d9cf0  ISIS-2158: change naming strategy for managed-beans
e3d9cf0 is described below

commit e3d9cf0bdb60dda026af4bdd2547d704bd6c6cb9
Author: Andi Huber <ah...@apache.org>
AuthorDate: Tue Oct 15 12:08:11 2019 +0200

    ISIS-2158: change naming strategy for managed-beans
    
    - the bean-name for managed-beans is already required before meta-model
    creation
    - so we allow @DomainService(objectType=) to override the bean-name as
    recognized by Spring immediately after the scan-phase (before the
    post-construct phase begins)
    - later during meta-model creation, the bean-name as determined above
    gets projected into the corresponding meta-model facets; this replaces
    the previous behavior of looking up the bean name using annotation
    inspection and other naming strategies
    - hence the getId() naming strategy for services is no longer supported
---
 .../IsisBeanFactoryPostProcessorForSpring.java     |  10 +-
 .../config/beans/IsisComponentScanInterceptor.java |  23 +++-
 .../isis/config/registry/IsisBeanTypeRegistry.java |  76 +++++-------
 .../apache/isis/config/registry/TypeMetaData.java  |  77 +++++-------
 ...jectSpecIdFacetDerivedFromClassNameFactory.java |  23 ++--
 ...ctSpecIdFacetDerivedFromIoCNamingStrategy.java} |   7 +-
 .../isis/metamodel/services/ServiceUtil.java       | 135 +--------------------
 .../services/layout/LayoutServiceDefault.java      |   3 +-
 .../services/registry/ServiceRegistryDefault.java  |   5 -
 .../isis/metamodel/spec/ObjectSpecification.java   |  14 ++-
 .../specloader/SpecificationLoaderDefault.java     |   9 +-
 .../specimpl/dflt/ObjectSpecificationDefault.java  |  16 ++-
 .../ObjectSpecificationOnStandaloneList.java       |   7 ++
 .../isis/metamodel/services/ServiceUtil_Test.java  | 104 ----------------
 .../testspec/ObjectSpecificationStub.java          |   6 +
 .../menubars/bootstrap3/MenuBarsServiceBS3.java    |   1 -
 .../java/domainapp/application/menubars.layout.xml |  24 ++--
 .../dom/actions/assoc/AssociatedActionMenu.java    |   2 +-
 .../dom/actions/async/AsyncActionMenu.java         |   2 +-
 .../actions/depargs/DependentArgsActionMenu.java   |   2 +-
 .../main/java/domainapp/dom/error/ErrorMenu.java   |   2 +-
 .../java/domainapp/dom/events/EventLogMenu.java    |   2 +-
 .../src/main/java/domainapp/dom/jee/JeeMenu.java   |   2 +-
 .../java/domainapp/dom/tooltip/TooltipMenu.java    |   2 +-
 .../main/java/domainapp/dom/tree/TreeDemoMenu.java |   2 +-
 .../domainapp/dom/types/FeaturedTypesMenu.java     |   2 +-
 26 files changed, 165 insertions(+), 393 deletions(-)

diff --git a/core/config/src/main/java/org/apache/isis/config/beans/IsisBeanFactoryPostProcessorForSpring.java b/core/config/src/main/java/org/apache/isis/config/beans/IsisBeanFactoryPostProcessorForSpring.java
index 549391c..47761cd 100644
--- a/core/config/src/main/java/org/apache/isis/config/beans/IsisBeanFactoryPostProcessorForSpring.java
+++ b/core/config/src/main/java/org/apache/isis/config/beans/IsisBeanFactoryPostProcessorForSpring.java
@@ -69,13 +69,15 @@ public class IsisBeanFactoryPostProcessorForSpring implements BeanFactoryPostPro
                 continue; // check next beanDefinition
             }
             
-            val typeMetaData = TypeMetaData.of(beanDefinition.getBeanClassName());
+            val typeMetaData = TypeMetaData.of(
+                    beanDefinition.getBeanClassName(),
+                    beanDefinitionName);
             
-            val injectable = interceptor.isInjectable(typeMetaData);
+            interceptor.intercept(typeMetaData);
             
-            if(injectable) {
+            if(typeMetaData.isInjectable()) {
                 
-                val beanNameOverride = interceptor.getBeanNameOverride(typeMetaData);
+                val beanNameOverride = typeMetaData.getBeanNameOverride(); 
                 if(beanNameOverride!=null) {
                     registry.removeBeanDefinition(beanDefinitionName);
                     registry.registerBeanDefinition(beanNameOverride, beanDefinition);
diff --git a/core/config/src/main/java/org/apache/isis/config/beans/IsisComponentScanInterceptor.java b/core/config/src/main/java/org/apache/isis/config/beans/IsisComponentScanInterceptor.java
index ff5a5c1..08cbabd 100644
--- a/core/config/src/main/java/org/apache/isis/config/beans/IsisComponentScanInterceptor.java
+++ b/core/config/src/main/java/org/apache/isis/config/beans/IsisComponentScanInterceptor.java
@@ -31,21 +31,34 @@ import org.apache.isis.config.registry.TypeMetaData;
 public interface IsisComponentScanInterceptor {
 
     /**
-     * Whether given {@link Component} annotated or meta-annotated type should be made
+     * Allows for the given type-meta to by modified before bean-definition registration 
+     * is finalized by the IoC immediately after the type-scan phase. 
+     * Supported aspects to be modified: 
+     * <p>- Whether given {@link Component} annotated or meta-annotated type should be made
      * available for injection.
+     * <p>- Naming strategy to override that of the IoC.
+     * 
      * @param type
      * @apiNote implementing classes might have side effects, eg. intercept 
      * discovered types into a type registry
      */
-    boolean isInjectable(TypeMetaData type);
-    
-    String getBeanNameOverride(TypeMetaData type);
+    void intercept(TypeMetaData type);
 
     /**
+     * If given type is available for injection, returns the <em>Managed Bean's</em> name (id) as
+     * recognized by the IoC container, {@code null} otherwise;
+     * @param type
+     * @return
+     */
+    String getManagedBeanNameForType(Class<?> type);
+    
+    /**
      * Whether given type is available for injection. Is a <em>Managed Bean</em>. 
      * @param type
      * @return 
      */
-    boolean isManagedBean(Class<?> type);
+    default boolean isManagedBean(Class<?> type) {
+        return getManagedBeanNameForType(type)!=null;
+    }
     
 }
diff --git a/core/config/src/main/java/org/apache/isis/config/registry/IsisBeanTypeRegistry.java b/core/config/src/main/java/org/apache/isis/config/registry/IsisBeanTypeRegistry.java
index e68bcf9..ca303f0 100644
--- a/core/config/src/main/java/org/apache/isis/config/registry/IsisBeanTypeRegistry.java
+++ b/core/config/src/main/java/org/apache/isis/config/registry/IsisBeanTypeRegistry.java
@@ -73,14 +73,13 @@ public final class IsisBeanTypeRegistry implements IsisComponentScanInterceptor,
 
     // -- DISTINCT CATEGORIES OF BEAN SORTS
     
-    @Getter private final Set<Class<?>> managedBeanTypes = new HashSet<>();
+    @Getter private final Map<Class<?>, String> managedBeanNamesByType = new HashMap<>();
     @Getter private final Set<Class<?>> entityTypes = new HashSet<>();
     @Getter private final Set<Class<?>> mixinTypes = new HashSet<>();
     @Getter private final Set<Class<?>> viewModelTypes = new HashSet<>();
     @Getter private final Set<Class<?>> vetoedTypes = _Sets.newConcurrentHashSet();
     
     private final List<Set<? extends Class<? extends Object>>> allCategorySets = _Lists.of(
-            managedBeanTypes,
             entityTypes,
             mixinTypes,
             viewModelTypes,
@@ -96,25 +95,27 @@ public final class IsisBeanTypeRegistry implements IsisComponentScanInterceptor,
 //            return;
 //        }
 
+        managedBeanNamesByType.clear();
         introspectableTypes.clear();
         allCategorySets.forEach(Set::clear);
     }
 
     // -- INBOX
 
-    public void addIntrospectableType(BeanSort sort, Class<?> type) {
+    public void addIntrospectableType(BeanSort sort, TypeMetaData typeMeta) {
+        val type = typeMeta.getUnderlyingClass();
         synchronized (introspectableTypes) {
             introspectableTypes.put(type, sort);
             
             switch (sort) {
             case MANAGED_BEAN:
-                managedBeanTypes.add(type);
+                managedBeanNamesByType.put(type, typeMeta.getEffectiveBeanName());
                 return;
             case MIXIN:
                 mixinTypes.add(type);
                 return;
             case ENTITY:
-                entityTypes.add(type); //TODO redundant
+                entityTypes.add(type);
                 return;
             case VIEW_MODEL:
                 viewModelTypes.add(type);
@@ -154,55 +155,27 @@ public final class IsisBeanTypeRegistry implements IsisComponentScanInterceptor,
     // -- FILTER
 
     @Override
-    public boolean isInjectable(TypeMetaData typeMeta) {
+    public void intercept(TypeMetaData typeMeta) {
         
         val type = typeMeta.getUnderlyingClass();
-        
-        intercept(type);
-        
-        if(findNearestAnnotation(type, DomainObject.class).isPresent()) {
-            return false; // reject
-        }
-        
-        if(findNearestAnnotation(type, ViewModel.class).isPresent()) {
-            return false; // reject
-        }
-        
-        if(findNearestAnnotation(type, Mixin.class).isPresent()) {
-            return false; // reject
-        }
-        
-        if(findNearestAnnotation(type, Vetoed.class).isPresent()) {
-            return false; // reject
-        }
-        
-        return true;
-    }
-    
-    @Override
-    public String getBeanNameOverride(TypeMetaData typeMeta) {
-        return extractObjectType(typeMeta.getUnderlyingClass()).orElse(null);
-    }
-    
-    @Override
-    public boolean isManagedBean(Class<?> type) {
-        if(vetoedTypes.contains(type)) { // vetos are coming from the spec-loader during init
-            return false;
-        }
-        return managedBeanTypes.contains(type);
-    }
-    
-    // -- HELPER
-    
-    private void intercept(Class<?> type) {
-
         val beanSort = quickClassify(type);
 
+        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(typeMeta.getUnderlyingClass()).orElse(null));
+        }
+        
         val isToBeRegistered = beanSort.isManagedBean();
         val isToBeInspected = !beanSort.isUnknown();
 
         if(isToBeInspected) {
-            addIntrospectableType(beanSort, type);
+            addIntrospectableType(beanSort, typeMeta);
         }
 
         if(log.isDebugEnabled()) {
@@ -214,7 +187,18 @@ public final class IsisBeanTypeRegistry implements IsisComponentScanInterceptor,
             }
         }
 
+        
     }
+    
+    @Override
+    public String getManagedBeanNameForType(Class<?> type) {
+        if(vetoedTypes.contains(type)) { // vetos are coming from the spec-loader during init
+            return null;
+        }
+        return managedBeanNamesByType.get(type);
+    }
+    
+    // -- HELPER
 
     // the SpecLoader does a better job at this
     private BeanSort quickClassify(Class<?> type) {
diff --git a/core/config/src/main/java/org/apache/isis/config/registry/TypeMetaData.java b/core/config/src/main/java/org/apache/isis/config/registry/TypeMetaData.java
index 02d4ee8..3bc7626 100644
--- a/core/config/src/main/java/org/apache/isis/config/registry/TypeMetaData.java
+++ b/core/config/src/main/java/org/apache/isis/config/registry/TypeMetaData.java
@@ -18,52 +18,42 @@
  */
 package org.apache.isis.config.registry;
 
+import org.apache.isis.commons.internal.base._Strings;
 import org.apache.isis.commons.internal.context._Context;
 import org.apache.isis.commons.internal.exceptions._Exceptions;
 
 import lombok.Getter;
-import lombok.Value;
+import lombok.RequiredArgsConstructor;
+import lombok.Setter;
 import lombok.val;
 
-@Value(staticConstructor="of")
+@RequiredArgsConstructor(staticName = "of")
 public final class TypeMetaData {
 
     /**
      * Fully qualified name of the underlying class.
      */
-    String className;
-
-    //    /**
-    //     * Fully qualified class names of all annotation types that are present on the underlying class.
-    //     */
-    //    Set<String> annotationTypes;
-
-    //    public boolean hasSingletonAnnotation() {
-    //        return annotationTypes.contains(singletonAnnotation);
-    //    }
-    //    
-    //    public boolean hasRequestScopedAnnotation() {
-    //        return annotationTypes.contains(requestScopedAnnotation);
-    //    }
-    //    
-    //    public boolean hasDomainServiceAnnotation() {
-    //        return annotationTypes.contains(domainServiceAnnotation);
-    //    }
-    //    
-    //    public boolean hasDomainObjectAnnotation() {
-    //        return annotationTypes.contains(domainObjectAnnotation);
-    //    }
-    //    
-    //    public boolean hasMixinAnnotation() {
-    //        return annotationTypes.contains(mixinAnnotation);
-    //    }
-    //    
-    //    public boolean hasViewModelAnnotation() {
-    //        return annotationTypes.contains(viewModelAnnotation);
-    //    }
-
+    @Getter private final String className;
+    
+    /**
+     * As proposed by IoC, before any overrides.
+     */
+    @Getter private final String proposedBeanName;
+    
+    /**
+     * Name override, applied only if not empty. 
+     */
+    @Getter @Setter
+    private String beanNameOverride;
+    
+    /**
+     * Whether this type should be made available to resolve injection points.  
+     */
+    @Getter @Setter
+    private boolean injectable = true;
+    
     @Getter(lazy=true)
-    final Class<?> underlyingClass = resolveClass();
+    private final Class<?> underlyingClass = resolveClass();
     
     /**
      * @return the underlying class of this TypeMetaData
@@ -77,20 +67,11 @@ public final class TypeMetaData {
         }
     }
 
-    //    private final static String singletonAnnotation = 
-    //    		javax.inject.Singleton.class.getName();
-    //    private final static String requestScopedAnnotation = 
-    //    		javax.enterprise.context.RequestScoped.class.getName();
-    //    private final static String domainServiceAnnotation = 
-    //            org.apache.isis.applib.annotation.DomainService.class.getName();
-    //    private final static String domainObjectAnnotation = 
-    //            org.apache.isis.applib.annotation.DomainObject.class.getName();
-    //    private final static String mixinAnnotation = 
-    //            org.apache.isis.applib.annotation.Mixin.class.getName();
-    //    private final static String viewModelAnnotation = 
-    //            org.apache.isis.applib.annotation.ViewModel.class.getName();
-
-
+    public String getEffectiveBeanName() {
+        return _Strings.isNullOrEmpty(beanNameOverride)
+                ? proposedBeanName 
+                        : beanNameOverride;
+    }
 
 
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/object/objectspecid/classname/ObjectSpecIdFacetDerivedFromClassNameFactory.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/object/objectspecid/classname/ObjectSpecIdFacetDerivedFromClassNameFactory.java
index 2f4b275..597ca89 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/object/objectspecid/classname/ObjectSpecIdFacetDerivedFromClassNameFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/object/objectspecid/classname/ObjectSpecIdFacetDerivedFromClassNameFactory.java
@@ -33,7 +33,6 @@ import org.apache.isis.metamodel.facets.ObjectSpecIdFacetFactory;
 import org.apache.isis.metamodel.facets.object.domainservice.DomainServiceFacet;
 import org.apache.isis.metamodel.facets.object.objectspecid.ObjectSpecIdFacet;
 import org.apache.isis.metamodel.progmodel.ProgrammingModel;
-import org.apache.isis.metamodel.services.ServiceUtil;
 import org.apache.isis.metamodel.spec.ObjectSpecification;
 import org.apache.isis.metamodel.spec.feature.Contributed;
 import org.apache.isis.metamodel.spec.feature.ObjectAction;
@@ -73,24 +72,26 @@ implements MetaModelRefiner, ObjectSpecIdFacetFactory {
     }
 
     private static ObjectSpecIdFacet createObjectSpecIdFacet(
-            final FacetHolder facetHolder, final Class<?> substitutedClass) {
-        final boolean isService = isService(facetHolder);
+            final FacetHolder facetHolder, 
+            final Class<?> substitutedClass) {
+        
+        val serviceId = getServiceId(facetHolder);
+        val isService = serviceId!=null;
+        
         if (isService) {
-
-            final String id = ServiceUtil.getExplicitIdOfType(substitutedClass).orElse(null);
-            if (id != null) {
-                return new ObjectSpecIdFacetDerivedFromDomainServiceAnnotationElseGetId(id, facetHolder);
-            }
+            return new ObjectSpecIdFacetDerivedFromIoCNamingStrategy(serviceId, facetHolder);
         }
         return new ObjectSpecIdFacetDerivedFromClassName(substitutedClass, facetHolder);
     }
 
-    private static boolean isService(final FacetHolder facetHolder) {
+    private static String getServiceId(final FacetHolder facetHolder) {
         if(facetHolder instanceof ObjectSpecification) {
             ObjectSpecification objectSpecification = (ObjectSpecification) facetHolder;
-            return objectSpecification.isManagedBean();
+            if(objectSpecification.isManagedBean()) {
+                return objectSpecification.getManagedBeanName();
+            }
         }
-        return false;
+        return null;
     }
 
     @Override
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/object/objectspecid/classname/ObjectSpecIdFacetDerivedFromDomainServiceAnnotationElseGetId.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/object/objectspecid/classname/ObjectSpecIdFacetDerivedFromIoCNamingStrategy.java
similarity index 82%
rename from core/metamodel/src/main/java/org/apache/isis/metamodel/facets/object/objectspecid/classname/ObjectSpecIdFacetDerivedFromDomainServiceAnnotationElseGetId.java
rename to core/metamodel/src/main/java/org/apache/isis/metamodel/facets/object/objectspecid/classname/ObjectSpecIdFacetDerivedFromIoCNamingStrategy.java
index 91daf65..b4e7002 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/object/objectspecid/classname/ObjectSpecIdFacetDerivedFromDomainServiceAnnotationElseGetId.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/object/objectspecid/classname/ObjectSpecIdFacetDerivedFromIoCNamingStrategy.java
@@ -22,9 +22,12 @@ package org.apache.isis.metamodel.facets.object.objectspecid.classname;
 import org.apache.isis.metamodel.facetapi.FacetHolder;
 import org.apache.isis.metamodel.facets.object.objectspecid.ObjectSpecIdFacetAbstract;
 
-public class ObjectSpecIdFacetDerivedFromDomainServiceAnnotationElseGetId extends ObjectSpecIdFacetAbstract {
+/**
+ * @since 2.0
+ */
+public class ObjectSpecIdFacetDerivedFromIoCNamingStrategy extends ObjectSpecIdFacetAbstract {
 
-    ObjectSpecIdFacetDerivedFromDomainServiceAnnotationElseGetId(final String value, final FacetHolder holder) {
+    ObjectSpecIdFacetDerivedFromIoCNamingStrategy(final String value, final FacetHolder holder) {
         super(value, holder);
     }
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/services/ServiceUtil.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/services/ServiceUtil.java
index c33b1b1..3304d24 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/services/ServiceUtil.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/services/ServiceUtil.java
@@ -18,17 +18,7 @@
  */
 package org.apache.isis.metamodel.services;
 
-import java.io.Serializable;
-import java.lang.reflect.Method;
-import java.util.Optional;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-import javax.enterprise.inject.spi.Bean;
-
-import org.apache.isis.applib.annotation.DomainService;
-import org.apache.isis.commons.internal.base._Strings;
-import org.apache.isis.commons.internal.functions._Functions;
+import org.apache.isis.commons.internal.assertions._Assert;
 import org.apache.isis.metamodel.spec.ManagedObject;
 import org.apache.isis.metamodel.spec.ObjectSpecification;
 
@@ -37,128 +27,15 @@ public final class ServiceUtil {
     private ServiceUtil() {
     }
 
-    //[2033] I found no standardized way yet to do this, maybe create a list during bean-scan?
-    //TODO no longer referenced, remove?
-    private static String idOfBean(final Bean<?> serviceBean) {
-
-        // serviceBean might also be a producer method
-        // eg. org.jboss.weld.bean.ProducerMethod
-
-        final Class<?> serviceClass = serviceBean.getBeanClass();
-
-        final Set<Class<?>> implementedTypes = serviceBean.getTypes().stream()
-                .filter(type->!type.getTypeName().equals(Object.class.getTypeName()))
-                .filter(type->!type.getTypeName().equals(Serializable.class.getTypeName()))
-                .filter(type->type instanceof Class)
-                .map(type->(Class<?>) type)
-                .collect(Collectors.toSet());
-
-
-        for(Class<?> implementing : implementedTypes) {
-            if(implementing.isAssignableFrom(serviceClass)) {
-
-                //TODO [2033] explicitIdOfType() no longer supported ...
-                //    			
-                //    	        return explicitIdOfType(serviceClass, serviceClass::newInstance)
-                //              .orElseGet(()->normalize(serviceClass));
-
-                return normalize(serviceClass);
-            }
-        }
-
-        if(implementedTypes.size()==1) {
-            // we have a producer method
-            return normalize(implementedTypes.iterator().next());	
-        }
-
-        // try to get a name from injection points
-        final Set<Class<?>> requiredTypes = serviceBean.getInjectionPoints().stream()
-                .map(ip->ip.getType())
-                .filter(type->!type.getTypeName().equals(Object.class.getTypeName()))
-                .filter(type->!type.getTypeName().equals(Serializable.class.getTypeName()))
-                .filter(type->type instanceof Class)
-                .map(type->(Class<?>) type)
-                .collect(Collectors.toSet());
-
-        if(requiredTypes.size()==1) {
-            // we found a unique required type as defined by injection points for this bean
-            return normalize(requiredTypes.iterator().next());	
-        }
-
-        return serviceBean.toString();
-
-        //    	throw _Exceptions.unrecoverable(
-        //    			String.format("Could not extract a service id from the given bean '%s', "
-        //    					+ "implementedTypes='%s' requiredTypes='%s' from types %s.", 
-        //    					serviceBean, 
-        //    					implementedTypes,
-        //    					requiredTypes,
-        //    					serviceBean.getTypes()));
-
-
-    }
-
-    public static String idOfPojo(final Object serviceObject) {
-        final Class<?> serviceClass = serviceObject.getClass();
-        return explicitIdOfType(serviceClass, ()->serviceObject)
-                .orElseGet(()->normalize(serviceClass));
-    }
-
     public static String idOfSpec(final ObjectSpecification serviceSpec) {
-        final Class<?> serviceClass = serviceSpec.getCorrespondingClass();
-        return explicitIdOfType(serviceClass, serviceClass::newInstance)
-                .orElseGet(()->normalize(serviceClass));
+        _Assert.assertEquals("expected same", 
+                serviceSpec.getManagedBeanName(), 
+                serviceSpec.getSpecId().asString());
+        return serviceSpec.getManagedBeanName();
     }
 
     public static String idOfAdapter(final ManagedObject serviceAdapter) {
-        return idOfPojo(serviceAdapter.getPojo());
-    }
-
-    public static Optional<String> getExplicitIdOfType(final Class<?> serviceClass) {
-        return explicitIdOfType(serviceClass, serviceClass::newInstance);
-    }
-
-    // -- HELPER
-
-    private static Optional<String> explicitIdOfType(
-            final Class<?> serviceClass, 
-            final _Functions.CheckedSupplier<Object> serviceInstanceSupplier) {
-
-        final String serviceType = serviceTypeUsingAnnotation(serviceClass);
-        if (serviceType != null) {
-            return Optional.of(serviceType);
-        }
-        return serviceTypeUsingIdGetter(serviceClass, serviceInstanceSupplier);
+        return idOfSpec(serviceAdapter.getSpecification());
     }
 
-    private static String serviceTypeUsingAnnotation(final Class<?> serviceClass) {
-        final String serviceType;
-        final DomainService domainService = serviceClass.getAnnotation(DomainService.class);
-        if(domainService != null) {
-            serviceType = domainService.objectType();
-            if(!_Strings.isNullOrEmpty(serviceType)) {
-                return serviceType;
-            }
-        }
-        return null;
-    }
-
-    private static Optional<String> serviceTypeUsingIdGetter(
-            final Class<?> serviceClass, 
-            final _Functions.CheckedSupplier<Object> serviceInstanceSupplier
-            ) {
-
-        try {
-            final Method m = serviceClass.getMethod("getId");
-            return Optional.ofNullable((String) m.invoke(serviceInstanceSupplier.get()));
-        } catch (Exception e) {
-            return Optional.empty();
-        }
-    }
-
-    private static String normalize(Class<?> serviceClass) {
-        return serviceClass.getName();
-    }
-
-
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/services/layout/LayoutServiceDefault.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/services/layout/LayoutServiceDefault.java
index 0abe7df..75c41e3 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/services/layout/LayoutServiceDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/services/layout/LayoutServiceDefault.java
@@ -23,7 +23,6 @@ import java.util.Collection;
 import java.util.List;
 
 import javax.inject.Inject;
-import javax.inject.Singleton;
 import javax.xml.bind.Marshaller;
 
 import org.springframework.stereotype.Service;
@@ -95,7 +94,7 @@ public class LayoutServiceDefault implements LayoutService {
 
         val zipWriter = ZipWriter.ofFailureMessage("Unable to create zip of layouts");
 
-        for (final ObjectSpecification objectSpec : domainObjectSpecs) {
+        for (val objectSpec : domainObjectSpecs) {
             val domainClass = objectSpec.getCorrespondingClass();
             val grid = toGrid(domainClass, style);
             if(grid != null) {
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/services/registry/ServiceRegistryDefault.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/services/registry/ServiceRegistryDefault.java
index e2ebe73..765147a 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/services/registry/ServiceRegistryDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/services/registry/ServiceRegistryDefault.java
@@ -31,7 +31,6 @@ import org.apache.isis.applib.services.registry.ServiceRegistry;
 import org.apache.isis.commons.internal.base._Lazy;
 import org.apache.isis.commons.internal.base._NullSafe;
 import org.apache.isis.commons.internal.collections._Maps;
-import org.apache.isis.commons.internal.debug._Probe;
 import org.apache.isis.commons.internal.environment.IsisSystemEnvironment;
 import org.apache.isis.commons.internal.ioc.ManagedBeanAdapter;
 import org.apache.isis.commons.internal.ioc.spring._Spring;
@@ -65,12 +64,8 @@ public final class ServiceRegistryDefault implements ServiceRegistry {
     private final _Lazy<Map<String, ManagedBeanAdapter>> managedBeansById = 
             _Lazy.threadSafe(this::enumerateManagedBeans);
 
-    private final static _Probe probe = _Probe.maxCallsThenIgnore(5).label("service reg");
-    
     private Map<String, ManagedBeanAdapter> enumerateManagedBeans() {
         
-        probe.println("#### enumerate");
-        
         val filter = IsisBeanTypeRegistry.current();
         val managedBeanAdapterByName = _Maps.<String, ManagedBeanAdapter>newHashMap();
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/spec/ObjectSpecification.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/spec/ObjectSpecification.java
index 3bb747c..63deb83 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/spec/ObjectSpecification.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/spec/ObjectSpecification.java
@@ -358,12 +358,20 @@ ObjectAssociationContainer, Hierarchical,  DefaultProvider {
     boolean isHidden();
 
     /**
-     * Whether this specification represents a bean, that is a managed object
+     * Whether this specification represents a bean, that is a managed bean
      * with scoped life-cycle, available for dependency injection. 
      */
     default boolean isManagedBean() {
-        return getBeanSort().isManagedBean();
+        return getManagedBeanName()!=null;
     }
+    
+    /**
+     * If this specification represents a bean, that is a managed bean, then
+     * returns the bean's name/id as recognized by the IoC container.
+     * <p>Otherwise returns {@code null}. 
+     * @return
+     */
+    String getManagedBeanName();
 
     default boolean isViewModel() {
         return getBeanSort().isViewModel();
@@ -435,4 +443,6 @@ ObjectAssociationContainer, Hierarchical,  DefaultProvider {
     void introspectUpTo(IntrospectionState upTo);
 
 
+
+
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/specloader/SpecificationLoaderDefault.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/specloader/SpecificationLoaderDefault.java
index 35544c1..06f8d07 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/specloader/SpecificationLoaderDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/specloader/SpecificationLoaderDefault.java
@@ -32,7 +32,6 @@ import org.apache.isis.commons.internal.base._Blackhole;
 import org.apache.isis.commons.internal.base._Lazy;
 import org.apache.isis.commons.internal.base._Timing;
 import org.apache.isis.commons.internal.collections._Lists;
-import org.apache.isis.commons.internal.debug._Probe;
 import org.apache.isis.commons.internal.environment.IsisSystemEnvironment;
 import org.apache.isis.config.IsisConfiguration;
 import org.apache.isis.config.registry.IsisBeanTypeRegistry;
@@ -316,8 +315,6 @@ public class SpecificationLoaderDefault implements SpecificationLoader {
 
     // -- HELPER
     
-    private final static _Probe probe = _Probe.maxCallsThenIgnore(5).label("specloader"); 
-
     /**
      * Creates the appropriate type of {@link ObjectSpecification}.
      */
@@ -335,15 +332,13 @@ public class SpecificationLoaderDefault implements SpecificationLoader {
                     new FacetedMethodsBuilderContext(
                             this, facetProcessor);
 
-            probe.println("#### check is managed");
-            
-            val isManagedBean = IsisBeanTypeRegistry.current().isManagedBean(cls);
+            val managedBeanNameIfAny = IsisBeanTypeRegistry.current().getManagedBeanNameForType(cls);
 
             objectSpec = new ObjectSpecificationDefault(
                     cls,
                     facetedMethodsBuilderContext,
                     facetProcessor, 
-                    isManagedBean, 
+                    managedBeanNameIfAny, 
                     postProcessor);
         }
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/specloader/specimpl/dflt/ObjectSpecificationDefault.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/specloader/specimpl/dflt/ObjectSpecificationDefault.java
index d30e80c..3f9d383 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/specloader/specimpl/dflt/ObjectSpecificationDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/specloader/specimpl/dflt/ObjectSpecificationDefault.java
@@ -90,17 +90,21 @@ public class ObjectSpecificationDefault extends ObjectSpecificationAbstract impl
     private Map<Method, ObjectMember> membersByMethod = null;
 
     private final FacetedMethodsBuilder facetedMethodsBuilder;
-    private final boolean isManagedBean;
+    
+    /**
+     * available only for managed-beans
+     */
+    private final String nameIfIsManagedBean;
 
     public ObjectSpecificationDefault(
             final Class<?> correspondingClass,
             final FacetedMethodsBuilderContext facetedMethodsBuilderContext,
             final FacetProcessor facetProcessor,
-            final boolean isManagedBean,
+            final String nameIfIsManagedBean,
             final PostProcessor postProcessor) {
         super(correspondingClass, determineShortName(correspondingClass), facetProcessor, postProcessor);
 
-        this.isManagedBean = isManagedBean;
+        this.nameIfIsManagedBean = nameIfIsManagedBean;
 
         this.facetedMethodsBuilder = new FacetedMethodsBuilder(this, facetedMethodsBuilderContext);
 
@@ -271,10 +275,10 @@ public class ObjectSpecificationDefault extends ObjectSpecificationAbstract impl
     }
 
     @Override
-    public boolean isManagedBean() {
-        return isManagedBean;
+    public String getManagedBeanName() {
+        return nameIfIsManagedBean;
     }
-
+    
     // -- getObjectAction
 
     @Override
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/specloader/specimpl/standalonelist/ObjectSpecificationOnStandaloneList.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/specloader/specimpl/standalonelist/ObjectSpecificationOnStandaloneList.java
index 7dcaed0..971687c 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/specloader/specimpl/standalonelist/ObjectSpecificationOnStandaloneList.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/specloader/specimpl/standalonelist/ObjectSpecificationOnStandaloneList.java
@@ -170,6 +170,13 @@ public class ObjectSpecificationOnStandaloneList extends ObjectSpecificationAbst
                 null);
     }
 
+
+
+    @Override
+    public String getManagedBeanName() {
+        return null; // not a managed-bean
+    }
+
     // --
 
 
diff --git a/core/metamodel/src/test/java/org/apache/isis/metamodel/services/ServiceUtil_Test.java b/core/metamodel/src/test/java/org/apache/isis/metamodel/services/ServiceUtil_Test.java
deleted file mode 100644
index 5e50714..0000000
--- a/core/metamodel/src/test/java/org/apache/isis/metamodel/services/ServiceUtil_Test.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package org.apache.isis.metamodel.services;
-
-import org.junit.Test;
-
-import org.apache.isis.applib.annotation.DomainService;
-
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.nullValue;
-import static org.junit.Assert.assertThat;
-
-public class ServiceUtil_Test {
-
-    @DomainService(objectType = "foo.SomeServiceAnnotated")
-    public static class SomeServiceAnnotated {}
-
-
-    @DomainService()
-    public static class SomeServiceWithId {
-
-        public String getId() {
-            return "bar.SomeServiceWithId";
-        }
-    }
-
-
-    @DomainService(objectType = "bop.SomeServiceAnnotated")
-    public static class SomeServiceAnnotatedAndWithId {
-
-        public String getId() {
-            return "bop.SomeServiceWithId";
-        }
-    }
-
-    @DomainService()
-    public static class SomeServiceWithoutAnnotationOrId {
-
-    }
-
-    @Test
-    public void annotated() throws Exception {
-
-        assertThat(
-                ServiceUtil.idOfPojo(new SomeServiceAnnotated()),
-                is(equalTo("foo.SomeServiceAnnotated")));
-
-        assertThat(
-                ServiceUtil.getExplicitIdOfType(SomeServiceAnnotated.class).orElse(null),
-                is(equalTo("foo.SomeServiceAnnotated")));
-    }
-
-    @Test
-    public void id() throws Exception {
-
-        assertThat(
-                ServiceUtil.idOfPojo(new SomeServiceWithId()),
-                is(equalTo("bar.SomeServiceWithId")));
-
-        assertThat(
-                ServiceUtil.getExplicitIdOfType(SomeServiceWithId.class).orElse(null),
-                is(equalTo("bar.SomeServiceWithId")));
-    }
-
-    @Test
-    public void annotated_precedence_over_id() throws Exception {
-
-        assertThat(
-                ServiceUtil.idOfPojo(new SomeServiceAnnotatedAndWithId()),
-                is(equalTo("bop.SomeServiceAnnotated")));
-
-        assertThat(
-                ServiceUtil.getExplicitIdOfType(SomeServiceAnnotatedAndWithId.class).orElse(null),
-                is(equalTo("bop.SomeServiceAnnotated")));
-    }
-
-    @Test
-    public void fallback_to_fqcn_for_obj_but_to_null_for_service() throws Exception {
-        assertThat(
-                ServiceUtil.idOfPojo(new SomeServiceWithoutAnnotationOrId()),
-                is(equalTo("org.apache.isis.metamodel.services.ServiceUtil_Test$SomeServiceWithoutAnnotationOrId")));
-        assertThat(
-                ServiceUtil.getExplicitIdOfType(SomeServiceWithoutAnnotationOrId.class).orElse(null),
-                is(nullValue()));
-    }
-
-}
\ No newline at end of file
diff --git a/core/metamodel/src/test/java/org/apache/isis/metamodel/testspec/ObjectSpecificationStub.java b/core/metamodel/src/test/java/org/apache/isis/metamodel/testspec/ObjectSpecificationStub.java
index a3706c7..aff4fa6 100644
--- a/core/metamodel/src/test/java/org/apache/isis/metamodel/testspec/ObjectSpecificationStub.java
+++ b/core/metamodel/src/test/java/org/apache/isis/metamodel/testspec/ObjectSpecificationStub.java
@@ -344,4 +344,10 @@ public class ObjectSpecificationStub extends FacetHolderImpl implements ObjectSp
         // [2158] not implemented yet
     }
 
+    @Override
+    public String getManagedBeanName() {
+        // [2158] not implemented yet
+        return null;
+    }
+
 }
diff --git a/core/runtime-services/src/main/java/org/apache/isis/runtime/services/menubars/bootstrap3/MenuBarsServiceBS3.java b/core/runtime-services/src/main/java/org/apache/isis/runtime/services/menubars/bootstrap3/MenuBarsServiceBS3.java
index ba9fb09..d585913 100644
--- a/core/runtime-services/src/main/java/org/apache/isis/runtime/services/menubars/bootstrap3/MenuBarsServiceBS3.java
+++ b/core/runtime-services/src/main/java/org/apache/isis/runtime/services/menubars/bootstrap3/MenuBarsServiceBS3.java
@@ -45,7 +45,6 @@ import org.apache.isis.commons.internal.base._Strings;
 import org.apache.isis.commons.internal.collections._Lists;
 import org.apache.isis.commons.internal.collections._Maps;
 import org.apache.isis.commons.internal.collections._Sets;
-import org.apache.isis.commons.internal.context._Context;
 import org.apache.isis.commons.internal.environment.IsisSystemEnvironment;
 import org.apache.isis.metamodel.MetaModelContext;
 import org.apache.isis.metamodel.facets.actions.notinservicemenu.NotInServiceMenuFacet;
diff --git a/examples/apps/demo/src/main/java/domainapp/application/menubars.layout.xml b/examples/apps/demo/src/main/java/domainapp/application/menubars.layout.xml
index 40c7739..3b1fe43 100644
--- a/examples/apps/demo/src/main/java/domainapp/application/menubars.layout.xml
+++ b/examples/apps/demo/src/main/java/domainapp/application/menubars.layout.xml
@@ -4,13 +4,13 @@
         <mb3:menu>
             <mb3:named>Featured Types</mb3:named>
             <mb3:section>
-                <mb3:serviceAction objectType="domainapp.dom.types.FeaturedTypesMenu" id="temporals">
+                <mb3:serviceAction objectType="demo.FeaturedTypesMenu" id="temporals">
                     <cpt:named>Temporal Types</cpt:named>
                 </mb3:serviceAction>
-                <mb3:serviceAction objectType="domainapp.dom.types.FeaturedTypesMenu" id="text">
+                <mb3:serviceAction objectType="demo.FeaturedTypesMenu" id="text">
                     <cpt:named>Text</cpt:named>
                 </mb3:serviceAction>
-                <mb3:serviceAction objectType="domainapp.dom.types.FeaturedTypesMenu" id="blobs">
+                <mb3:serviceAction objectType="demo.FeaturedTypesMenu" id="blobs">
                     <cpt:named>Blob Type</cpt:named>
                 </mb3:serviceAction>
             </mb3:section>
@@ -19,7 +19,7 @@
         <mb3:menu>
             <mb3:named>Tooltips</mb3:named>
             <mb3:section>
-                <mb3:serviceAction objectType="domainapp.dom.tooltip.TooltipMenu" id="tooltipDemo">
+                <mb3:serviceAction objectType="demo.TooltipMenu" id="tooltipDemo">
                     <cpt:named>Tooltip Demo</cpt:named>
                 </mb3:serviceAction>
             </mb3:section>
@@ -28,7 +28,7 @@
         <mb3:menu>
             <mb3:named>Trees</mb3:named>
             <mb3:section>
-                <mb3:serviceAction objectType="domainapp.dom.tree.TreeDemoMenu" id="fileSystemTree">
+                <mb3:serviceAction objectType="demo.TreeDemoMenu" id="fileSystemTree">
                     <cpt:named>File System Tree</cpt:named>
                 </mb3:serviceAction>
             </mb3:section>
@@ -36,13 +36,13 @@
         <mb3:menu>
             <mb3:named>Actions</mb3:named>
             <mb3:section>
-                <mb3:serviceAction objectType="domainapp.dom.actions.assoc.AssociatedActionMenu" id="associatedActions">
+                <mb3:serviceAction objectType="demo.AssociatedActionMenu" id="associatedActions">
                     <cpt:named>Associated Actions</cpt:named>
                 </mb3:serviceAction>
-                <mb3:serviceAction objectType="domainapp.dom.actions.async.AsyncActionMenu" id="asyncActions">
+                <mb3:serviceAction objectType="demo.AsyncActionMenu" id="asyncActions">
                     <cpt:named>Asynchronous Actions</cpt:named>
                 </mb3:serviceAction>
-                <mb3:serviceAction objectType="domainapp.dom.actions.depargs.DependentArgsActionMenu" id="dependentArgsActions">
+                <mb3:serviceAction objectType="demo.DependentArgsActionMenu" id="dependentArgsActions">
                     <cpt:named>Actions w/ dependent Arguments</cpt:named>
                 </mb3:serviceAction>
             </mb3:section>
@@ -50,10 +50,10 @@
         <mb3:menu>
             <mb3:named>Events</mb3:named>
             <mb3:section>
-                <mb3:serviceAction objectType="domainapp.dom.events.EventLogMenu" id="listEvents">
+                <mb3:serviceAction objectType="demo.EventLogMenu" id="listEvents">
                     <cpt:named>List Events</cpt:named>
                 </mb3:serviceAction>
-                <mb3:serviceAction objectType="domainapp.dom.events.EventLogMenu" id="triggerEvent">
+                <mb3:serviceAction objectType="demo.EventLogMenu" id="triggerEvent">
                     <cpt:named>Trigger Event</cpt:named>
                 </mb3:serviceAction>
             </mb3:section>
@@ -61,7 +61,7 @@
         <mb3:menu>
             <mb3:named>Error Handling</mb3:named>
             <mb3:section>
-                <mb3:serviceAction objectType="domainapp.dom.error.ErrorMenu" id="errorHandling">
+                <mb3:serviceAction objectType="demo.ErrorMenu" id="errorHandling">
                     <cpt:named>Error Handling</cpt:named>
                 </mb3:serviceAction>
             </mb3:section>
@@ -69,7 +69,7 @@
 		<mb3:menu>
             <mb3:named>JEE/CDI</mb3:named>
             <mb3:section>
-                <mb3:serviceAction objectType="domainapp.dom.jee.JeeMenu" id="jeeInjectDemo">
+                <mb3:serviceAction objectType="demo.JeeMenu" id="jeeInjectDemo">
                     <cpt:named>JEE Inject Demo</cpt:named>
                 </mb3:serviceAction>
             </mb3:section>
diff --git a/examples/apps/demo/src/main/java/domainapp/dom/actions/assoc/AssociatedActionMenu.java b/examples/apps/demo/src/main/java/domainapp/dom/actions/assoc/AssociatedActionMenu.java
index c236fd6..2c0da7f 100644
--- a/examples/apps/demo/src/main/java/domainapp/dom/actions/assoc/AssociatedActionMenu.java
+++ b/examples/apps/demo/src/main/java/domainapp/dom/actions/assoc/AssociatedActionMenu.java
@@ -29,7 +29,7 @@ import org.apache.isis.applib.services.factory.FactoryService;
 
 import lombok.val;
 
-@DomainService(nature=NatureOfService.VIEW)
+@DomainService(nature=NatureOfService.VIEW, objectType = "demo.AssociatedActionMenu")
 @DomainObjectLayout(named="Associated Action")
 public class AssociatedActionMenu {
 
diff --git a/examples/apps/demo/src/main/java/domainapp/dom/actions/async/AsyncActionMenu.java b/examples/apps/demo/src/main/java/domainapp/dom/actions/async/AsyncActionMenu.java
index 6387d0e..3569b08 100644
--- a/examples/apps/demo/src/main/java/domainapp/dom/actions/async/AsyncActionMenu.java
+++ b/examples/apps/demo/src/main/java/domainapp/dom/actions/async/AsyncActionMenu.java
@@ -29,7 +29,7 @@ import org.apache.isis.applib.services.factory.FactoryService;
 
 import lombok.val;
 
-@DomainService(nature=NatureOfService.VIEW)
+@DomainService(nature=NatureOfService.VIEW, objectType = "demo.AsyncActionMenu")
 @DomainObjectLayout(named="Async Actions")
 public class AsyncActionMenu {
 
diff --git a/examples/apps/demo/src/main/java/domainapp/dom/actions/depargs/DependentArgsActionMenu.java b/examples/apps/demo/src/main/java/domainapp/dom/actions/depargs/DependentArgsActionMenu.java
index a38aae0..956fdc6 100644
--- a/examples/apps/demo/src/main/java/domainapp/dom/actions/depargs/DependentArgsActionMenu.java
+++ b/examples/apps/demo/src/main/java/domainapp/dom/actions/depargs/DependentArgsActionMenu.java
@@ -29,7 +29,7 @@ import org.apache.isis.applib.services.factory.FactoryService;
 
 import lombok.val;
 
-@DomainService(nature=NatureOfService.VIEW)
+@DomainService(nature=NatureOfService.VIEW, objectType = "demo.DependentArgsActionMenu")
 @DomainObjectLayout(named="Associated Action")
 public class DependentArgsActionMenu {
 
diff --git a/examples/apps/demo/src/main/java/domainapp/dom/error/ErrorMenu.java b/examples/apps/demo/src/main/java/domainapp/dom/error/ErrorMenu.java
index 52d3616..e0cc882 100644
--- a/examples/apps/demo/src/main/java/domainapp/dom/error/ErrorMenu.java
+++ b/examples/apps/demo/src/main/java/domainapp/dom/error/ErrorMenu.java
@@ -29,7 +29,7 @@ import org.apache.isis.applib.services.factory.FactoryService;
 
 import lombok.val;
 
-@DomainService(nature=NatureOfService.VIEW)
+@DomainService(nature=NatureOfService.VIEW, objectType = "demo.ErrorMenu")
 @DomainObjectLayout(named="Error Handling")
 public class ErrorMenu {
 
diff --git a/examples/apps/demo/src/main/java/domainapp/dom/events/EventLogMenu.java b/examples/apps/demo/src/main/java/domainapp/dom/events/EventLogMenu.java
index fb0c697..ea2aee4 100644
--- a/examples/apps/demo/src/main/java/domainapp/dom/events/EventLogMenu.java
+++ b/examples/apps/demo/src/main/java/domainapp/dom/events/EventLogMenu.java
@@ -30,7 +30,7 @@ import org.apache.isis.applib.annotation.NatureOfService;
 import org.apache.isis.applib.events.domain.ActionDomainEvent;
 import org.apache.isis.applib.services.eventbus.EventBusService;
 
-@DomainService(nature=NatureOfService.VIEW)
+@DomainService(nature=NatureOfService.VIEW, objectType = "demo.EventLogMenu")
 @DomainObjectLayout(named="Event Demo")
 public class EventLogMenu {
 
diff --git a/examples/apps/demo/src/main/java/domainapp/dom/jee/JeeMenu.java b/examples/apps/demo/src/main/java/domainapp/dom/jee/JeeMenu.java
index 33b77d0..7575444 100644
--- a/examples/apps/demo/src/main/java/domainapp/dom/jee/JeeMenu.java
+++ b/examples/apps/demo/src/main/java/domainapp/dom/jee/JeeMenu.java
@@ -28,7 +28,7 @@ import org.apache.isis.applib.services.factory.FactoryService;
 
 import lombok.val;
 
-@DomainService(nature=NatureOfService.VIEW)
+@DomainService(nature=NatureOfService.VIEW, objectType = "demo.JeeMenu")
 public class JeeMenu {
 
     @Inject private FactoryService factoryService;
diff --git a/examples/apps/demo/src/main/java/domainapp/dom/tooltip/TooltipMenu.java b/examples/apps/demo/src/main/java/domainapp/dom/tooltip/TooltipMenu.java
index 871f6af..3d4f6d9 100644
--- a/examples/apps/demo/src/main/java/domainapp/dom/tooltip/TooltipMenu.java
+++ b/examples/apps/demo/src/main/java/domainapp/dom/tooltip/TooltipMenu.java
@@ -28,7 +28,7 @@ import org.apache.isis.applib.services.factory.FactoryService;
 
 import lombok.val;
 
-@DomainService(nature=NatureOfService.VIEW)
+@DomainService(nature=NatureOfService.VIEW, objectType = "demo.TooltipMenu")
 public class TooltipMenu {
 
     @Inject private FactoryService factoryService;
diff --git a/examples/apps/demo/src/main/java/domainapp/dom/tree/TreeDemoMenu.java b/examples/apps/demo/src/main/java/domainapp/dom/tree/TreeDemoMenu.java
index 96f2f00..20f1aec 100644
--- a/examples/apps/demo/src/main/java/domainapp/dom/tree/TreeDemoMenu.java
+++ b/examples/apps/demo/src/main/java/domainapp/dom/tree/TreeDemoMenu.java
@@ -30,7 +30,7 @@ import org.apache.isis.applib.services.factory.FactoryService;
 import domainapp.utils.DemoStub;
 import lombok.val;
 
-@DomainService(nature=NatureOfService.VIEW)
+@DomainService(nature=NatureOfService.VIEW, objectType = "demo.TreeDemoMenu")
 @DomainObjectLayout(named="Tree Demo")
 public class TreeDemoMenu {
 
diff --git a/examples/apps/demo/src/main/java/domainapp/dom/types/FeaturedTypesMenu.java b/examples/apps/demo/src/main/java/domainapp/dom/types/FeaturedTypesMenu.java
index 6178f16..355fb22 100644
--- a/examples/apps/demo/src/main/java/domainapp/dom/types/FeaturedTypesMenu.java
+++ b/examples/apps/demo/src/main/java/domainapp/dom/types/FeaturedTypesMenu.java
@@ -32,7 +32,7 @@ import domainapp.dom.types.text.TextDemo;
 import domainapp.dom.types.time.TemporalDemo;
 import lombok.val;
 
-@DomainService(nature=NatureOfService.VIEW)
+@DomainService(nature=NatureOfService.VIEW, objectType = "demo.FeaturedTypesMenu")
 @DomainObjectLayout(named="Featured Types")
 public class FeaturedTypesMenu {