Skip to content

Commit

Permalink
Provide a New Naming Rule checking if classes, methods and fields ann…
Browse files Browse the repository at this point in the history
…otated with special annotation match naming

CLoses gh-23
CLoses gh-22
CLoses gh-21
  • Loading branch information
mnhock authored and mnhock committed Jun 14, 2024
1 parent c4853d8 commit 8859574
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 17 deletions.
10 changes: 8 additions & 2 deletions docs/USERGUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ Architecture rules are defined using Taikai's fluent API, allowing developers to
| | Naming | `classesShouldNotMatch` | Classes should not match specific naming patterns (e.g., `.*Impl`) | Default (WITHOUT_TESTS) |
| | Naming | `methodsShouldNotMatch` | Methods should not match specific naming patterns | Default (WITHOUT_TESTS) |
| | Naming | `fieldsShouldNotMatch` | Fields should not match specific naming patterns | Default (WITHOUT_TESTS) |
| | Naming | `classesAnnotatedWithShouldMatch` | Classes annotated with should match specific naming patterns | Default (WITHOUT_TESTS) |
| | Naming | `methodsAnnotatedWithShouldMatch` | Methods annotated with should match specific naming patterns | Default (WITHOUT_TESTS) |
| | Naming | `fieldsAnnotatedWithShouldMatch` | Fields annotated with should match specific naming patterns | Default (WITHOUT_TESTS) |
| | Naming | `constantsShouldFollowConvention` | Constants should follow naming conventions | Default (WITHOUT_TESTS) |
| | Naming | `interfacesShouldNotHavePrefixI` | Interfaces should not have the prefix `I` | Default (WITHOUT_TESTS) |
| **Test** | JUnit 5 | `jclassesShouldNotBeAnnotatedWithDisabled` | Ensure JUnit 5 classes are not annotated with `@Disabled` | Default (WITH_TESTS) |
Expand Down Expand Up @@ -135,9 +138,12 @@ Taikai.builder()
.java(java -> java
.naming(naming -> naming
.classesShouldNotMatch(".*Impl")
.methodsShouldNotMatch("blameThrower")
.fieldsShouldNotMatch("notGonnaGiveYouUp")
.methodsShouldNotMatch("coolMethod")
.fieldsShouldNotMatch("coolField")
.constantsShouldFollowConvention()
.classesAnnotatedWithShouldMatch(Annotation.class, "coolClass")
.methodsAnnotatedWithShouldMatch(Annotation.class, "coolMethods")
.fieldsAnnotatedWithShouldMatch(Annotation.class, "coolField")
.interfacesShouldNotHavePrefixI())))
.build()
.check();
Expand Down
106 changes: 91 additions & 15 deletions src/main/java/com/enofex/taikai/java/NamingConfigurer.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.fields;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.methods;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noFields;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noMethods;
Expand All @@ -15,6 +16,7 @@
import com.tngtech.archunit.lang.ArchCondition;
import com.tngtech.archunit.lang.ConditionEvents;
import com.tngtech.archunit.lang.SimpleConditionEvent;
import java.lang.annotation.Annotation;
import java.util.regex.Pattern;

