You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2021/07/24 14:41:42 UTC

[isis] branch ISIS-2820 updated (610da62 -> 36c18df)

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

danhaywood pushed a change to branch ISIS-2820
in repository https://gitbox.apache.org/repos/asf/isis.git.


    from 610da62  ISIS-2820: polishes docs
     add 192d936  Merge pull request #683 from apache/ISIS-2820
     add 7e730cb  ISIS-2573: remove TransactionService#nextTransaction()
     add 4ea9fab  ISIS-2573: de-duplicate publishing test code (JDO/JPA)
     add 2958cb9  ISIS-2573: exclude 'programmatic' test when publishing not supported programmatically
     add 8750347  ISIS-2573: fixes test code that had swallowed failure cases
     new 36c18df  ISIS-2820: fixes for arch tests

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../applib/services/xactn/TransactionService.java  |  13 +-
 .../org/apache/isis/commons/collections/Can.java   |   9 +-
 .../transaction/TransactionServiceSpring.java      |  96 ++++++-----
 ...est.java => CommandPublishingTestAbstract.java} |  48 ++----
 ...Test.java => EntityPublishingTestAbstract.java} |  44 +----
 ...t.java => ExecutionPublishingTestAbstract.java} |  59 +++----
 .../publishing/HasPersistenceStandard.java         |  32 ++--
 ...st.java => PropertyPublishingTestAbstract.java} |  48 +-----
 .../publishing/jdo/HasPersistenceStandardJdo.java  |  13 +-
 .../publishing/jdo/JdoCommandPublishingTest.java   |  80 +--------
 .../publishing/jdo/JdoEntityPublishingTest.java    |  49 +-----
 .../publishing/jdo/JdoExecutionPublishingTest.java |  96 +----------
 .../publishing/jdo/JdoPropertyPublishingTest.java  |  47 +-----
 .../publishing/jpa/HasPersistenceStandardJpa.java  |  13 +-
 .../publishing/jpa/JpaCommandPublishingTest.java   |  82 +--------
 .../publishing/jpa/JpaEntityPublishingTest.java    |  49 +-----
 .../publishing/jpa/JpaExecutionPublishingTest.java |  96 +----------
 .../publishing/jpa/JpaPropertyPublishingTest.java  |  48 +-----
 .../publishing/PublishingTestFactoryAbstract.java  | 185 +++++++++++++++------
 .../publishing/PublishingTestFactoryJdo.java       | 145 ++++++----------
 .../publishing/PublishingTestFactoryJpa.java       | 142 ++++++----------
 .../subscriber/ExecutionSubscriberForTesting.java  |   9 +-
 .../adoc/modules/archtestsupport/pages/about.adoc  |   4 +-
 .../applib/classrules/ArchitectureDomainRules.java |  57 +++++--
 .../applib/classrules/ArchitectureJdoRules.java    |  13 +-
 .../applib/classrules/ArchitectureJpaRules.java    |   9 +-
 .../modulerules/ArchitectureModuleRules.java       |  85 +++-------
 .../applib/modulerules/SubpackageEnum.java         |   4 -
 .../applib/domain/dom/ChamberOfCommerceCode.java   |  23 +++
 .../domain/dom/SomeDomainObject_actionMixin.java   |   2 +-
 .../applib/domain/dom/SomeDomainRepository.java    |   3 +
 .../applib/entity/jdo/JdoEntityArchTests.java      |   4 -
 .../applib/entity/jdo/dom/JdoEntity2.java          |  13 +-
 .../applib/entity/jpa/dom/JpaEntity2.java          |  13 +-
 34 files changed, 534 insertions(+), 1099 deletions(-)
 copy regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/{jpa/JpaCommandPublishingTest.java => CommandPublishingTestAbstract.java} (67%)
 copy regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/{jpa/JpaEntityPublishingTest.java => EntityPublishingTestAbstract.java} (62%)
 copy regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/{jpa/JpaExecutionPublishingTest.java => ExecutionPublishingTestAbstract.java} (73%)
 copy viewers/common/src/main/java/org/apache/isis/viewer/common/model/branding/BrandingUiModel.java => regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/HasPersistenceStandard.java (58%)
 copy regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/{jpa/JpaPropertyPublishingTest.java => PropertyPublishingTestAbstract.java} (53%)
 copy core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetapi/HasSemanticEqualityByClass.java => regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jdo/HasPersistenceStandardJdo.java (69%)
 copy core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetapi/HasSemanticEqualityByClass.java => regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/HasPersistenceStandardJpa.java (69%)
 create mode 100644 testing/archtestsupport/applib/src/test/java/org/apache/isis/testing/archtestsupport/applib/domain/dom/ChamberOfCommerceCode.java

