You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2022/12/05 11:57:56 UTC

[isis] branch master updated: ISIS-2297: introduces a builder for violation messages

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/isis.git


The following commit(s) were added to refs/heads/master by this push:
     new 523b2cc9d5 ISIS-2297: introduces a builder for violation messages
523b2cc9d5 is described below

commit 523b2cc9d53b81cf6f3f6edbbc127acef7689d97
Author: Andi Huber <ah...@apache.org>
AuthorDate: Mon Dec 5 12:57:47 2022 +0100

    ISIS-2297: introduces a builder for violation messages
---
 .../progmodel/ProgrammingModelConstants.java       | 46 +++++++++++++--------
 ...reteTypeToBeIncludedWithMetamodelValidator.java | 12 ++++--
 .../actions/action/ActionOverloadingValidator.java | 10 +++--
 .../DomainObjectAnnotationFacetFactory.java        | 11 +++--
 .../logicaltype/LogicalTypeMalformedValidator.java | 13 +++---
 .../method/NavigableParentFacetViaMethod.java      | 15 +++----
 .../annotation/TitleFacetViaTitleAnnotation.java   |  8 ++--
 .../object/viewmodel/ViewModelFacetFactory.java    | 19 ++++-----
 .../ViewModelFacetForViewModelInterface.java       | 47 +++++++++-------------
 ...tionEnforcesMetamodelContributionValidator.java | 13 +++---
 .../_OrphanedSupportingMethodValidator.java        |  6 ++-
 .../specloader/SpecificationLoaderDefault.java     | 12 +++---
 .../DomainModelTest_usingBadDomain.java            | 15 ++++---
 ...elTest_usingBadDomain_noAnnotationEnforced.java |  2 +-
 .../interaction/DomainObjectTesterFactory.java     | 12 +++---
 15 files changed, 129 insertions(+), 112 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 160f990cce..2ba31737e5 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
@@ -29,6 +29,7 @@ import java.time.format.DateTimeFormatter;
 import java.time.format.DateTimeFormatterBuilder;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
@@ -469,7 +470,7 @@ public final class ProgrammingModelConstants {
 
     //maybe gradually consolidate all MM validation raisers here
     @RequiredArgsConstructor
-    public static enum Validation {
+    public static enum Violation {
         CONFLICTING_TITLE_STRATEGIES(
                 "${type} has title() method with @Title annotation, which is not allowed; "
                 + "consider either removing the @Title annotation or renaming the method"),
@@ -522,25 +523,36 @@ 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}"),
+        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}"),
         ;
 
         private final String template;
-        public String getMessage(final Identifier featureIdentifier) {
-            return getMessageForTypeAndMemberId(
-                    featureIdentifier.getLogicalType().getClassName(),
-                    featureIdentifier.getMemberLogicalName());
-        }
-        public String getMessageForType(final String type) {
-            return getMessage(Map.of(
-                    "type", type));
-        }
-        public String getMessageForTypeAndMemberId(final String type, final String memberId) {
-            return getMessage(Map.of(
-                    "type", type,
-                    "member", memberId));
-        }
-        public String getMessage(final Map<String, String> templateVars) {
-            return processMessageTemplate(template, templateVars);
+
+        public ViolationBuilder builder() {
+            return new ViolationBuilder(this);
+        }
+        @RequiredArgsConstructor
+        public static class ViolationBuilder {
+            private final Violation violaton;
+            private final Map<String, String> vars = new HashMap<>();
+            public ViolationBuilder addVariable(final String name, final String value) {
+                vars.put(name, value);
+                return this;
+            }
+            public ViolationBuilder addVariable(final String name, final Number value) {
+                vars.put(name, ""+value);
+                return this;
+            }
+            public ViolationBuilder addVariablesFor(final Identifier featureIdentifier) {
+                addVariable("type", featureIdentifier.getLogicalType().getClassName());
+                addVariable("member", featureIdentifier.getMemberLogicalName());
+                return this;
+            }
+            public String buildMessage() {
+                return processMessageTemplate(violaton.template, vars);
+            }
         }
     }
 
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/actions/action/ActionAnnotationShouldEnforceConcreteTypeToBeIncludedWithMetamodelValidator.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/actions/action/ActionAnnotationShouldEnforceConcreteTypeToBeIncludedWithMetamodelValidator.java
index 7b5d5c953a..2697ca2081 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/actions/action/ActionAnnotationShouldEnforceConcreteTypeToBeIncludedWithMetamodelValidator.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/actions/action/ActionAnnotationShouldEnforceConcreteTypeToBeIncludedWithMetamodelValidator.java
@@ -24,6 +24,7 @@ import javax.inject.Inject;
 
 import org.apache.causeway.applib.Identifier;
 import org.apache.causeway.applib.services.metamodel.BeanSort;
+import org.apache.causeway.core.config.progmodel.ProgrammingModelConstants;
 import org.apache.causeway.core.metamodel.context.MetaModelContext;
 import org.apache.causeway.core.metamodel.spec.ObjectSpecification;
 import org.apache.causeway.core.metamodel.spec.feature.MixedIn;
@@ -59,10 +60,13 @@ extends MetaModelVisitingValidatorAbstract {
 
                 ValidationFailure.raiseFormatted(
                         spec,
-                        "%s: is a (concrete) but UNKNOWN sort, yet has %d actions: {%s}",
-                        spec.getCorrespondingClass().getName(),
-                        numActions,
-                        actionIds);
+                        ProgrammingModelConstants.Violation.UNKNONW_SORT_WITH_ACTION
+                            .builder()
+                            .addVariable("type", spec.getCorrespondingClass().getName())
+                            .addVariable("actions", actionIds)
+                            .addVariable("actionCount", numActions)
+                            .buildMessage());
+
             }
 
         }
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/actions/action/ActionOverloadingValidator.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/actions/action/ActionOverloadingValidator.java
index 5010c21b82..409da3cd88 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/actions/action/ActionOverloadingValidator.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/actions/action/ActionOverloadingValidator.java
@@ -23,6 +23,7 @@ import javax.inject.Inject;
 import org.apache.causeway.applib.services.metamodel.BeanSort;
 import org.apache.causeway.commons.internal.base._Blackhole;
 import org.apache.causeway.commons.internal.collections._Sets;
