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 2021/07/04 07:53:14 UTC

[isis] branch master updated: ISIS-2787: prepare layout testing infra.

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 c778298  ISIS-2787: prepare layout testing infra.
c778298 is described below

commit c7782986c700bf53dd534751955bd8f08055b8ce
Author: andi-huber <ah...@apache.org>
AuthorDate: Sun Jul 4 09:53:06 2021 +0200

    ISIS-2787: prepare layout testing infra.
---
 .../applib/services/grid/GridSystemService.java    |  7 --
 .../isis/applib/services/menu/MenuBarsService.java | 14 ++++
 .../commons/internal/ioc/_ManagedBeanAdapter.java  | 13 ++++
 ...ava => _ManagedBeanAdapter_forTestingLazy.java} | 28 ++++---
 .../_testing/MetaModelContext_forTesting.java      | 90 +++++++++++++++++++++-
 .../_testing/ServiceRegistry_forTesting.java       | 41 ++--------
 .../services/grid/GridLoaderServiceDefault.java    |  8 +-
 .../services/grid/GridReaderUsingJaxb.java         | 27 ++++---
 .../services/grid/GridServiceDefault.java          | 39 ++++++----
 .../services/grid/GridSystemServiceAbstract.java   | 47 +++--------
 .../bootstrap3/GridSystemServiceBootstrap.java     | 38 ++++++++-
 .../services/layout/LayoutServiceDefault.java      | 29 ++++---
 ...ipTest.java => GridInferringRoundtripTest.java} | 17 +++-
 .../GridLoaderServiceDefault_resourceNameTest.java |  6 +-
 ...{BS3GridTest.java => GridXmlRoundtripTest.java} | 31 +++++---
 15 files changed, 278 insertions(+), 157 deletions(-)

diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/grid/GridSystemService.java b/api/applib/src/main/java/org/apache/isis/applib/services/grid/GridSystemService.java
index ecba5e6..b431fe8 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/grid/GridSystemService.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/grid/GridSystemService.java
@@ -21,7 +21,6 @@ package org.apache.isis.applib.services.grid;
 import org.apache.isis.applib.layout.grid.Grid;
 
 /**
- *
  * Encapsulates a single layout grid system which can be used to customize the layout
  * of domain objects.
  *
@@ -36,9 +35,6 @@ import org.apache.isis.applib.layout.grid.Grid;
  */
 public interface GridSystemService<G extends Grid> {
 
-
-
-
     /**
      * The concrete subclass of {@link Grid} supported by this implementation.
      *
@@ -136,7 +132,4 @@ public interface GridSystemService<G extends Grid> {
      */
     void minimal(G grid, Class<?> domainClass);
 
-
-
-
 }
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/menu/MenuBarsService.java b/api/applib/src/main/java/org/apache/isis/applib/services/menu/MenuBarsService.java
index 5bed767..e013781 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/menu/MenuBarsService.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/menu/MenuBarsService.java
@@ -21,6 +21,7 @@ package org.apache.isis.applib.services.menu;
 import org.apache.isis.applib.IsisModuleApplib;
 import org.apache.isis.applib.annotation.Value;
 import org.apache.isis.applib.layout.menubars.MenuBars;
+import org.apache.isis.commons.internal.exceptions._Exceptions;
 
 /**
  * Responsible for returning a {@link MenuBarsService} instance, a data
@@ -66,4 +67,17 @@ public interface MenuBarsService {
      * @param type - as requested
      */
     MenuBars menuBars(final Type type);
+
+    // -- JUNIT SUPPORT
+
+    static MenuBarsService forTesting() {
+        return new MenuBarsService() {
+
+            @Override
+            public MenuBars menuBars(Type type) {
+                throw _Exceptions.unsupportedOperation();
+            }
+
+        };
+    }
 }
diff --git a/commons/src/main/java/org/apache/isis/commons/internal/ioc/_ManagedBeanAdapter.java b/commons/src/main/java/org/apache/isis/commons/internal/ioc/_ManagedBeanAdapter.java
index efc320f..8e29a5c 100644
--- a/commons/src/main/java/org/apache/isis/commons/internal/ioc/_ManagedBeanAdapter.java
+++ b/commons/src/main/java/org/apache/isis/commons/internal/ioc/_ManagedBeanAdapter.java
@@ -18,6 +18,8 @@
  */
 package org.apache.isis.commons.internal.ioc;
 
