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 9149425dad CAUSEWAY-3767: refactor validation message to be a template
9149425dad is described below

commit 9149425dadb8690295ee8be059dfc0161115203a
Author: andi-huber <[email protected]>
AuthorDate: Mon Jun 10 08:51:48 2024 +0200

    CAUSEWAY-3767: refactor validation message to be a template
    
    - also implements skip on FixtureScript
---
 .../progmodel/ProgrammingModelConstants.java       |  8 +++
 .../LogicalTypeFacetFromClassNameFactory.java      | 78 ++++++++--------------
 .../core/metamodel/object/MmSpecUtils.java         | 26 ++++++++
 3 files changed, 61 insertions(+), 51 deletions(-)

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 c323f8d40c..d2f50387d4 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,14 @@ public final class ProgrammingModelConstants {
                 + "Consider importing type ${type} with Spring's @Import 
annotation. "
                 + "Types of sort VALUE should instead register a 
ValueSemanticsProvider with Spring, "
                 + "to be properly understood by the framework."),
+        LOGICAL_TYPE_NAME_IS_NOT_EXPLICIT("The object type ${type} of sort 
${beanSort} "
+                + "must be specified explicitly "
+                + "('${configProperty}' config property). "
+                + "Defaulting the object type from the package/class/package 
name can lead "
+                + "to data migration issues for apps deployed to production 
(if the class is "
+                + "subsequently refactored). "
+                + "Use @Discriminator, @Named or "
+                + "@PersistenceCapable(schema=...) to specify explicitly."),
         NON_UNIQUE_LOGICAL_TYPE_NAME_OR_ALIAS("Logical type name (or alias) 
${logicalTypeName} "
                 + "mapped to multiple non-abstract classes:\n"
                 + "${csv}"),
diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/logicaltype/classname/LogicalTypeFacetFromClassNameFactory.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/logicaltype/classname/LogicalTypeFacetFromClassNameFactory.java
index 224cd3f242..2d4c46c72f 100644
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/logicaltype/classname/LogicalTypeFacetFromClassNameFactory.java
+++ 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/logicaltype/classname/LogicalTypeFacetFromClassNameFactory.java
@@ -21,11 +21,13 @@ package 
org.apache.causeway.core.metamodel.facets.object.logicaltype.classname;
 import javax.inject.Inject;
 import javax.xml.bind.annotation.XmlType;
 
+import 
org.apache.causeway.core.config.progmodel.ProgrammingModelConstants.MessageTemplate;
 import org.apache.causeway.core.metamodel.context.MetaModelContext;
 import org.apache.causeway.core.metamodel.facetapi.FeatureType;
 import org.apache.causeway.core.metamodel.facetapi.MetaModelRefiner;
 import org.apache.causeway.core.metamodel.facets.FacetFactoryAbstract;
 import org.apache.causeway.core.metamodel.facets.ObjectTypeFacetFactory;
+import org.apache.causeway.core.metamodel.object.MmSpecUtils;
 import org.apache.causeway.core.metamodel.progmodel.ProgrammingModel;
 import org.apache.causeway.core.metamodel.spec.ObjectSpecification;
 import org.apache.causeway.core.metamodel.spec.feature.MixedIn;
@@ -62,75 +64,49 @@ implements
         // no-op.
     }
 
-
     @Override
     public void refineProgrammingModel(final ProgrammingModel 
programmingModel) {
-
         val shouldCheck = 
getConfiguration().getCore().getMetaModel().getValidator().isExplicitLogicalTypeNames();
-        if(!shouldCheck) {
-            return;
-        }
+        if(!shouldCheck) return;
 
         programmingModel.addValidatorSkipManagedBeans(objectSpec-> {
-
-            if(!check(objectSpec)) {
-                return;
-            }
+            if(skip(objectSpec)) return;
 
             val logicalType = objectSpec.getLogicalType();
-
+            
             //XXX has a slight chance to be a false positive; would need to 
check whether annotated with @Named
             
if(logicalType.getClassName().equals(logicalType.getLogicalTypeName())) {
-                ValidationFailure.raiseFormatted(
-                        objectSpec,
-                        "%s: the object type must be specified explicitly 
('%s' config property). "
-                                + "Defaulting the object type from the 
package/class/package name can lead "
-                                + "to data migration issues for apps deployed 
to production (if the class is "
-                                + "subsequently refactored). "
-                                + "Use @Discriminator, @Named or "
-                                + "@PersistenceCapable(schema=...) to specify 
explicitly.",
-                        objectSpec.getFullIdentifier(),
-                        
"causeway.core.meta-model.validator.explicit-logical-type-names");
+                ValidationFailure.raise(objectSpec, 
MessageTemplate.LOGICAL_TYPE_NAME_IS_NOT_EXPLICIT
+                        .builder()
+                        .addVariable("type", objectSpec.getFullIdentifier())
+                        .addVariable("beanSort", 
objectSpec.getBeanSort().name())
+                        .addVariable("configProperty", 
"causeway.core.meta-model.validator.explicit-logical-type-names")
+                        .buildMessage());
             }
-
-            });
-
+        });
     }