+import org.apache.causeway.core.config.progmodel.ProgrammingModelConstants;
 import org.apache.causeway.core.metamodel.context.MetaModelContext;
 import org.apache.causeway.core.metamodel.spec.ActionScope;
 import org.apache.causeway.core.metamodel.spec.ObjectSpecification;
@@ -68,10 +69,11 @@ extends MetaModelVisitingValidatorAbstract {
 
                 ValidationFailure.raiseFormatted(
                         spec,
-                        "Action method overloading is not allowed, "
-                        + "yet %s has action(s) that have a the same member name: %s",
-                        spec.getCorrespondingClass().getName(),
-                        overloadedNames);
+                        ProgrammingModelConstants.Violation.ACTION_METHOD_OVERLOADING_NOT_ALLOWED
+                            .builder()
+                            .addVariable("type", spec.getCorrespondingClass().getName())
+                            .addVariable("overloadedNames", overloadedNames.toString())
+                            .buildMessage());
             }
 
         }
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 43712fb781..636086c25e 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
@@ -21,7 +21,6 @@ package org.apache.causeway.core.metamodel.facets.object.domainobject;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.util.List;
-import java.util.Map;
 import java.util.Optional;
 import java.util.stream.Collectors;
 
@@ -606,11 +605,11 @@ implements
                             val csv = asCsv(collidingSpecs);
                             collidingSpecs.forEach(spec->{
                                 ValidationFailure.raiseFormatted(spec,
-                                        ProgrammingModelConstants.Validation
-                                        .NON_UNIQUE_LOGICAL_TYPE_NAME_OR_ALIAS
-                                        .getMessage(Map.of(
-                                                "logicalTypeName", spec.getLogicalTypeName(),
-                                                "csv", csv)));
+                                        ProgrammingModelConstants.Violation.NON_UNIQUE_LOGICAL_TYPE_NAME_OR_ALIAS
+                                            .builder()
+                                            .addVariable("logicalTypeName", spec.getLogicalTypeName())
+                                            .addVariable("csv", csv)
+                                            .buildMessage());
                             });
                         }
                     });
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/logicaltype/LogicalTypeMalformedValidator.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/logicaltype/LogicalTypeMalformedValidator.java
index 659f70462c..0fe18861e3 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/logicaltype/LogicalTypeMalformedValidator.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/logicaltype/LogicalTypeMalformedValidator.java
@@ -18,8 +18,6 @@
  */
 package org.apache.causeway.core.metamodel.facets.object.logicaltype;
 