+import java.util.function.Supplier;
+
 import org.apache.isis.commons.collections.Can;
 
 /**
@@ -31,4 +33,15 @@ public interface _ManagedBeanAdapter {
 
     boolean isCandidateFor(Class<?> requiredType);
 
+    // -- TEST FACTORIES
+
+    public static <T> _ManagedBeanAdapter forTestingLazy(Class<T> beanClass, Supplier<T> beanProvider) {
+        return _ManagedBeanAdapter_forTestingLazy.of(beanClass.getName(), beanClass, beanProvider);
+    }
+
+    public static <T> _ManagedBeanAdapter forTesting(T bean) {
+        return _ManagedBeanAdapter_forTestingLazy.of(bean.getClass().getName(), bean.getClass(), ()->bean);
+    }
+
+
 }
\ No newline at end of file
diff --git a/commons/src/main/java/org/apache/isis/commons/internal/ioc/_ManagedBeanAdapter.java b/commons/src/main/java/org/apache/isis/commons/internal/ioc/_ManagedBeanAdapter_forTestingLazy.java
similarity index 63%
copy from commons/src/main/java/org/apache/isis/commons/internal/ioc/_ManagedBeanAdapter.java
copy to commons/src/main/java/org/apache/isis/commons/internal/ioc/_ManagedBeanAdapter_forTestingLazy.java
index efc320f..583c42b 100644
--- a/commons/src/main/java/org/apache/isis/commons/internal/ioc/_ManagedBeanAdapter.java
+++ b/commons/src/main/java/org/apache/isis/commons/internal/ioc/_ManagedBeanAdapter_forTestingLazy.java
@@ -18,17 +18,27 @@
  */
 package org.apache.isis.commons.internal.ioc;
 
+import java.util.function.Supplier;
+
 import org.apache.isis.commons.collections.Can;
 
-/**
- * @since 2.0
- */
-public interface _ManagedBeanAdapter {
+import lombok.Value;
+
+@Value(staticConstructor="of")
+final class _ManagedBeanAdapter_forTestingLazy implements _ManagedBeanAdapter {
+
+    private final String id;
+    private final Class<?> beanClass;
+    private final Supplier<?> beanProvider;
 
-    String getId();
-    Can<?> getInstance();
-    Class<?> getBeanClass();
+    @Override
+    public boolean isCandidateFor(Class<?> requiredType) {
+        return requiredType.isAssignableFrom(beanClass);
+    }
 
-    boolean isCandidateFor(Class<?> requiredType);
+    @Override
+    public Can<?> getInstance() {
+        return Can.ofSingleton(beanProvider.get());
+    }
 
-}
\ No newline at end of file
+}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/_testing/MetaModelContext_forTesting.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/_testing/MetaModelContext_forTesting.java
index 267ae87..8998e1b 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/_testing/MetaModelContext_forTesting.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/_testing/MetaModelContext_forTesting.java
@@ -23,15 +23,22 @@ import java.util.List;
 import java.util.Map;
 import java.util.function.Consumer;
 import java.util.function.Function;
+import java.util.function.Supplier;
 import java.util.stream.Stream;
 
 import org.springframework.core.env.AbstractEnvironment;
 
 import org.apache.isis.applib.services.factory.FactoryService;
+import org.apache.isis.applib.services.grid.GridLoaderService;
+import org.apache.isis.applib.services.grid.GridService;
 import org.apache.isis.applib.services.i18n.TranslationService;
 import org.apache.isis.applib.services.iactn.InteractionProvider;
 import org.apache.isis.applib.services.iactnlayer.InteractionContext;
 import org.apache.isis.applib.services.inject.ServiceInjector;
+import org.apache.isis.applib.services.jaxb.JaxbService;
+import org.apache.isis.applib.services.layout.LayoutService;
+import org.apache.isis.applib.services.menu.MenuBarsService;
+import org.apache.isis.applib.services.message.MessageService;
 import org.apache.isis.applib.services.registry.ServiceRegistry;
 import org.apache.isis.applib.services.repository.RepositoryService;
 import org.apache.isis.applib.services.title.TitleService;
@@ -43,6 +50,8 @@ import org.apache.isis.commons.internal.base._Lazy;
 import org.apache.isis.commons.internal.base._NullSafe;
 import org.apache.isis.commons.internal.collections._Lists;
 import org.apache.isis.commons.internal.collections._Maps;
+import org.apache.isis.commons.internal.exceptions._Exceptions;
+import org.apache.isis.commons.internal.ioc._ManagedBeanAdapter;
 import org.apache.isis.core.config.IsisConfiguration;
 import org.apache.isis.core.config.beans.IsisBeanFactoryPostProcessorForSpring;
 import org.apache.isis.core.config.beans.IsisBeanTypeClassifier;
@@ -60,6 +69,12 @@ import org.apache.isis.core.metamodel.progmodel.ProgrammingModelInitFilterDefaul
 import org.apache.isis.core.metamodel.progmodels.dflt.ProgrammingModelFacetsJava8;
 import org.apache.isis.core.metamodel.services.classsubstitutor.ClassSubstitutorRegistry;
 import org.apache.isis.core.metamodel.services.events.MetamodelEventService;