public final class NamingConfigurer extends AbstractConfigurer {
Expand All @@ -28,18 +30,94 @@ public NamingConfigurer classesShouldNotMatch(String regex) {
}

public NamingConfigurer classesShouldNotMatch(String regex, Configuration configuration) {
return addRule(TaikaiRule.of(noClasses()
.should().haveNameMatching(regex)
return addRule(TaikaiRule.of(noClasses().should().haveNameMatching(regex)
.as("Classes should not have names matching %s".formatted(regex)), configuration));
}

public NamingConfigurer classesAnnotatedWithShouldMatch(
Class<? extends Annotation> annotationType, String regex) {
return classesAnnotatedWithShouldMatch(annotationType, regex, null);
}

public NamingConfigurer classesAnnotatedWithShouldMatch(
Class<? extends Annotation> annotationType, String regex, Configuration configuration) {
return addRule(TaikaiRule.of(
classes().that().areMetaAnnotatedWith(annotationType).should().haveNameMatching(regex)
.as("Classes annotated with %s should not have names matching %s".formatted(
annotationType.getName(), regex)), configuration));
}

public NamingConfigurer classesAnnotatedWithShouldMatch(
String annotationType, String regex) {
return classesAnnotatedWithShouldMatch(annotationType, regex, null);
}

public NamingConfigurer classesAnnotatedWithShouldMatch(
String annotationType, String regex, Configuration configuration) {
return addRule(TaikaiRule.of(
classes().that().areMetaAnnotatedWith(annotationType).should().haveNameMatching(regex)
.as("Classes annotated with %s should not have names matching %s".formatted(
annotationType, regex)), configuration));
}

public NamingConfigurer methodsAnnotatedWithShouldMatch(
Class<? extends Annotation> annotationType, String regex) {
return methodsAnnotatedWithShouldMatch(annotationType, regex, null);
}

public NamingConfigurer methodsAnnotatedWithShouldMatch(
Class<? extends Annotation> annotationType, String regex, Configuration configuration) {
return addRule(TaikaiRule.of(
methods().that().areMetaAnnotatedWith(annotationType).should().haveNameMatching(regex)
.as("Methods annotated with %s should not have names matching %s".formatted(
annotationType.getName(), regex)), configuration));
}

public NamingConfigurer methodsAnnotatedWithShouldMatch(
String annotationType, String regex) {
return methodsAnnotatedWithShouldMatch(annotationType, regex, null);
}

public NamingConfigurer methodsAnnotatedWithShouldMatch(
String annotationType, String regex, Configuration configuration) {
return addRule(TaikaiRule.of(
methods().that().areMetaAnnotatedWith(annotationType).should().haveNameMatching(regex)
.as("Methods annotated with %s should not have names matching %s".formatted(
annotationType, regex)), configuration));
}

public NamingConfigurer fieldsAnnotatedWithShouldMatch(
Class<? extends Annotation> annotationType, String regex) {
return fieldsAnnotatedWithShouldMatch(annotationType, regex, null);
}

public NamingConfigurer fieldsAnnotatedWithShouldMatch(
Class<? extends Annotation> annotationType, String regex, Configuration configuration) {
return addRule(TaikaiRule.of(
fields().that().areMetaAnnotatedWith(annotationType).should().haveNameMatching(regex)
.as("Fields annotated with %s should not have names matching %s".formatted(
annotationType.getName(), regex)), configuration));
}

public NamingConfigurer fieldsAnnotatedWithShouldMatch(
String annotationType, String regex) {
return fieldsAnnotatedWithShouldMatch(annotationType, regex, null);
}

public NamingConfigurer fieldsAnnotatedWithShouldMatch(
String annotationType, String regex, Configuration configuration) {
return addRule(TaikaiRule.of(
fields().that().areMetaAnnotatedWith(annotationType).should().haveNameMatching(regex)
.as("Fields annotated with %s should not have names matching %s".formatted(
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)
return addRule(TaikaiRule.of(noMethods().should().haveNameMatching(regex)
.as("Methods should not have names matching %s".formatted(regex)), configuration));
}

Expand All @@ -48,8 +126,7 @@ public NamingConfigurer fieldsShouldNotMatch(String regex) {
}

public NamingConfigurer fieldsShouldNotMatch(String regex, Configuration configuration) {
return addRule(TaikaiRule.of(noFields()
.should().haveNameMatching(regex)
return addRule(TaikaiRule.of(noFields().should().haveNameMatching(regex)
.as("Fields should not have names matching %s".formatted(regex)), configuration));
}

Expand All @@ -58,8 +135,7 @@ public NamingConfigurer interfacesShouldNotHavePrefixI() {
}

public NamingConfigurer interfacesShouldNotHavePrefixI(Configuration configuration) {
return addRule(TaikaiRule.of(classes().that().areInterfaces()
.should(notBePrefixedWithI())
return addRule(TaikaiRule.of(classes().that().areInterfaces().should(notBePrefixedWithI())
.as("Interfaces should not be prefixed with I"), configuration));
}

Expand All @@ -80,9 +156,9 @@ public NamingConfigurer constantsShouldFollowConvention() {
}

public NamingConfigurer constantsShouldFollowConvention(Configuration configuration) {
return addRule(TaikaiRule.of(fields().that().areFinal().and().areStatic()
.should(shouldFollowConstantNamingConvention())
.as("Constants should follow constant naming convention"), configuration));
return addRule(TaikaiRule.of(
fields().that().areFinal().and().areStatic().should(shouldFollowConstantNamingConvention())
.as("Constants should follow constant naming convention"), configuration));
}

private static ArchCondition<JavaField> shouldFollowConstantNamingConvention() {
Expand All @@ -92,11 +168,11 @@ private static ArchCondition<JavaField> shouldFollowConstantNamingConvention() {

@Override
public void check(JavaField field, ConditionEvents events) {
if (!field.getOwner().isEnum()
&& !CONSTANT_NAME_PATTERN.matcher(field.getName()).matches()) {
if (!field.getOwner().isEnum() && !CONSTANT_NAME_PATTERN.matcher(field.getName())
.matches()) {
String message = String.format(
"Constant %s in class %s does not follow the naming convention",
field.getName(), field.getOwner().getName());
"Constant %s in class %s does not follow the naming convention", field.getName(),
field.getOwner().getName());
events.add(SimpleConditionEvent.violated(field, message));
}
}
Expand Down

0 comments on commit 8859574

Please sign in to comment.