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

ahuber pushed a commit to branch 3973-backport.layout.switch
in repository https://gitbox.apache.org/repos/asf/causeway.git


The following commit(s) were added to refs/heads/3973-backport.layout.switch by 
this push:
     new 1900ca6db45 CAUSEWAY-3973: [v2] support for layout variant export in 
Object_downloadLayout
1900ca6db45 is described below

commit 1900ca6db458a4a39d1bd863c98d3e1f5c20665e
Author: andi-huber <[email protected]>
AuthorDate: Fri Mar 6 08:24:19 2026 +0100

    CAUSEWAY-3973: [v2] support for layout variant export in
    Object_downloadLayout
---
 .../mixins/layout/Object_downloadLayout.java       | 23 ++++++----
 .../causeway/applib/services/grid/GridService.java |  9 ++--
 .../applib/services/layout/LayoutService.java      | 12 +++++-
 .../services/layout/LayoutServiceDefault.java      | 50 ++++++++++++++--------
 .../metamodel/services/grid/GridLoadingTest.java   |  6 +--
 5 files changed, 66 insertions(+), 34 deletions(-)

diff --git 
a/api/applib/src/main/java/org/apache/causeway/applib/mixins/layout/Object_downloadLayout.java
 
b/api/applib/src/main/java/org/apache/causeway/applib/mixins/layout/Object_downloadLayout.java
index 6350671c4e4..54378e843a0 100644
--- 
a/api/applib/src/main/java/org/apache/causeway/applib/mixins/layout/Object_downloadLayout.java
+++ 
b/api/applib/src/main/java/org/apache/causeway/applib/mixins/layout/Object_downloadLayout.java
@@ -37,7 +37,6 @@
 import org.apache.causeway.applib.value.NamedWithMimeType.CommonMimeType;
 
 import lombok.RequiredArgsConstructor;
