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

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


The following commit(s) were added to refs/heads/main by this push:
     new 9dea5a10a74 CAUSEWAY-3859: flattens LayoutFacet
9dea5a10a74 is described below

commit 9dea5a10a74bdf2bf130632a9f550f1d449aa57d
Author: Andi Huber <[email protected]>
AuthorDate: Sat Mar 1 09:44:30 2025 +0100

    CAUSEWAY-3859: flattens LayoutFacet
---
 .../DomainObjectLayoutFacetFactory.java            |  36 ++----
 ...inObjectLayoutAnnotationUsingLayoutUiEvent.java | 108 ----------------
 .../facets/object/layout/LayoutFacet.java          | 144 ++++++++++++++++++++-
 .../facets/object/layout/LayoutFacetAbstract.java  |  42 ------
 .../facets/object/layout/LayoutFacetFallback.java  |  43 ------
 .../object/layout/LayoutFacetViaLayoutMethod.java  |  78 -----------
 .../object/support/ObjectSupportFacetFactory.java  |   4 +-
 .../object/ident/layout/LayoutFacetMethodTest.java |  14 +-
 8 files changed, 160 insertions(+), 309 deletions(-)

diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/domainobjectlayout/DomainObjectLayoutFacetFactory.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/domainobjectlayout/DomainObjectLayoutFacetFactory.java
index 538b3cef8a7..5d0e211b992 100644
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/domainobjectlayout/DomainObjectLayoutFacetFactory.java
+++ 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/domainobjectlayout/DomainObjectLayoutFacetFactory.java
@@ -24,6 +24,7 @@
 import org.apache.causeway.core.metamodel.facetapi.FeatureType;
 import org.apache.causeway.core.metamodel.facets.FacetFactoryAbstract;
 import 
org.apache.causeway.core.metamodel.facets.object.domainobjectlayout.tabledec.TableDecoratorFacetForDomainObjectLayoutAnnotation;
+import org.apache.causeway.core.metamodel.facets.object.layout.LayoutFacet;
 import 
org.apache.causeway.core.metamodel.services.events.MetamodelEventService;
 
 public class DomainObjectLayoutFacetFactory
