Skip to content

Commit

Permalink
Provide a new Java Naming Rule checking if fields of a specific type …
Browse files Browse the repository at this point in the history
…match a regex

Closes gh-48
  • Loading branch information
mnhock authored and mnhock committed Jun 20, 2024
1 parent 47fb731 commit d5a4d1e
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 32 deletions.
36 changes: 20 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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();
Expand Down
21 changes: 12 additions & 9 deletions docs/USERGUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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` |
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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()
Expand Down
40 changes: 33 additions & 7 deletions src/main/java/com/enofex/taikai/java/NamingConfigurer.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<? extends Annotation> annotationType, String regex) {
return fieldsAnnotatedWithShouldMatch(annotationType, regex, null);
Expand Down Expand Up @@ -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) {
Expand All @@ -148,7 +174,7 @@ public NamingConfigurer interfacesShouldNotHavePrefixI(Configuration configurati
}

private static ArchCondition<JavaClass> 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(
Expand Down
1 change: 1 addition & 0 deletions src/test/java/com/enofex/taikai/Usage.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public static void main(String[] args) {
.classesShouldNotMatch(".*Impl")
.methodsShouldNotMatch("foo")
.fieldsShouldNotMatch("bar")
.fieldsShouldMatch("com.awesome.Foo", "foo")
.constantsShouldFollowConvention()
.interfacesShouldNotHavePrefixI()))
.build()
Expand Down

0 comments on commit d5a4d1e

Please sign in to comment.