-
-    public static boolean check(final ObjectSpecification objectSpec) {
-            //TODO
-            // as a special case, don't enforce this for fixture scripts...
-            // we never invoke actions on fixture scripts anyway
-
-        if(objectSpec.isAbstract()) {
-            return false; //skip validation
-        }
-        if (objectSpec.isEntity()) {
-            return true;
-        }
+    
+    // -- HELPER
+
+    private boolean skip(final ObjectSpecification objectSpec) {
+        if (objectSpec.isAbstract()
+                || objectSpec.isMixin()
+                || objectSpec.isValue()
+                || MmSpecUtils.isFixtureScript(objectSpec)) return true;
+        if (objectSpec.isEntity()) return false;
         if (objectSpec.isViewModel()) {
-            //final ViewModelFacet viewModelFacet = 
objectSpec.getFacet(ViewModelFacet.class);
-            // don't check JAXB DTOs
-            final XmlType xmlType = 
objectSpec.getCorrespondingClass().getAnnotation(XmlType.class);
-            if(xmlType != null) {
-                return false; //skip validation
-            }
-            return true;
-        }
-        if(objectSpec.isMixin()) {
-            return false; //skip validation
+            // skip JAXB DTOs
+            return 
objectSpec.getCorrespondingClass().getAnnotation(XmlType.class) != null;
         }
         if (objectSpec.isInjectable()) {
             // only check if its a domain service (that is potentially 
contributing to UI or Web-API(s).
-            if(!objectSpec.isDomainService()) {
-                return false; //skip validation
-            }
+            if(!objectSpec.isDomainService()) return true; 
 
-            // don't check if domain service has only programmatic methods
-            return 
objectSpec.streamAnyActions(MixedIn.INCLUDED).findAny().isPresent();
+            // skip if domain service has only programmatic methods
+            return 
objectSpec.streamAnyActions(MixedIn.INCLUDED).findAny().isEmpty();
 
         }
-        return false; //skip validation
+        return true; //skip validation
     }
 
 }
diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/MmSpecUtils.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/MmSpecUtils.java
index 90e925594e..fd66476383 100644
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/MmSpecUtils.java
+++ 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/MmSpecUtils.java
@@ -22,13 +22,19 @@ import java.util.ArrayList;
 import java.util.LinkedHashMap;
 import java.util.List;
 
+import org.springframework.lang.Nullable;
+
 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.context._Context;
 import org.apache.causeway.core.metamodel.spec.ObjectSpecification;
 import org.apache.causeway.core.metamodel.specloader.SpecificationLoader;
 
+import lombok.AccessLevel;
+import lombok.Getter;
 import lombok.NonNull;
+import lombok.SneakyThrows;
 import lombok.val;
 import lombok.experimental.UtilityClass;
 
@@ -103,5 +109,25 @@ public final class MmSpecUtils {
 
         return sb.toString();
     }
+    
+    /**
+     * Whether given {@link ObjectSpecification} represents a FixtureScript 
(from testing.fixtures.applib). 
+     */
+    public boolean isFixtureScript(final @Nullable ObjectSpecification spec) {
+        if(spec==null) return false;
+        return 
getFixtureScriptClass().isAssignableFrom(spec.getCorrespondingClass());
+    }
+    
+    // -- HELPER 
+    
+    @Getter(lazy = true, value = AccessLevel.PRIVATE)
+    private final Class<?> fixtureScriptClass = loadFixtureScriptClass();
+    
+    @SneakyThrows
+    private Class<?> loadFixtureScriptClass() {
+        return _Context.loadClass(
+                
"org.apache.causeway.testing.fixtures.applib.fixturescripts.FixtureScript");
+    }
+    
 
 }
\ No newline at end of file

Reply via email to