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

ahuber pushed a commit to branch 3937-grid.api.overhaul
in repository https://gitbox.apache.org/repos/asf/causeway.git

commit 835258b7735f8d879ae8117099c83fe167d1caf3
Author: Andi Huber <[email protected]>
AuthorDate: Mon Oct 27 08:07:45 2025 +0100

    CAUSEWAY-2297: grid refactoring
---
 .../apache/causeway/applib/layout/grid/Grid.java   |  41 +--
 .../applib/layout/grid/bootstrap/BSElement.java    |  14 +-
 .../applib/layout/grid/bootstrap/BSGrid.java       |  13 +-
 .../layout/grid/bootstrap/BSGridTransformer.java   |   7 +-
 .../applib/layout/grid/bootstrap/BSUtil.java       |  11 +-
 .../applib/layout/grid/bootstrap/BSWalker.java     | 113 +++----
 .../applib/services/grid/GridLoaderService.java    |  40 +--
 .../applib/services/grid/GridMarshaller.java       |  13 +-
 .../causeway/applib/services/grid/GridService.java | 120 +++----
 .../applib/services/grid/GridSystemService.java    |  71 ++--
 .../metamodel/facets/object/grid/BSGridFacet.java  |  21 +-
 .../metamodel/facets/object/grid/GridFacet.java    |   5 +-
 .../core/metamodel/layout/LayoutFacetUtil.java     | 372 ++++++++++-----------
 .../services/grid/GridLoaderServiceDefault.java    |  13 +-
 .../services/grid/GridServiceDefault.java          |  18 +-
 .../services/grid/GridSystemServiceAbstract.java   |  25 +-
 .../grid/XsiSchemaLocationProviderForGrid.java     |  39 +--
 .../grid/bootstrap/GridInitializationModel.java    |   8 +-
 .../bootstrap/GridMarshallerServiceBootstrap.java  |   4 +-
 .../grid/bootstrap/GridSystemServiceBootstrap.java |  28 +-
 .../causeway/core/metamodel/util/Facets.java       |   1 -
 .../mmtestsupport/MetaModelContext_forTesting.java |  37 +-
 .../sitemap/SitemapServiceDefault.java             |   4 +-
 .../help/topics/welcome/WelcomeHelpPage.java       |  45 +--
 .../resources/DomainObjectResourceServerside.java  |   9 +-
 25 files changed, 460 insertions(+), 612 deletions(-)

diff --git 
a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/Grid.java 
b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/Grid.java
index 2175f0a2ec7..f3592af66ec 100644
--- a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/Grid.java
+++ b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/Grid.java
@@ -18,13 +18,13 @@
  */
 package org.apache.causeway.applib.layout.grid;
 
+import java.io.Serializable;
+import java.util.Map;
 import java.util.stream.Stream;
 
 import org.apache.causeway.applib.annotation.Programmatic;
 import org.apache.causeway.applib.layout.component.ActionLayoutData;
 import org.apache.causeway.applib.layout.component.CollectionLayoutData;
-import org.apache.causeway.applib.layout.component.DomainObjectLayoutData;
-import org.apache.causeway.applib.layout.component.FieldSet;
 import org.apache.causeway.applib.layout.component.PropertyLayoutData;
 import org.apache.causeway.applib.services.layout.LayoutService;
 
@@ -35,11 +35,19 @@
  *
  * @since 1.x revised for 4.0 {@index}
  */