@@ -41,48 +42,37 @@ public void process(final ProcessClassContext 
processClassContext) {
         var domainObjectLayoutIfAny = 
processClassContext.synthesizeOnType(DomainObjectLayout.class);
         var metamodelEventService = this.metamodelEventService.get();
 
-        addFacetIfPresent(
-                TitleFacetViaDomainObjectLayoutAnnotationUsingTitleUiEvent
+        
addFacetIfPresent(TitleFacetViaDomainObjectLayoutAnnotationUsingTitleUiEvent
                 .create(domainObjectLayoutIfAny, metamodelEventService, 
facetHolder));
 
-        addFacetIfPresent(
-                IconFacetViaDomainObjectLayoutAnnotationUsingIconUiEvent
+        
addFacetIfPresent(IconFacetViaDomainObjectLayoutAnnotationUsingIconUiEvent
                 .create(domainObjectLayoutIfAny, metamodelEventService, 
facetHolder));
 
-        addFacetIfPresent(
-                
CssClassFacetViaDomainObjectLayoutAnnotationUsingCssClassUiEvent
+        
addFacetIfPresent(CssClassFacetViaDomainObjectLayoutAnnotationUsingCssClassUiEvent
                 .create(domainObjectLayoutIfAny, metamodelEventService, 
facetHolder));
 
-        addFacetIfPresent(
-                LayoutFacetViaDomainObjectLayoutAnnotationUsingLayoutUiEvent
-                .create(domainObjectLayoutIfAny, metamodelEventService, 
facetHolder));
+        
addFacetIfPresent(LayoutFacet.forDomainObjectLayoutAnnotationUsingLayoutUiEvent(
+                    domainObjectLayoutIfAny, metamodelEventService, 
facetHolder));
 
-        addFacetIfPresent(
-                CssClassFacetForDomainObjectLayoutAnnotation
+        addFacetIfPresent(CssClassFacetForDomainObjectLayoutAnnotation
                 .create(domainObjectLayoutIfAny, facetHolder));
 
-        addFacetIfPresent(
-                FaFacetForDomainObjectLayoutAnnotation
+        addFacetIfPresent(FaFacetForDomainObjectLayoutAnnotation
                 .create(domainObjectLayoutIfAny, facetHolder));
 
-        addFacetIfPresent(
-                ObjectDescribedFacetForDomainObjectLayoutAnnotation
+        addFacetIfPresent(ObjectDescribedFacetForDomainObjectLayoutAnnotation
                 .create(domainObjectLayoutIfAny, facetHolder));
 
-        addFacetIfPresent(
-                ObjectNamedFacetForDomainObjectLayoutAnnotation
+        addFacetIfPresent(ObjectNamedFacetForDomainObjectLayoutAnnotation
                 .create(domainObjectLayoutIfAny, facetHolder));
 
-        addFacetIfPresent(
-                TableDecoratorFacetForDomainObjectLayoutAnnotation
+        addFacetIfPresent(TableDecoratorFacetForDomainObjectLayoutAnnotation
                         .create(domainObjectLayoutIfAny, facetHolder));
 
-        addFacetIfPresent(
-                PagedFacetForDomainObjectLayoutAnnotation
+        addFacetIfPresent(PagedFacetForDomainObjectLayoutAnnotation
                 .create(domainObjectLayoutIfAny, facetHolder));
 
-        addFacetIfPresent(
-                BookmarkPolicyFacetForDomainObjectLayoutAnnotation
+        addFacetIfPresent(BookmarkPolicyFacetForDomainObjectLayoutAnnotation
                 .create(domainObjectLayoutIfAny, facetHolder));
 
         return;
diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/domainobjectlayout/LayoutFacetViaDomainObjectLayoutAnnotationUsingLayoutUiEvent.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/domainobjectlayout/LayoutFacetViaDomainObjectLayoutAnnotationUsingLayoutUiEvent.java
deleted file mode 100644
index b4b5ab3d92f..00000000000
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/domainobjectlayout/LayoutFacetViaDomainObjectLayoutAnnotationUsingLayoutUiEvent.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package org.apache.causeway.core.metamodel.facets.object.domainobjectlayout;
-
-import java.util.Optional;
-import java.util.function.BiConsumer;
-
-import org.apache.causeway.applib.annotation.DomainObjectLayout;
-import org.apache.causeway.applib.events.EventObjectBase;
-import org.apache.causeway.applib.events.ui.LayoutUiEvent;
-import org.apache.causeway.commons.internal.base._Casts;
-import org.apache.causeway.core.metamodel.facetapi.FacetHolder;
-import org.apache.causeway.core.metamodel.facets.object.layout.LayoutFacet;
-import 
org.apache.causeway.core.metamodel.facets.object.layout.LayoutFacetAbstract;
-import org.apache.causeway.core.metamodel.object.ManagedObject;
-import org.apache.causeway.core.metamodel.object.MmEventUtils;
-import 
org.apache.causeway.core.metamodel.services.events.MetamodelEventService;
-
-public class LayoutFacetViaDomainObjectLayoutAnnotationUsingLayoutUiEvent
-extends LayoutFacetAbstract
-implements LayoutFacet {
-
-    public static 
Optional<LayoutFacetViaDomainObjectLayoutAnnotationUsingLayoutUiEvent> create(
-            final Optional<DomainObjectLayout> domainObjectLayoutIfAny,
-            final MetamodelEventService metamodelEventService,
-            final FacetHolder facetHolder) {
-
-        return domainObjectLayoutIfAny
-                .map(DomainObjectLayout::layoutUiEvent)
-                .filter(layoutUiEvent -> MmEventUtils.eventTypeIsPostable(
-                        layoutUiEvent,
-                        LayoutUiEvent.Noop.class,
-                        LayoutUiEvent.Default.class,
-                        
facetHolder.getConfiguration().getApplib().getAnnotation()
-                            
.getDomainObjectLayout().getLayoutUiEvent().isPostForDefault()))
-                .map(layoutUiEvent -> {
-
-                    return new 
LayoutFacetViaDomainObjectLayoutAnnotationUsingLayoutUiEvent(
-                            layoutUiEvent, metamodelEventService, facetHolder);
-                });
-    }
-
-    private final Class<? extends LayoutUiEvent<Object>> layoutUiEventClass;
-    private final MetamodelEventService metamodelEventService;
-
-    private LayoutFacetViaDomainObjectLayoutAnnotationUsingLayoutUiEvent(
-            final Class<? extends LayoutUiEvent<?>> layoutUiEventClass,
-                    final MetamodelEventService metamodelEventService,
-                    final FacetHolder holder) {
-        super(holder, Precedence.EVENT);
-        this.layoutUiEventClass = _Casts.uncheckedCast(layoutUiEventClass);
-        this.metamodelEventService = metamodelEventService;
-    }
-
-    @Override
-    public String layout(final ManagedObject owningAdapter) {
-
-        if(owningAdapter == null) {
-            return null;
-        }
-
-        final LayoutUiEvent<Object> layoutUiEvent = 
newLayoutUiEvent(owningAdapter);
-
-        metamodelEventService.fireLayoutUiEvent(layoutUiEvent);
-
-        final String layout = layoutUiEvent.getLayout();
-
-        if(layout == null) {
-            // ie no subscribers out there...
-
-            final LayoutFacet underlyingLayoutFacet = getSharedFacetRanking()
-            
.flatMap(facetRanking->facetRanking.getWinnerNonEvent(LayoutFacet.class))
-            .orElse(null);
-
-            if(underlyingLayoutFacet!=null) {
-                return underlyingLayoutFacet.layout(owningAdapter);
-            }
-        }
-
-        return layout;
-    }
-
-    private LayoutUiEvent<Object> newLayoutUiEvent(final ManagedObject 
owningAdapter) {
-        return 
EventObjectBase.getInstanceWithSourceSupplier(layoutUiEventClass, 
owningAdapter::getPojo).orElseThrow();
-    }
-
-    @Override
-    public void visitAttributes(final BiConsumer<String, Object> visitor) {
-        super.visitAttributes(visitor);
-        visitor.accept("layoutUiEventClass", layoutUiEventClass);
-    }
-}
diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/layout/LayoutFacet.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/layout/LayoutFacet.java
index 43971dbab20..208f0158b17 100644
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/layout/LayoutFacet.java
+++ 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/layout/LayoutFacet.java
@@ -18,19 +18,151 @@
  */
 package org.apache.causeway.core.metamodel.facets.object.layout;
 
+import java.util.Optional;
+import java.util.function.BiConsumer;
+
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
+
+import org.apache.causeway.applib.annotation.DomainObjectLayout;
+import org.apache.causeway.applib.events.EventObjectBase;
+import org.apache.causeway.applib.events.ui.LayoutUiEvent;
+import org.apache.causeway.commons.internal.base._Casts;
+import 
org.apache.causeway.commons.internal.reflection._GenericResolver.ResolvedMethod;
 import org.apache.causeway.core.metamodel.facetapi.Facet;
+import org.apache.causeway.core.metamodel.facetapi.FacetHolder;
+import org.apache.causeway.core.metamodel.facets.HasImperativeAspect;
+import org.apache.causeway.core.metamodel.facets.ImperativeAspect;
+import org.apache.causeway.core.metamodel.facets.object.icon.IconFacet;
+import org.apache.causeway.core.metamodel.facets.object.title.TitleFacet;
 import org.apache.causeway.core.metamodel.object.ManagedObject;
+import org.apache.causeway.core.metamodel.object.ManagedObjects;
+import org.apache.causeway.core.metamodel.object.MmEventUtils;
+import 
org.apache.causeway.core.metamodel.services.events.MetamodelEventService;
 
-/*
- * Layout for an object.
- *
+/**
+ * Provides the null-able layout prefix for an object.
+ * The prefix - if present - is used to lookup concrete layout variants.
  * <p>
- * In the standard Apache Causeway Programming Model, typically corresponds to 
a method named <tt>layout</tt>.
+ * Typically corresponds to a method named <tt>layout</tt>.
  *
  * @see TitleFacet
  * @see IconFacet
  */
-public interface LayoutFacet extends Facet {
+public record LayoutFacet(
+    @NonNull String origin,
+    @NonNull LayoutProvider layoutProvider,
+    @NonNull FacetHolder facetHolder,
+    Facet.@NonNull Precedence precedence
+) implements Facet, HasImperativeAspect {
+
+    public interface LayoutProvider {
+        String layout(LayoutFacet layoutFacet, @Nullable ManagedObject 
managedObject);
+        default void visitAttributes(final BiConsumer<String, Object> visitor) 
{}
+    }
+
+    // -- LAYOUT PROVIDERS
+
+    private record LayoutProviderForImperativeAspect(
+        ImperativeAspect imperativeAspect) implements LayoutProvider {
+        @Override public String layout(final LayoutFacet layoutFacet, 
@Nullable final ManagedObject managedObject) {
+            if(ManagedObjects.isNullOrUnspecifiedOrEmpty(managedObject)) 
return null;
+            try {
+                return (String) 
imperativeAspect.invokeSingleMethod(managedObject);
+            } catch (final RuntimeException ex) {
+                return null;
+            }
+        }
+        @Override public void visitAttributes(final BiConsumer<String, Object> 
visitor) {
+            imperativeAspect.visitAttributes(visitor);
+        }
+    }
+
+    private record LayoutProviderForUiEvent(
+        Class<? extends LayoutUiEvent<Object>> layoutUiEventClass,
+        MetamodelEventService metamodelEventService) implements 
LayoutFacet.LayoutProvider {
+        @Override public String layout(final LayoutFacet layoutFacet, final 
ManagedObject managedObject) {
+            if(ManagedObjects.isNullOrUnspecifiedOrEmpty(managedObject)) 
return null;
+
+            final LayoutUiEvent<Object> layoutUiEvent = 
newLayoutUiEvent(managedObject);
+
+            metamodelEventService.fireLayoutUiEvent(layoutUiEvent);
+
+            final String layout = layoutUiEvent.getLayout();
+            if(layout != null) return layout;
+
+            // ie no subscribers out there, then fallback to the underlying ...
+            return layoutFacet.getSharedFacetRanking()
+                
.flatMap(facetRanking->facetRanking.getWinnerNonEvent(LayoutFacet.class))
+                
.map(underlyingLayoutFacet->underlyingLayoutFacet.layout(managedObject))
+                .orElse(null);
+        }
+        @Override public void visitAttributes(final BiConsumer<String, Object> 
visitor) {
+            visitor.accept("layoutUiEventClass", layoutUiEventClass);
+        }
+        private LayoutUiEvent<Object> newLayoutUiEvent(final ManagedObject 
owningAdapter) {
+            return 
EventObjectBase.getInstanceWithSourceSupplier(layoutUiEventClass, 
owningAdapter::getPojo).orElseThrow();
+        }
+    }
+
+    // -- FACTORIES
+
+    public static LayoutFacet fallback(final FacetHolder facetHolder) {
+        return new LayoutFacet("Fallback", (lf, mo)->null, facetHolder, 
Precedence.FALLBACK);
+    }
+
+    public static Optional<LayoutFacet> forLayoutMethod(
+        final @Nullable ResolvedMethod methodIfAny,
+        final FacetHolder holder) {
+
+        return Optional.ofNullable(methodIfAny)
+            .map(method->ImperativeAspect.singleRegularMethod(method, 
Intent.UI_HINT))
+            .map(LayoutProviderForImperativeAspect::new)
+            .map(layoutProvider->
+                new LayoutFacet("LayoutMethod", layoutProvider, holder, 
Precedence.DEFAULT));
+    }
+
+    public static Optional<LayoutFacet> 
forDomainObjectLayoutAnnotationUsingLayoutUiEvent(
+            final Optional<DomainObjectLayout> domainObjectLayoutIfAny,
+            final MetamodelEventService metamodelEventService,
+            final FacetHolder facetHolder) {
+
+        return domainObjectLayoutIfAny
+                .map(DomainObjectLayout::layoutUiEvent)
+                .filter(layoutUiEvent -> MmEventUtils.eventTypeIsPostable(
+                        layoutUiEvent,
+                        LayoutUiEvent.Noop.class,
+                        LayoutUiEvent.Default.class,
+                        
facetHolder.getConfiguration().getApplib().getAnnotation()
+                            
.getDomainObjectLayout().getLayoutUiEvent().isPostForDefault()))
+                .map(layoutUiEvent -> new 
LayoutProviderForUiEvent(_Casts.uncheckedCast(layoutUiEvent), 
metamodelEventService))
+                .map(layoutProvider -> new 
LayoutFacet("DomainObjectLayoutAnnotationWithLayoutUiEvent",
+                    layoutProvider,
+                        facetHolder, Precedence.EVENT));
+    }
+
+    // -- METHODS
+
+    @Override public Class<? extends Facet> facetType() { return getClass(); }
+    @Override public Precedence getPrecedence() { return precedence(); }
+    @Override public FacetHolder getFacetHolder() { return facetHolder(); }
+
+    public String layout(final ManagedObject managedObject) {
+        return layoutProvider().layout(this, managedObject);
+    }
+
+    @Override
+    public ImperativeAspect getImperativeAspect() {
+        return layoutProvider() instanceof LayoutProviderForImperativeAspect 
aspectHolder
+            ? aspectHolder.imperativeAspect()
+            : null;
+    }
+
+    @Override
+    public void visitAttributes(final BiConsumer<String, Object> visitor) {
+        visitor.accept("origin", origin());
+        visitor.accept("precedence", getPrecedence().name());
+        layoutProvider().visitAttributes(visitor);
+    }
 
-    public String layout(final ManagedObject objectAdapterIfAny);
 }
diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/layout/LayoutFacetAbstract.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/layout/LayoutFacetAbstract.java
deleted file mode 100644
index 6256129a17a..00000000000
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/layout/LayoutFacetAbstract.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package org.apache.causeway.core.metamodel.facets.object.layout;
-
-import org.apache.causeway.core.metamodel.facetapi.Facet;
-import org.apache.causeway.core.metamodel.facetapi.FacetAbstract;
-import org.apache.causeway.core.metamodel.facetapi.FacetHolder;
-
-public abstract class LayoutFacetAbstract
-extends FacetAbstract implements LayoutFacet {
-
-    private static final Class<? extends Facet> type() {
-        return LayoutFacet.class;
-    }
-
-    protected LayoutFacetAbstract(final FacetHolder holder) {
-        super(type(), holder);
-    }
-
-    protected LayoutFacetAbstract(
-            final FacetHolder holder,
-            final Facet.Precedence precedence) {
-        super(type(), holder, precedence);
-    }
-
-}
diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/layout/LayoutFacetFallback.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/layout/LayoutFacetFallback.java
deleted file mode 100644
index 360104dccaa..00000000000
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/layout/LayoutFacetFallback.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package org.apache.causeway.core.metamodel.facets.object.layout;
-
-import java.util.function.BiConsumer;
-
-import org.apache.causeway.core.metamodel.facetapi.Facet;
-import org.apache.causeway.core.metamodel.facetapi.FacetHolder;
-import org.apache.causeway.core.metamodel.object.ManagedObject;
-
-public class LayoutFacetFallback extends LayoutFacetAbstract {
-
-    public LayoutFacetFallback(final FacetHolder holder) {
-        super(holder, Facet.Precedence.FALLBACK);
-    }
-
-    @Override
-    public String layout(final ManagedObject objectAdapterIfAny) {
-        return null;
-    }
-
-    @Override
-    public void visitAttributes(final BiConsumer<String, Object> visitor) {
-        super.visitAttributes(visitor);
-    }
-
-}
diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/layout/LayoutFacetViaLayoutMethod.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/layout/LayoutFacetViaLayoutMethod.java
deleted file mode 100644
index 6ba8bd78d19..00000000000
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/layout/LayoutFacetViaLayoutMethod.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package org.apache.causeway.core.metamodel.facets.object.layout;
-
-import java.util.Optional;
-import java.util.function.BiConsumer;
-
-import org.jspecify.annotations.Nullable;
-
-import 
org.apache.causeway.commons.internal.reflection._GenericResolver.ResolvedMethod;
-import org.apache.causeway.core.metamodel.facetapi.FacetHolder;
-import org.apache.causeway.core.metamodel.facets.HasImperativeAspect;
-import org.apache.causeway.core.metamodel.facets.ImperativeAspect;
-import org.apache.causeway.core.metamodel.object.ManagedObject;
-import org.apache.causeway.core.metamodel.object.ManagedObjects;
-
-import lombok.Getter;
-import org.jspecify.annotations.NonNull;
-
-public class LayoutFacetViaLayoutMethod
-extends LayoutFacetAbstract
-implements HasImperativeAspect {
-
-    @Getter(onMethod_ = {@Override}) private final @NonNull ImperativeAspect 
imperativeAspect;
-
-    public static Optional<LayoutFacet> create(
-            final @Nullable ResolvedMethod methodIfAny,
-            final FacetHolder holder) {
-
-        return Optional.ofNullable(methodIfAny)
-        .map(method->
-            new LayoutFacetViaLayoutMethod(
-                    ImperativeAspect.singleRegularMethod(method, 
Intent.UI_HINT),
-                    holder));
-    }
-
-    private LayoutFacetViaLayoutMethod(
-            final ImperativeAspect imperativeAspect,
-            final FacetHolder holder) {
-        super(holder);
-        this.imperativeAspect = imperativeAspect;
-    }
-
-    @Override
-    public String layout(final ManagedObject domainObject) {
-        if(ManagedObjects.isNullOrUnspecifiedOrEmpty(domainObject)) {
-            return null;
-        }
-        try {
-            return (String) imperativeAspect.invokeSingleMethod(domainObject);
-        } catch (final RuntimeException ex) {
-            return null;
-        }
-    }
-
-    @Override
-    public void visitAttributes(final BiConsumer<String, Object> visitor) {
-        super.visitAttributes(visitor);
-        imperativeAspect.visitAttributes(visitor);
-    }
-
-}
diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/support/ObjectSupportFacetFactory.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/support/ObjectSupportFacetFactory.java
index 071d5fea784..438759af5bc 100644
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/support/ObjectSupportFacetFactory.java
+++ 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/support/ObjectSupportFacetFactory.java
@@ -41,7 +41,7 @@
 import 
org.apache.causeway.core.metamodel.facets.object.hidden.method.HiddenObjectFacetViaMethod;
 import 
org.apache.causeway.core.metamodel.facets.object.icon.method.IconFacetViaIconNameMethod;
 import 
org.apache.causeway.core.metamodel.facets.object.iconfa.method.FaFacetViaIconFaLayersMethod;
-import 
org.apache.causeway.core.metamodel.facets.object.layout.LayoutFacetViaLayoutMethod;
+import org.apache.causeway.core.metamodel.facets.object.layout.LayoutFacet;
 import 
org.apache.causeway.core.metamodel.facets.object.title.methods.TitleFacetFromToStringMethod;
 import 
org.apache.causeway.core.metamodel.facets.object.title.methods.TitleFacetViaTitleMethod;
 import org.apache.causeway.core.metamodel.methods.MethodFinder;
@@ -84,7 +84,7 @@ public final void process(final ProcessClassContext 
processClassContext) {
         processObjectSupport(processClassContext, ObjectSupportMethod.HIDDEN, 
HiddenObjectFacetViaMethod::create);
         processObjectSupport(processClassContext, 
ObjectSupportMethod.DISABLED, DisabledObjectFacetViaMethod::create);
         processObjectSupport(processClassContext, ObjectSupportMethod.TITLE, 
TitleFacetViaTitleMethod::create);
-        processObjectSupport(processClassContext, ObjectSupportMethod.LAYOUT, 
LayoutFacetViaLayoutMethod::create);
+        processObjectSupport(processClassContext, ObjectSupportMethod.LAYOUT, 
LayoutFacet::forLayoutMethod);
         processObjectSupport(processClassContext, 
ObjectSupportMethod.ICON_NAME, IconFacetViaIconNameMethod::create);
         processObjectSupport(processClassContext, 
ObjectSupportMethod.ICON_FA_LAYERS, FaFacetViaIconFaLayersMethod::create);
         processObjectSupport(processClassContext, 
ObjectSupportMethod.CSS_CLASS, CssClassFacetViaCssClassMethod::create);
diff --git 
a/core/metamodel/src/test/java/org/apache/causeway/core/metamodel/facets/object/ident/layout/LayoutFacetMethodTest.java
 
b/core/metamodel/src/test/java/org/apache/causeway/core/metamodel/facets/object/ident/layout/LayoutFacetMethodTest.java
index de502f09f9c..9a51b8d6a12 100644
--- 
a/core/metamodel/src/test/java/org/apache/causeway/core/metamodel/facets/object/ident/layout/LayoutFacetMethodTest.java
+++ 
b/core/metamodel/src/test/java/org/apache/causeway/core/metamodel/facets/object/ident/layout/LayoutFacetMethodTest.java
@@ -29,12 +29,12 @@
 
 import org.apache.causeway.commons.internal.reflection._GenericResolver;
 import org.apache.causeway.core.metamodel.facetapi.FacetHolder;
-import 
org.apache.causeway.core.metamodel.facets.object.layout.LayoutFacetViaLayoutMethod;
+import org.apache.causeway.core.metamodel.facets.object.layout.LayoutFacet;
 import org.apache.causeway.core.metamodel.object.ManagedObject;
 
 class LayoutFacetMethodTest {
 
-    private LayoutFacetViaLayoutMethod facet;
+    private LayoutFacet facet;
     private ManagedObject mockOwningAdapter;
 
     private DomainObjectWithProblemInLayoutMethod pojo;
@@ -46,14 +46,14 @@ public String layout() {
     }
 
     @BeforeEach
-    public void setUp() throws Exception {
+    void setUp() throws Exception {
 
         pojo = new DomainObjectWithProblemInLayoutMethod();
 
         var iconNameMethod = _GenericResolver.testing
                 .resolveMethod(DomainObjectWithProblemInLayoutMethod.class, 
"layout");
-        facet = (LayoutFacetViaLayoutMethod) LayoutFacetViaLayoutMethod
-                    .create(iconNameMethod, Mockito.mock(FacetHolder.class))
+        facet = LayoutFacet.forLayoutMethod(
+                        iconNameMethod, Mockito.mock(FacetHolder.class))
                     .orElse(null);
 
         mockOwningAdapter = Mockito.mock(ManagedObject.class);
@@ -61,12 +61,12 @@ public void setUp() throws Exception {
     }
 
     @AfterEach
-    public void tearDown() throws Exception {
+    void tearDown() throws Exception {
         facet = null;
     }
 
     @Test
-    public void when_layout_throws_exception() {
+    void when_layout_throws_exception() {
         //assertThrows(NullPointerException.class, 
()->facet.layout(mockOwningAdapter));
         final String layout = facet.layout(mockOwningAdapter);
         assertThat(layout, is(nullValue()));

Reply via email to