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

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


The following commit(s) were added to refs/heads/master by this push:
     new 135526f23e CAUSEWAY-3687: adds MM validation when UI contributing 
proxy is detected
135526f23e is described below

commit 135526f23e708cab7f1f301808d2850fd1e4a08d
Author: Andi Huber <[email protected]>
AuthorDate: Tue Feb 27 19:37:40 2024 +0100

    CAUSEWAY-3687: adds MM validation when UI contributing proxy is detected
---
 .../org/apache/causeway/applib/id/LogicalType.java |  4 ++
 .../progmodel/ProgrammingModelConstants.java       |  4 ++
 .../DomainObjectAnnotationFacetFactory.java        | 48 ++++++++++++++++++----
 .../services/registry/ServiceRegistryDefault.java  | 17 +++++---
 4 files changed, 59 insertions(+), 14 deletions(-)

diff --git 
a/api/applib/src/main/java/org/apache/causeway/applib/id/LogicalType.java 
b/api/applib/src/main/java/org/apache/causeway/applib/id/LogicalType.java
index 67faa63f6d..590deb7d67 100644
--- a/api/applib/src/main/java/org/apache/causeway/applib/id/LogicalType.java
+++ b/api/applib/src/main/java/org/apache/causeway/applib/id/LogicalType.java
@@ -155,6 +155,8 @@ implements
             final @NonNull Class<?> correspondingClass,
             final @NonNull Supplier<String> logicalNameProvider) {
 
+        //[CAUSEWAY-3687] would allow CGLIB proxies to be added, but we 
decided to not allow this for UI contributing beans
+        //this.correspondingClass = 
ClassUtils.getUserClass(correspondingClass);
         this.correspondingClass = correspondingClass;
         this.logicalNameProvider = logicalNameProvider;
     }