-import java.util.Map;
-
 import org.apache.causeway.commons.collections.Can;
 import org.apache.causeway.commons.internal.base._Strings;
 import org.apache.causeway.core.config.progmodel.ProgrammingModelConstants;
@@ -60,13 +58,14 @@ implements MetaModelRefiner {
                         .anyMatch(String::isEmpty)) {
 
                 val validationResponse = spec.isInjectable()
-                        ? ProgrammingModelConstants.Validation.DOMAIN_SERVICE_MISSING_A_NAMESPACE
-                        : ProgrammingModelConstants.Validation.DOMAIN_OBJECT_MISSING_A_NAMESPACE;
+                        ? ProgrammingModelConstants.Violation.DOMAIN_SERVICE_MISSING_A_NAMESPACE
+                        : ProgrammingModelConstants.Violation.DOMAIN_OBJECT_MISSING_A_NAMESPACE;
 
                 ValidationFailure.raiseFormatted(spec,
-                        validationResponse.getMessage(Map.of(
-                                "type", spec.getFullIdentifier(),
-                                "logicalTypeName", logicalTypeName)));
+                        validationResponse.builder()
+                            .addVariable("type", spec.getFullIdentifier())
+                            .addVariable("logicalTypeName", logicalTypeName)
+                            .buildMessage());
             }
 
         });
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/navparent/method/NavigableParentFacetViaMethod.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/navparent/method/NavigableParentFacetViaMethod.java
index fda3c0a44e..d1e68779c8 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/navparent/method/NavigableParentFacetViaMethod.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/navparent/method/NavigableParentFacetViaMethod.java
@@ -21,7 +21,6 @@ package org.apache.causeway.core.metamodel.facets.object.navparent.method;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.reflect.Method;
-import java.util.Map;
 import java.util.Optional;
 import java.util.function.BiConsumer;
 
@@ -56,13 +55,15 @@ extends NavigableParentFacetAbstract {
                 Optional.of(new NavigableParentFacetViaMethod(methodHandle, facetHolder)),
             // failure
             deficiency->{
-                val validationResponse =
-                        ProgrammingModelConstants.Validation.DOMAIN_OBJECT_INVALID_NAVIGABLE_PARENT;
+
                 ValidationFailure.raiseFormatted(facetHolder,
-                        validationResponse.getMessage(Map.of(
-                                "type", processedClass.getName(),
-                                "parentType", method.getReturnType().getName(),
-                                "parentTypeDeficiency", deficiency)));
+                        ProgrammingModelConstants.Violation.DOMAIN_OBJECT_INVALID_NAVIGABLE_PARENT
+                            .builder()
+                            .addVariable("type", processedClass.getName())
+                            .addVariable("parentType", method.getReturnType().getName())
+                            .addVariable("parentTypeDeficiency", deficiency)
+                            .buildMessage());
+
                 return Optional.empty();
             });
     }
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/title/annotation/TitleFacetViaTitleAnnotation.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/title/annotation/TitleFacetViaTitleAnnotation.java
index e22b065821..69f9ef6044 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/title/annotation/TitleFacetViaTitleAnnotation.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/title/annotation/TitleFacetViaTitleAnnotation.java
@@ -35,7 +35,7 @@ import org.apache.causeway.commons.internal.reflection._Annotations;
 import org.apache.causeway.commons.internal.reflection._Reflect.InterfacePolicy;
 import org.apache.causeway.commons.internal.reflection._Reflect.TypeHierarchyPolicy;
 import org.apache.causeway.core.config.progmodel.ProgrammingModelConstants.ObjectSupportMethod;
-import org.apache.causeway.core.config.progmodel.ProgrammingModelConstants.Validation;
+import org.apache.causeway.core.config.progmodel.ProgrammingModelConstants.Violation;
 import org.apache.causeway.core.metamodel.facetapi.FacetHolder;
 import org.apache.causeway.core.metamodel.facets.Evaluators;
 import org.apache.causeway.core.metamodel.facets.Evaluators.MethodEvaluator;
