From d5a4d1efc3e39565778fcaae569417313173a032 Mon Sep 17 00:00:00 2001 From: mnhock Date: Thu, 20 Jun 2024 17:46:41 +0200 Subject: [PATCH] Provide a new Java Naming Rule checking if fields of a specific type match a regex Closes gh-48 --- README.md | 36 +++++++++-------- docs/USERGUIDE.md | 21 +++++----- .../enofex/taikai/java/NamingConfigurer.java | 40 +++++++++++++++---- src/test/java/com/enofex/taikai/Usage.java | 1 + 4 files changed, 66 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 19f556a..2f6f5ad 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,25 @@ Here's an example demonstrating the usage of Taikai with JUnit 5. Customize rule void shouldFulfillConstraints() { Taikai.builder() .namespace("com.enofex.taikai") + .java(java -> java + .noUsageOfDeprecatedAPIs() + .methodsShouldNotDeclareGenericExceptions() + .utilityClassesShouldBeFinalAndHavePrivateConstructor() + .imports(imports -> imports + .shouldHaveNoCycles() + .shouldNotImport("..shaded..") + .shouldNotImport("org.junit..")) + .naming(naming -> naming + .classesShouldNotMatch(".*Impl") + .methodsShouldNotMatch("foo") + .fieldsShouldNotMatch("bar") + .fieldsShouldMatch("com.awesome.Foo", "foo") + .constantsShouldFollowConvention() + .interfacesShouldNotHavePrefixI())) + .test(test -> test + .junit5(junit5 -> junit5 + .classesShouldNotBeAnnotatedWithDisabled() + .methodsShouldNotBeAnnotatedWithDisabled())) .spring(spring -> spring .noAutowiredFields() .boot(boot -> boot @@ -47,22 +66,7 @@ void shouldFulfillConstraints() { .repositories(repositories -> repositories .shouldBeAnnotatedWithRepository() .shouldNotDependOnServices() - .namesShouldEndWithRepository())) - .test(test -> test - .junit5(junit5 -> junit5 - .classesShouldNotBeAnnotatedWithDisabled() - .methodsShouldNotBeAnnotatedWithDisabled())) - .java(java -> java - .noUsageOfDeprecatedAPIs() - .methodsShouldNotDeclareGenericExceptions() - .utilityClassesShouldBeFinalAndHavePrivateConstructor() - .imports(imports -> imports - .shouldHaveNoCycles() - .shouldNotImport("..shaded..") - .shouldNotImport("org.junit..")) - .naming(naming -> naming - .classesShouldNotMatch(".*Impl") - .interfacesShouldNotHavePrefixI())) + .namesShouldEndWithRepository())) .addRule(TaikaiRule.of(...)) // Add custom ArchUnit rule here .build() .check(); diff --git a/docs/USERGUIDE.md b/docs/USERGUIDE.md index 095d554..fea21c2 100644 --- a/docs/USERGUIDE.md +++ b/docs/USERGUIDE.md @@ -42,10 +42,11 @@ The default mode is `WITHOUT_TESTS`, which excludes test classes from the import | Imports | `shouldHaveNoCycles` | No cyclic dependencies in imports | | Imports | `shouldNotImport` | Disallow specific imports (e.g., `..shaded..`) | | Naming | `classesShouldNotMatch` | Classes should not match specific naming patterns (e.g., `.*Impl`) | -| Naming | `methodsShouldNotMatch` | Methods should not match specific naming patterns | -| Naming | `fieldsShouldNotMatch` | Fields should not match specific naming patterns | | Naming | `classesAnnotatedWithShouldMatch` | Classes annotated with should match specific naming patterns | +| Naming | `methodsShouldNotMatch` | Methods should not match specific naming patterns | | Naming | `methodsAnnotatedWithShouldMatch` | Methods annotated with should match specific naming patterns | +| Naming | `fieldsShouldNotMatch` | Fields should not match specific naming patterns | +| Naming | `fieldsShouldMatch` | Fields should match specific naming patterns for specific classes | | Naming | `fieldsAnnotatedWithShouldMatch` | Fields annotated with should match specific naming patterns | | Naming | `constantsShouldFollowConvention` | Constants should follow naming conventions, except `serialVersionUID` | | Naming | `interfacesShouldNotHavePrefixI` | Interfaces should not have the prefix `I` | @@ -170,12 +171,14 @@ Taikai.builder() .java(java -> java .naming(naming -> naming .classesShouldNotMatch(".*Impl") + .classesAnnotatedWithShouldMatch(Annotation.class, "coolClass") .methodsShouldNotMatch("coolMethod") - .fieldsShouldNotMatch("coolField") - .constantsShouldFollowConvention() - .classesAnnotatedWithShouldMatch(Annotation.class, "coolClass") .methodsAnnotatedWithShouldMatch(Annotation.class, "coolMethods") + .fieldsShouldNotMatch("coolField") + .fieldsShouldMatch("com.awesome.Foo", "foo") + .fieldsShouldMatch(Foo.class, "foo") .fieldsAnnotatedWithShouldMatch(Annotation.class, "coolField") + .constantsShouldFollowConvention() .interfacesShouldNotHavePrefixI()))) .build() .check(); @@ -447,15 +450,15 @@ class ArchitectureTest { void shouldFulfilConstrains() { Taikai.builder() .namespace("com.company.yourproject") - .test(test -> test - .junit5(junit5 -> junit5 - .classesShouldNotBeAnnotatedWithDisabled() - .methodsShouldNotBeAnnotatedWithDisabled())) .java(java -> java .noUsageOfDeprecatedAPIs() .classesShouldImplementHashCodeAndEquals() .methodsShouldNotDeclareGenericExceptions() .utilityClassesShouldBeFinalAndHavePrivateConstructor()) + .test(test -> test + .junit5(junit5 -> junit5 + .classesShouldNotBeAnnotatedWithDisabled() + .methodsShouldNotBeAnnotatedWithDisabled())) .spring(spring -> spring .repositories(repositories -> repositories .namesShouldEndWithRepository() diff --git a/src/main/java/com/enofex/taikai/java/NamingConfigurer.java b/src/main/java/com/enofex/taikai/java/NamingConfigurer.java index 4ffec3c..1cfed58 100644 --- a/src/main/java/com/enofex/taikai/java/NamingConfigurer.java +++ b/src/main/java/com/enofex/taikai/java/NamingConfigurer.java @@ -89,6 +89,16 @@ public NamingConfigurer methodsAnnotatedWithShouldMatch(String annotationType, S annotationType, regex)), configuration)); } + public NamingConfigurer methodsShouldNotMatch(String regex) { + return methodsShouldNotMatch(regex, null); + } + + public NamingConfigurer methodsShouldNotMatch(String regex, Configuration configuration) { + return addRule(TaikaiRule.of(noMethods() + .should().haveNameMatching(regex) + .as("Methods should not have names matching %s".formatted(regex)), configuration)); + } + public NamingConfigurer fieldsAnnotatedWithShouldMatch( Class annotationType, String regex) { return fieldsAnnotatedWithShouldMatch(annotationType, regex, null); @@ -116,14 +126,30 @@ public NamingConfigurer fieldsAnnotatedWithShouldMatch(String annotationType, St annotationType, regex)), configuration)); } - public NamingConfigurer methodsShouldNotMatch(String regex) { - return methodsShouldNotMatch(regex, null); + public NamingConfigurer fieldsShouldMatch(String typeName, String regex) { + return fieldsShouldMatch(typeName, regex, null); } - public NamingConfigurer methodsShouldNotMatch(String regex, Configuration configuration) { - return addRule(TaikaiRule.of(noMethods() - .should().haveNameMatching(regex) - .as("Methods should not have names matching %s".formatted(regex)), configuration)); + public NamingConfigurer fieldsShouldMatch(String typeName, String regex, + Configuration configuration) { + return addRule(TaikaiRule.of(fields() + .that().haveRawType(typeName) + .should().haveNameMatching(regex) + .as("Fields of type %s should have names matching %s".formatted(typeName, regex)), + configuration)); + } + + public NamingConfigurer fieldsShouldMatch(Class clazz, String regex) { + return fieldsShouldMatch(clazz, regex, null); + } + + public NamingConfigurer fieldsShouldMatch(Class clazz, String regex, + Configuration configuration) { + return addRule(TaikaiRule.of(fields() + .that().haveRawType(clazz) + .should().haveNameMatching(regex) + .as("Fields of type %s should have names matching %s".formatted(clazz, regex)), + configuration)); } public NamingConfigurer fieldsShouldNotMatch(String regex) { @@ -148,7 +174,7 @@ public NamingConfigurer interfacesShouldNotHavePrefixI(Configuration configurati } private static ArchCondition notBePrefixedWithI() { - return new ArchCondition<>("not be prefixed with I.") { + return new ArchCondition<>("not be prefixed with I") { @Override public void check(JavaClass javaClass, ConditionEvents events) { if (javaClass.getSimpleName().startsWith("I") && Character.isUpperCase( diff --git a/src/test/java/com/enofex/taikai/Usage.java b/src/test/java/com/enofex/taikai/Usage.java index 2595adb..f9cf296 100644 --- a/src/test/java/com/enofex/taikai/Usage.java +++ b/src/test/java/com/enofex/taikai/Usage.java @@ -60,6 +60,7 @@ public static void main(String[] args) { .classesShouldNotMatch(".*Impl") .methodsShouldNotMatch("foo") .fieldsShouldNotMatch("bar") + .fieldsShouldMatch("com.awesome.Foo", "foo") .constantsShouldFollowConvention() .interfacesShouldNotHavePrefixI())) .build()