[isis] 01/01: ISIS-2820: fixes for arch tests

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

danhaywood pushed a commit to branch ISIS-2820
in repository https://gitbox.apache.org/repos/asf/isis.git

commit 36c18dfa7ea3476c7fa06cfa868553b57aea388f
Author: danhaywood <da...@haywood-associates.co.uk>
AuthorDate: Sat Jul 24 15:40:34 2021 +0100

    ISIS-2820: fixes for arch tests
---
 .../adoc/modules/archtestsupport/pages/about.adoc  |  4 +-
 .../applib/classrules/ArchitectureDomainRules.java | 57 +++++++++++----
 .../applib/classrules/ArchitectureJdoRules.java    | 13 +---
 .../applib/classrules/ArchitectureJpaRules.java    |  9 ++-
 .../modulerules/ArchitectureModuleRules.java       | 85 +++++++---------------
 .../applib/modulerules/SubpackageEnum.java         |  4 -
 .../applib/domain/dom/ChamberOfCommerceCode.java   | 23 ++++++
 .../domain/dom/SomeDomainObject_actionMixin.java   |  2 +-
 .../applib/domain/dom/SomeDomainRepository.java    |  3 +
 .../applib/entity/jdo/JdoEntityArchTests.java      |  4 -
 .../applib/entity/jdo/dom/JdoEntity2.java          | 13 ++--
 .../applib/entity/jpa/dom/JpaEntity2.java          | 13 ++--
 12 files changed, 116 insertions(+), 114 deletions(-)

diff --git a/testing/archtestsupport/adoc/modules/archtestsupport/pages/about.adoc b/testing/archtestsupport/adoc/modules/archtestsupport/pages/about.adoc
index 97e3dfc..cd34338 100644
--- a/testing/archtestsupport/adoc/modules/archtestsupport/pages/about.adoc
+++ b/testing/archtestsupport/adoc/modules/archtestsupport/pages/about.adoc
@@ -195,10 +195,10 @@ Entity rule checks are provided for both xref:pjpa::about.adoc[] and xref:pjdo::
 * encourage static factory methods for entities:
 
 ** `every_jpa_Entity_must_have_protected_no_arg_constructor()`
-** `every_jdo_PersistenceCapable_must_have_protected_no_arg_constructor()`
 
 
-None of these rules take any arguments, so simply include (as a static field) those that you wish to enforce.
+None of these rules takes any arguments, so simply call those (from a static field) those that you wish to enforce.
+
 
 == Module Rules
 
diff --git a/testing/archtestsupport/applib/src/main/java/org/apache/isis/testing/archtestsupport/applib/classrules/ArchitectureDomainRules.java b/testing/archtestsupport/applib/src/main/java/org/apache/isis/testing/archtestsupport/applib/classrules/ArchitectureDomainRules.java
index 6867ac5..d3c073e 100644
--- a/testing/archtestsupport/applib/src/main/java/org/apache/isis/testing/archtestsupport/applib/classrules/ArchitectureDomainRules.java
+++ b/testing/archtestsupport/applib/src/main/java/org/apache/isis/testing/archtestsupport/applib/classrules/ArchitectureDomainRules.java
@@ -2,6 +2,8 @@ package org.apache.isis.testing.archtestsupport.applib.classrules;
 
 import java.io.Serializable;
 import java.lang.annotation.Annotation;
+import java.util.function.Function;
+import java.util.function.Predicate;
 
 import javax.inject.Inject;
 import javax.xml.bind.annotation.XmlRootElement;
@@ -11,6 +13,7 @@ import com.tngtech.archunit.base.DescribedPredicate;
 import com.tngtech.archunit.core.domain.JavaAnnotation;
 import com.tngtech.archunit.core.domain.JavaClass;
 import com.tngtech.archunit.core.domain.JavaCodeUnit;
+import com.tngtech.archunit.core.domain.JavaMethod;
 import com.tngtech.archunit.core.domain.JavaModifier;
 import com.tngtech.archunit.lang.ArchCondition;
 import com.tngtech.archunit.lang.ArchRule;