+@Deprecated
 @Programmatic
 public interface Grid {
 
     Class<?> domainClass();
 
+    /**
+     * Arbitrary additional 'runtime' data attributed to this grid,
+     * but not part of the DTO specification.
+     * @since 4.0
+     */
+    Map<String, Serializable> attributes();
+
     /**
      * Indicates whether or not this grid is a fallback.
      * {@code True}, if this Grid originates from
@@ -55,33 +63,4 @@ public interface Grid {
     Stream<CollectionLayoutData> streamCollectionLayoutData();
     Stream<ActionLayoutData> streamActionLayoutData();
 
-    interface Visitor {
-        default void visit(final DomainObjectLayoutData 
domainObjectLayoutData) {}
-        default void visit(final ActionLayoutData actionLayoutData) {}
-        default void visit(final PropertyLayoutData propertyLayoutData) {}
-        default void visit(final CollectionLayoutData collectionLayoutData) {}
-        default void visit(final FieldSet fieldSet) {}
-    }
-
-    void visit(final Grid.Visitor visitor);
-
-    // -- EMPTY GRID
-
-    final static Grid EMPTY = new EmptyGrid(Object.class);
-    static Grid empty() { return EMPTY; }
-
-    public record EmptyGrid(Class<?> domainClass) implements Grid {
-        @Override public boolean isFallback() { return false; }
-        @Override public boolean isNormalized() { return true; }
-        @Override public Stream<PropertyLayoutData> streamPropertyLayoutData() 
{
-            return Stream.empty();
-        }
-        @Override public Stream<CollectionLayoutData> 
streamCollectionLayoutData() {
-            return Stream.empty();
-        }
-        @Override public Stream<ActionLayoutData> streamActionLayoutData() {
-            return Stream.empty();
-        }
-        @Override public void visit(Visitor visitor) { }
-    };
 }
diff --git 
a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSElement.java
 
b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSElement.java
index cf75b3ae304..665f88969fa 100644
--- 
a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSElement.java
+++ 
b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSElement.java
@@ -20,7 +20,11 @@
 
 import java.io.Serializable;
 
-import org.apache.causeway.applib.layout.grid.Grid;
+import org.apache.causeway.applib.layout.component.ActionLayoutData;
+import org.apache.causeway.applib.layout.component.CollectionLayoutData;
+import org.apache.causeway.applib.layout.component.DomainObjectLayoutData;
+import org.apache.causeway.applib.layout.component.FieldSet;
+import org.apache.causeway.applib.layout.component.PropertyLayoutData;
 
 /**
  * @since 1.x {@index}
@@ -35,7 +39,7 @@ public interface BSElement extends Serializable {
     String getCssClass();
     void setCssClass(final String cssClass);
 
-    public interface Visitor extends Grid.Visitor {
+    public interface BSElementVisitor {
         default void preVisit(final BSGrid bsGrid) {}
         default void visit(final BSGrid bsGrid) {}
         default void postVisit(final BSGrid bsGrid) {}
@@ -52,6 +56,12 @@ default void postVisit(final BSTabGroup bsTabGroup) {}
         default void preVisit(final BSTab bsTab) {}
         default void visit(final BSTab bsTab) {}
         default void postVisit(final BSTab bsTab) {}
+
+        default void visit(final DomainObjectLayoutData 
domainObjectLayoutData) {}
+        default void visit(final ActionLayoutData actionLayoutData) {}
+        default void visit(final PropertyLayoutData propertyLayoutData) {}
+        default void visit(final CollectionLayoutData collectionLayoutData) {}
+        default void visit(final FieldSet fieldSet) {}
     }
 
 }
diff --git 
a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSGrid.java
 
b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSGrid.java
index bf75467581c..5638d4aa404 100644
--- 
a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSGrid.java
+++ 
b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSGrid.java
@@ -18,8 +18,10 @@
  */
 package org.apache.causeway.applib.layout.grid.bootstrap;
 
+import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 import java.util.stream.Stream;
 
 import jakarta.xml.bind.annotation.XmlAccessType;
@@ -54,6 +56,8 @@ public final class BSGrid implements Grid, BSElement, Dto, 
BSRowOwner {
 
     @XmlTransient @Getter @Accessors(fluent=true)  @Setter private Class<?> 
domainClass;
     @XmlTransient @Getter @Setter private boolean fallback;
+    @XmlTransient @Getter @Accessors(fluent=true) private final Map<String, 
Serializable> attributes = Map.of();
+
     @XmlTransient @Getter @Setter private boolean normalized;
 
     @XmlAttribute(required = false)
@@ -67,15 +71,14 @@ public final class BSGrid implements Grid, BSElement, Dto, 
BSRowOwner {
     @XmlElement(name = "metadataError", required = false)
     @Getter private final List<String> metadataErrors = new ArrayList<>();
 
-    @Override
-    public void visit(final Grid.Visitor visitor) {
+    public void visit(final BSElementVisitor visitor) {
         new BSWalker(this).walk(visitor);
     }
 
     @Override
     public Stream<PropertyLayoutData> streamPropertyLayoutData() {
         final var properties = new ArrayList<PropertyLayoutData>();
-        visit(new BSElement.Visitor() {
+        visit(new BSElementVisitor() {
             @Override
             public void visit(final PropertyLayoutData propertyLayoutData) {
                 properties.add(propertyLayoutData);
@@ -87,7 +90,7 @@ public void visit(final PropertyLayoutData 
propertyLayoutData) {
     @Override
     public Stream<CollectionLayoutData> streamCollectionLayoutData() {
         final var collections = new ArrayList<CollectionLayoutData>();
-        visit(new BSElement.Visitor() {
+        visit(new BSElementVisitor() {
             @Override
             public void visit(final CollectionLayoutData collectionLayoutData) 
{
                 collections.add(collectionLayoutData);
@@ -99,7 +102,7 @@ public void visit(final CollectionLayoutData 
collectionLayoutData) {
     @Override
     public Stream<ActionLayoutData> streamActionLayoutData() {
         final var actions = new ArrayList<ActionLayoutData>();
-        visit(new BSElement.Visitor() {
+        visit(new BSElementVisitor() {
             @Override
             public void visit(final ActionLayoutData actionLayoutData) {
                 actions.add(actionLayoutData);
diff --git 
a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSGridTransformer.java
 
b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSGridTransformer.java
index 36605c7360d..4bc5ed8da04 100644
--- 
a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSGridTransformer.java
+++ 
b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSGridTransformer.java
@@ -26,6 +26,7 @@
 import org.apache.causeway.applib.layout.component.CollectionLayoutData;
 import org.apache.causeway.applib.layout.component.DomainObjectLayoutData;
 import org.apache.causeway.applib.layout.component.PropertyLayoutData;
+import 
org.apache.causeway.applib.layout.grid.bootstrap.BSElement.BSElementVisitor;
 import org.apache.causeway.commons.internal.base._NullSafe;
 
 @FunctionalInterface
@@ -45,7 +46,7 @@ public BSGrid apply(final BSGrid bsGrid) {
             var emptyTabs = new ArrayList<BSTab>();
 
             // first phase: collect all empty tabs for removal
-            bsGrid.visit(new BSElement.Visitor() {
+            bsGrid.visit(new BSElementVisitor() {
 
                 final Stack<Flag> stack = new Stack<Flag>();
 
@@ -102,7 +103,7 @@ static final class Flag {
         public BSGrid apply(final BSGrid bsGrid) {
             var emptyRows = new ArrayList<BSRow>();
 
-            bsGrid.visit(new BSElement.Visitor() {
+            bsGrid.visit(new BSElementVisitor() {
 
                 final Stack<Flag> stack = new Stack<Flag>();
 
@@ -152,7 +153,7 @@ record CollapseIfOneTab() implements BSGridTransformer {
 
         @Override
         public BSGrid apply(final BSGrid bsGrid) {
-            bsGrid.visit(new BSElement.Visitor() {
+            bsGrid.visit(new BSElementVisitor() {
                 @Override
                 public void visit(final BSTabGroup bsTabGroup) {
                     if(bsTabGroup.getTabs().size()!=1) return; // when has no 
tabs is also a no-op
diff --git 
a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSUtil.java
 
b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSUtil.java
index e03d859cbdc..235ef3b9c82 100644
--- 
a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSUtil.java
+++ 
b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSUtil.java
@@ -25,6 +25,7 @@
 import org.apache.causeway.applib.layout.component.CollectionLayoutData;
 import org.apache.causeway.applib.layout.component.DomainObjectLayoutData;
 import org.apache.causeway.applib.layout.component.PropertyLayoutData;
+import 
org.apache.causeway.applib.layout.grid.bootstrap.BSElement.BSElementVisitor;
 import org.apache.causeway.commons.internal.base._Casts;
 import org.apache.causeway.commons.internal.resources._Serializables;
 
@@ -46,7 +47,7 @@ public class BSUtil {
      */
     public boolean hasContent(final BSTab thisBsTab) {
         final AtomicBoolean foundContent = new AtomicBoolean(false);
-        new BSWalker(thisBsTab).walk(new BSElement.Visitor() {
+        new BSWalker(thisBsTab).walk(new BSElementVisitor() {
             @Override
             public void visit(final DomainObjectLayoutData 
domainObjectLayoutData) {
                 foundContent.set(true);
@@ -84,28 +85,28 @@ public BSGrid resolveOwners(final BSGrid grid) {
     // -- REMOVERS
 
     /** removes the tab from its owner and returns the owner */
-    public Optional<BSTabOwner> remove(BSTab tab) {
+    public Optional<BSTabOwner> remove(final BSTab tab) {
         var ownerOpt = Optional.ofNullable(tab.owner());
         ownerOpt.ifPresent(owner->owner.getTabs().remove(tab));
         tab.owner(null);
         return ownerOpt;
     }
     /** removes the col from its owner and returns the owner */
-    public Optional<BSRowContentOwner> remove(BSCol col) {
+    public Optional<BSRowContentOwner> remove(final BSCol col) {
         var ownerOpt = Optional.ofNullable(col.owner());
         ownerOpt.ifPresent(owner->owner.getRowContents().remove(col));
         col.owner(null);
         return ownerOpt;
     }
     /** removes the tabGroup from its owner and returns the owner */
-    public Optional<BSTabGroupOwner> remove(BSTabGroup tabGroup) {
+    public Optional<BSTabGroupOwner> remove(final BSTabGroup tabGroup) {
         var ownerOpt = Optional.ofNullable(tabGroup.owner());
         ownerOpt.ifPresent(owner->owner.getTabGroups().remove(tabGroup));
         tabGroup.owner(null);
         return ownerOpt;
     }
     /** removes the row from its owner and returns the owner */
-    public Optional<BSRowOwner> remove(BSRow row) {
+    public Optional<BSRowOwner> remove(final BSRow row) {
         var ownerOpt = Optional.ofNullable(row.owner());
         ownerOpt.ifPresent(owner->owner.getRows().remove(row));
         row.owner(null);
diff --git 
a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSWalker.java
 
b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSWalker.java
index 94e81bdf6e1..afe19771755 100644
--- 
a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSWalker.java
+++ 
b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSWalker.java
@@ -29,47 +29,46 @@
 import org.apache.causeway.applib.layout.component.FieldSet;
 import org.apache.causeway.applib.layout.component.FieldSetOwner;
 import org.apache.causeway.applib.layout.component.PropertyLayoutData;
-import org.apache.causeway.applib.layout.grid.Grid;
+import 
org.apache.causeway.applib.layout.grid.bootstrap.BSElement.BSElementVisitor;
 
 public record BSWalker(BSRowOwner root) {
 
-    public void walk(final Grid.Visitor visitor) {
-        final BSElement.Visitor bsVisitor = asBsVisitor(visitor);
+    public void walk(final BSElementVisitor visitor) {
         if(root instanceof BSGrid bsGrid) {
-            bsVisitor.preVisit(bsGrid);
-            bsVisitor.visit(bsGrid);
-            traverseRows(root, bsVisitor);
-            bsVisitor.postVisit(bsGrid);
+            visitor.preVisit(bsGrid);
+            visitor.visit(bsGrid);
+            traverseRows(root, visitor);
+            visitor.postVisit(bsGrid);
         } else {
-            traverseRows(root, bsVisitor);
+            traverseRows(root, visitor);
         }
     }
 
-    private void traverseRows(final BSRowOwner rowOwner, final 
BSElement.Visitor bsVisitor) {
+    private void traverseRows(final BSRowOwner rowOwner, final 
BSElementVisitor visitor) {
         final List<BSRow> rows = rowOwner.getRows();
         for (BSRow bsRow : new ArrayList<>(rows)) {
-            bsVisitor.preVisit(bsRow);
-            bsVisitor.visit(bsRow);
-            traverseCols(bsRow, bsVisitor);
-            bsVisitor.postVisit(bsRow);
+            visitor.preVisit(bsRow);
+            visitor.visit(bsRow);
+            traverseCols(bsRow, visitor);
+            visitor.postVisit(bsRow);
         }
     }
 
-    private void traverseCols(final BSRow bsRow, final BSElement.Visitor 
bsVisitor) {
+    private void traverseCols(final BSRow bsRow, final BSElementVisitor 
visitor) {
         final List<BSRowContent> cols = bsRow.getRowContents();
         for (BSRowContent rowContent : new ArrayList<>(cols)) {
             if(rowContent instanceof BSCol bsCol) {
-                bsVisitor.preVisit(bsCol);
-                bsVisitor.visit(bsCol);
-                traverseDomainObject(bsCol, bsVisitor);
-                traverseTabGroups(bsCol, bsVisitor);
-                traverseActions(bsCol, bsVisitor);
-                traverseFieldSets(bsCol, bsVisitor);
-                traverseCollections(bsCol, bsVisitor);
-                traverseRows(bsCol, bsVisitor);
-                bsVisitor.postVisit(bsCol);
+                visitor.preVisit(bsCol);
+                visitor.visit(bsCol);
+                traverseDomainObject(bsCol, visitor);
+                traverseTabGroups(bsCol, visitor);
+                traverseActions(bsCol, visitor);
+                traverseFieldSets(bsCol, visitor);
+                traverseCollections(bsCol, visitor);
+                traverseRows(bsCol, visitor);
+                visitor.postVisit(bsCol);
             } else if (rowContent instanceof BSClearFix bsClearFix) {
-                bsVisitor.visit(bsClearFix);
+                visitor.visit(bsClearFix);
             } else {
                 throw new IllegalStateException(
                         "Unrecognized implementation of BSRowContent, " + 
rowContent);
@@ -77,83 +76,61 @@ private void traverseCols(final BSRow bsRow, final 
BSElement.Visitor bsVisitor)
         }
     }
 
-    private void traverseDomainObject(final BSCol bsCol, final 
BSElement.Visitor bsVisitor) {
+    private void traverseDomainObject(final BSCol bsCol, final 
BSElementVisitor visitor) {
         final DomainObjectLayoutData domainObject = bsCol.getDomainObject();
         if(domainObject == null) return;
-        bsVisitor.visit(domainObject);
+        visitor.visit(domainObject);
     }
 
-    private void traverseTabGroups(final BSTabGroupOwner bsTabGroupOwner, 
final BSElement.Visitor bsVisitor) {
+    private void traverseTabGroups(final BSTabGroupOwner bsTabGroupOwner, 
final BSElementVisitor visitor) {
         final List<BSTabGroup> tabGroups = bsTabGroupOwner.getTabGroups();
         for (BSTabGroup bsTabGroup : new ArrayList<>(tabGroups)) {
-            bsVisitor.preVisit(bsTabGroup);
-            bsVisitor.visit(bsTabGroup);
-            traverseTabs(bsTabGroup, bsVisitor);
-            bsVisitor.postVisit(bsTabGroup);
+            visitor.preVisit(bsTabGroup);
+            visitor.visit(bsTabGroup);
+            traverseTabs(bsTabGroup, visitor);
+            visitor.postVisit(bsTabGroup);
         }
     }
 
-    private void traverseTabs(final BSTabOwner bsTabOwner, final 
BSElement.Visitor bsVisitor) {
+    private void traverseTabs(final BSTabOwner bsTabOwner, final 
BSElementVisitor visitor) {
         final List<BSTab> tabs = bsTabOwner.getTabs();
         for (BSTab tab : new ArrayList<>(tabs)) {
-            bsVisitor.preVisit(tab);
-            bsVisitor.visit(tab);
-            traverseRows(tab, bsVisitor);
-            bsVisitor.postVisit(tab);
+            visitor.preVisit(tab);
+            visitor.visit(tab);
+            traverseRows(tab, visitor);
+            visitor.postVisit(tab);
         }
     }
 
-    private void traverseActions(final ActionLayoutDataOwner 
actionLayoutDataOwner, final BSElement.Visitor bsVisitor) {
+    private void traverseActions(final ActionLayoutDataOwner 
actionLayoutDataOwner, final BSElementVisitor visitor) {
         final List<ActionLayoutData> actionLayoutDatas = 
actionLayoutDataOwner.getActions();
         if(actionLayoutDatas == null) return;
 
         for (final ActionLayoutData actionLayoutData : new 
ArrayList<>(actionLayoutDatas)) {
-            bsVisitor.visit(actionLayoutData);
+            visitor.visit(actionLayoutData);
         }
     }
 
-    private void traverseFieldSets(final FieldSetOwner fieldSetOwner, final 
BSElement.Visitor bsVisitor) {
+    private void traverseFieldSets(final FieldSetOwner fieldSetOwner, final 
BSElementVisitor visitor) {
         final List<FieldSet> fieldSets = fieldSetOwner.getFieldSets();
         for (FieldSet fieldSet : new ArrayList<>(fieldSets)) {
-            bsVisitor.visit(fieldSet);
-            traverseActions(fieldSet, bsVisitor);
+            visitor.visit(fieldSet);
+            traverseActions(fieldSet, visitor);
             final List<PropertyLayoutData> properties = 
fieldSet.getProperties();
             for (final PropertyLayoutData property : new 
ArrayList<>(properties)) {
-                bsVisitor.visit(property);
-                traverseActions(property, bsVisitor);
+                visitor.visit(property);
+                traverseActions(property, visitor);
             }
         }
     }
 
     private void traverseCollections(
-            final CollectionLayoutDataOwner owner, final BSElement.Visitor 
bsVisitor) {
+            final CollectionLayoutDataOwner owner, final BSElementVisitor 
visitor) {
         final List<CollectionLayoutData> collections = owner.getCollections();
         for (CollectionLayoutData collection : new ArrayList<>(collections)) {
-            bsVisitor.visit(collection);
-            traverseActions(collection, bsVisitor);
+            visitor.visit(collection);
+            traverseActions(collection, visitor);
         }
     }
 
-    private BSElement.Visitor asBsVisitor(final Grid.Visitor visitor) {
-        return visitor instanceof BSElement.Visitor bsGridVisistor
-            ? bsGridVisistor
-            : new BSElement.Visitor() {
-                @Override public void visit(final DomainObjectLayoutData 
domainObjectLayoutData) {
-                    visitor.visit(domainObjectLayoutData);
-                }
-                @Override public void visit(final ActionLayoutData 
actionLayoutData) {
-                    visitor.visit(actionLayoutData);
-                }
-                @Override public void visit(final PropertyLayoutData 
propertyLayoutData) {
-                    visitor.visit(propertyLayoutData);
-                }
-                @Override public void visit(final CollectionLayoutData 
collectionLayoutData) {
-                    visitor.visit(collectionLayoutData);
-                }
-                @Override public void visit(final FieldSet fieldSet) {
-                    visitor.visit(fieldSet);
-                }
-            };
-    }
-
 }
diff --git 
a/api/applib/src/main/java/org/apache/causeway/applib/services/grid/GridLoaderService.java
 
b/api/applib/src/main/java/org/apache/causeway/applib/services/grid/GridLoaderService.java
index aac3248b272..623f3c67d10 100644
--- 
a/api/applib/src/main/java/org/apache/causeway/applib/services/grid/GridLoaderService.java
+++ 
b/api/applib/src/main/java/org/apache/causeway/applib/services/grid/GridLoaderService.java
@@ -25,11 +25,12 @@
 import org.jspecify.annotations.Nullable;
 
 import org.apache.causeway.applib.layout.grid.Grid;
+import org.apache.causeway.applib.layout.grid.bootstrap.BSGrid;
 import org.apache.causeway.applib.mixins.metamodel.Object_rebuildMetamodel;
 import org.apache.causeway.applib.value.NamedWithMimeType.CommonMimeType;
 
 /**
- * Provides the ability to load the XML layout (grid) for a domain class.
+ * Loads the XML layout (grid) for a domain class.
  *
  * @since 1.x - revised for 2.0 {@index}
  */
@@ -38,56 +39,51 @@ public interface GridLoaderService {
     /**
      * Whether dynamic reloading of layouts is enabled.
      *
-     * <p>
-     *     The default implementation enables reloading for prototyping mode,
-     *     disables in production
-     * </p>
+     * <p> The default implementation enables reloading for prototyping mode,
+     * disables in production
      */
     boolean supportsReloading();
 
     /**
      * To support metamodel invalidation/rebuilding of spec.
      *
-     * <p>
-     *     This is called by the {@link Object_rebuildMetamodel} mixin action.
-     * </p>
+     * <p>This is called by the {@link Object_rebuildMetamodel} mixin action.
      */
     void remove(Class<?> domainClass);
 
     /**
      * Whether any persisted layout metadata (eg a <code>.layout.xml</code> 
file) exists for this domain class.
      *
-     * <p>
-     *     If none exists, will return null (and the calling {@link 
GridService}  will use {@link GridSystemService}
-     *     to obtain a default grid for the domain class).
-     * </p>
+     * <p>If none exists, will return null (and the calling {@link 
GridService}  will use {@link GridSystemService}
+     * to obtain a default grid for the domain class).
      */
     boolean existsFor(Class<?> domainClass, EnumSet<CommonMimeType> 
supportedFormats);
 
     /**
      * Optionally returns a new instance of a {@link Grid},
      * based on whether the underlying resource could be found, loaded and 
parsed.
-     * <p>
-     *     The layout alternative will typically be specified through a
-     *     `layout()` method on the domain object, the value of which is used
-     *     for the suffix of the layout file (eg "Customer-layout.archived.xml"
-     *     to use a different layout for customers that have been archived).
-     * </p>
+     *
+     * <p>The layout alternative will typically be specified through a
+     * `layout()` method on the domain object, the value of which is used
+     * for the suffix of the layout file (eg "Customer-layout.archived.xml"
+     * to use a different layout for customers that have been archived).
+     *
      * @throws UnsupportedOperationException - when format is not supported
      */
-    <T extends Grid> Optional<T> load(
+    Optional<BSGrid> load(
             Class<?> domainClass,
             @Nullable String layoutIfAny,
-            @NonNull GridMarshaller<T> marshaller);
+            @NonNull GridMarshaller marshaller);
 
     /**
      * Optionally returns a new instance of a {@link Grid},
      * based on whether the underlying resource could be found, loaded and 
parsed.
+     *
      * @throws UnsupportedOperationException - when format is not supported
      */
-    default <T extends Grid> Optional<T> load(
+    default Optional<BSGrid> load(
             final Class<?> domainClass,
-            final @NonNull GridMarshaller<T> marshaller) {
+            final @NonNull GridMarshaller marshaller) {
         return load(domainClass, null, marshaller);
     }
 
diff --git 
a/api/applib/src/main/java/org/apache/causeway/applib/services/grid/GridMarshaller.java
 
b/api/applib/src/main/java/org/apache/causeway/applib/services/grid/GridMarshaller.java
index 4b3d36e807e..6e2678791bd 100644
--- 
a/api/applib/src/main/java/org/apache/causeway/applib/services/grid/GridMarshaller.java
+++ 
b/api/applib/src/main/java/org/apache/causeway/applib/services/grid/GridMarshaller.java
@@ -24,6 +24,7 @@
 import org.jspecify.annotations.Nullable;
 
 import org.apache.causeway.applib.layout.grid.Grid;
+import org.apache.causeway.applib.layout.grid.bootstrap.BSGrid;
 import org.apache.causeway.applib.services.marshal.Marshaller;
 import org.apache.causeway.applib.value.NamedWithMimeType.CommonMimeType;
 import org.apache.causeway.commons.functional.Try;
@@ -35,25 +36,25 @@
  *
  * @since 2.0 revised for 4.0 {@index}
  */
-public interface GridMarshaller<T extends Grid> {
+public interface GridMarshaller {
 
-    Class<T> supportedClass();
+    Class<BSGrid> supportedClass();
 
     /**
-     * Supported format(s) for {@link #unmarshal(String, CommonMimeType)}
-     * and {@link #marshal(Object, CommonMimeType)}.
+     * Supported format(s) for {@link #unmarshal(Class, String, 
CommonMimeType)}
+     * and {@link #marshal(BSGrid, CommonMimeType)}.
      */
     EnumSet<CommonMimeType> supportedFormats();
 
     /**
      * @throws UnsupportedOperationException when format is not supported
      */
-    String marshal(@NonNull T value, @NonNull CommonMimeType format);
+    String marshal(@NonNull BSGrid value, @NonNull CommonMimeType format);
 
     /**
      * Returns a new de-serialized instance wrapped in a {@link Try}.
      * @throws UnsupportedOperationException when format is not supported (not 
wrapped)
      */
-    Try<T> unmarshal(Class<?> domainClass, @Nullable String content, @NonNull 
CommonMimeType format);
+    Try<BSGrid> unmarshal(Class<?> domainClass, @Nullable String content, 
@NonNull CommonMimeType format);
 
 }
diff --git 
a/api/applib/src/main/java/org/apache/causeway/applib/services/grid/GridService.java
 
b/api/applib/src/main/java/org/apache/causeway/applib/services/grid/GridService.java
index 47cbbfab17b..7da28a7fe09 100644
--- 
a/api/applib/src/main/java/org/apache/causeway/applib/services/grid/GridService.java
+++ 
b/api/applib/src/main/java/org/apache/causeway/applib/services/grid/GridService.java
@@ -23,12 +23,14 @@
 import org.apache.causeway.applib.annotation.DomainObjectLayout;
 import org.apache.causeway.applib.annotation.PropertyLayout;
 import org.apache.causeway.applib.layout.grid.Grid;
+import org.apache.causeway.applib.layout.grid.bootstrap.BSGrid;
 import org.apache.causeway.applib.services.layout.LayoutExportStyle;
 import org.apache.causeway.commons.internal.exceptions._Exceptions;
 
 /**
- * Provides the ability to load the XML layout (grid) for a domain class.
+ * Loads the layout (grid) for any domain class.
  *
+ * <p> Acts on top of {@link GridLoaderService}, {@link GridMarshaller} and 
any {@link GridSystemService}(s) registered with Spring.
  * @since 1.x {@index}
  */
 public interface GridService {
@@ -36,31 +38,25 @@ public interface GridService {
     /**
      * Whether dynamic reloading of layouts is enabled.
      *
-     * <p>
-     *     The default implementation just delegates to the configured
-     *     {@link GridLoaderService}; the default implementation of <i>that</i>
-     *     service enables reloading wihle prototyping, disables in production.
-     * </p>
+     * <p> The default implementation just delegates to the configured
+     * {@link GridLoaderService}; the default implementation of <i>that</i>
+     * service enables reloading while prototyping, disables in production.
      */
     boolean supportsReloading();
 
     /**
      * To support metamodel invalidation/rebuilding of spec.
      *
-     * <p>
-     *     The default implementation just delegates to the configured
-     *     {@link GridLoaderService}.
-     * </p>
+     * <p>The default implementation just delegates to the configured
+     * {@link GridLoaderService}.
      */
     void remove(Class<?> domainClass);
 
     /**
      * Whether any persisted layout metadata (eg a <code>.layout.xml</code> 
file) exists for this domain class.
      *
-     * <p>
-     *     The default implementation just delegates to the configured
-     *     {@link GridLoaderService}.
-     * </p>
+     * <p>The default implementation just delegates to the configured
+     * {@link GridLoaderService}.
      */
     boolean existsFor(Class<?> domainClass);
 
@@ -68,103 +64,85 @@ public interface GridService {
      * Returns a new instance of a {@link Grid} for the specified domain class,
      * for example as loaded from a <code>layout.xml</code> file.
      *
-     * <p>
-     *     If non exists, returns <code>null</code>.  (The caller can then
-     *     use {@link GridService#defaultGridFor(Class)} to obtain a
-     *     default grid if necessary).
-     * </p>
+     * <p>If non exists, returns <code>null</code>.  (The caller can then
+     * use {@link GridService#defaultGridFor(Class)} to obtain a
+     * default grid if necessary).
      *
-     * <p>
-     *     The default implementation just delegates to the configured
-     *     {@link GridLoaderService}.
-     * </p>
+     * <p>The default implementation just delegates to the configured
+     * {@link GridLoaderService}.
      */
-    Grid load(final Class<?> domainClass);
+    BSGrid load(final Class<?> domainClass);
 
     /**
      * Returns an alternative layout for the domain class.
      *
-     * <p>
-     *     The alternative layout name can for example be returned by the
-     *     domain object's <code>layout()</code> method, whereby - based on the
-     *     state of the domain object - it requests a different layout be used.
-     * </p>
+     * <p>The alternative layout name can for example be returned by the
+     * domain object's <code>layout()</code> method, whereby - based on the
+     * state of the domain object - it requests a different layout be used.
      *
-     * <p>
-     *     The default implementation just delegates to the configured
-     *     {@link GridLoaderService}; the default implementation of <i>that</i>
-     *     service uses the layout name to search for a differently
-     *      named layout file, <code>[domainClass].layout.[layout].xml</code>.
-     * </p>
+     * <p>The default implementation just delegates to the configured
+     * {@link GridLoaderService}; the default implementation of <i>that</i>
+     * service uses the layout name to search for a differently
+     * named layout file, <code>[domainClass].layout.[layout].xml</code>.
      */
-    Grid load(Class<?> domainClass, String layout);
+    BSGrid load(Class<?> domainClass, String layout);
 
     /**
      * Returns a default grid; eg where none can be loaded using {@link 
#load(Class)}.
      *
-     * <p>
-     * Used when no existing grid layout exists for a domain class.
-     * </p>
+     * <p>Used when no existing grid layout exists for a domain class.
      *
-     * <p>
-     *     The default implementation searches through all available
-     *     {@link GridSystemService}s and asks each in turn for a
-     *     {@link GridSystemService#defaultGrid(Class) default grid}.
-     * </p>
+     * <p>The default implementation searches through all available
+     * {@link GridSystemService}s and asks each in turn for a
+     * {@link GridSystemService#defaultGrid(Class) default grid}.
      */
-    Grid defaultGridFor(Class<?> domainClass);
+    BSGrid defaultGridFor(Class<?> domainClass);
 
     /**
      * Returns a normalized grid for the domain class obtained previously 
using {@link #load(Class)}.
      *
-     * <p>
-     *     If a 'normalized' grid is persisted as the <code>layout.xml</code>, 
then the expectation is that
-     *     any ordering metadata from layout annotations can be removed from 
the domain class
-     *     because the binding of properties/collections/actions will be 
within the XML.  However, the layout
-     *     annotations ({@link DomainObjectLayout}, {@link ActionLayout}, 
{@link PropertyLayout} and
-     *     {@link CollectionLayout}) (if present) will continue to be used to 
provide additional layout metadata.  Of
-     *     course, there is nothing to prevent the developer from extending 
the layout XML to also include the
-     *     layout XML (in other words moving towards a {@link #complete(Grid) 
complete} grid.  Metadata within the
-     *     <code>layout.xml</code> file takes precedence over any annotations.
-     * </p>
+     * <p>If a 'normalized' grid is persisted as the <code>layout.xml</code>, 
then the expectation is that
+     * any ordering metadata from layout annotations can be removed from the 
domain class
+     * because the binding of properties/collections/actions will be within 
the XML.  However, the layout
+     * annotations ({@link DomainObjectLayout}, {@link ActionLayout}, {@link 
PropertyLayout} and
+     * {@link CollectionLayout}) (if present) will continue to be used to 
provide additional layout metadata.  Of
+     * course, there is nothing to prevent the developer from extending the 
layout XML to also include the
+     * layout XML (in other words moving towards a {@link #complete(BSGrid) 
complete} grid.  Metadata within the
+     * <code>layout.xml</code> file takes precedence over any annotations.
      */
-    Grid normalize(final Grid grid);
+    BSGrid normalize(BSGrid grid);
 
     /**
      * Modifies the provided {@link Grid} with additional metadata, broadly 
speaking corresponding to the
      * {@link DomainObjectLayout}, {@link ActionLayout}, {@link 
PropertyLayout} and {@link CollectionLayout}.
      *
-     * <p>
-     *     If a 'complete' grid is persisted as the <code>layout.xml</code>, 
then there should be no need
-     *     for any of the layout annotations,
-     *     to be required in the domain class itself.
-     * </p>
+     * <p>If a 'complete' grid is persisted as the <code>layout.xml</code>, 
then there should be no need
+     * for any of the layout annotations,
+     * to be required in the domain class itself.
      */
-    Grid complete(Grid grid);
+    BSGrid complete(BSGrid grid);
 
     /**
      * Modifies the provided {@link Grid}, removing all metadata except the 
basic grid structure.
      *
-     * <p>
-     *     If a 'minimal' grid is persisted as the <code>layout.xml</code>, 
then the expectation is that
-     *     most of the layout annotations ({@link DomainObjectLayout}, {@link 
ActionLayout}, {@link PropertyLayout},
-     *     {@link CollectionLayout} will still be retained in the domain class 
code.
-     * </p>
+     * <p>If a 'minimal' grid is persisted as the <code>layout.xml</code>, 
then the expectation is that
+     * most of the layout annotations ({@link DomainObjectLayout}, {@link 
ActionLayout}, {@link PropertyLayout},
+     * {@link CollectionLayout} will still be retained in the domain class 
code.
      *
      * @param grid
      */
-    Grid minimal(Grid grid);
+    BSGrid minimal(BSGrid grid);
 
     // -- LAYOUT EXPORT
 
-    GridMarshaller<? extends Grid> marshaller();
+    GridMarshaller marshaller(); //TODO rename
 
-    default Grid toGridForExport(
+    default BSGrid toGridForExport(
             final Class<?> domainClass,
             final LayoutExportStyle style) {
 
         // don't use the grid from the facet, because it will be modified 
subsequently.
-        Grid grid = load(domainClass);
+        BSGrid grid = load(domainClass);
         if(grid == null) {
             grid = defaultGridFor(domainClass);
         }
diff --git 
a/api/applib/src/main/java/org/apache/causeway/applib/services/grid/GridSystemService.java
 
b/api/applib/src/main/java/org/apache/causeway/applib/services/grid/GridSystemService.java
index c9cfaaf1d12..7737534c74f 100644
--- 
a/api/applib/src/main/java/org/apache/causeway/applib/services/grid/GridSystemService.java
+++ 
b/api/applib/src/main/java/org/apache/causeway/applib/services/grid/GridSystemService.java
@@ -19,75 +19,47 @@
 package org.apache.causeway.applib.services.grid;
 
 import org.apache.causeway.applib.layout.grid.Grid;
+import org.apache.causeway.applib.layout.grid.bootstrap.BSGrid;
 
 /**
  * Encapsulates a single layout grid system which can be used to customize the 
layout
  * of domain objects.
  *
- * <p>
- * In particular this means being able to return a "normalized" form
+ * <p>In particular this means being able to return a "normalized" form
  * (validating and associating domain object members into the various regions
  * of the grid) and in providing a default grid if there is no other metadata
  * available.
- * </p>
  *
  * @since 1.x {@index}
  */
-public interface GridSystemService<G extends Grid> {
+public interface GridSystemService {
 
     /**
      * The concrete subclass of {@link Grid} supported by this implementation.
      *
-     * <p>
-     *     There can be multiple implementations of this service, this 
indicates
-     *     the base class used by the implementation.
-     * </p>
+     * <p>There can be multiple implementations of this service, this indicates
+     * the base class used by the implementation.
      */
-    Class<G> gridImplementation();
-
-    /**
-     * The target namespace for this grid system.
-     *
-     * <p>
-     *     This is used when generating the XML.  The Bootstrap grid system
-     *     provided by the framework returns the value
-     *     `https://causeway.apache.org/applib/layout/grid/bootstrap3`.
-     * </p>
-     */
-    String tns();
-
-    /**
-     * The schema location for the XSD.
-     *
-     * <p>
-     *     Every grid system is expected to provide a schema XSD in order to
-     *     provide code completion in an IDE. The Bootstrap grid system
-     *     provided by the framework returns the value
-     *     
`https://causeway.apache.org/applib/layout/grid/bootstrap3/bootstrap3.xsd`.
-     * </p>
-     */
-    String schemaLocation();
+    Class<BSGrid> gridImplementation();
 
     /**
      * A default grid, used when no grid layout can be found for the domain
      * class.
      *
-     * <p>
-     *     For example, this layout could define two columns in ratio 4:8.
-     * </p>
+     * <p>For example, this layout could define two columns in ratio 4:8.
      *
      * @param domainClass
      */
-    G defaultGrid(Class<?> domainClass);
+    BSGrid defaultGrid(Class<?> domainClass);
 
     /**
      * Validates and normalizes a grid, modifying the grid so that all of the
      * domain object's members (properties, collections, actions) are bound to
      * regions of the grid.
-     * <p>
-     * E.g. for properties (and similar for collections and actions) the 
annotation attributes
-     * {@link org.apache.causeway.applib.annotation.PropertyLayout#sequence()} 
-     * and 
+     *
+     * <p>E.g. for properties (and similar for collections and actions) the 
annotation attributes
+     * {@link org.apache.causeway.applib.annotation.PropertyLayout#sequence()}
+     * and
      * {@link 
org.apache.causeway.applib.annotation.PropertyLayout#fieldSetId()}
      * or
      * {@link 
org.apache.causeway.applib.annotation.PropertyLayout#fieldSetName()}
@@ -96,14 +68,14 @@ public interface GridSystemService<G extends Grid> {
      * allows the various layout annotation attributes to be unspecified or 
removed from the source code
      * of the domain class.
      */
-    void normalize(G grid, Class<?> domainClass);
+    void normalize(BSGrid grid, Class<?> domainClass);
 
     /**
      * Takes a normalized grid and enriches it with all the available metadata
      * (taken from Apache Causeway' internal metadata) that can be represented 
in
      * the layout XML.
-     * <p>
-     * Such a grid, if persisted as the layout XML file for the domain class,
+     *
+     * <p>Such a grid, if persisted as the layout XML file for the domain 
class,
      * allows all layout annotations
      * ({@link org.apache.causeway.applib.annotation.ActionLayout},
      * {@link org.apache.causeway.applib.annotation.PropertyLayout},
@@ -112,24 +84,25 @@ public interface GridSystemService<G extends Grid> {
      * @param grid
      * @param domainClass
      */
-    void complete(G grid, Class<?> domainClass);
+    void complete(BSGrid grid, Class<?> domainClass);
 
     /**
      * Takes a normalized grid and strips out removes all members, leaving only
      * the grid structure.
-     * <p>
-     * Such a grid, if persisted as the layout XML file for the domain class, 
+     *
+     * <p>Such a grid, if persisted as the layout XML file for the domain 
class,
      * requires that e.g. for properties (and similar for collections and 
actions) the annotation attributes
-     * {@link org.apache.causeway.applib.annotation.PropertyLayout#sequence()} 
-     * and 
+     * {@link org.apache.causeway.applib.annotation.PropertyLayout#sequence()}
+     * and
      * {@link 
org.apache.causeway.applib.annotation.PropertyLayout#fieldSetId()}
      * or
      * {@link 
org.apache.causeway.applib.annotation.PropertyLayout#fieldSetName()}
      * are retained in the source code of said class in order to bind
      * members to the regions of the grid.
+     *
      * @param grid
      * @param domainClass
      */
-    void minimal(G grid, Class<?> domainClass);
+    void minimal(BSGrid grid, Class<?> domainClass);
 
 }
diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/grid/BSGridFacet.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/grid/BSGridFacet.java
index 0e59392558c..e4abfe06f87 100644
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/grid/BSGridFacet.java
+++ 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/grid/BSGridFacet.java
@@ -26,7 +26,6 @@
 import org.jspecify.annotations.NonNull;
 import org.jspecify.annotations.Nullable;
 
-import org.apache.causeway.applib.layout.grid.Grid;
 import org.apache.causeway.applib.layout.grid.bootstrap.BSGrid;
 import org.apache.causeway.applib.services.grid.GridService;
 import org.apache.causeway.commons.internal.base._Lazy;
@@ -64,12 +63,7 @@ public static GridFacet create(
     @Override public FacetHolder getFacetHolder() { return facetHolder(); }
 
     @Override
-    public boolean supports(Class<? extends Grid> gridClass) {
-        return BSGrid.class.equals(gridClass);
-    }
-
-    @Override
-    public Grid getGrid(final @Nullable ManagedObject mo) {
+    public BSGrid getGrid(final @Nullable ManagedObject mo) {
         guardAgainstObjectOfDifferentType(mo);
         return normalized(mo);
     }
@@ -125,7 +119,7 @@ private BSGrid load(final @NonNull String layoutPrefix) {
                 gridService.load(domainClass, 
_Strings.emptyToNull(layoutPrefix)))
                 // loads from default-XML if available
                 .orElseGet(()->gridService.defaultGridFor(domainClass));
-        var bsGrid = (BSGrid) gridService.normalize(grid);
+        var bsGrid = gridService.normalize(grid);
         return bsGrid;
     }
 
@@ -140,17 +134,12 @@ record NoLayout(
         @Override public Precedence getPrecedence() { return precedence(); }
         @Override public FacetHolder getFacetHolder() { return facetHolder(); }
 
-        @Override public void visitAttributes(BiConsumer<String, Object> 
visitor) {
+        @Override public void visitAttributes(final BiConsumer<String, Object> 
visitor) {
             visitor.accept("precedence", getPrecedence().name());
         }
-        @Override public Grid getGrid(@Nullable ManagedObject mo) {
-            return Grid.empty();
+        @Override public BSGrid getGrid(@Nullable final ManagedObject mo) {
+            return null;
         }
-        @Override
-        public boolean supports(Class<? extends Grid> gridClass) {
-            return false;
-        }
-
     }
 
 }
diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/grid/GridFacet.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/grid/GridFacet.java
index be6fe67eb26..5a74ff77707 100644
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/grid/GridFacet.java
+++ 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/grid/GridFacet.java
@@ -20,7 +20,7 @@
 
 import org.jspecify.annotations.Nullable;
 
-import org.apache.causeway.applib.layout.grid.Grid;
+import org.apache.causeway.applib.layout.grid.bootstrap.BSGrid;
 import org.apache.causeway.applib.services.grid.GridSystemService;
 import org.apache.causeway.applib.services.layout.LayoutService;
 import org.apache.causeway.core.metamodel.facetapi.Facet;
@@ -34,7 +34,6 @@
  */
 public interface GridFacet extends Facet {
 
-    boolean supports(Class<? extends Grid> gridClass);
-    Grid getGrid(@Nullable ManagedObject mo);
+    BSGrid getGrid(@Nullable ManagedObject mo);
 
 }
diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/layout/LayoutFacetUtil.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/layout/LayoutFacetUtil.java
index abcb90f87b7..9654b1a156b 100644
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/layout/LayoutFacetUtil.java
+++ 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/layout/LayoutFacetUtil.java
@@ -35,7 +35,7 @@
 import org.apache.causeway.applib.layout.component.HasHidden;
 import org.apache.causeway.applib.layout.component.HasNamed;
 import org.apache.causeway.applib.layout.component.PropertyLayoutData;
-import org.apache.causeway.applib.layout.grid.Grid;
+import 
org.apache.causeway.applib.layout.grid.bootstrap.BSElement.BSElementVisitor;
 import org.apache.causeway.commons.internal.base._Strings;
 import org.apache.causeway.commons.internal.functions._Functions;
 import org.apache.causeway.core.metamodel.facetapi.Facet;
@@ -60,21 +60,105 @@
 import 
org.apache.causeway.core.metamodel.facets.objectvalue.typicallen.TypicalLengthFacet;
 import org.apache.causeway.core.metamodel.spec.ObjectSpecification;
 
-import org.jspecify.annotations.NonNull;
-import lombok.RequiredArgsConstructor;
 import lombok.experimental.UtilityClass;
 
-/**
- *
- * @since 2.0
- *
- */
 @UtilityClass
 public class LayoutFacetUtil {
 
-    public void setBookmarkingIfAny(
-            final HasBookmarking hasBookmarking,
-            final FacetHolder facetHolder) {
+    public record LayoutDataFactory(MetamodelToGridOverridingVisitor helper) {
+
+        public LayoutDataFactory(final ObjectSpecification objectSpec) {
+            this(new MetamodelToGridOverridingVisitor(objectSpec));
+        }
+
+        public ActionLayoutData createActionLayoutData(final String id) {
+            var layoutData = new ActionLayoutData(id);
+            helper.visit(layoutData);
+            return layoutData;
+        }
+
+        public CollectionLayoutData createCollectionLayoutData(final String 
id) {
+            var layoutData = new CollectionLayoutData(id);
+            helper.visit(layoutData);
+            return layoutData;
+        }
+
+        public PropertyLayoutData createPropertyLayoutData(final String id) {
+            var layoutData = new PropertyLayoutData(id);
+            helper.visit(layoutData);
+            return layoutData;
+        }
+
+        public DomainObjectLayoutData createDomainObjectLayoutData() {
+            var layoutData = new DomainObjectLayoutData();
+            helper.visit(layoutData);
+            return layoutData;
+        }
+
+    }
+
+    public record MetamodelToGridOverridingVisitor(ObjectSpecification 
objectSpec) implements BSElementVisitor {
+
+        @Override
+        public void visit(final ActionLayoutData actionLayoutData) {
+            objectSpec.getAction(actionLayoutData.getId())
+            .ifPresent(objectAction->{
+                setCssClassIfAny(actionLayoutData, objectAction);
+                setCssClassFaIfAny(actionLayoutData, objectAction);
+                setMemberDescribedIfAny(actionLayoutData, objectAction);
+                setHiddenIfAny(actionLayoutData, objectAction);
+                setMemberNamedIfAny(actionLayoutData, objectAction);
+                setActionPositionIfAny(actionLayoutData, objectAction);
+            });
+        }
+
+        @Override
+        public void visit(final CollectionLayoutData collectionLayoutData) {
+            objectSpec.getAssociation(collectionLayoutData.getId())
+            .ifPresent(collection->{
+                setCssClassIfAny(collectionLayoutData, collection);
+                setDefaultViewIfAny(collectionLayoutData, collection);
+                setMemberDescribedIfAny(collectionLayoutData, collection);
+                setHiddenIfAny(collectionLayoutData, collection);
+                setMemberNamedIfAny(collectionLayoutData, collection);
+                setPagedIfAny(collectionLayoutData, collection, objectSpec);
+                setTableDecoratorIfAny(collectionLayoutData, collection, 
objectSpec);
+                setSortedByIfAny(collectionLayoutData, collection);
+            });
+        }
+
+        @Override
+        public void visit(final PropertyLayoutData propertyLayoutData) {
+            objectSpec.getAssociation(propertyLayoutData.getId())
+            .ifPresent(property->{
+                setCssClassIfAny(propertyLayoutData, property);
+                setMemberDescribedIfAny(propertyLayoutData, property);
+                setHiddenIfAny(propertyLayoutData, property);
+                setMemberNamedIfAny(propertyLayoutData, property);
+                setLabelPositionIfAny(propertyLayoutData, property);
+                setMultiLineIfAny(propertyLayoutData, property);
+                setRenderedAsDayBeforeIfAny(propertyLayoutData, property);
+                setTypicalLengthIfAny(propertyLayoutData, property);
+            });
+        }
+
+        @Override
+        public void visit(final DomainObjectLayoutData domainObjectLayoutData) 
{
+            setBookmarkingIfAny(domainObjectLayoutData, objectSpec);
+            setCssClassIfAny(domainObjectLayoutData, objectSpec);
+            setCssClassFaIfAny(domainObjectLayoutData, objectSpec);
+            setObjectDescribedIfAny(domainObjectLayoutData, objectSpec);
+            setObjectNamedIfAny(domainObjectLayoutData, objectSpec);
+            setPagedIfAny(domainObjectLayoutData, objectSpec);
+            setTableDecoratorIfAny(domainObjectLayoutData, objectSpec);
+        }
+    }
+
+    // -- HELPER
+
+    private void setBookmarkingIfAny(
+        final HasBookmarking hasBookmarking,
+        final FacetHolder facetHolder) {
 
         var bookmarkPolicyFacet = 
facetHolder.getFacet(BookmarkPolicyFacet.class);
         if(isNonFallback(bookmarkPolicyFacet)) {
@@ -85,9 +169,9 @@ public void setBookmarkingIfAny(
         }
     }
 
-    public void setCssClassIfAny(
-            final HasCssClass hasCssClass,
-            final FacetHolder facetHolder) {
+    private void setCssClassIfAny(
+        final HasCssClass hasCssClass,
+        final FacetHolder facetHolder) {
 
         var cssClassFacet = facetHolder.getFacet(CssClassFacet.class);
         if(isNonFallback(cssClassFacet)) {
@@ -103,27 +187,27 @@ public void setCssClassIfAny(
         }
     }
 
-    public void setCssClassFaIfAny(
-            final HasCssClassFa hasCssClassFa,
-            final FacetHolder facetHolder) {
+    private void setCssClassFaIfAny(
+        final HasCssClassFa hasCssClassFa,
+        final FacetHolder facetHolder) {
 
         facetHolder.lookupNonFallbackFacet(FaFacet.class)
         .map(FaFacet::getSpecialization)
         .ifPresent(specialization->
-            specialization.accept(
-                    faStaticFacet->{
-                        final String cssClassFa = 
faStaticFacet.getLayers().toQuickNotation();
-                        if(!_Strings.isNullOrEmpty(cssClassFa)) {
-                            hasCssClassFa.setCssClassFa(cssClassFa);
-                            
hasCssClassFa.setCssClassFaPosition(faStaticFacet.getLayers().position());
-                        }
-                    },
-                    _Functions.noopConsumer())); // not supported for 
imperative fa-icons
+        specialization.accept(
+            faStaticFacet->{
+                final String cssClassFa = 
faStaticFacet.getLayers().toQuickNotation();
+                if(!_Strings.isNullOrEmpty(cssClassFa)) {
+                    hasCssClassFa.setCssClassFa(cssClassFa);
+                    
hasCssClassFa.setCssClassFaPosition(faStaticFacet.getLayers().position());
+                }
+            },
+            _Functions.noopConsumer())); // not supported for imperative 
fa-icons
     }
 
-    public void setDefaultViewIfAny(
-            final CollectionLayoutData collectionLayoutData,
-            final FacetHolder facetHolder) {
+    private void setDefaultViewIfAny(
+        final CollectionLayoutData collectionLayoutData,
+        final FacetHolder facetHolder) {
 
         var defaultViewFacet = facetHolder.getFacet(DefaultViewFacet.class);
         if(isNonFallback(defaultViewFacet)) {
@@ -135,8 +219,8 @@ public void setDefaultViewIfAny(
     }
 
     private void setObjectNamedIfAny(
-            final HasNamed hasNamed,
-            final FacetHolder facetHolder) {
+        final HasNamed hasNamed,
+        final FacetHolder facetHolder) {
 
         facetHolder.lookupNonFallbackFacet(ObjectNamedFacet.class)
         .filter(ObjectNamedFacet::isNounPresent)
@@ -145,8 +229,8 @@ private void setObjectNamedIfAny(
     }
 
     private void setObjectDescribedIfAny(
-            final HasDescribedAs hasDescribedAs,
-            final FacetHolder facetHolder) {
+        final HasDescribedAs hasDescribedAs,
+        final FacetHolder facetHolder) {
 
         facetHolder.lookupNonFallbackFacet(ObjectDescribedFacet.class)
         .map(ObjectDescribedFacet::translated)
@@ -154,9 +238,9 @@ private void setObjectDescribedIfAny(
         .ifPresent(hasDescribedAs::setDescribedAs);
     }
 
-    public void setPagedIfAny(
-            final DomainObjectLayoutData domainObjectLayoutData,
-            final FacetHolder facetHolder) {
+    private void setPagedIfAny(
+        final DomainObjectLayoutData domainObjectLayoutData,
+        final FacetHolder facetHolder) {
 
         var pagedFacet = FacetUtil.lookupFacetIn(PagedFacet.class, 
facetHolder).orElse(null);
         if(isNonFallback(pagedFacet)) {
@@ -167,56 +251,53 @@ public void setPagedIfAny(
         }
     }
 
-    public void setTableDecoratorIfAny(
-            final DomainObjectLayoutData domainObjectLayoutData,
-            final FacetHolder facetHolder) {
+    private void setTableDecoratorIfAny(
+        final DomainObjectLayoutData domainObjectLayoutData,
+        final FacetHolder facetHolder) {
 
-        var tableDecoratorFacet = 
FacetUtil.lookupFacetIn(TableDecoratorFacet.class, facetHolder).orElse(null);
-        if(isNonFallback(tableDecoratorFacet)) {
-            final Class<? extends TableDecorator> value = 
tableDecoratorFacet.value();
-            if(value != TableDecorator.Default.class) {
-                domainObjectLayoutData.setTableDecorator(value);
-            }
-        }
+        facetHolder.lookupNonFallbackFacet(TableDecoratorFacet.class)
+            .map(TableDecoratorFacet::value)
+            .filter(it->it!=TableDecorator.Default.class)
+            .ifPresent(domainObjectLayoutData::setTableDecorator);
     }
 
     private void setMemberNamedIfAny(
-            final HasNamed hasNamed,
-            final FacetHolder facetHolder) {
+        final HasNamed hasNamed,
+        final FacetHolder facetHolder) {
 
         facetHolder.lookupNonFallbackFacet(MemberNamedFacet.class)
         .map(MemberNamedFacet::getSpecialization)
         .ifPresent(specialization->
-            specialization.accept(
-                    hasStaticText->{
-                        var describedAs = hasStaticText.translated();
-                        if(_Strings.isNotEmpty(describedAs)) {
-                            hasNamed.setNamed(describedAs);
-                        }
-                    },
-                    _Functions.noopConsumer())); // not supported for 
imperative text
+        specialization.accept(
+            hasStaticText->{
+                var describedAs = hasStaticText.translated();
+                if(_Strings.isNotEmpty(describedAs)) {
+                    hasNamed.setNamed(describedAs);
+                }
+            },
+            _Functions.noopConsumer())); // not supported for imperative text
     }
 
     private void setMemberDescribedIfAny(
-            final HasDescribedAs hasDescribedAs,
-            final FacetHolder facetHolder) {
+        final HasDescribedAs hasDescribedAs,
+        final FacetHolder facetHolder) {
 
         facetHolder.lookupNonFallbackFacet(MemberDescribedFacet.class)
         .map(MemberDescribedFacet::getSpecialization)
         .ifPresent(specialization->
-            specialization.accept(
-                    hasStaticText->{
-                        var describedAs = hasStaticText.translated();
-                        if(_Strings.isNotEmpty(describedAs)) {
-                            hasDescribedAs.setDescribedAs(describedAs);
-                        }
-                    },
-                    _Functions.noopConsumer())); // not supported for 
imperative text
+        specialization.accept(
+            hasStaticText->{
+                var describedAs = hasStaticText.translated();
+                if(_Strings.isNotEmpty(describedAs)) {
+                    hasDescribedAs.setDescribedAs(describedAs);
+                }
+            },
+            _Functions.noopConsumer())); // not supported for imperative text
     }
 
-    public void setHiddenIfAny(
-            final HasHidden hasHidden,
-            final FacetHolder facetHolder) {
+    private void setHiddenIfAny(
+        final HasHidden hasHidden,
+        final FacetHolder facetHolder) {
 
         var hiddenFacet = facetHolder.getFacet(HiddenFacet.class);
         if (isNonFallback(hiddenFacet)) {
@@ -227,9 +308,9 @@ public void setHiddenIfAny(
         }
     }
 
-    public void setLabelPositionIfAny(
-            final PropertyLayoutData propertyLayoutData,
-            final FacetHolder facetHolder) {
+    private void setLabelPositionIfAny(
+        final PropertyLayoutData propertyLayoutData,
+        final FacetHolder facetHolder) {
 
         var labelAtFacet = facetHolder.getFacet(LabelAtFacet.class);
         if(isNonFallback(labelAtFacet)) {
@@ -240,9 +321,9 @@ public void setLabelPositionIfAny(
         }
     }
 
-    public void setMultiLineIfAny(
-            final PropertyLayoutData propertyLayoutData,
-            final FacetHolder facetHolder) {
+    private void setMultiLineIfAny(
+        final PropertyLayoutData propertyLayoutData,
+        final FacetHolder facetHolder) {
 
         var multiLineFacet = facetHolder.getFacet(MultiLineFacet.class);
         if(isNonFallback(multiLineFacet)) {
@@ -253,9 +334,9 @@ public void setMultiLineIfAny(
         }
     }
 
-    public void setPagedIfAny(
-            final CollectionLayoutData collectionLayoutData,
-            final FacetHolder facetHolder, final ObjectSpecification 
objectSpec) {
+    private void setPagedIfAny(
+        final CollectionLayoutData collectionLayoutData,
+        final FacetHolder facetHolder, final ObjectSpecification objectSpec) {
 
         var pagedFacet = FacetUtil.lookupFacetIn(PagedFacet.class, 
facetHolder, objectSpec).orElse(null);
         if(isNonFallback(pagedFacet)) {
@@ -266,9 +347,9 @@ public void setPagedIfAny(
         }
     }
 
-    public void setTableDecoratorIfAny(
-            final CollectionLayoutData collectionLayoutData,
-            final FacetHolder facetHolder, final ObjectSpecification 
objectSpec) {
+    private void setTableDecoratorIfAny(
+        final CollectionLayoutData collectionLayoutData,
+        final FacetHolder facetHolder, final ObjectSpecification objectSpec) {
 
         var tableDecoratorFacet = 
FacetUtil.lookupFacetIn(TableDecoratorFacet.class, facetHolder, 
objectSpec).orElse(null);
         if(isNonFallback(tableDecoratorFacet)) {
@@ -279,9 +360,9 @@ public void setTableDecoratorIfAny(
         }
     }
 
-    public void setActionPositionIfAny(
-            final ActionLayoutData actionLayoutData,
-            final FacetHolder facetHolder) {
+    private void setActionPositionIfAny(
+        final ActionLayoutData actionLayoutData,
+        final FacetHolder facetHolder) {
 
         var actionPositionFacet = 
facetHolder.getFacet(ActionPositionFacet.class);
         if(isNonFallback(actionPositionFacet)) {
@@ -292,32 +373,32 @@ public void setActionPositionIfAny(
         }
     }
 
-    public void setRenderedAsDayBeforeIfAny(
-            final PropertyLayoutData propertyLayoutData,
-            final FacetHolder facetHolder) {
+    private void setRenderedAsDayBeforeIfAny(
+        final PropertyLayoutData propertyLayoutData,
+        final FacetHolder facetHolder) {
 
         facetHolder.lookupNonFallbackFacet(DateRenderAdjustFacet.class)
         .ifPresent(dateRenderAdjustFacet->
-            
propertyLayoutData.setDateRenderAdjustDays(dateRenderAdjustFacet.getDateRenderAdjustDays()));
+        
propertyLayoutData.setDateRenderAdjustDays(dateRenderAdjustFacet.getDateRenderAdjustDays()));
     }
 
-    public void setSortedByIfAny(
-            final CollectionLayoutData collectionLayoutData,
-            final FacetHolder facetHolder) {
+    private void setSortedByIfAny(
+        final CollectionLayoutData collectionLayoutData,
+        final FacetHolder facetHolder) {
 
         var sortedByFacet = facetHolder.getFacet(SortedByFacet.class);
         if(isNonFallback(sortedByFacet)) {
             final Class<? extends Comparator<?>> cls = sortedByFacet.value();
             if(cls != null
-                    && cls.getCanonicalName()!=null) {
+                && cls.getCanonicalName()!=null) {
                 collectionLayoutData.setSortedBy(cls.getName());
             }
         }
     }
 
-    public void setTypicalLengthIfAny(
-            final PropertyLayoutData propertyLayoutData,
-            final FacetHolder facetHolder) {
+    private void setTypicalLengthIfAny(
+        final PropertyLayoutData propertyLayoutData,
+        final FacetHolder facetHolder) {
 
         var typicalLengthFacet = 
facetHolder.getFacet(TypicalLengthFacet.class);
         if(isNonFallback(typicalLengthFacet)) {
@@ -328,108 +409,9 @@ public void setTypicalLengthIfAny(
         }
     }
 
-    public static class LayoutDataFactory {
-
-        private final MetamodelToGridOverridingVisitor helper;
-
-        public static LayoutDataFactory of(final ObjectSpecification 
objectSpec) {
-            return new LayoutDataFactory(objectSpec);
-        }
-
-        private LayoutDataFactory(final ObjectSpecification objectSpec) {
-            this.helper = MetamodelToGridOverridingVisitor.of(objectSpec);
-        }
-
-        public ActionLayoutData createActionLayoutData(final String id) {
-            var layoutData = new ActionLayoutData(id);
-            helper.visit(layoutData);
-            return layoutData;
-        }
-
-        public CollectionLayoutData createCollectionLayoutData(final String 
id) {
-            var layoutData = new CollectionLayoutData(id);
-            helper.visit(layoutData);
-            return layoutData;
-        }
-
-        public PropertyLayoutData createPropertyLayoutData(final String id) {
-            var layoutData = new PropertyLayoutData(id);
-            helper.visit(layoutData);
-            return layoutData;
-        }
-
-        public DomainObjectLayoutData createDomainObjectLayoutData() {
-            var layoutData = new DomainObjectLayoutData();
-            helper.visit(layoutData);
-            return layoutData;
-        }
-
-    }
-
-    @RequiredArgsConstructor(staticName = "of")
-    public static class MetamodelToGridOverridingVisitor implements 
Grid.Visitor  {
-
-        private final @NonNull ObjectSpecification objectSpec;
-
-        @Override
-        public void visit(final ActionLayoutData actionLayoutData) {
-            objectSpec.getAction(actionLayoutData.getId())
-            .ifPresent(objectAction->{
-                setCssClassIfAny(actionLayoutData, objectAction);
-                setCssClassFaIfAny(actionLayoutData, objectAction);
-                setMemberDescribedIfAny(actionLayoutData, objectAction);
-                setHiddenIfAny(actionLayoutData, objectAction);
-                setMemberNamedIfAny(actionLayoutData, objectAction);
-                setActionPositionIfAny(actionLayoutData, objectAction);
-            });
-        }
-
-        @Override
-        public void visit(final CollectionLayoutData collectionLayoutData) {
-            objectSpec.getAssociation(collectionLayoutData.getId())
-            .ifPresent(collection->{
-                setCssClassIfAny(collectionLayoutData, collection);
-                setDefaultViewIfAny(collectionLayoutData, collection);
-                setMemberDescribedIfAny(collectionLayoutData, collection);
-                setHiddenIfAny(collectionLayoutData, collection);
-                setMemberNamedIfAny(collectionLayoutData, collection);
-                setPagedIfAny(collectionLayoutData, collection, objectSpec);
-                setTableDecoratorIfAny(collectionLayoutData, collection, 
objectSpec);
-                setSortedByIfAny(collectionLayoutData, collection);
-            });
-        }
-
-        @Override
-        public void visit(final PropertyLayoutData propertyLayoutData) {
-            objectSpec.getAssociation(propertyLayoutData.getId())
-            .ifPresent(property->{
-                setCssClassIfAny(propertyLayoutData, property);
-                setMemberDescribedIfAny(propertyLayoutData, property);
-                setHiddenIfAny(propertyLayoutData, property);
-                setMemberNamedIfAny(propertyLayoutData, property);
-                setLabelPositionIfAny(propertyLayoutData, property);
-                setMultiLineIfAny(propertyLayoutData, property);
-                setRenderedAsDayBeforeIfAny(propertyLayoutData, property);
-                setTypicalLengthIfAny(propertyLayoutData, property);
-            });
-        }
-
-        @Override
-        public void visit(final DomainObjectLayoutData domainObjectLayoutData) 
{
-            setBookmarkingIfAny(domainObjectLayoutData, objectSpec);
-            setCssClassIfAny(domainObjectLayoutData, objectSpec);
-            setCssClassFaIfAny(domainObjectLayoutData, objectSpec);
-            setObjectDescribedIfAny(domainObjectLayoutData, objectSpec);
-            setObjectNamedIfAny(domainObjectLayoutData, objectSpec);
-            setPagedIfAny(domainObjectLayoutData, objectSpec);
-        }
-    }
-
-    // -- HELPER
-
     private static boolean isNonFallback(final Facet facet) {
         return facet != null
-                && !facet.getPrecedence().isFallback();
+            && !facet.getPrecedence().isFallback();
     }
 
 }
diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/GridLoaderServiceDefault.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/GridLoaderServiceDefault.java
index ff7048e054b..599495ade14 100644
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/GridLoaderServiceDefault.java
+++ 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/GridLoaderServiceDefault.java
@@ -37,7 +37,7 @@
 import org.springframework.stereotype.Service;
 
 import org.apache.causeway.applib.annotation.PriorityPrecedence;
-import org.apache.causeway.applib.layout.grid.Grid;
+import org.apache.causeway.applib.layout.grid.bootstrap.BSGrid;
 import org.apache.causeway.applib.services.grid.GridLoaderService;
 import org.apache.causeway.applib.services.grid.GridMarshaller;
 import org.apache.causeway.applib.services.message.MessageService;
@@ -95,7 +95,7 @@ record LayoutKey(
     // for better logging messages (used only in prototyping mode)
     private final Map<LayoutKey, String> badContentByKey = _Maps.newHashMap();
     // cache (used only in prototyping mode)
-    private final Map<LayoutKey, Grid> gridCache = _Maps.newHashMap();
+    private final Map<LayoutKey, BSGrid> gridCache = _Maps.newHashMap();
 
     @Override
     public void remove(final Class<?> domainClass) {
@@ -114,10 +114,10 @@ public boolean existsFor(final Class<?> domainClass, 
final EnumSet<CommonMimeTyp
     }
 
     @Override
-    public <T extends Grid> Optional<T> load(
+    public Optional<BSGrid> load(
             final Class<?> domainClass,
             final String layoutIfAny,
-            final @NonNull GridMarshaller<T> marshaller) {
+            final @NonNull GridMarshaller marshaller) {
 
         var supportedFormats = marshaller.supportedFormats();
 
@@ -146,15 +146,14 @@ public <T extends Grid> Optional<T> load(
             }
         } else {
             // if cached, serve from cache - otherwise fall through
-            @SuppressWarnings("unchecked")
-            final T grid = (T)gridCache.get(layoutKey);
+            final BSGrid grid = gridCache.get(layoutKey);
             if(grid != null) {
                 return Optional.of(grid);
             }
         }
 
         try {
-            final T grid = marshaller
+            final BSGrid grid = marshaller
                 .unmarshal(domainClass, layoutResource.content(), 
layoutResource.format())
                 .getValue().orElseThrow();
             if(supportsReloading()) {
diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/GridServiceDefault.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/GridServiceDefault.java
index f995294bca2..00a234e5eae 100644
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/GridServiceDefault.java
+++ 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/GridServiceDefault.java
@@ -27,7 +27,7 @@
 import org.springframework.stereotype.Service;
 
 import org.apache.causeway.applib.annotation.PriorityPrecedence;
-import org.apache.causeway.applib.layout.grid.Grid;
+import org.apache.causeway.applib.layout.grid.bootstrap.BSGrid;
 import org.apache.causeway.applib.services.grid.GridLoaderService;
 import org.apache.causeway.applib.services.grid.GridMarshaller;
 import org.apache.causeway.applib.services.grid.GridService;
@@ -46,8 +46,8 @@
 @Qualifier("Default")
 public record GridServiceDefault(
     GridLoaderService gridLoaderService,
-    GridMarshaller<? extends Grid> marshaller,
-    List<GridSystemService<? extends Grid>> gridSystemServices) implements 
GridService {
+    GridMarshaller marshaller,
+    List<GridSystemService> gridSystemServices) implements GridService {
 
     @Override
     public boolean supportsReloading() {
@@ -65,19 +65,19 @@ public boolean existsFor(final Class<?> domainClass) {
     }
 
     @Override
-    public Grid load(final Class<?> domainClass) {
+    public BSGrid load(final Class<?> domainClass) {
         return gridLoaderService.load(domainClass, marshaller).orElse(null);
     }
 
     @Override
-    public Grid load(final Class<?> domainClass, final String layout) {
+    public BSGrid load(final Class<?> domainClass, final String layout) {
         return gridLoaderService.load(domainClass, layout, 
marshaller).orElse(null);
     }
 
     // --
 
     @Override
-    public Grid defaultGridFor(final Class<?> domainClass) {
+    public BSGrid defaultGridFor(final Class<?> domainClass) {
         for (var gridSystemService : gridSystemServices()) {
             var grid = gridSystemService.defaultGrid(domainClass);
             if(grid != null) return grid;
@@ -87,7 +87,7 @@ public Grid defaultGridFor(final Class<?> domainClass) {
     }
 
     @Override
-    public Grid normalize(final Grid grid) {
+    public BSGrid normalize(final BSGrid grid) {
         if(grid.isNormalized()) return grid;
 
         var domainClass = grid.domainClass();
@@ -98,7 +98,7 @@ public Grid normalize(final Grid grid) {
     }
 
     @Override
-    public Grid complete(final Grid grid) {
+    public BSGrid complete(final BSGrid grid) {
         var domainClass = grid.domainClass();
         for (var gridSystemService : gridSystemServices()) {
             gridSystemService.complete(_Casts.uncheckedCast(grid), 
domainClass);
@@ -107,7 +107,7 @@ public Grid complete(final Grid grid) {
     }
 
     @Override
-    public Grid minimal(final Grid grid) {
+    public BSGrid minimal(final BSGrid grid) {
         var domainClass = grid.domainClass();
         for (var gridSystemService : gridSystemServices()) {
             gridSystemService.minimal(_Casts.uncheckedCast(grid), domainClass);
diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/GridSystemServiceAbstract.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/GridSystemServiceAbstract.java
index 1b3dc7feac4..82f89a3c5d7 100644
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/GridSystemServiceAbstract.java
+++ 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/GridSystemServiceAbstract.java
@@ -31,7 +31,8 @@
 import org.apache.causeway.applib.layout.component.DomainObjectLayoutDataOwner;
 import org.apache.causeway.applib.layout.component.FieldSet;
 import org.apache.causeway.applib.layout.component.PropertyLayoutData;
-import org.apache.causeway.applib.layout.grid.Grid;
+import 
org.apache.causeway.applib.layout.grid.bootstrap.BSElement.BSElementVisitor;
+import org.apache.causeway.applib.layout.grid.bootstrap.BSGrid;
 import org.apache.causeway.applib.services.grid.GridSystemService;
 import org.apache.causeway.applib.services.i18n.TranslationService;
 import org.apache.causeway.applib.services.message.MessageService;
@@ -85,8 +86,8 @@
 
 @RequiredArgsConstructor(onConstructor_ = {@Inject}, access = 
AccessLevel.PROTECTED)
 @Slf4j
-public abstract class GridSystemServiceAbstract<G extends 
org.apache.causeway.applib.layout.grid.Grid>
-implements GridSystemService<G> {
+public abstract class GridSystemServiceAbstract
+implements GridSystemService {
 
     protected final Provider<SpecificationLoader> specLoaderProvider;
     protected final TranslationService translationService;
@@ -94,7 +95,7 @@ public abstract class GridSystemServiceAbstract<G extends 
org.apache.causeway.ap
     protected final CausewaySystemEnvironment causewaySystemEnvironment;
 
     @Override
-    public void normalize(final G grid, final Class<?> domainClass) {
+    public void normalize(final BSGrid grid, final Class<?> domainClass) {
 
         // ignore any other grid implementations
         if(!gridImplementation().isAssignableFrom(grid.getClass())) return;
@@ -113,7 +114,7 @@ public void normalize(final G grid, final Class<?> 
domainClass) {
         }
     }
 
-    protected abstract String toXml(Grid grid);
+    protected abstract String toXml(BSGrid grid);
 
     /**
      * Mandatory hook method for subclasses, where they must ensure that all 
object members (properties, collections
@@ -121,7 +122,7 @@ public void normalize(final G grid, final Class<?> 
domainClass) {
      * (eg facets from annotations) or just by applying default rules.
      */
     protected abstract boolean validateAndNormalize(
-            final Grid grid,
+            final BSGrid grid,
             final Class<?> domainClass);
 
     /**
@@ -131,7 +132,7 @@ protected abstract boolean validateAndNormalize(
      * because the layout might be reloaded from XML if reloading is supported.
      */
     private void overwriteFacets(
-            final G fcGrid,
+            final BSGrid fcGrid,
             final Class<?> domainClass) {
 
         var objectSpec = 
specLoaderProvider.get().specForTypeElseFail(domainClass);
@@ -146,7 +147,7 @@ private void overwriteFacets(
                 : Facet.Precedence.HIGH; // non-fallback case: XML layout 
overrules layout from annotations
 
         final AtomicInteger propertySequence = new AtomicInteger(0);
-        fcGrid.visit(new Grid.Visitor() {
+        fcGrid.visit(new BSElementVisitor() {
             private int collectionSequence = 1;
 
             private int actionDomainObjectSequence = 1;
@@ -366,17 +367,17 @@ public void visit(final CollectionLayoutData 
collectionLayoutData) {
 
     @Programmatic
     @Override
-    public void complete(final G grid, final Class<?> domainClass) {
+    public void complete(final BSGrid grid, final Class<?> domainClass) {
         normalize(grid, domainClass);
         var objectSpec = 
specLoaderProvider.get().specForTypeElseFail(domainClass);
-        grid.visit(MetamodelToGridOverridingVisitor.of(objectSpec));
+        grid.visit(new MetamodelToGridOverridingVisitor(objectSpec));
     }
 
     @Programmatic
     @Override
-    public void minimal(final G grid, final Class<?> domainClass) {
+    public void minimal(final BSGrid grid, final Class<?> domainClass) {
         normalize(grid, domainClass);
-        grid.visit(new Grid.Visitor() {
+        grid.visit(new BSElementVisitor() {
             @Override
             public void visit(final ActionLayoutData actionLayoutData) {
                 actionLayoutData.owner().getActions().remove(actionLayoutData);
diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/XsiSchemaLocationProviderForGrid.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/XsiSchemaLocationProviderForGrid.java
index a11ca6e5106..fe18cc31c36 100644
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/XsiSchemaLocationProviderForGrid.java
+++ 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/XsiSchemaLocationProviderForGrid.java
@@ -19,19 +19,11 @@
 package org.apache.causeway.core.metamodel.services.grid;
 
 import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
 import java.util.stream.Collectors;
 
 import jakarta.xml.bind.Marshaller;
 
-import org.springframework.stereotype.Service;
-
-import org.apache.causeway.applib.layout.grid.Grid;
-import org.apache.causeway.applib.services.grid.GridSystemService;
-
-@Service
-public record XsiSchemaLocationProviderForGrid(List<GridSystemService<? 
extends Grid>> gridSystemServices) {
+public record XsiSchemaLocationProviderForGrid() {
 
     static final String COMPONENT_TNS = 
"https://causeway.apache.org/applib/layout/component";;
     static final String COMPONENT_SCHEMA_LOCATION = 
"https://causeway.apache.org/applib/layout/component/component.xsd";;
@@ -39,26 +31,13 @@ public record 
XsiSchemaLocationProviderForGrid(List<GridSystemService<? extends
     static final String LINKS_TNS = 
"https://causeway.apache.org/applib/layout/links";;
     static final String LINKS_SCHEMA_LOCATION = 
"https://causeway.apache.org/applib/layout/links/links.xsd";;
 
-    public XsiSchemaLocationProviderForGrid {
-        final var gridImplementations = new HashSet<Class<?>>();
-        /*
-         * For all of the {@link GridSystemService}s available, return only 
the first one for any that
-         * are for the same grid implementation.
-         *
-         * <p>This allows default implementations (eg for bootstrap3) to be 
overridden while also allowing for the more
-         * general idea of multiple implementations.
-         */
-        gridSystemServices = gridSystemServices
-                .stream()
-                // true only if gridImplementations did not already contain 
the specified element
-                
.filter(gridService->gridImplementations.add(gridService.gridImplementation()))
-                .toList();
-    }
+    static final String BS_TNS = 
"https://causeway.apache.org/applib/layout/grid/bootstrap3";;
+    static final String BS_SCHEMA_LOCATION = 
"https://causeway.apache.org/applib/layout/grid/bootstrap3/bootstrap3.xsd";;
 
     /**
      * @see Marshaller#JAXB_SCHEMA_LOCATION
      */
-    public String xsiSchemaLocation(final Class<? extends Grid> gridClass) {
+    public String xsiSchemaLocation() {
         var parts = new ArrayList<String>();
 
         parts.add(COMPONENT_TNS);
@@ -67,13 +46,9 @@ public String xsiSchemaLocation(final Class<? extends Grid> 
gridClass) {
         parts.add(LINKS_TNS);
         parts.add(LINKS_SCHEMA_LOCATION);
 
-        for (var gridSystemService : gridSystemServices()) {
-            var gridImpl = gridSystemService.gridImplementation();
-            if(gridImpl.isAssignableFrom(gridClass)) {
-                parts.add(gridSystemService.tns());
-                parts.add(gridSystemService.schemaLocation());
-            }
-        }
+        parts.add(BS_TNS);
+        parts.add(BS_SCHEMA_LOCATION);
+
         return parts.stream()
                 .collect(Collectors.joining(" "));
     }
diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/bootstrap/GridInitializationModel.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/bootstrap/GridInitializationModel.java
index ab5e84e04de..7f88800c6c3 100644
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/bootstrap/GridInitializationModel.java
+++ 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/bootstrap/GridInitializationModel.java
@@ -24,12 +24,13 @@
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
+
 import org.apache.causeway.applib.layout.component.ActionLayoutData;
 import org.apache.causeway.applib.layout.component.CollectionLayoutData;
 import org.apache.causeway.applib.layout.component.FieldSet;
 import org.apache.causeway.applib.layout.component.PropertyLayoutData;
 import org.apache.causeway.applib.layout.grid.bootstrap.BSCol;
-import org.apache.causeway.applib.layout.grid.bootstrap.BSElement;
+import 
org.apache.causeway.applib.layout.grid.bootstrap.BSElement.BSElementVisitor;
 import org.apache.causeway.applib.layout.grid.bootstrap.BSGrid;
 import org.apache.causeway.applib.layout.grid.bootstrap.BSRow;
 import org.apache.causeway.applib.layout.grid.bootstrap.BSTabGroup;
@@ -38,6 +39,7 @@
 import org.apache.causeway.commons.internal.collections._Multimaps;
 import org.apache.causeway.commons.internal.collections._Sets;
 import 
org.apache.causeway.core.metamodel.facets.members.layout.group.GroupIdAndName;
+
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 
@@ -67,7 +69,7 @@ public static Optional<GridInitializationModel> 
createFrom(final BSGrid bsGrid)
 
         var gridModel = new GridInitializationModel();
 
-        bsGrid.visit(new BSElement.Visitor() {
+        bsGrid.visit(new BSElementVisitor() {
             @Override
             public void visit(final BSRow bsRow) {
                 final String id = bsRow.getId();
@@ -116,7 +118,7 @@ public void visit(final FieldSet fieldSet) {
             return Optional.empty();
         }
 
-        bsGrid.visit(new BSElement.Visitor(){
+        bsGrid.visit(new BSElementVisitor(){
 
             @Override
             public void visit(final BSCol bsCol) {
diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/bootstrap/GridMarshallerServiceBootstrap.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/bootstrap/GridMarshallerServiceBootstrap.java
index aa361fa8ae1..36fd1f48a59 100644
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/bootstrap/GridMarshallerServiceBootstrap.java
+++ 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/bootstrap/GridMarshallerServiceBootstrap.java
@@ -58,7 +58,7 @@ public record GridMarshallerServiceBootstrap(
         JaxbService jaxbService,
         XsiSchemaLocationProviderForGrid schemaLocationProvider,
         EnumSet<CommonMimeType> supportedFormats
-    ) implements GridMarshaller<BSGrid> {
+    ) implements GridMarshaller {
 
     @Inject
     public GridMarshallerServiceBootstrap(final JaxbService jaxbService, final 
XsiSchemaLocationProviderForGrid schemaLocationProvider) {
@@ -84,7 +84,7 @@ public String marshal(final @NonNull BSGrid bsGrid, final 
@NonNull CommonMimeTyp
         case XML:{
             return jaxbService.toXml(bsGrid,
                     Map.of(jakarta.xml.bind.Marshaller.JAXB_SCHEMA_LOCATION,
-                        
schemaLocationProvider.xsiSchemaLocation(BSGrid.class)));
+                        schemaLocationProvider.xsiSchemaLocation()));
         }
         default:
             throw _Exceptions.unsupportedOperation("supported format %s is not 
implemented", format.name());
diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/bootstrap/GridSystemServiceBootstrap.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/bootstrap/GridSystemServiceBootstrap.java
index e3c1928b877..a63e106344b 100644
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/bootstrap/GridSystemServiceBootstrap.java
+++ 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/bootstrap/GridSystemServiceBootstrap.java
@@ -46,7 +46,6 @@
 import org.apache.causeway.applib.layout.component.DomainObjectLayoutData;
 import org.apache.causeway.applib.layout.component.FieldSet;
 import org.apache.causeway.applib.layout.component.PropertyLayoutData;
-import org.apache.causeway.applib.layout.grid.Grid;
 import org.apache.causeway.applib.layout.grid.bootstrap.BSCol;
 import org.apache.causeway.applib.layout.grid.bootstrap.BSGrid;
 import org.apache.causeway.applib.layout.grid.bootstrap.BSRow;
@@ -100,10 +99,7 @@
 @Qualifier("Bootstrap")
 @Slf4j
 public class GridSystemServiceBootstrap
-extends GridSystemServiceAbstract<BSGrid> {
-
-    public static final String TNS = 
"https://causeway.apache.org/applib/layout/grid/bootstrap3";;
-    public static final String SCHEMA_LOCATION = 
"https://causeway.apache.org/applib/layout/grid/bootstrap3/bootstrap3.xsd";;
+extends GridSystemServiceAbstract {
 
     /**
      * SPI to customize layout fallback behavior on a per class basis.
@@ -118,7 +114,7 @@ public static interface FallbackLayoutDataSource {
 
     @Inject @Lazy // circular dependency (late binding)
     @Setter @Accessors(chain = true) // JUnit support
-    private GridMarshaller<BSGrid> marshaller;
+    private GridMarshaller marshaller;
 
     private final CausewayConfiguration config;
     private final Can<FallbackLayoutDataSource> fallbackLayoutDataSources;
@@ -143,18 +139,8 @@ public Class<BSGrid> gridImplementation() {
     }
 
     @Override
-    public String tns() {
-        return TNS;
-    }
-
-    @Override
-    public String schemaLocation() {
-        return SCHEMA_LOCATION;
-    }
-
-    @Override
-    protected String toXml(Grid grid) {
-        return marshaller.marshal((BSGrid) grid, CommonMimeType.XML);
+    protected String toXml(final BSGrid grid) {
+        return marshaller.marshal(grid, CommonMimeType.XML);
     }
 
     @Override
@@ -240,11 +226,9 @@ static void addFieldSetsToColumn(
 
     @Override
     protected boolean validateAndNormalize(
-            final Grid grid,
+            final BSGrid bsGrid,
             final Class<?> domainClass) {
 
-        var bsGrid = (BSGrid) grid;
-
         var gridModelIfValid = GridInitializationModel.createFrom(bsGrid);
         if(!gridModelIfValid.isPresent()) return false; // only present if 
valid
 
@@ -255,7 +239,7 @@ protected boolean validateAndNormalize(
         var oneToManyAssociationById = 
ObjectMember.mapById(objSpec.streamCollections(MixedIn.INCLUDED));
         var objectActionById = 
ObjectMember.mapById(objSpec.streamRuntimeActions(MixedIn.INCLUDED));
 
-        var layoutDataFactory = LayoutDataFactory.of(objSpec);
+        var layoutDataFactory = new LayoutDataFactory(objSpec);
 
         // * left  ... those defined in the grid model but not available with 
the meta-model
         // * right ... those available with the meta-model but missing in the 
grid-model
diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/util/Facets.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/util/Facets.java
index 649be57a99f..c779e530803 100644
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/util/Facets.java
+++ 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/util/Facets.java
@@ -124,7 +124,6 @@ public BookmarkPolicy 
bookmarkPolicyOrElseNotSpecified(final @Nullable FacetHold
     public Optional<BSGrid> bootstrapGrid(
             final ObjectSpecification objectSpec, final @Nullable 
ManagedObject mo) {
         return objectSpec.lookupFacet(GridFacet.class)
-            .filter(facet->facet.supports(BSGrid.class))
             .map(gridFacet->gridFacet.getGrid(mo))
             .flatMap(grid->_Casts.castTo(BSGrid.class, grid));
     }
diff --git 
a/core/mmtestsupport/src/main/java/org/apache/causeway/core/mmtestsupport/MetaModelContext_forTesting.java
 
b/core/mmtestsupport/src/main/java/org/apache/causeway/core/mmtestsupport/MetaModelContext_forTesting.java
index f6541c9e69b..71af4f7c29d 100644
--- 
a/core/mmtestsupport/src/main/java/org/apache/causeway/core/mmtestsupport/MetaModelContext_forTesting.java
+++ 
b/core/mmtestsupport/src/main/java/org/apache/causeway/core/mmtestsupport/MetaModelContext_forTesting.java
@@ -34,7 +34,6 @@
 import org.springframework.boot.test.util.TestPropertyValues;
 import org.springframework.util.ClassUtils;
 
-import org.apache.causeway.applib.layout.grid.Grid;
 import org.apache.causeway.applib.services.factory.FactoryService;
 import org.apache.causeway.applib.services.grid.GridLoaderService;
 import org.apache.causeway.applib.services.grid.GridMarshaller;
@@ -457,45 +456,43 @@ private final MenuBarsService createMenuBarsService() {
     }
 
     @Getter(lazy = true)
-    private final GridMarshaller gridMarshallerService = 
createGridMarshallerService();
-    //XXX lombok issue: won't compile if inlined
-    private final GridMarshaller<? extends Grid> createGridMarshallerService() 
{
-        return new GridMarshallerServiceBootstrap(getJaxbService(), new 
XsiSchemaLocationProviderForGrid(List.of()));
+    private final GridMarshaller gridMarshaller = createGridMarshaller();
+    private final GridMarshaller createGridMarshaller() {
+        return new GridMarshallerServiceBootstrap(getJaxbService(), new 
XsiSchemaLocationProviderForGrid());
     }
 
     @Getter(lazy = true)
-    private final List<GridSystemService<? extends Grid>> gridSystemServices = 
List.of(
-        new GridSystemServiceBootstrap(
-            getConfiguration(),
-            ()->getSpecificationLoader(),
-            getTranslationService(),
-            getJaxbService(),
-            getMessageService(),
-            getSystemEnvironment(),
-            List.of())
-            .setMarshaller(getGridMarshallerService()));
+    private final List<GridSystemService> gridSystemServices = 
createGridSystemService();
+    private final List<GridSystemService> createGridSystemService() {
+        return List.of(
+            new GridSystemServiceBootstrap(
+                getConfiguration(),
+                ()->getSpecificationLoader(),
+                getTranslationService(),
+                getJaxbService(),
+                getMessageService(),
+                getSystemEnvironment(),
+                List.of())
+                .setMarshaller(getGridMarshaller()));
+    }
 
     @Getter(lazy = true)
     private final GridLoaderService gridLoaderService = 
createGridLoaderService();
-    //XXX lombok issue: won't compile if inlined
     private final GridLoaderService createGridLoaderService() {
         return new GridLoaderServiceDefault(getMessageService(), Can.of(new 
LayoutResourceLoaderDefault()), /*support reloading*/true);
     }
 
     @Getter(lazy = true)
     private final GridService gridService = createGridService();
-    //XXX lombok issue: won't compile if inlined
-    @SuppressWarnings("unchecked")
     private final GridService createGridService() {
         return new GridServiceDefault(
             getGridLoaderService(),
-            getGridMarshallerService(),
+            getGridMarshaller(),
             getGridSystemServices());
     }
 
     @Getter(lazy = true)
     private final LayoutService layoutService = createLayoutService();
-    //XXX lombok issue: won't compile if inlined
     private final LayoutService createLayoutService() {
         return new LayoutServiceDefault(
                 getSpecificationLoader(),
diff --git 
a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/sitemap/SitemapServiceDefault.java
 
b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/sitemap/SitemapServiceDefault.java
index 43b5fb405ce..6f96a0cee82 100644
--- 
a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/sitemap/SitemapServiceDefault.java
+++ 
b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/sitemap/SitemapServiceDefault.java
@@ -34,7 +34,7 @@
 import org.apache.causeway.applib.layout.component.FieldSet;
 import org.apache.causeway.applib.layout.component.PropertyLayoutData;
 import org.apache.causeway.applib.layout.component.ServiceActionLayoutData;
-import org.apache.causeway.applib.layout.grid.Grid;
+import 
org.apache.causeway.applib.layout.grid.bootstrap.BSElement.BSElementVisitor;
 import org.apache.causeway.applib.layout.menubars.bootstrap.BSMenuBars;
 import org.apache.causeway.applib.services.menu.MenuBarsService;
 import org.apache.causeway.applib.services.sitemap.SitemapService;
@@ -120,7 +120,7 @@ public String toSitemapAdoc(final String title) {
                     var grid = 
specificationLoader.specForType(actionElementType.getCorrespondingClass())
                                 .flatMap(mo->Facets.bootstrapGrid(mo))
                                 .orElse(null);
-                    grid.visit(new Grid.Visitor() {
+                    grid.visit(new BSElementVisitor() {
                         @Override public void visit(final ActionLayoutData 
actionLayoutData) {
                             
actionElementType.getAction(actionLayoutData.getId(), 
ActionScope.PRODUCTION_ONLY)
                             .ifPresent(action->{
diff --git 
a/extensions/core/docgen/help/src/main/java/org/apache/causeway/extensions/docgen/help/topics/welcome/WelcomeHelpPage.java
 
b/extensions/core/docgen/help/src/main/java/org/apache/causeway/extensions/docgen/help/topics/welcome/WelcomeHelpPage.java
index 0f30c638286..419ee9133fe 100644
--- 
a/extensions/core/docgen/help/src/main/java/org/apache/causeway/extensions/docgen/help/topics/welcome/WelcomeHelpPage.java
+++ 
b/extensions/core/docgen/help/src/main/java/org/apache/causeway/extensions/docgen/help/topics/welcome/WelcomeHelpPage.java
@@ -33,7 +33,8 @@
 import org.apache.causeway.applib.layout.component.FieldSet;
 import org.apache.causeway.applib.layout.component.PropertyLayoutData;
 import org.apache.causeway.applib.layout.component.ServiceActionLayoutData;
-import org.apache.causeway.applib.layout.grid.Grid;
+import 
org.apache.causeway.applib.layout.grid.bootstrap.BSElement.BSElementVisitor;
+import org.apache.causeway.applib.layout.grid.bootstrap.BSGrid;
 import org.apache.causeway.applib.layout.menubars.MenuBars;
 import org.apache.causeway.applib.layout.menubars.bootstrap.BSMenuBars;
 import org.apache.causeway.applib.services.homepage.HomePageResolverService;
@@ -169,7 +170,7 @@ private String getDocumentationAsHtml() {
     private StringBuffer documentationForObjectType(final ObjectSpecification 
objectSpec) {
         StringBuffer html = new StringBuffer();
 
-        Grid grid = toGrid(objectSpec.getCorrespondingClass());
+        var grid = toGrid(objectSpec.getCorrespondingClass());
         html.append("<ul>");
         {
             html.append("<ul>");
@@ -225,7 +226,7 @@ private StringBuffer documentationForObjectType(final 
ObjectSpecification object
             html.append("</ul>");
             html.append("<ul>");
             {
-                grid.visit(new Grid.Visitor() {
+                grid.visit(new BSElementVisitor() {
                     @Override
                     public void visit(final FieldSet fieldSet) {
                         if (_NullSafe.isEmpty(fieldSet.getProperties())) {
@@ -235,25 +236,25 @@ public void visit(final FieldSet fieldSet) {
                             html.append("<ul>");
                             for (PropertyLayoutData layout : 
fieldSet.getProperties()) {
                                 objectSpec.getProperty(layout.getId())
-                                        .ifPresent(member -> {
-                                            if (!member.isAlwaysHidden()) {
-                                                String describedAs = 
member.getCanonicalDescription()
-                                                        .map(desc -> 
String.format("%s", desc))
-                                                        .orElse("");
-                                                
html.append(String.format("<li><b>%s</b>: %s.",
-                                                        
member.getCanonicalFriendlyName(),
-                                                        describedAs));
-                                                if 
(member.getElementType().logicalType().correspondingClass()
-                                                        
.isAnnotationPresent(DomainObject.class)) {
-                                                    
html.append(String.format(" <i> See: <a href='#%s'>%s</a></i>",
-                                                            
member.getElementType().logicalTypeName(),
-                                                            
member.getElementType().getSingularName()));
-                                                } else {
-                                                    //none
-                                                }
-                                                html.append("</li>\n");
+                                    .ifPresent(member -> {
+                                        if (!member.isAlwaysHidden()) {
+                                            String describedAs = 
member.getCanonicalDescription()
+                                                    .map(desc -> 
String.format("%s", desc))
+                                                    .orElse("");
+                                            
html.append(String.format("<li><b>%s</b>: %s.",
+                                                    
member.getCanonicalFriendlyName(),
+                                                    describedAs));
+                                            if 
(member.getElementType().logicalType().correspondingClass()
+                                                    
.isAnnotationPresent(DomainObject.class)) {
+                                                html.append(String.format(" 
<i> See: <a href='#%s'>%s</a></i>",
+                                                        
member.getElementType().logicalTypeName(),
+                                                        
member.getElementType().getSingularName()));
+                                            } else {
+                                                //none
                                             }
-                                        });
+                                            html.append("</li>\n");
+                                        }
+                                    });
                             }
                             html.append("</ul>");
                         }
@@ -272,7 +273,7 @@ private Optional<ObjectAction> lookupAction(final 
ServiceActionLayoutData action
                 .map(typeSpec -> typeSpec.getAction(actionLayout.getId(), 
ActionScope.PRODUCTION_ONLY).orElse(null));
     }
 
-    private Grid toGrid(final Class<?> domainClass) {
+    private BSGrid toGrid(final Class<?> domainClass) {
         return specificationLoader.specForType(domainClass)
                 .flatMap(spec -> spec.lookupFacet(GridFacet.class))
                 .map(gridFacet -> gridFacet.getGrid(null))
diff --git 
a/viewers/restfulobjects/viewer/src/main/java/org/apache/causeway/viewer/restfulobjects/viewer/resources/DomainObjectResourceServerside.java
 
b/viewers/restfulobjects/viewer/src/main/java/org/apache/causeway/viewer/restfulobjects/viewer/resources/DomainObjectResourceServerside.java
index f7efa8465b9..042c6b73980 100644
--- 
a/viewers/restfulobjects/viewer/src/main/java/org/apache/causeway/viewer/restfulobjects/viewer/resources/DomainObjectResourceServerside.java
+++ 
b/viewers/restfulobjects/viewer/src/main/java/org/apache/causeway/viewer/restfulobjects/viewer/resources/DomainObjectResourceServerside.java
@@ -32,7 +32,8 @@
 import org.apache.causeway.applib.layout.component.CollectionLayoutData;
 import org.apache.causeway.applib.layout.component.DomainObjectLayoutData;
 import org.apache.causeway.applib.layout.component.PropertyLayoutData;
-import org.apache.causeway.applib.layout.grid.Grid;
+import 
org.apache.causeway.applib.layout.grid.bootstrap.BSElement.BSElementVisitor;
+import org.apache.causeway.applib.layout.grid.bootstrap.BSGrid;
 import org.apache.causeway.applib.layout.links.Link;
 import org.apache.causeway.commons.io.UrlUtils;
 import org.apache.causeway.core.metamodel.consent.Consent;
@@ -250,7 +251,7 @@ public ResponseEntity<Object> layout(
                 .orElseGet(ResponseFactory::notFound));
     }
 
-    private Optional<Grid> layoutAsGrid(
+    private Optional<BSGrid> layoutAsGrid(
             final String domainType,
             final String instanceId) {
 
@@ -267,9 +268,9 @@ public static void addLinks(
             final ResourceContext resourceContext,
             final String domainType,
             final String instanceId,
-            final Grid grid) {
+            final BSGrid grid) {
 
-        grid.visit(new Grid.Visitor() {
+        grid.visit(new BSElementVisitor() {
             @Override
             public void visit(final DomainObjectLayoutData 
domainObjectLayoutData) {
                 Link link = newLink(

Reply via email to