-import lombok.val;
 
 /**
  * Provides the ability to download the serialized layout (eg. XML) for any 
domain
@@ -65,7 +64,9 @@ public class Object_downloadLayout {
     public static class ActionDomainEvent
     extends 
org.apache.causeway.applib.CausewayModuleApplib.ActionDomainEvent<Object_downloadLayout>
 {}
 
-    private final Object holder;
+    @Inject LayoutService layoutService;
+
+    private final Object mixee;
 
     @MemberSupport public Object act(
             @ParameterLayout(
@@ -75,15 +76,19 @@ public static class ActionDomainEvent
             final LayoutExportStyle style,
             final CommonMimeType format) {
 
-        val xmlString = layoutService.objectLayout(holder.getClass(), style, 
format);
-        return Clob.of(fileName, format, xmlString);
+        var layoutKey = layoutService.layoutKey(mixee).orElseThrow();
+        var xmlString = layoutService.objectLayout(layoutKey, style, format);
+        var infix= layoutKey.isVariant()
+            ? "-" + layoutKey.layoutIfAny()
+            : "";
+        return Clob.of(fileName + infix + ".layout", format, xmlString);
     }
 
     /**
      * Defaults to the (simple) name of the domain object's class, with a 
<code>.layout</code> suffix
      */
     @MemberSupport public String default0Act() {
-        return holder.getClass().getSimpleName() + ".layout";
+        return mixee.getClass().getSimpleName();
     }
     /**
      * Default style is {@link LayoutExportStyle#MINIMAL}.
@@ -93,10 +98,10 @@ public static class ActionDomainEvent
     }
 
     @MemberSupport public CommonMimeType default2Act() {
-        return layoutService.supportedObjectLayoutFormats().iterator().next(); 
}
+        return layoutService.supportedObjectLayoutFormats().iterator().next();
+    }
     @MemberSupport public Set<CommonMimeType> choices2Act() {
-        return layoutService.supportedObjectLayoutFormats(); }
-
-    @Inject LayoutService layoutService;
+        return layoutService.supportedObjectLayoutFormats();
+    }
 
 }
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 eac3e5b6d8c..836f132bf77 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
@@ -196,13 +196,16 @@ public LayoutKey(final Class<?> domainClass) {
     GridMarshallerService<? extends Grid> marshaller();
 
     default Grid toGridForExport(
-            final Class<?> domainClass,
+            final LayoutKey layoutKey,
             final LayoutExportStyle style) {
 
         // don't use the grid from the facet, because it will be modified 
subsequently.
-        Grid grid = load(domainClass);
+        Grid grid = load(layoutKey.domainClass);
         if(grid == null) {
-            grid = defaultGridFor(domainClass);
+            grid = defaultGridFor(layoutKey.domainClass);
+            grid.layoutKey(new LayoutKey(layoutKey.domainClass, null));
+        } else {
+               grid.layoutKey(layoutKey);
         }
         grid = normalize(grid); // required so the grid's tns and 
schema-locations get populated
         if (style == LayoutExportStyle.COMPLETE) {
diff --git 
a/api/applib/src/main/java/org/apache/causeway/applib/services/layout/LayoutService.java
 
b/api/applib/src/main/java/org/apache/causeway/applib/services/layout/LayoutService.java
index 2266a75f092..14f371e52d4 100644
--- 
a/api/applib/src/main/java/org/apache/causeway/applib/services/layout/LayoutService.java
+++ 
b/api/applib/src/main/java/org/apache/causeway/applib/services/layout/LayoutService.java
@@ -19,20 +19,28 @@
 package org.apache.causeway.applib.services.layout;
 
 import java.util.EnumSet;
+import java.util.Optional;
 
+import org.apache.causeway.applib.services.grid.GridService.LayoutKey;
 import org.apache.causeway.applib.services.menu.MenuBarsService;
 import org.apache.causeway.applib.value.NamedWithMimeType.CommonMimeType;
+import org.springframework.lang.Nullable;
 
 /**
  * Provides the ability to obtain the serialized layout (eg. XML) for a single 
domain object or
  * for all domain objects, as well as the serialized layout for the 
application's menu-bars.
  *
- * @since 1.x - revised for 2.0 {@index}
+ * @since 1.x - revised for 2.0 and 4.0 {@index}
  */
 public interface LayoutService {
 
     // -- OBJECT LAYOUT
 
+    /**
+     * @since 4.0
+     */
+    Optional<LayoutKey> layoutKey(@Nullable Object domainObject);
+
     /**
      * Supported format(s) for {@link #objectLayout(Class, LayoutExportStyle, 
CommonMimeType)}
      * and {@link #toZip(LayoutExportStyle, CommonMimeType)}.
@@ -43,7 +51,7 @@ public interface LayoutService {
      * Obtains the serialized form of the object layout (grid) for the 
specified domain class.
      * @throws UnsupportedOperationException when format is not supported
      */
-    String objectLayout(Class<?> domainClass, LayoutExportStyle style, 
CommonMimeType format);
+    String objectLayout(LayoutKey layoutKey, LayoutExportStyle style, 
CommonMimeType format);
 
     /**
      * Obtains a zip file of the serialized layouts (grids) of all domain 
entities and view models.
diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/layout/LayoutServiceDefault.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/layout/LayoutServiceDefault.java
index 0e3af14b426..aa70c7d8eb5 100644
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/layout/LayoutServiceDefault.java
+++ 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/layout/LayoutServiceDefault.java
@@ -20,18 +20,16 @@
 
 import java.io.File;
 import java.util.EnumSet;
+import java.util.Optional;
 
 import javax.annotation.Priority;
 import javax.inject.Inject;
 import javax.inject.Named;
 
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.lang.Nullable;
-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.services.grid.GridService;
+import org.apache.causeway.applib.services.grid.GridService.LayoutKey;
 import org.apache.causeway.applib.services.layout.LayoutExportStyle;
 import org.apache.causeway.applib.services.layout.LayoutService;
 import org.apache.causeway.applib.services.menu.MenuBarsService;
@@ -40,11 +38,16 @@
 import org.apache.causeway.commons.internal.base._Casts;
 import org.apache.causeway.commons.io.ZipUtils;
 import org.apache.causeway.core.metamodel.CausewayModuleCoreMetamodel;
+import org.apache.causeway.core.metamodel.context.MetaModelContext;
+import org.apache.causeway.core.metamodel.facets.object.layout.LayoutFacet;
+import org.apache.causeway.core.metamodel.object.ManagedObjects;
 import org.apache.causeway.core.metamodel.spec.ObjectSpecification;
 import org.apache.causeway.core.metamodel.specloader.SpecificationLoader;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.lang.Nullable;
+import org.springframework.stereotype.Service;
 
 import lombok.RequiredArgsConstructor;
-import lombok.val;
 import lombok.extern.log4j.Log4j2;
 
 /**
@@ -60,7 +63,7 @@
 @Log4j2
 public class LayoutServiceDefault implements LayoutService {
 
-    private final SpecificationLoader specificationLoader;
+    private final SpecificationLoader specLoader;
     private final GridService gridService;
     private final MenuBarsService menuBarsService;
 
@@ -75,20 +78,33 @@ public EnumSet<CommonMimeType> 
supportedMenuBarsLayoutFormats() {
     public String menuBarsLayout(
             final MenuBarsService.Type type,
             final CommonMimeType format) {
-        val menuBars = menuBarsService.menuBars(type);
+        var menuBars = menuBarsService.menuBars(type);
         return 
menuBarsService.marshaller().marshal(_Casts.uncheckedCast(menuBars), format);
     }
 
     // -- OBJECT LAYOUT
 
+    @Override
+    public Optional<LayoutKey> layoutKey(final @Nullable Object domainObject) {
+        var mo = MetaModelContext.instanceElseFail()
+            .getObjectManager()
+            .adapt(domainObject);
+        if(ManagedObjects.isNullOrUnspecifiedOrEmpty(mo))
+            return Optional.empty();
+        var layoutPrefix = mo.objSpec().lookupFacet(LayoutFacet.class)
+                .map(layoutPrefixFacet->layoutPrefixFacet.layout(mo))
+                .orElse(null);
+        return Optional.of(new LayoutKey(domainObject.getClass(), 
layoutPrefix));
+    }
+
     @Override
     public EnumSet<CommonMimeType> supportedObjectLayoutFormats() {
         return gridService.marshaller().supportedFormats();
     }
 
     @Override
-    public String objectLayout(final Class<?> domainClass, final 
LayoutExportStyle style, final CommonMimeType format) {
-        return tryGridToFormatted(domainClass, style, format)
+    public String objectLayout(final LayoutKey layoutKey, final 
LayoutExportStyle style, final CommonMimeType format) {
+        return tryGridToFormatted(layoutKey, style, format)
                 .ifFailureFail()
                 .getValue()
                 .orElse(null);
@@ -96,18 +112,18 @@ public String objectLayout(final Class<?> domainClass, 
final LayoutExportStyle s
 
     @Override
     public byte[] toZip(final LayoutExportStyle style, final CommonMimeType 
format) {
-        val domainObjectSpecs = specificationLoader.snapshotSpecifications()
+        var domainObjectSpecs = specLoader.snapshotSpecifications()
                 .filter(spec ->
                         !spec.isAbstract()
                         && (spec.isEntity() || spec.isViewModel()));
 
-        val zipBuilder = ZipUtils.zipEntryBuilder();
+        var zipBuilder = ZipUtils.zipEntryBuilder();
 
-        for (val objectSpec : domainObjectSpecs) {
-            val domainClass = objectSpec.getCorrespondingClass();
+        for (var objectSpec : domainObjectSpecs) {
+            var domainClass = objectSpec.getCorrespondingClass();
 
-            tryGridToFormatted(domainClass, style, format)
-            .accept(
+            tryGridToFormatted(new LayoutKey(domainClass), style, format)
+                .accept(
                     failure->
                         log.warn("failed to generate layout file for {}", 
domainClass),
                     contentIfAny->{
@@ -122,11 +138,11 @@ public byte[] toZip(final LayoutExportStyle style, final 
CommonMimeType format)
     // -- HELPER
 
     private Try<String> tryGridToFormatted(
-            final Class<?> domainClass,
+            final LayoutKey layoutKey,
             final LayoutExportStyle style,
             final CommonMimeType format) {
         return Try.call(()->
-            gridToFormatted(gridService.toGridForExport(domainClass, style), 
format));
+            gridToFormatted(gridService.toGridForExport(layoutKey, style), 
format));
     }
 
     private String gridToFormatted(final @Nullable Grid grid, final 
CommonMimeType format) {
diff --git 
a/core/metamodel/src/test/java/org/apache/causeway/core/metamodel/services/grid/GridLoadingTest.java
 
b/core/metamodel/src/test/java/org/apache/causeway/core/metamodel/services/grid/GridLoadingTest.java
index 1795e230be6..4431ccdf97a 100644
--- 
a/core/metamodel/src/test/java/org/apache/causeway/core/metamodel/services/grid/GridLoadingTest.java
+++ 
b/core/metamodel/src/test/java/org/apache/causeway/core/metamodel/services/grid/GridLoadingTest.java
@@ -54,10 +54,10 @@ protected void afterSetUp() {
 
     // test blueprint, for future work
     void blueprint() {
-        val domainClassAndLayout = new LayoutKey(Bar.class, null);
-        gridLoaderService.loadLayoutResource(domainClassAndLayout, 
EnumSet.of(CommonMimeType.XML));
+        val layoutKey = new LayoutKey(Bar.class, null);
+        gridLoaderService.loadLayoutResource(layoutKey, 
EnumSet.of(CommonMimeType.XML));
 
-        val xml = layoutService.objectLayout(Bar.class, 
LayoutExportStyle.MINIMAL, CommonMimeType.XML);
+        val xml = layoutService.objectLayout(layoutKey, 
LayoutExportStyle.MINIMAL, CommonMimeType.XML);
         System.out.println(xml);
     }
 

Reply via email to