+import org.apache.isis.core.metamodel.services.grid.GridLoaderServiceDefault;
+import org.apache.isis.core.metamodel.services.grid.GridReaderUsingJaxb;
+import org.apache.isis.core.metamodel.services.grid.GridServiceDefault;
+import org.apache.isis.core.metamodel.services.grid.bootstrap3.GridSystemServiceBootstrap;
+import org.apache.isis.core.metamodel.services.layout.LayoutServiceDefault;
+import org.apache.isis.core.metamodel.services.message.MessageServiceNoop;
 import org.apache.isis.core.metamodel.services.title.TitleServiceDefault;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
@@ -72,6 +87,7 @@ import static java.util.Objects.requireNonNull;
 import lombok.Builder;
 import lombok.Getter;
 import lombok.Singular;
+import lombok.Value;
 import lombok.val;
 
 @Builder @Getter
@@ -168,9 +184,28 @@ implements MetaModelContext {
         return getSystemEnvironment().ioc().getSingletonElseFail(type);
     }
 
-    public Stream<Object> streamSingletons() {
+    @Value @Builder
+    static class ManagedBeanProvider implements _ManagedBeanAdapter {
 
-        val fields = _Lists.of(
+        String id;
+        Supplier<?> instanceProvider;
+        public Class<?> beanClass;
+
+        @Override
+        public boolean isCandidateFor(Class<?> requiredType) {
+            throw _Exceptions.notImplemented();
+        }
+
+        @Override
+        public Can<?> getInstance() {
+            return Can.ofSingleton(instanceProvider.get());
+        }
+
+    }
+
+    private Stream<Object> streamSingletons() {
+
+        val fields = Stream.of(
                 getConfiguration(),
                 getObjectManager(),
                 getWrapperFactory(),
@@ -181,6 +216,7 @@ implements MetaModelContext {
                 serviceInjector,
                 serviceRegistry,
                 metamodelEventService,
+                messageService,
                 specificationLoader,
                 interactionProvider,
                 getTranslationService(),
@@ -193,10 +229,25 @@ implements MetaModelContext {
                 transactionState,
                 this);
 
-        return Stream.concat(fields.stream(), getSingletons().stream())
+        return Stream.concat(
+                fields,
+                getSingletons().stream())
                 .filter(_NullSafe::isPresent);
     }
 
+    Stream<_ManagedBeanAdapter> streamBeanAdapters() {
+        return Stream.concat(
+                streamSingletons().map(_ManagedBeanAdapter::forTesting),
+                Stream.of(
+                    // support for lazy bean providers,
+                    _ManagedBeanAdapter.forTestingLazy(GridLoaderService.class, this::getGridLoaderService),
+                    _ManagedBeanAdapter.forTestingLazy(GridService.class, this::getGridService),
+                    _ManagedBeanAdapter.forTestingLazy(JaxbService.class, this::getJaxbService),
+                    _ManagedBeanAdapter.forTestingLazy(MenuBarsService.class, this::getMenuBarsService),
+                    _ManagedBeanAdapter.forTestingLazy(LayoutService.class, this::getLayoutService)
+                ));
+    }
+
     private static IsisSystemEnvironment newIsisSystemEnvironment() {
         val env = new IsisSystemEnvironment();
         env.setUnitTesting(true);
@@ -300,6 +351,9 @@ implements MetaModelContext {
         return specificationLoader;
     }
 
+    @Builder.Default
+    private final MessageService messageService = new MessageServiceNoop();
+
     @Override
     public ManagedObject getHomePageAdapter() {
         // not supported
@@ -322,6 +376,7 @@ implements MetaModelContext {
         return wrapperFactory;
     }
 
+
     public void runWithConfigProperties(final Consumer<Map<String, String>> setup, final Runnable runnable) {
         val properties = _Maps.<String, String>newHashMap();
         setup.accept(properties);
@@ -343,4 +398,33 @@ implements MetaModelContext {
 
     }
 
+    // -- LAYOUT TESTING SUPPORT
+
+    @Getter(lazy = true)
+    private final JaxbService jaxbService = new JaxbService.Simple();
+
+    @Getter(lazy = true)
+    private final GridReaderUsingJaxb gridReader = new GridReaderUsingJaxb(getJaxbService(), null);
+
+    @Getter(lazy = true)
+    private final GridLoaderService gridLoaderService =
+        new GridLoaderServiceDefault(getMessageService(), getGridReader(), getSystemEnvironment());
+
+    @Getter(lazy = true)
+    private final GridService gridService = new GridServiceDefault(
+            getGridLoaderService(), _Lists.of(
+                    new GridSystemServiceBootstrap(getGridReader(),
+                            getSpecificationLoader(),
+                            getTranslationService(),
+                            getJaxbService(),
+                            getMessageService(),
+                            getSystemEnvironment())));
+
+    @Getter(lazy = true)
+    private final MenuBarsService menuBarsService = MenuBarsService.forTesting();
+
+    @Getter(lazy = true)
+    private final LayoutService layoutService = new LayoutServiceDefault(
+            getSpecificationLoader(), getJaxbService(), getGridService(), getMenuBarsService());
+
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/_testing/ServiceRegistry_forTesting.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/_testing/ServiceRegistry_forTesting.java
index 4625eaf..dfe9fc2 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/_testing/ServiceRegistry_forTesting.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/_testing/ServiceRegistry_forTesting.java
@@ -34,12 +34,10 @@ import org.apache.isis.commons.internal.ioc._IocContainer;
 import org.apache.isis.commons.internal.ioc._ManagedBeanAdapter;
 import org.apache.isis.core.metamodel.context.MetaModelContext;
 
-import lombok.Builder;
 import lombok.Getter;
 import lombok.NonNull;
 import lombok.RequiredArgsConstructor;
 import lombok.Setter;
-import lombok.Value;
 import lombok.val;
 
 @RequiredArgsConstructor
@@ -62,8 +60,9 @@ class ServiceRegistry_forTesting implements ServiceRegistry {
 //            throw _Exceptions.notImplemented();
 //        }
 
-        Optional<T> match = streamSingletons()
-                .filter(singleton->type.isAssignableFrom(singleton.getClass()))
+        Optional<T> match = streamBeans()
+                .filter(beanAdapter->type.isAssignableFrom(beanAdapter.getBeanClass()))
+                .map(beanAdapter->beanAdapter.getInstance().getFirstOrFail())
                 .map(_Casts::<T>uncheckedCast)
                 .findFirst();
 
@@ -96,15 +95,13 @@ class ServiceRegistry_forTesting implements ServiceRegistry {
         throw _Exceptions.notImplemented();
     }
 
-
     // -- HELPER
 
     private Set<_ManagedBeanAdapter> registeredBeans() {
         synchronized(registeredBeans) {
             if(registeredBeans.isEmpty()) {
 
-                streamSingletons()
-                .map(s->toBeanAdapter(s))
+                streamBeans()
                 .filter(_NullSafe::isPresent)
                 .forEach(registeredBeans::add);
             }
@@ -112,41 +109,15 @@ class ServiceRegistry_forTesting implements ServiceRegistry {
         return registeredBeans;
     }
 
-    private Stream<Object> streamSingletons() {
+    private Stream<_ManagedBeanAdapter> streamBeans() {
         // lookup the MetaModelContextBean's list of singletons
         val mmc = metaModelContext;
         if(mmc instanceof MetaModelContext_forTesting) {
             val mmcb = (MetaModelContext_forTesting) mmc;
-            return mmcb.streamSingletons();
+            return mmcb.streamBeanAdapters();
         }
         return Stream.empty();
     }
 
-    @Value @Builder
-    private static class PojoBeanAdapter implements _ManagedBeanAdapter {
-
-        String id;
-        Can<?> instance;
-        public Class<?> beanClass;
-
-        @Override
-        public boolean isCandidateFor(Class<?> requiredType) {
-            throw _Exceptions.notImplemented();
-        }
-
-    }
-
-    private _ManagedBeanAdapter toBeanAdapter(Object singleton) {
-
-        return PojoBeanAdapter.builder()
-                .id(singleton.getClass().getName())
-                .instance(Can.ofSingleton(singleton))
-                .beanClass(singleton.getClass())
-                .build();
-
-
-    }
-
-
 
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/grid/GridLoaderServiceDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/grid/GridLoaderServiceDefault.java
index 439ce98..a963d77 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/grid/GridLoaderServiceDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/grid/GridLoaderServiceDefault.java
@@ -44,6 +44,7 @@ import org.apache.isis.commons.internal.resources._Resources;
 import org.apache.isis.core.config.environment.IsisSystemEnvironment;
 
 import lombok.NonNull;
+import lombok.RequiredArgsConstructor;
 import lombok.Value;
 import lombok.val;
 import lombok.extern.log4j.Log4j2;
@@ -52,12 +53,13 @@ import lombok.extern.log4j.Log4j2;
 @Named("isis.metamodel.GridLoaderServiceDefault")
 @Priority(PriorityPrecedence.MIDPOINT)
 @Qualifier("Default")
+@RequiredArgsConstructor(onConstructor_ = {@Inject})
 @Log4j2
 public class GridLoaderServiceDefault implements GridLoaderService {
 
-    @Inject private MessageService messageService;
-    @Inject private GridReaderUsingJaxb gridReader;
-    @Inject private IsisSystemEnvironment isisSystemEnvironment;
+    private final MessageService messageService;
+    private final GridReaderUsingJaxb gridReader;
+    private final IsisSystemEnvironment isisSystemEnvironment;
 
     @Value
     static class DomainClassAndLayout {
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/grid/GridReaderUsingJaxb.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/grid/GridReaderUsingJaxb.java
index f72d14a..3b47125 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/grid/GridReaderUsingJaxb.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/grid/GridReaderUsingJaxb.java
@@ -18,14 +18,7 @@
  */
 package org.apache.isis.core.metamodel.services.grid;
 
-import org.apache.isis.applib.annotation.PriorityPrecedence;
-import org.apache.isis.applib.layout.grid.Grid;
-import org.apache.isis.applib.services.grid.GridSystemService;
-import org.apache.isis.applib.services.jaxb.JaxbService;
-import org.apache.isis.commons.internal.base._NullSafe;
-import org.apache.isis.commons.internal.collections._Arrays;
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.stereotype.Service;
+import java.util.List;
 
 import javax.annotation.PostConstruct;
 import javax.annotation.Priority;
@@ -33,7 +26,18 @@ import javax.inject.Inject;
 import javax.inject.Named;
 import javax.xml.bind.JAXBContext;
 import javax.xml.bind.JAXBException;
-import java.util.List;
+
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.stereotype.Service;
+
+import org.apache.isis.applib.annotation.PriorityPrecedence;
+import org.apache.isis.applib.layout.grid.Grid;
+import org.apache.isis.applib.services.grid.GridSystemService;
+import org.apache.isis.applib.services.jaxb.JaxbService;
+import org.apache.isis.commons.internal.base._NullSafe;
+import org.apache.isis.commons.internal.collections._Arrays;
+
+import lombok.RequiredArgsConstructor;
 
 /**
  *
@@ -44,10 +48,11 @@ import java.util.List;
 @Named("isis.metamodel.GridReaderUsingJaxb")
 @Priority(PriorityPrecedence.MIDPOINT)
 @Qualifier("Default")
+@RequiredArgsConstructor(onConstructor_ = {@Inject})
 public class GridReaderUsingJaxb {
 
-    @Inject private JaxbService jaxbService;
-    @Inject private List<GridSystemService<?>> gridSystemServices;
+    private final JaxbService jaxbService;
+    private final List<GridSystemService<?>> gridSystemServices;
 
     private JAXBContext jaxbContext;
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/grid/GridServiceDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/grid/GridServiceDefault.java
index cafdf6b..9378dbc 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/grid/GridServiceDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/grid/GridServiceDefault.java
@@ -18,7 +18,17 @@
  */
 package org.apache.isis.core.metamodel.services.grid;
 
-import lombok.val;
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import javax.annotation.Priority;
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.stereotype.Service;
+
 import org.apache.isis.applib.annotation.PriorityPrecedence;
 import org.apache.isis.applib.layout.grid.Grid;
 import org.apache.isis.applib.services.grid.GridLoaderService;
@@ -27,20 +37,15 @@ import org.apache.isis.applib.services.grid.GridSystemService;
 import org.apache.isis.commons.internal.base._Casts;
 import org.apache.isis.commons.internal.collections._Lists;
 import org.apache.isis.commons.internal.collections._Sets;
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.stereotype.Service;
 
-import javax.annotation.Priority;
-import javax.inject.Inject;
-import javax.inject.Named;
-import java.util.Collection;
-import java.util.List;
-import java.util.stream.Collectors;
+import lombok.RequiredArgsConstructor;
+import lombok.val;
 
 @Service
 @Named("isis.metamodel.GridServiceDefault")
 @Priority(PriorityPrecedence.MIDPOINT)
 @Qualifier("Default")
+@RequiredArgsConstructor(onConstructor_ = {@Inject})
 public class GridServiceDefault implements GridService {
 
     public static final String COMPONENT_TNS = "http://isis.apache.org/applib/layout/component";
@@ -49,8 +54,8 @@ public class GridServiceDefault implements GridService {
     public static final String LINKS_TNS = "http://isis.apache.org/applib/layout/links";
     public static final String LINKS_SCHEMA_LOCATION = "http://isis.apache.org/applib/layout/links/links.xsd";
 
-    @Inject private GridLoaderService gridLoaderService;
-    @Inject private List<GridSystemService<?>> gridSystemServices;
+    private final GridLoaderService gridLoaderService;
+    private final List<GridSystemService<? extends Grid>> gridSystemServices;
 
     // //////////////////////////////////////
 
@@ -85,7 +90,7 @@ public class GridServiceDefault implements GridService {
     public Grid defaultGridFor(Class<?> domainClass) {
 
         for (val gridSystemService : gridSystemServices()) {
-            val grid = (Grid) gridSystemService.defaultGrid(domainClass);
+            val grid = gridSystemService.defaultGrid(domainClass);
             if(grid != null) {
                 return grid;
             }
@@ -162,7 +167,7 @@ public class GridServiceDefault implements GridService {
 
     ////////////////////////////////////////////////////////
 
-    private List<GridSystemService<?>> filteredGridSystemServices;
+    private List<GridSystemService<? extends Grid>> filteredGridSystemServices;
 
     /**
      * For all of the {@link GridSystemService}s available, return only the first one for any that
@@ -173,7 +178,7 @@ public class GridServiceDefault implements GridService {
      *   general idea of multiple implementations.
      * </p>
      */
-    protected List<GridSystemService<?>> gridSystemServices() {
+    protected List<GridSystemService<? extends Grid>> gridSystemServices() {
 
         if (filteredGridSystemServices == null) {
 
@@ -191,11 +196,11 @@ public class GridServiceDefault implements GridService {
 
     // -- poor man's testing support
 
-    List<GridSystemService<?>> gridSystemServicesForTest;
-    Collection<GridSystemService<?>> getGridSystemServices() {
+    List<GridSystemService<? extends Grid>> gridSystemServicesForTest;
+    Collection<GridSystemService<? extends Grid>> getGridSystemServices() {
         return gridSystemServices!=null
                 ? gridSystemServices
-                        : gridSystemServicesForTest;
+                : gridSystemServicesForTest;
     }
 
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/grid/GridSystemServiceAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/grid/GridSystemServiceAbstract.java
index df5f45a..b85c702 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/grid/GridSystemServiceAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/grid/GridSystemServiceAbstract.java
@@ -86,56 +86,27 @@ import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
 import static org.apache.isis.core.metamodel.facetapi.FacetUtil.addFacet;
 import static org.apache.isis.core.metamodel.facetapi.FacetUtil.addFacetIfPresent;
 
+import lombok.AccessLevel;
+import lombok.RequiredArgsConstructor;
 import lombok.Value;
 import lombok.val;
 import lombok.extern.log4j.Log4j2;
 
+@RequiredArgsConstructor(onConstructor_ = {@Inject}, access = AccessLevel.PROTECTED)
 @Log4j2
 public abstract class GridSystemServiceAbstract<G extends org.apache.isis.applib.layout.grid.Grid>
 implements GridSystemService<G> {
 
-    @Inject protected SpecificationLoader specificationLoader;
-    @Inject protected TranslationService translationService;
-    @Inject protected JaxbService jaxbService;
-    @Inject protected MessageService messageService;
-    @Inject IsisSystemEnvironment isisSystemEnvironment;
-
-    private final Class<G> gridImplementation;
-    private final String tns;
-    private final String schemaLocation;
-
-    protected GridSystemServiceAbstract(
-            final Class<G> gridImplementation,
-            final String tns,
-            final String schemaLocation) {
-
-        this.gridImplementation = gridImplementation;
-        this.tns = tns;
-        this.schemaLocation = schemaLocation;
-    }
-
-    // //////////////////////////////////////
-
-    @Override
-    public Class<G> gridImplementation() {
-        return gridImplementation;
-    }
-
-    @Override
-    public String tns() {
-        return tns;
-    }
-
-    @Override
-    public String schemaLocation() {
-        return schemaLocation;
-    }
-
+    protected final SpecificationLoader specificationLoader;
+    protected final TranslationService translationService;
+    protected final JaxbService jaxbService;
+    protected final MessageService messageService;
+    protected final IsisSystemEnvironment isisSystemEnvironment;
 
     @Override
     public void normalize(final G grid, final Class<?> domainClass) {
 
-        if(!gridImplementation.isAssignableFrom(grid.getClass())) {
+        if(!gridImplementation().isAssignableFrom(grid.getClass())) {
             // ignore any other grid implementations
             return;
         }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/grid/bootstrap3/GridSystemServiceBootstrap.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/grid/bootstrap3/GridSystemServiceBootstrap.java
index 6af68dc..920664c 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/grid/bootstrap3/GridSystemServiceBootstrap.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/grid/bootstrap3/GridSystemServiceBootstrap.java
@@ -50,12 +50,16 @@ import org.apache.isis.applib.layout.grid.bootstrap3.BS3Tab;
 import org.apache.isis.applib.layout.grid.bootstrap3.BS3TabGroup;
 import org.apache.isis.applib.layout.grid.bootstrap3.Size;
 import org.apache.isis.applib.mixins.layout.LayoutMixinConstants;
+import org.apache.isis.applib.services.i18n.TranslationService;
+import org.apache.isis.applib.services.jaxb.JaxbService;
+import org.apache.isis.applib.services.message.MessageService;
 import org.apache.isis.commons.internal.base._NullSafe;
 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.exceptions._Exceptions;
 import org.apache.isis.commons.internal.resources._Resources;
+import org.apache.isis.core.config.environment.IsisSystemEnvironment;
 import org.apache.isis.core.metamodel.facets.actions.position.ActionPositionFacet;
 import org.apache.isis.core.metamodel.facets.members.layout.group.GroupIdAndName;
 import org.apache.isis.core.metamodel.facets.members.layout.group.LayoutGroupFacet;
@@ -69,6 +73,7 @@ import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
 import org.apache.isis.core.metamodel.spec.feature.ObjectMember;
 import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
 import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
+import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
 
 import static org.apache.isis.commons.internal.base._NullSafe.stream;
 
@@ -80,18 +85,43 @@ import lombok.extern.log4j.Log4j2;
 @Priority(PriorityPrecedence.MIDPOINT)
 @Qualifier("Bootstrap")
 @Log4j2
-public class GridSystemServiceBootstrap extends GridSystemServiceAbstract<BS3Grid> {
+public class GridSystemServiceBootstrap
+extends GridSystemServiceAbstract<BS3Grid> {
 
     public static final String TNS = "http://isis.apache.org/applib/layout/grid/bootstrap3";
     public static final String SCHEMA_LOCATION = "http://isis.apache.org/applib/layout/grid/bootstrap3/bootstrap3.xsd";
 
-    @Inject private GridReaderUsingJaxb gridReader;
+    private final GridReaderUsingJaxb gridReader;
+
+    @Inject
+    public GridSystemServiceBootstrap(
+            final GridReaderUsingJaxb gridReader,
+            final SpecificationLoader specificationLoader,
+            final TranslationService translationService,
+            final JaxbService jaxbService,
+            final MessageService messageService,
+            final IsisSystemEnvironment isisSystemEnvironment) {
+        super(specificationLoader, translationService, jaxbService, messageService, isisSystemEnvironment);
+        this.gridReader = gridReader;
+    }
 
-    public GridSystemServiceBootstrap() {
-        super(BS3Grid.class, TNS, SCHEMA_LOCATION);
+    @Override
+    public Class<BS3Grid> gridImplementation() {
+        return BS3Grid.class;
+    }
+
+    @Override
+    public String tns() {
+        return TNS;
     }
 
     @Override
+    public String schemaLocation() {
+        return SCHEMA_LOCATION;
+    }
+
+
+    @Override
     public BS3Grid defaultGrid(final Class<?> domainClass) {
 
         try {
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/layout/LayoutServiceDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/layout/LayoutServiceDefault.java
index b5da4be..7d69e7b 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/layout/LayoutServiceDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/layout/LayoutServiceDefault.java
@@ -18,7 +18,16 @@
  */
 package org.apache.isis.core.metamodel.services.layout;
 
-import lombok.val;
+import java.io.File;
+
+import javax.annotation.Priority;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.xml.bind.Marshaller;
+
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.stereotype.Service;
+
 import org.apache.isis.applib.annotation.PriorityPrecedence;
 import org.apache.isis.applib.layout.grid.Grid;
 import org.apache.isis.applib.layout.menubars.MenuBars;
@@ -32,25 +41,21 @@ import org.apache.isis.commons.internal.collections._Maps;
 import org.apache.isis.core.metamodel.facets.object.grid.GridFacet;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.stereotype.Service;
 
-import javax.annotation.Priority;
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.xml.bind.Marshaller;
-import java.io.File;
+import lombok.RequiredArgsConstructor;
+import lombok.val;
 
 @Service
 @Named("isis.metamodel.LayoutServiceDefault")
 @Priority(PriorityPrecedence.MIDPOINT)
 @Qualifier("Default")
+@RequiredArgsConstructor(onConstructor_ = {@Inject})
 public class LayoutServiceDefault implements LayoutService {
 
-    @Inject private SpecificationLoader specificationLoader;
-    @Inject private JaxbService jaxbService;
-    @Inject private GridService gridService;
-    @Inject private MenuBarsService menuBarsService;
+    private final SpecificationLoader specificationLoader;
+    private final JaxbService jaxbService;
+    private final GridService gridService;
+    private final MenuBarsService menuBarsService;
 
     @Override
     public String toXml(final Class<?> domainClass, final Style style) {
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/grid/GridLoaderRoundtripTest.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/grid/GridInferringRoundtripTest.java
similarity index 71%
rename from core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/grid/GridLoaderRoundtripTest.java
rename to core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/grid/GridInferringRoundtripTest.java
index aff6fa5..70d8aed 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/grid/GridLoaderRoundtripTest.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/grid/GridInferringRoundtripTest.java
@@ -20,19 +20,23 @@ package org.apache.isis.core.metamodel.services.grid;
 
 import org.junit.jupiter.api.Test;
 
+import org.apache.isis.applib.services.grid.GridLoaderService;
+import org.apache.isis.applib.services.layout.LayoutService;
+import org.apache.isis.applib.services.layout.Style;
 import org.apache.isis.core.metamodel.MetaModelTestAbstract;
-import org.apache.isis.core.metamodel._testing.MetaModelContext_forTesting.MetaModelContext_forTestingBuilder;
 
 import lombok.val;
 
-class GridLoaderRoundtripTest
+class GridInferringRoundtripTest
 extends MetaModelTestAbstract {
 
     private GridLoaderServiceDefault gridLoaderService;
+    private LayoutService layoutService;
 
     @Override
-    protected void onSetUp(MetaModelContext_forTestingBuilder mmcBuilder) {
-        mmcBuilder.singleton(gridLoaderService = new GridLoaderServiceDefault());
+    protected void afterSetUp() {
+        layoutService = getServiceRegistry().lookupServiceElseFail(LayoutService.class);
+        gridLoaderService = (GridLoaderServiceDefault)getServiceRegistry().lookupServiceElseFail(GridLoaderService.class);
     }
 
     @Test
@@ -42,6 +46,11 @@ extends MetaModelTestAbstract {
 
         getSpecificationLoader().specForType(Bar.class);
 
+        val xml = layoutService.toXml(Bar.class, Style.NORMALIZED);
+
+        System.out.println(xml);
+
+
         //TODO compare loaded with generated
         //TODO inspect ObjectNamed and MemberNamed (canonical) facets
     }
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/grid/GridLoaderServiceDefault_resourceNameTest.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/grid/GridLoaderServiceDefault_resourceNameTest.java
index 4576dd4..4fc15f9 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/grid/GridLoaderServiceDefault_resourceNameTest.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/grid/GridLoaderServiceDefault_resourceNameTest.java
@@ -21,17 +21,17 @@ package org.apache.isis.core.metamodel.services.grid;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
 import org.apache.isis.core.metamodel.services.grid.GridLoaderServiceDefault.DomainClassAndLayout;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
 class GridLoaderServiceDefault_resourceNameTest {
 
     private GridLoaderServiceDefault gridLoaderServiceDefault;
 
     @BeforeEach
     void setUp() throws Exception {
-        gridLoaderServiceDefault = new GridLoaderServiceDefault();
+        gridLoaderServiceDefault = new GridLoaderServiceDefault(null, null, null);
     }
 
     @Test
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/grid/BS3GridTest.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/grid/GridXmlRoundtripTest.java
similarity index 86%
rename from core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/grid/BS3GridTest.java
rename to core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/grid/GridXmlRoundtripTest.java
index f8cde75..669bb19 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/grid/BS3GridTest.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/grid/GridXmlRoundtripTest.java
@@ -22,7 +22,6 @@ import java.util.Map;
 
 import javax.xml.bind.Marshaller;
 
-import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
 import org.apache.isis.applib.layout.component.ActionLayoutData;
@@ -35,30 +34,40 @@ import org.apache.isis.applib.layout.grid.bootstrap3.BS3Grid;
 import org.apache.isis.applib.layout.grid.bootstrap3.BS3Row;
 import org.apache.isis.applib.layout.grid.bootstrap3.BS3Tab;
 import org.apache.isis.applib.layout.grid.bootstrap3.BS3TabGroup;
+import org.apache.isis.applib.services.grid.GridService;
 import org.apache.isis.applib.services.jaxb.IsisSchemas;
 import org.apache.isis.applib.services.jaxb.JaxbService;
 import org.apache.isis.commons.internal.collections._Lists;
 import org.apache.isis.commons.internal.collections._Maps;
-import org.apache.isis.core.metamodel.services.grid.bootstrap3.GridSystemServiceBootstrap;
+import org.apache.isis.core.metamodel.MetaModelTestAbstract;
 
 import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
 
-class BS3GridTest {
+class GridXmlRoundtripTest
+extends MetaModelTestAbstract {
 
     private JaxbService jaxbService;
+//    private GridLoaderServiceDefault gridLoaderService;
+//    private LayoutService layoutService;
     private GridServiceDefault gridServiceDefault;
-    private GridSystemServiceBootstrap gridSystemServiceBS3;
-
-    @BeforeEach
-    void setUp() throws Exception {
-        jaxbService = new JaxbService.Simple() {};
-        gridServiceDefault = new GridServiceDefault();
-        gridSystemServiceBS3 = new GridSystemServiceBootstrap();
-        gridServiceDefault.gridSystemServicesForTest = _Lists.of(gridSystemServiceBS3);
+//    private GridSystemServiceBootstrap gridSystemServiceBS3;
+
+    @Override
+    protected void afterSetUp() {
+        jaxbService = getServiceRegistry().lookupServiceElseFail(JaxbService.class);
+        gridServiceDefault = (GridServiceDefault)getServiceRegistry().lookupServiceElseFail(GridService.class);
+        //gridLoaderService = (GridLoaderServiceDefault)getServiceRegistry().lookupServiceElseFail(GridLoaderService.class);
     }
 
+//    @BeforeEach
+//    void setUp() throws Exception {
+//
+//        gridSystemServiceBS3 = new GridSystemServiceBootstrap(null);
+//        gridServiceDefault.gridSystemServicesForTest = _Lists.of(gridSystemServiceBS3);
+//    }
+
 
     @Test
     void happy_case() throws Exception {