@@ -199,8 +199,10 @@ implements ImperativeFacet {
             final Runnable onTrue) {
         if(ObjectSupportMethod.TITLE.getMethodNames().contains(evaluator.name())) {
             ValidationFailure.raise(facetHolder,
-                    Validation.CONFLICTING_TITLE_STRATEGIES
-                    .getMessage(facetHolder.getFeatureIdentifier()));
+                    Violation.CONFLICTING_TITLE_STRATEGIES
+                        .builder()
+                        .addVariablesFor(facetHolder.getFeatureIdentifier())
+                        .buildMessage());
             onTrue.run();
             return true;
         }
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/viewmodel/ViewModelFacetFactory.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/viewmodel/ViewModelFacetFactory.java
index e5c4623225..2c0c066936 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/viewmodel/ViewModelFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/viewmodel/ViewModelFacetFactory.java
@@ -18,8 +18,6 @@
  */
 package org.apache.causeway.core.metamodel.facets.object.viewmodel;
 
-import java.util.Map;
-
 import javax.inject.Inject;
 import javax.xml.bind.annotation.XmlRootElement;
 
@@ -88,8 +86,10 @@ implements
                     && objectSpec.getBeanSort().isViewModel()
                     && !objectSpec.viewmodelFacet().isPresent()) {
                 ValidationFailure.raiseFormatted(objectSpec,
-                        ProgrammingModelConstants.Validation.VIEWMODEL_MISSING_SERIALIZATION_STRATEGY
-                            .getMessageForType(objectSpec.getCorrespondingClass().getName()));
+                        ProgrammingModelConstants.Violation.VIEWMODEL_MISSING_SERIALIZATION_STRATEGY
+                            .builder()
+                            .addVariable("type", objectSpec.getCorrespondingClass().getName())
+                            .buildMessage());
             }
 
             objectSpec.viewmodelFacet()
@@ -98,11 +98,12 @@ implements
                 facetRanking
                 .visitTopRankPairsSemanticDiffering(ViewModelFacet.class, (a, b)->{
                     ValidationFailure.raiseFormatted(objectSpec,
-                            ProgrammingModelConstants.Validation.VIEWMODEL_CONFLICTING_SERIALIZATION_STRATEGIES
-                                .getMessage(Map.of(
-                                        "type", objectSpec.getFullIdentifier(),
-                                        "facetA", a.getClass().getSimpleName(),
-                                        "facetB", b.getClass().getSimpleName())));
+                            ProgrammingModelConstants.Violation.VIEWMODEL_CONFLICTING_SERIALIZATION_STRATEGIES
+                                .builder()
+                                .addVariable("type", objectSpec.getFullIdentifier())
+                                .addVariable("facetA", a.getClass().getSimpleName())
+                                .addVariable("facetB", b.getClass().getSimpleName())
+                                .buildMessage());
                 });
             });
         });
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/viewmodel/ViewModelFacetForViewModelInterface.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/viewmodel/ViewModelFacetForViewModelInterface.java
index 8d45c6d186..a05aad3a97 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/viewmodel/ViewModelFacetForViewModelInterface.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/viewmodel/ViewModelFacetForViewModelInterface.java
@@ -19,7 +19,6 @@
 package org.apache.causeway.core.metamodel.facets.object.viewmodel;
 
 import java.lang.reflect.Constructor;
-import java.util.Map;
 import java.util.Optional;
 import java.util.stream.Collectors;
 