@@ -120,7 +123,9 @@ public class ArchitectureDomainRules {
      * </p>
      */
     public static ArchRule every_Action_mixin_must_follow_naming_convention() {
-        return mixin_must_follow_naming_conventions(Action.class, "act");
+        return mixin_must_follow_naming_conventions(Action.class, "act",
+                mixinMethodNameToFind ->
+                        javaMethodCandidate -> javaMethodCandidate.getName().equals(mixinMethodNameToFind));
     }
 
     /**
@@ -135,7 +140,10 @@ public class ArchitectureDomainRules {
      * </p>
      */
     public static ArchRule every_Property_mixin_must_follow_naming_convention() {
-        return mixin_must_follow_naming_conventions(Property.class, "prop");
+        return mixin_must_follow_naming_conventions(Property.class, "prop",
+                mixinMethodNameToFind ->
+                        javaMethodCandidate -> javaMethodCandidate.getName().equals(mixinMethodNameToFind) &&
+                                javaMethodCandidate.getRawParameterTypes().size() == 0);
     }
 
     /**
@@ -150,51 +158,59 @@ public class ArchitectureDomainRules {
      * </p>
      */
     public static ArchRule every_Collection_mixin_must_follow_naming_convention() {
-        return mixin_must_follow_naming_conventions(Collection.class, "coll");
+        return mixin_must_follow_naming_conventions(Collection.class, "coll",
+                mixinMethodNameToFind ->
+                        javaMethodCandidate -> javaMethodCandidate.getName().equals(mixinMethodNameToFind) &&
+                                javaMethodCandidate.getRawParameterTypes().size() == 0);
     }
 
     private static ClassesShouldConjunction mixin_must_follow_naming_conventions(
             final Class<? extends Annotation> type,
-            final String mixinMethodNameDefault) {
+            final String mixinMethodNameDefault, final Function<String, Predicate<JavaMethod>> function) {
         return classes()
                 .that().areAnnotatedWith(type)
                 .should(new ArchCondition<JavaClass>("follow mixin naming conventions") {
                     @Override
                     public void check(final JavaClass item, final ConditionEvents events) {
-                        if(!item.isTopLevelClass()) {
+                        if (!item.isTopLevelClass() || item.isAnnotation()) {
                             return;
                         }
                         val oneArgConstructorParameterTypeIfAny = item.getConstructors().stream()
-                                .filter(x -> x.getRawParameterTypes().size() == 1)
                                 .map(JavaCodeUnit::getRawParameterTypes)
+                                .filter(rawParameterTypes -> rawParameterTypes.size() == 1)
                                 .map(x -> x.get(0))
-                                .findFirst()
-                                ;
-                        if(!oneArgConstructorParameterTypeIfAny.isPresent()) {
-                            events.add(new SimpleConditionEvent(item, false, item.getSimpleName() + " does not have a 1-arg constructor"));
+                                .findFirst();
+                        if (!oneArgConstructorParameterTypeIfAny.isPresent()) {
+                            events.add(new SimpleConditionEvent(item, false,
+                                    item.getSimpleName() + " does not have a 1-arg constructor"));
                             return;
                         }
                         final JavaClass parameterType = oneArgConstructorParameterTypeIfAny.get();
                         val constructorClassName = parameterType.getSimpleName();
                         val requiredPrefix = constructorClassName + "_";
-                        if(! item.getSimpleName().startsWith(requiredPrefix)) {
-                            events.add(new SimpleConditionEvent(item, false, item.getSimpleName() + " should have a prefix of '" + requiredPrefix
-                                    + "'" ));
+                        if (!item.getSimpleName().startsWith(requiredPrefix)) {
+                            events.add(new SimpleConditionEvent(item, false,
+                                    item.getSimpleName() + " should have a prefix of '" + requiredPrefix
+                                            + "'"));
                             return;
                         }
                         val mixinMethodName = item
                                 .tryGetAnnotationOfType(DomainObject.class)
                                 .transform(DomainObject::mixinMethod)
                                 .or(mixinMethodNameDefault);
-                        if(!item.tryGetMethod(mixinMethodName).isPresent()) {
+                        val mixinMethodIfAny = item.getAllMethods().stream()
+                                .filter(function.apply(mixinMethodName)).findAny();
+                        if (!mixinMethodIfAny.isPresent()) {
                             events.add(new SimpleConditionEvent(item, false,
                                     String.format("%s does not have a mixin method named '%s'",
                                             item.getSimpleName(), mixinMethodName)));
                         }
                     }
+
                 });
     }
 
+
     /**
      * This rule requires that classes annotated with the {@link Repository} annotation should follow the naming
      * convention <code>XxxRepository</code>.
@@ -332,16 +348,21 @@ public class ArchitectureDomainRules {
      *     they must return an <code>Optional&lt;Customer&gt;</code> instead.  This forces the caller to
      *     handle the fact that the result might be empty (ie no result).
      * </p>
-     * @return
+     *
+     * <p>
+     *     One exception is that methods named &quot;findOrCreate&quot;, which are allowed to return an instance
+     *     rather than an optional.
+     * </p>
      */
     public static ArchRule every_finder_method_in_Repository_must_return_either_Collection_or_Optional() {
         return methods()
                 .that().haveNameMatching("find.*")
+                .and().haveNameNotMatching("findOrCreate.*")
                 .and().areDeclaredInClassesThat().areAnnotatedWith(Repository.class)
                 .should().haveRawReturnType(eitherOptionalOrCollection());
     }
 
-    private static DescribedPredicate<JavaClass> eitherOptionalOrCollection() {
+    static DescribedPredicate<JavaClass> eitherOptionalOrCollection() {
         return new DescribedPredicate<JavaClass>("either Optional or Collection") {
             @Override
             public boolean apply(JavaClass input) {
@@ -353,4 +374,8 @@ public class ArchitectureDomainRules {
 
 
 
+
+
+
+
 }
diff --git a/testing/archtestsupport/applib/src/main/java/org/apache/isis/testing/archtestsupport/applib/classrules/ArchitectureJdoRules.java b/testing/archtestsupport/applib/src/main/java/org/apache/isis/testing/archtestsupport/applib/classrules/ArchitectureJdoRules.java
index 072732e..5d0bf73 100644
--- a/testing/archtestsupport/applib/src/main/java/org/apache/isis/testing/archtestsupport/applib/classrules/ArchitectureJdoRules.java
+++ b/testing/archtestsupport/applib/src/main/java/org/apache/isis/testing/archtestsupport/applib/classrules/ArchitectureJdoRules.java
@@ -8,6 +8,7 @@ import com.tngtech.archunit.base.DescribedPredicate;
 import com.tngtech.archunit.core.domain.JavaAnnotation;
 import com.tngtech.archunit.core.domain.JavaClass;
 import com.tngtech.archunit.core.domain.JavaEnumConstant;
+import com.tngtech.archunit.core.domain.JavaModifier;
 import com.tngtech.archunit.lang.ArchRule;
 
 import org.apache.isis.applib.annotation.DomainObject;
@@ -186,18 +187,6 @@ public class ArchitectureJdoRules {
         };
     }
 
-    /**
-     * This rule requires that classes annotated with the JDO {@link PersistenceCapable} annotation have a
-     * no-arg constructor with <code>protected</code> visibility.
-     *
-     * <p>
-     * The rationale is to encourage the use of static factory methods.
-     * </p>
-     */
-    public static ArchRule every_jdo_PersistenceCapable_must_have_protected_no_arg_constructor() {
-        return classes().that().areAnnotatedWith(PersistenceCapable.class)
-                .should(haveNoArgProtectedConstructor());
-    }
 
 
 }
diff --git a/testing/archtestsupport/applib/src/main/java/org/apache/isis/testing/archtestsupport/applib/classrules/ArchitectureJpaRules.java b/testing/archtestsupport/applib/src/main/java/org/apache/isis/testing/archtestsupport/applib/classrules/ArchitectureJpaRules.java
index dfa093d..16bd187 100644
--- a/testing/archtestsupport/applib/src/main/java/org/apache/isis/testing/archtestsupport/applib/classrules/ArchitectureJpaRules.java
+++ b/testing/archtestsupport/applib/src/main/java/org/apache/isis/testing/archtestsupport/applib/classrules/ArchitectureJpaRules.java
@@ -16,6 +16,7 @@ import javax.persistence.Version;
 import com.tngtech.archunit.base.DescribedPredicate;
 import com.tngtech.archunit.core.domain.JavaAnnotation;
 import com.tngtech.archunit.core.domain.JavaClass;
+import com.tngtech.archunit.core.domain.JavaModifier;
 import com.tngtech.archunit.lang.ArchCondition;
 import com.tngtech.archunit.lang.ArchRule;
 import com.tngtech.archunit.lang.ConditionEvents;
@@ -274,15 +275,17 @@ public class ArchitectureJpaRules {
     }
 
     /**
-     * This rule requires that classes annotated with the JPA {@link Entity} annotation have a no-arg constructor
-     * with <code>protected</code> visibility.
+     * This rule requires that concrete classes annotated with the JPA {@link Entity} annotation have a no-arg
+     * constructor with <code>protected</code> visibility.
      *
      * <p>
      * The rationale is to encourage the use of static factory methods.
      * </p>
      */
     public static ArchRule every_jpa_Entity_must_have_protected_no_arg_constructor() {
-        return classes().that().areAnnotatedWith(Entity.class)
+        return classes()
+                .that().areAnnotatedWith(Entity.class)
+                .and().doNotHaveModifier(JavaModifier.ABSTRACT)
                 .should(haveNoArgProtectedConstructor());
     }
 
diff --git a/testing/archtestsupport/applib/src/main/java/org/apache/isis/testing/archtestsupport/applib/modulerules/ArchitectureModuleRules.java b/testing/archtestsupport/applib/src/main/java/org/apache/isis/testing/archtestsupport/applib/modulerules/ArchitectureModuleRules.java
index c5a35ab..d8d4142 100644
--- a/testing/archtestsupport/applib/src/main/java/org/apache/isis/testing/archtestsupport/applib/modulerules/ArchitectureModuleRules.java
+++ b/testing/archtestsupport/applib/src/main/java/org/apache/isis/testing/archtestsupport/applib/modulerules/ArchitectureModuleRules.java
@@ -92,7 +92,6 @@ public class ArchitectureModuleRules {
                 transitiveDependenciesByImporting.keySet());
         importingClassesNotImported.removeAll(transitiveDependenciesByImported.keySet());
 
-        checkNoAccessToTopmostLayers(layeredArchitecture, importingClassesNotImported);
         return layeredArchitecture;
     }
 
@@ -100,16 +99,12 @@ public class ArchitectureModuleRules {
             List<Class<?>> moduleClasses,
             Architectures.LayeredArchitecture layeredArchitecture,
             List<Subpackage> subpackages) {
-        moduleClasses.forEach(moduleClass -> {
-            layeredArchitecture.layer(nameOf(moduleClass)).definedBy(packageIdentifierFor(moduleClass));
-
-            subpackages
-                    .forEach(subpackage -> {
-                        val subpackageName = subpackage.getName();
-                        layeredArchitecture.optionalLayer(nameOf(moduleClass, subpackageName))
-                                .definedBy(packageIdentifierFor(moduleClass, subpackage));
-                    });
-        });
+        moduleClasses.forEach(moduleClass ->
+                subpackages.forEach(subpackage -> {
+                    val subpackageName = subpackage.getName();
+                    layeredArchitecture.optionalLayer(nameOf(moduleClass, subpackageName))
+                            .definedBy(packageIdentifierFor(moduleClass, subpackage));
+                }));
     }
 
     private static void computeDirectDependencies(
@@ -153,28 +148,25 @@ public class ArchitectureModuleRules {
             List<Subpackage> subpackages) {
         transitiveDependenciesByImported.forEach((importedModule, importingModules) -> {
 
-            layeredArchitecture
-                    // layering at the module level
-                    .whereLayer(
-                            nameOf(importedModule))
-                    .mayOnlyBeAccessedByLayers(
-                            namesOf(importingModules)
-                    );
-
-            // in particular, access to subpackages
             subpackages.forEach(subpackage -> {
 
                 val localModule = asArray(subpackage.mayBeAccessedBySubpackagesInSameModule(), subpackages);
                 val otherModules = asArray(subpackage.mayBeAccessedBySubpackagesInReferencingModules(), subpackages);
 
                 final String moduleName = nameOf(importedModule, subpackage.getName());
-                final String[] accessingModules = both(
-                        namesOf(importedModule, localModule),
-                        namesOf(importingModules, otherModules)
-                );
-                layeredArchitecture
-                        .whereLayer(moduleName)
-                        .mayOnlyBeAccessedByLayers(accessingModules);
+                val localModulePackageNames = namesOf(importedModule, localModule);
+                val importingModulePackageNames = namesOf(importingModules, otherModules);
+                val accessingModules = both(localModulePackageNames, importingModulePackageNames);
+                if(accessingModules.length > 0) {
+                    layeredArchitecture
+                            .whereLayer(moduleName)
+                            .mayOnlyBeAccessedByLayers(accessingModules);
+
+                } else {
+                    layeredArchitecture
+                            .whereLayer(moduleName)
+                            .mayNotBeAccessedByAnyLayer();
+                }
             });
 
         });
@@ -192,20 +184,6 @@ public class ArchitectureModuleRules {
         return otherModules;
     }
 
-    private static void checkNoAccessToTopmostLayers(
-            Architectures.LayeredArchitecture layeredArchitecture,
-            Set<Class<?>> importingClassesNotImported) {
-        importingClassesNotImported.forEach(importingClass -> {
-            final String importingModuleName = nameOf(importingClass);
-            layeredArchitecture
-                    .whereLayer(importingModuleName)
-                    .mayNotBeAccessedByAnyLayer();
-        });
-    }
-
-    static String nameOf(Class<?> moduleClass) {
-        return nameOf(moduleClass, null);
-    }
 
     static String nameOf(Class<?> moduleClass, @Nullable final String subpackageName) {
         val simpleName = moduleClass.getSimpleName();
@@ -214,29 +192,17 @@ public class ArchitectureModuleRules {
     }
 
     static String[] namesOf(Class<?> moduleClass, String... subpackageNames) {
-        val names = new ArrayList<String>();
-        if (subpackageNames == null) {
-            return null;
-        }
-        if (subpackageNames.length == 0 ||
-                subpackageNames.length == 1 && subpackageNames[0].equals("*")) {
-            names.add(nameOf(moduleClass));
-        } else {
-            Arrays.stream(subpackageNames).forEach(subpackageName ->
-                    names.add(nameOf(moduleClass, subpackageName)));
-        }
+        val names = Arrays.stream(subpackageNames)
+                .map(subpackageName -> nameOf(moduleClass, subpackageName))
+                .collect(Collectors.toList());
         return names.toArray(new String[] {});
     }
 
-    static String[] namesOf(Set<Class<?>> importingClasses, @Nullable String... subpackageNames) {
+    static String[] namesOf(Set<Class<?>> importingClasses, String... subpackageNames) {
         val names = new ArrayList<String>();
         importingClasses.forEach(importingClass -> {
-            if (subpackageNames == null || subpackageNames.length == 0) {
-                names.add(nameOf(importingClass));
-            } else {
-                Stream.of(subpackageNames).forEach(subpackageName ->
-                        names.add(nameOf(importingClass, subpackageName)));
-            }
+            Stream.of(subpackageNames).forEach(subpackageName ->
+                    names.add(nameOf(importingClass, subpackageName)));
         });
         return names.toArray(new String[] {});
     }
@@ -285,5 +251,4 @@ public class ArchitectureModuleRules {
                 accumulateTransitiveDependencies(directDependency, directDependenciesByReferringClass,
                         transitiveDependenciesOfReferringClass));
     }
-
 }
\ No newline at end of file
diff --git a/testing/archtestsupport/applib/src/main/java/org/apache/isis/testing/archtestsupport/applib/modulerules/SubpackageEnum.java b/testing/archtestsupport/applib/src/main/java/org/apache/isis/testing/archtestsupport/applib/modulerules/SubpackageEnum.java
index 7d0833e..134466d 100644
--- a/testing/archtestsupport/applib/src/main/java/org/apache/isis/testing/archtestsupport/applib/modulerules/SubpackageEnum.java
+++ b/testing/archtestsupport/applib/src/main/java/org/apache/isis/testing/archtestsupport/applib/modulerules/SubpackageEnum.java
@@ -162,8 +162,4 @@ public enum SubpackageEnum implements Subpackage {
         return referencing;
     }
 
-    private static String[] asArray(List<String> list) {
-        return list != null ?
-                list.toArray(new String[] {}) : null;
-    }
 }
diff --git a/testing/archtestsupport/applib/src/test/java/org/apache/isis/testing/archtestsupport/applib/domain/dom/ChamberOfCommerceCode.java b/testing/archtestsupport/applib/src/test/java/org/apache/isis/testing/archtestsupport/applib/domain/dom/ChamberOfCommerceCode.java
new file mode 100644
index 0000000..df067fd
--- /dev/null
+++ b/testing/archtestsupport/applib/src/test/java/org/apache/isis/testing/archtestsupport/applib/domain/dom/ChamberOfCommerceCode.java
@@ -0,0 +1,23 @@
+package org.apache.isis.testing.archtestsupport.applib.domain.dom;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.apache.isis.applib.annotation.Optionality;
+import org.apache.isis.applib.annotation.Parameter;
+import org.apache.isis.applib.annotation.ParameterLayout;
+import org.apache.isis.applib.annotation.Property;
+import org.apache.isis.applib.annotation.PropertyLayout;
+
+@javax.jdo.annotations.Column(length = ChamberOfCommerceCode.MAX_LEN, allowsNull = "true")
+@Property(maxLength = ChamberOfCommerceCode.MAX_LEN, optionality = Optionality.OPTIONAL)
+@PropertyLayout(named = "Chamber of Commerce Code")
+@Parameter(maxLength = ChamberOfCommerceCode.MAX_LEN, optionality = Optionality.OPTIONAL)
+@ParameterLayout(named = "Chamber of Commerce Code")
+@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ChamberOfCommerceCode {
+    int MAX_LEN = 30;
+}
diff --git a/testing/archtestsupport/applib/src/test/java/org/apache/isis/testing/archtestsupport/applib/domain/dom/SomeDomainObject_actionMixin.java b/testing/archtestsupport/applib/src/test/java/org/apache/isis/testing/archtestsupport/applib/domain/dom/SomeDomainObject_actionMixin.java
index e8247df..f862200 100644
--- a/testing/archtestsupport/applib/src/test/java/org/apache/isis/testing/archtestsupport/applib/domain/dom/SomeDomainObject_actionMixin.java
+++ b/testing/archtestsupport/applib/src/test/java/org/apache/isis/testing/archtestsupport/applib/domain/dom/SomeDomainObject_actionMixin.java
@@ -11,6 +11,6 @@ public class SomeDomainObject_actionMixin {
 
     final SomeDomainObject someDomainObject;
 
-    public void act() {}
+    public void act(final String x) {}
 
 }
diff --git a/testing/archtestsupport/applib/src/test/java/org/apache/isis/testing/archtestsupport/applib/domain/dom/SomeDomainRepository.java b/testing/archtestsupport/applib/src/test/java/org/apache/isis/testing/archtestsupport/applib/domain/dom/SomeDomainRepository.java
index 80806ce..3e53a26 100644
--- a/testing/archtestsupport/applib/src/test/java/org/apache/isis/testing/archtestsupport/applib/domain/dom/SomeDomainRepository.java
+++ b/testing/archtestsupport/applib/src/test/java/org/apache/isis/testing/archtestsupport/applib/domain/dom/SomeDomainRepository.java
@@ -13,4 +13,7 @@ public interface SomeDomainRepository {
     List<SomeDomainObject> findAll();
 
     Map<String,SomeDomainObject> notFinder();
+
+    // we allow these as an exception to the "finder" rule.
+    SomeDomainObject findOrCreate();
 }
diff --git a/testing/archtestsupport/applib/src/test/java/org/apache/isis/testing/archtestsupport/applib/entity/jdo/JdoEntityArchTests.java b/testing/archtestsupport/applib/src/test/java/org/apache/isis/testing/archtestsupport/applib/entity/jdo/JdoEntityArchTests.java
index d994760..f6ea0c5 100644
--- a/testing/archtestsupport/applib/src/test/java/org/apache/isis/testing/archtestsupport/applib/entity/jdo/JdoEntityArchTests.java
+++ b/testing/archtestsupport/applib/src/test/java/org/apache/isis/testing/archtestsupport/applib/entity/jdo/JdoEntityArchTests.java
@@ -12,7 +12,6 @@ import static org.apache.isis.testing.archtestsupport.applib.classrules.Architec
 import static org.apache.isis.testing.archtestsupport.applib.classrules.ArchitectureJdoRules.every_jdo_PersistenceCapable_must_be_annotated_as_XmlJavaAdapter_PersistentEntityAdapter;
 import static org.apache.isis.testing.archtestsupport.applib.classrules.ArchitectureJdoRules.every_jdo_PersistenceCapable_must_be_annotated_with_DomainObject_nature_of_ENTITY;
 import static org.apache.isis.testing.archtestsupport.applib.classrules.ArchitectureJdoRules.every_jdo_PersistenceCapable_must_be_annotated_with_Version;
-import static org.apache.isis.testing.archtestsupport.applib.classrules.ArchitectureJdoRules.every_jdo_PersistenceCapable_must_have_protected_no_arg_constructor;
 import static org.apache.isis.testing.archtestsupport.applib.classrules.ArchitectureJdoRules.every_jdo_PersistenceCapable_must_have_schema;
 import static org.apache.isis.testing.archtestsupport.applib.classrules.ArchitectureJdoRules.every_jdo_PersistenceCapable_must_implement_Comparable;
 import static org.apache.isis.testing.archtestsupport.applib.classrules.ArchitectureJdoRules.every_jdo_PersistenceCapable_with_DATASTORE_identityType_must_be_annotated_as_DataStoreIdentity;
@@ -56,8 +55,5 @@ public class JdoEntityArchTests {
   public static ArchRule every_injected_field_of_jdo_PersistenceCapable_must_be_annotated_with_NotPersistent =
       every_injected_field_of_jdo_PersistenceCapable_must_be_annotated_with_NotPersistent();
 
-  @ArchTest
-  public static ArchRule every_jdo_PersistenceCapable_must_have_protected_no_arg_constructor =
-      every_jdo_PersistenceCapable_must_have_protected_no_arg_constructor();
 
 }
diff --git a/testing/archtestsupport/applib/src/test/java/org/apache/isis/testing/archtestsupport/applib/entity/jdo/dom/JdoEntity2.java b/testing/archtestsupport/applib/src/test/java/org/apache/isis/testing/archtestsupport/applib/entity/jdo/dom/JdoEntity2.java
index 96d279d..a740743 100644
--- a/testing/archtestsupport/applib/src/test/java/org/apache/isis/testing/archtestsupport/applib/entity/jdo/dom/JdoEntity2.java
+++ b/testing/archtestsupport/applib/src/test/java/org/apache/isis/testing/archtestsupport/applib/entity/jdo/dom/JdoEntity2.java
@@ -11,18 +11,19 @@ import org.apache.isis.applib.annotation.DomainObject;
 import org.apache.isis.applib.annotation.Nature;
 import org.apache.isis.applib.jaxb.PersistentEntityAdapter;
 
-import lombok.AccessLevel;
-import lombok.RequiredArgsConstructor;
-
 @PersistenceCapable(schema = "jdo")
 @Unique(name = "name", members = {"name"})
 @Version
 @DomainObject(nature = Nature.ENTITY)
-@RequiredArgsConstructor(access = AccessLevel.PROTECTED)
 @XmlJavaTypeAdapter(PersistentEntityAdapter.class)
-public class JdoEntity2 implements Comparable<JdoEntity2> {
+public abstract class JdoEntity2 implements Comparable<JdoEntity2> {
+
+    private final String name;
 
-    private String name;
+    // abstract classes do not need to have no-arg constructor
+    public JdoEntity2(final String name) {
+        this.name = name;
+    }
 
     @Override public int compareTo(final JdoEntity2 o) {
         return Comparator.<JdoEntity2,String>comparing(x -> x.name).compare(this,o);
diff --git a/testing/archtestsupport/applib/src/test/java/org/apache/isis/testing/archtestsupport/applib/entity/jpa/dom/JpaEntity2.java b/testing/archtestsupport/applib/src/test/java/org/apache/isis/testing/archtestsupport/applib/entity/jpa/dom/JpaEntity2.java
index 0e2b89f..26b9988 100644
--- a/testing/archtestsupport/applib/src/test/java/org/apache/isis/testing/archtestsupport/applib/entity/jpa/dom/JpaEntity2.java
+++ b/testing/archtestsupport/applib/src/test/java/org/apache/isis/testing/archtestsupport/applib/entity/jpa/dom/JpaEntity2.java
@@ -16,9 +16,6 @@ import org.apache.isis.applib.annotation.Nature;
 import org.apache.isis.applib.jaxb.PersistentEntityAdapter;
 import org.apache.isis.persistence.jpa.applib.integration.JpaEntityInjectionPointResolver;
 
-import lombok.AccessLevel;
-import lombok.RequiredArgsConstructor;
-
 @Entity
 @Table(
         schema = "jpa",
@@ -26,9 +23,8 @@ import lombok.RequiredArgsConstructor;
 )
 @DomainObject(nature = Nature.ENTITY)
 @XmlJavaTypeAdapter(PersistentEntityAdapter.class)
-@RequiredArgsConstructor(access = AccessLevel.PROTECTED)
 @EntityListeners({ JpaEntityInjectionPointResolver.class})
-public class JpaEntity2 implements Comparable<JpaEntity2> {
+public abstract class JpaEntity2 implements Comparable<JpaEntity2> {
 
     @Id @Column(name = "id", nullable = false)
     private Long id;
@@ -36,7 +32,12 @@ public class JpaEntity2 implements Comparable<JpaEntity2> {
     @Version
     private Long version;
 
-    private String name;
+    private final String name;
+
+    // abstract classes do not need to have no-arg constructor
+    public JpaEntity2(final String name) {
+        this.name = name;
+    }
 
     @Override public int compareTo(final JpaEntity2 o) {
         return Comparator.<JpaEntity2,Long>comparing(x -> x.id).compare(this,o);