@@ -163,6 +165,8 @@ implements
             final @NonNull Class<?> correspondingClass,
             final String logicalName) {
 
+        //[CAUSEWAY-3687] would allow CGLIB proxies to be added, but we 
decided to not allow this for UI contributing beans
+        //this.correspondingClass = 
ClassUtils.getUserClass(correspondingClass);
         this.correspondingClass = correspondingClass;
         this.logicalName = requireNonEmpty(logicalName);
         this.logicalNameProvider = null;
diff --git 
a/core/config/src/main/java/org/apache/causeway/core/config/progmodel/ProgrammingModelConstants.java
 
b/core/config/src/main/java/org/apache/causeway/core/config/progmodel/ProgrammingModelConstants.java
index 0153c06cae..4d5efd7ac3 100644
--- 
a/core/config/src/main/java/org/apache/causeway/core/config/progmodel/ProgrammingModelConstants.java
+++ 
b/core/config/src/main/java/org/apache/causeway/core/config/progmodel/ProgrammingModelConstants.java
@@ -463,6 +463,10 @@ public final class ProgrammingModelConstants {
         NON_UNIQUE_LOGICAL_TYPE_NAME_OR_ALIAS("Logical type name (or alias) 
${logicalTypeName} "
                 + "mapped to multiple non-abstract classes:\n"
                 + "${csv}"),
+        PROXIED_SERVICE_BEAN_NOT_ALLOWED_TO_CONTRIBUTE_TO_UI("Logical type 
name (or alias) ${logicalTypeName} "
+                + "mapped to at least one proxied class:\n"
+                + "${csv}. Proxied service beans are not allowed to contribute 
to the UI. "
+                + "E.g. don't mix @Transactional with 
@DomainService(nature=VIEW)"),
         UNKNONW_SORT_WITH_ACTION("${type}: is a (concrete) but UNKNOWN sort, 
yet has ${actionCount} actions: ${actions}"),
         ACTION_METHOD_OVERLOADING_NOT_ALLOWED("Action method overloading is 
not allowed, "
                 + "yet ${type} has action(s) that have a the same member name: 
${overloadedNames}"),
diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/domainobject/DomainObjectAnnotationFacetFactory.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/domainobject/DomainObjectAnnotationFacetFactory.java
index 3fbe85e74a..19a7d102e1 100644
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/domainobject/DomainObjectAnnotationFacetFactory.java
+++ 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/domainobject/DomainObjectAnnotationFacetFactory.java
@@ -26,6 +26,9 @@ import java.util.stream.Collectors;
 import javax.inject.Inject;
 import javax.inject.Named;
 
+import org.springframework.lang.Nullable;
+import org.springframework.util.ClassUtils;
+
 import org.apache.causeway.applib.Identifier;
 import org.apache.causeway.applib.annotation.Action;
 import org.apache.causeway.applib.annotation.Collection;
@@ -41,6 +44,7 @@ import 
org.apache.causeway.applib.events.lifecycle.ObjectRemovingEvent;
 import org.apache.causeway.applib.events.lifecycle.ObjectUpdatedEvent;
 import org.apache.causeway.applib.events.lifecycle.ObjectUpdatingEvent;
 import org.apache.causeway.applib.id.LogicalType;
+import org.apache.causeway.commons.collections.Can;
 import org.apache.causeway.commons.internal.collections._Multimaps;
 import 
org.apache.causeway.commons.internal.reflection._GenericResolver.ResolvedMethod;
 import org.apache.causeway.core.config.progmodel.ProgrammingModelConstants;
@@ -78,6 +82,7 @@ import 
org.apache.causeway.core.metamodel.specloader.validator.ValidationFailure
 
 import static org.apache.causeway.commons.internal.base._NullSafe.stream;
 
+import lombok.NonNull;
 import lombok.val;
 import lombok.extern.log4j.Log4j2;
 
@@ -587,17 +592,35 @@ implements
 
                     specsByLogicalTypeName.forEach((logicalTypeName, 
collidingSpecs)->{
                         if(isObjectTypeCollision(collidingSpecs)) {
-                            val csv = asCsv(collidingSpecs);
-                            collidingSpecs.stream()
-                                    
.filter(this::logicalTypeNameIsNotIncludedInAliased)
-                                    .forEach(spec->{
-                                ValidationFailure.raiseFormatted(spec,
+
+                            // assuming, a check for proxies is only required 
when there is also a bean name collision
+                            // where the plain class and the proxied class 
collide having the same logical-type-name
+                            val proxies = proxiesIn(collidingSpecs);
+                            if(proxies.isNotEmpty()) {
+
+                                proxies.forEach(spec->{
+                                    ValidationFailure.raiseFormatted(spec,
+                                        
ProgrammingModelConstants.Violation.PROXIED_SERVICE_BEAN_NOT_ALLOWED_TO_CONTRIBUTE_TO_UI
+                                            .builder()
+                                            .addVariable("logicalTypeName", 
spec.getLogicalTypeName())
+                                            .addVariable("csv", 
asCsv(proxies.toList()))
+                                            .buildMessage());
+                                });
+
+                            } else {
+
+                                collidingSpecs.stream()
+                                
.filter(this::logicalTypeNameIsNotIncludedInAliased)
+                                .forEach(spec->{
+                                    ValidationFailure.raiseFormatted(spec,
                                         
ProgrammingModelConstants.Violation.NON_UNIQUE_LOGICAL_TYPE_NAME_OR_ALIAS
                                             .builder()
                                             .addVariable("logicalTypeName", 
spec.getLogicalTypeName())
-                                            .addVariable("csv", csv)
+                                            .addVariable("csv", 
asCsv(collidingSpecs))
                                             .buildMessage());
-                            });
+                                });
+
+                            }
                         }
                     });
 
@@ -605,7 +628,16 @@ implements
                     specsByLogicalTypeName.clear();
                 }
 
-                private boolean 
logicalTypeNameIsNotIncludedInAliased(ObjectSpecification objectSpecification) {
+                private boolean isProxy(final @NonNull ObjectSpecification 
spec) {
+                    val cls = spec.getCorrespondingClass();
+                    return !ClassUtils.getUserClass(cls).equals(cls);
+                }
+
+                private Can<ObjectSpecification> proxiesIn(final @Nullable 
List<ObjectSpecification> specs) {
+                    return 
stream(specs).filter(this::isProxy).collect(Can.toCan());
+                }
+
+                private boolean logicalTypeNameIsNotIncludedInAliased(final 
ObjectSpecification objectSpecification) {
                     if 
(getConfiguration().getCore().getMetaModel().getValidator().isAllowLogicalTypeNameAsAlias())
 {
                         return objectSpecification.getAliases()
                                 .map(LogicalType::getLogicalTypeName).stream()
diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/registry/ServiceRegistryDefault.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/registry/ServiceRegistryDefault.java
index e7a1fff85b..7ba8e1ab31 100644
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/registry/ServiceRegistryDefault.java
+++ 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/registry/ServiceRegistryDefault.java
@@ -21,6 +21,7 @@ package org.apache.causeway.core.metamodel.services.registry;
 import java.lang.annotation.Annotation;
 import java.util.Map;
 import java.util.Optional;
+import java.util.function.Predicate;
 import java.util.stream.Stream;
 
 import javax.annotation.Priority;
@@ -35,7 +36,6 @@ import org.apache.causeway.applib.id.LogicalType;
 import org.apache.causeway.applib.services.registry.ServiceRegistry;
 import org.apache.causeway.commons.collections.Can;
 import org.apache.causeway.commons.internal.base._Lazy;
-import org.apache.causeway.commons.internal.base._NullSafe;
 import org.apache.causeway.commons.internal.collections._Maps;
 import org.apache.causeway.commons.internal.ioc._SingletonBeanProvider;
 import org.apache.causeway.core.config.beans.CausewayBeanTypeRegistry;
@@ -88,16 +88,21 @@ public final class ServiceRegistryDefault implements 
ServiceRegistry {
 
     private Map<String, _SingletonBeanProvider> 
enumerateContributingDomainServices() {
         val managedBeanAdapterByName = _Maps.<String, 
_SingletonBeanProvider>newHashMap();
-        val managedBeansContributing = 
causewayBeanTypeRegistry.getManagedBeansContributing().keySet();
 
         causewaySystemEnvironment.getIocContainer()
         .streamAllBeans()
-        .filter(_NullSafe::isPresent)
-        .filter(bean->managedBeansContributing.contains(bean.getBeanClass())) 
// do not register unknown sort
-        .forEach(bean->
-            managedBeanAdapterByName.put(bean.getId(), bean));
+        .filter(contributes())
+        .forEach(singletonProvider->
+            managedBeanAdapterByName.put(singletonProvider.getId(), 
singletonProvider));
 
         return managedBeanAdapterByName;
     }
 
+    private Predicate<_SingletonBeanProvider> contributes() {
+        var managedBeansContributing = 
causewayBeanTypeRegistry.getManagedBeansContributing().keySet();
+        return singletonProvider->singletonProvider!=null
+                ? 
managedBeansContributing.contains(singletonProvider.getBeanClass()) // do not 
register unknown sort
+                : false;
+    }
+
 }

Reply via email to