@@ -65,37 +64,29 @@ extends ViewModelFacetAbstract {
             val explicitInjectConstructors = ProgrammingModelConstants.ViewmodelConstructor.PUBLIC_WITH_INJECT_SEMANTICS.getAll(cls);
             val publicConstructors = ProgrammingModelConstants.ViewmodelConstructor.PUBLIC_ANY.getAll(cls);
 
-            if(explicitInjectConstructors.getCardinality().isMultiple()) {
 
-                ValidationFailure.raiseFormatted(holder,
-                        ProgrammingModelConstants.Validation.VIEWMODEL_MULTIPLE_CONSTRUCTORS_WITH_INJECT_SEMANTICS
-                            .getMessage(Map.of(
-                                    "type", cls.getName(),
-                                    "found", explicitInjectConstructors.getCardinality().isMultiple()
-                                        ? "{" + explicitInjectConstructors.stream()
-                                                .map(Constructor::toString)
-                                                .collect(Collectors.joining(", ")) + "}"
-                                        : "none")));
-
-                return Optional.empty();
+            val violation = explicitInjectConstructors.getCardinality().isMultiple()
+                    ? ProgrammingModelConstants.Violation.VIEWMODEL_MULTIPLE_CONSTRUCTORS_WITH_INJECT_SEMANTICS
+                    : explicitInjectConstructors.getCardinality().isZero()
+                        && !publicConstructors.getCardinality().isOne()
+                            // in absence of a constructor with inject semantics there must be exactly one public to pick instead
+                            ? ProgrammingModelConstants.Violation.VIEWMODEL_MISSING_OR_MULTIPLE_PUBLIC_CONSTRUCTORS
+                            : null;
 
-            } else if(explicitInjectConstructors.getCardinality().isZero()) {
+            if(violation!=null) {
 
-                // in absence of a constructor with inject semantics there must be exactly one public to pick instead
-
-                if(!publicConstructors.getCardinality().isOne()) {
-                    ValidationFailure.raiseFormatted(holder,
-                            ProgrammingModelConstants.Validation.VIEWMODEL_MISSING_OR_MULTIPLE_PUBLIC_CONSTRUCTORS
-                                .getMessage(Map.of(
-                                        "type", cls.getName(),
-                                        "found", publicConstructors.getCardinality().isMultiple()
-                                            ? "{" + publicConstructors.stream()
-                                                    .map(Constructor::toString)
-                                                    .collect(Collectors.joining(", ")) + "}"
-                                            : "none")));
+                ValidationFailure.raiseFormatted(holder,
+                        violation
+                            .builder()
+                            .addVariable("type", cls.getName())
+                            .addVariable("found", explicitInjectConstructors.getCardinality().isMultiple()
+                                    ? "{" + explicitInjectConstructors.stream()
+                                            .map(Constructor::toString)
+                                            .collect(Collectors.joining(", ")) + "}"
+                                    : "none")
+                            .buildMessage());
 
-                    return Optional.empty();
-                }
+                return Optional.empty();
 
             }
 
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/methods/DomainIncludeAnnotationEnforcesMetamodelContributionValidator.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/methods/DomainIncludeAnnotationEnforcesMetamodelContributionValidator.java
index 3b1d4fdd39..73ff60d796 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/methods/DomainIncludeAnnotationEnforcesMetamodelContributionValidator.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/methods/DomainIncludeAnnotationEnforcesMetamodelContributionValidator.java
@@ -35,7 +35,7 @@ import org.apache.causeway.commons.internal.collections._Sets;
 import org.apache.causeway.commons.internal.reflection._Annotations;
 import org.apache.causeway.commons.internal.reflection._ClassCache;
 import org.apache.causeway.commons.internal.reflection._Reflect;
-import org.apache.causeway.core.config.progmodel.ProgrammingModelConstants.Validation;
+import org.apache.causeway.core.config.progmodel.ProgrammingModelConstants.Violation;
 import org.apache.causeway.core.metamodel.commons.MethodUtil;
 import org.apache.causeway.core.metamodel.context.MetaModelContext;
 import org.apache.causeway.core.metamodel.facetapi.FacetHolder;
@@ -130,11 +130,12 @@ extends MetaModelVisitingValidatorAbstract {
                     .collect(Collectors.joining("; "));
 
             ValidationFailure.raiseFormatted(spec,
-                    Validation.UNSATISFIED_DOMAIN_INCLUDE_SEMANTICS
-                    .getMessageForTypeAndMemberId(
-                            spec.getFeatureIdentifier().getClassName(),
-                            _Reflect.methodToShortString(notPickedUpMethod)
-                            )
+                    Violation.UNSATISFIED_DOMAIN_INCLUDE_SEMANTICS
+                        .builder()
+                        .addVariable("type", spec.getFeatureIdentifier().getClassName())
+                        .addVariable("member", _Reflect.methodToShortString(notPickedUpMethod))
+                        .buildMessage()
+
                     + " Unmet constraint(s): %s",
                     unmetContraints);
         });
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/methods/_OrphanedSupportingMethodValidator.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/methods/_OrphanedSupportingMethodValidator.java
index 5cbc417733..62ea8d843e 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/methods/_OrphanedSupportingMethodValidator.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/methods/_OrphanedSupportingMethodValidator.java
@@ -64,8 +64,10 @@ class _OrphanedSupportingMethodValidator {
 
             ValidationFailure.raise(
                     spec,
-                    ProgrammingModelConstants.Validation.ORPHANED_METHOD
-                    .getMessage(methodIdentifier));
+                    ProgrammingModelConstants.Violation.ORPHANED_METHOD
+                        .builder()
+                        .addVariablesFor(methodIdentifier)
+                        .buildMessage());
         });
 
         potentialOrphans.clear(); // no longer needed
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/SpecificationLoaderDefault.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/SpecificationLoaderDefault.java
index 595f345557..c45b6c46b9 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/SpecificationLoaderDefault.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/SpecificationLoaderDefault.java
@@ -21,7 +21,6 @@ package org.apache.causeway.core.metamodel.specloader;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
-import java.util.Map;
 import java.util.Optional;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.LinkedBlockingQueue;
@@ -606,13 +605,14 @@ public class SpecificationLoaderDefault implements SpecificationLoader {
         if(isMetamodelFullyIntrospected()
                 && causewayConfiguration.getCore().getMetaModel().getIntrospector().isLockAfterFullIntrospection()) {
 
-            val warningMessage = ProgrammingModelConstants.Validation.TYPE_NOT_EAGERLY_DISCOVERED
-                .getMessage(Map.of(
-                        "type", cls.getName(),
-                        "beanSort", causewayBeanTypeClassifier
+            val warningMessage = ProgrammingModelConstants.Violation.TYPE_NOT_EAGERLY_DISCOVERED
+                    .builder()
+                    .addVariable("type", cls.getName())
+                    .addVariable("beanSort", causewayBeanTypeClassifier
                             .classify(cls)
                             .getBeanSort()
-                            .name()));
+                            .name())
+                    .buildMessage();
 
             log.warn(warningMessage);
         }
diff --git a/regressiontests/stable-domainmodel/src/test/java/org/apache/causeway/testdomain/domainmodel/DomainModelTest_usingBadDomain.java b/regressiontests/stable-domainmodel/src/test/java/org/apache/causeway/testdomain/domainmodel/DomainModelTest_usingBadDomain.java
index 987f95d56d..6952cef3f0 100644
--- a/regressiontests/stable-domainmodel/src/test/java/org/apache/causeway/testdomain/domainmodel/DomainModelTest_usingBadDomain.java
+++ b/regressiontests/stable-domainmodel/src/test/java/org/apache/causeway/testdomain/domainmodel/DomainModelTest_usingBadDomain.java
@@ -51,7 +51,7 @@ import org.apache.causeway.core.config.environment.CausewaySystemEnvironment;
 import org.apache.causeway.core.config.metamodel.specloader.IntrospectionMode;
 import org.apache.causeway.core.config.presets.CausewayPresets;
 import org.apache.causeway.core.config.progmodel.ProgrammingModelConstants;
-import org.apache.causeway.core.config.progmodel.ProgrammingModelConstants.Validation;
+import org.apache.causeway.core.config.progmodel.ProgrammingModelConstants.Violation;
 import org.apache.causeway.core.metamodel.specloader.SpecificationLoader;
 import org.apache.causeway.testdomain.conf.Configuration_headless;
 import org.apache.causeway.testdomain.model.bad.AmbiguousMixinAnnotations;
@@ -129,7 +129,7 @@ class DomainModelTest_usingBadDomain {
         val tester = testerFactory.objectTester(InvalidOrphanedActionSupport.class);
 
         tester.assertValidationFailureOnMember(
-                ProgrammingModelConstants.Validation.ORPHANED_METHOD, "hideMe()");
+                ProgrammingModelConstants.Violation.ORPHANED_METHOD, "hideMe()");
     }
 
 
@@ -144,7 +144,7 @@ class DomainModelTest_usingBadDomain {
         val tester = testerFactory.objectTester(InvalidOrphanedPropertySupport.class);
 
         tester.assertValidationFailureOnMember(
-                ProgrammingModelConstants.Validation.ORPHANED_METHOD, "hideMe()");
+                ProgrammingModelConstants.Violation.ORPHANED_METHOD, "hideMe()");
     }
 
     @Test
@@ -158,7 +158,7 @@ class DomainModelTest_usingBadDomain {
         val tester = testerFactory.objectTester(InvalidOrphanedCollectionSupport.class);
 
         tester.assertValidationFailureOnMember(
-                ProgrammingModelConstants.Validation.ORPHANED_METHOD, "hideMe()");
+                ProgrammingModelConstants.Violation.ORPHANED_METHOD, "hideMe()");
     }
 
     @Test
@@ -387,8 +387,11 @@ class DomainModelTest_usingBadDomain {
     private String validationMessage(
             final String className,
             final String memberName) {
-        return Validation.UNSATISFIED_DOMAIN_INCLUDE_SEMANTICS
-                .getMessageForTypeAndMemberId(className, memberName);
+        return Violation.UNSATISFIED_DOMAIN_INCLUDE_SEMANTICS
+                .builder()
+                .addVariable("type", className)
+                .addVariable("member", memberName)
+                .buildMessage();
     }
 
 }
diff --git a/regressiontests/stable-domainmodel/src/test/java/org/apache/causeway/testdomain/domainmodel/DomainModelTest_usingBadDomain_noAnnotationEnforced.java b/regressiontests/stable-domainmodel/src/test/java/org/apache/causeway/testdomain/domainmodel/DomainModelTest_usingBadDomain_noAnnotationEnforced.java
index 3fac29618f..114a4be1cd 100644
--- a/regressiontests/stable-domainmodel/src/test/java/org/apache/causeway/testdomain/domainmodel/DomainModelTest_usingBadDomain_noAnnotationEnforced.java
+++ b/regressiontests/stable-domainmodel/src/test/java/org/apache/causeway/testdomain/domainmodel/DomainModelTest_usingBadDomain_noAnnotationEnforced.java
@@ -78,7 +78,7 @@ class DomainModelTest_usingBadDomain_noAnnotationEnforced {
         val tester = testerFactory.objectTester(InvalidOrphanedActionSupportNoAnnotationEnforced.class);
 
         tester.assertValidationFailureOnMember(
-                ProgrammingModelConstants.Validation.ORPHANED_METHOD, "hideOrphaned()");
+                ProgrammingModelConstants.Violation.ORPHANED_METHOD, "hideOrphaned()");
     }
 
 }
diff --git a/regressiontests/stable/src/main/java/org/apache/causeway/testdomain/util/interaction/DomainObjectTesterFactory.java b/regressiontests/stable/src/main/java/org/apache/causeway/testdomain/util/interaction/DomainObjectTesterFactory.java
index 1ec8aa3b2a..9c6da0f4f8 100644
--- a/regressiontests/stable/src/main/java/org/apache/causeway/testdomain/util/interaction/DomainObjectTesterFactory.java
+++ b/regressiontests/stable/src/main/java/org/apache/causeway/testdomain/util/interaction/DomainObjectTesterFactory.java
@@ -20,7 +20,6 @@ package org.apache.causeway.testdomain.util.interaction;
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Map;
 import java.util.Optional;
 import java.util.function.Consumer;
 import java.util.function.UnaryOperator;
@@ -202,7 +201,7 @@ public class DomainObjectTesterFactory {
         }
 
         public void assertValidationFailureOnMember(
-                final ProgrammingModelConstants.Validation validationEnum,
+                final ProgrammingModelConstants.Violation violation,
                 final String memberName) {
 
             val validateDomainModel =
@@ -211,10 +210,11 @@ public class DomainObjectTesterFactory {
             assertThrows(DomainModelException.class, validateDomainModel::throwIfInvalid);
             validateDomainModel.assertAnyFailuresContaining(
                     Identifier.classIdentifier(LogicalType.fqcn(getDomainObjectType())),
-                    validationEnum
-                    .getMessage(Map.of(
-                            "type", getDomainObjectType().getName(),
-                            "member", memberName)));
+                    violation
+                        .builder()
+                        .addVariable("type", getDomainObjectType().getName())
+                        .addVariable("member", memberName)
+                        .buildMessage());
         }
 
     }