Skip to content

Commit e83bcd9

Browse files
committed
add archrules-common to hold common Predicates, ArchConditions, and ChainableFunctions
1 parent d00443e commit e83bcd9

File tree

43 files changed

+863
-146
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+863
-146
lines changed

README.md

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,48 @@
11
# Nebula ArchRules
22

3-
This repository contains several libraries of ArchRules which can be used in projects by using the [ArchRules Runner](https://github.com/nebula-plugins/nebula-archrules-plugin?tab=readme-ov-file#running-rules) plugin.
3+
## ArchRule Building Blocks
4+
This repository contains the `archrules-common` library which contains ArchUnit primitives (DescribedPredicates, ChainableFunctions, and ArchConditions) which assist in writing rules. These extend what comes out-of-the box in ArchUnit to cover more cases.
45

6+
[![Maven Central](https://img.shields.io/maven-central/v/com.netflix.nebula/archrules-common?style=for-the-badge&color=01AF01)](https://repo1.maven.org/maven2/com/netflix/nebula/archrules-common/)
57

6-
## Deprecation Rules
8+
## ArchRule Libraries
9+
This repository also contains several libraries of ArchRules which can be used in projects by using the [ArchRules Runner](https://github.com/nebula-plugins/nebula-archrules-plugin?tab=readme-ov-file#running-rules) plugin.
10+
11+
12+
### Deprecation Rules
713
[![Maven Central](https://img.shields.io/maven-central/v/com.netflix.nebula/archrules-deprecation?style=for-the-badge&color=01AF01)](https://repo1.maven.org/maven2/com/netflix/nebula/archrules-deprecation/)
814

9-
## Gradle Plugin Development
15+
### Gradle Plugin Development
1016
[![Maven Central](https://img.shields.io/maven-central/v/com.netflix.nebula/archrules-gradle-plugin-development?style=for-the-badge&color=01AF01)](https://repo1.maven.org/maven2/com/netflix/nebula/archrules-gradle-plugin-development/)
1117

1218
These rules enforce best practices when developing Gradle plugins.
1319

14-
## Guava Rules
20+
### Guava Rules
1521
[![Maven Central](https://img.shields.io/maven-central/v/com.netflix.nebula/archrules-guava?style=for-the-badge&color=01AF01)](https://repo1.maven.org/maven2/com/netflix/nebula/archrules-guava/)
1622

1723
These rules detect the usage of certain APIs from Guava which have standard library replacements.
1824

19-
## Javax Rules
25+
### Javax Rules
2026
[![Maven Central](https://img.shields.io/maven-central/v/com.netflix.nebula/archrules-joda?style=for-the-badge&color=01AF01)](https://repo1.maven.org/maven2/com/netflix/nebula/archrules-javax/)
2127

2228
These rules enforce the usage of `jakarta` over `javax`.
2329

24-
## Joda Rules
30+
### Joda Rules
2531
[![Maven Central](https://img.shields.io/maven-central/v/com.netflix.nebula/archrules-joda?style=for-the-badge&color=01AF01)](https://repo1.maven.org/maven2/com/netflix/nebula/archrules-joda/)
2632

2733
These rules enforce the usage of `java.time` over Joda Time.
2834

29-
## Nullability Rules
35+
### Nullability Rules
3036
[![Maven Central](https://img.shields.io/maven-central/v/com.netflix.nebula/archrules-nullability?style=for-the-badge&color=01AF01)](https://repo1.maven.org/maven2/com/netflix/nebula/archrules-nullability/)
3137

3238
These rules enforce JSpecify nullability annotations on public code. Kotlin classes are exempt from the rule, as Kotlin has nullability built into its type system, which is compatible with JSpecify.
3339

34-
## Security Rules
40+
### Security Rules
3541
[![Maven Central](https://img.shields.io/maven-central/v/com.netflix.nebula/archrules-security?style=for-the-badge&color=01AF01)](https://repo1.maven.org/maven2/com/netflix/nebula/archrules-archrules-security/)
3642

3743
These rules ensure calls are not made to known insecure OSS Java APIs.
3844

39-
## Testing Frameworks Rules
45+
### Testing Frameworks Rules
4046
[![Maven Central](https://img.shields.io/maven-central/v/com.netflix.nebula/archrules-testing-frameworks?style=for-the-badge&color=01AF01)](https://repo1.maven.org/maven2/com/netflix/nebula/archrules-testing-frameworks/)
4147

4248
These rules enforce upgrading to JUnit Jupiter.

archrules-common/build.gradle.kts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
plugins {
2+
id("com.netflix.nebula.library")
3+
}
4+
description = "Common Predicates and Chanable Functions for building rules"
5+
6+
dependencies {
7+
implementation(libs.jspecify)
8+
api("com.tngtech.archunit:archunit:1.+")
9+
10+
testImplementation(libs.assertj)
11+
testImplementation(libs.logback)
12+
testImplementation("org.jetbrains.kotlin:kotlin-stdlib:2.2.0")
13+
testImplementation("com.netflix.nebula:nebula-archrules-core:0.+")
14+
}
15+
java {
16+
toolchain {
17+
languageVersion = JavaLanguageVersion.of(8)
18+
}
19+
}
20+
tasks.named<JavaCompile>("compileTestJava") {
21+
javaCompiler.set(javaToolchains.compilerFor {
22+
languageVersion.set(JavaLanguageVersion.of(11))
23+
})
24+
}
25+
dependencyLocking {
26+
lockAllConfigurations()
27+
}
28+
testing {
29+
suites {
30+
named<JvmTestSuite>("test") {
31+
useJUnitJupiter()
32+
}
33+
}
34+
}

archrules-common/gradle.lockfile

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# This is a Gradle generated file for dependency locking.
2+
# Manual edits can break the build and are not advised.
3+
# This file is expected to be part of source control.
4+
ch.qos.logback:logback-classic:1.5.20=testArchRulesRuntime,testCompileClasspath,testRuntimeClasspath
5+
ch.qos.logback:logback-core:1.5.20=testArchRulesRuntime,testCompileClasspath,testRuntimeClasspath
6+
com.netflix.nebula:archrules-deprecation:0.7.1=archRules,mainArchRulesRuntime,testArchRulesRuntime
7+
com.netflix.nebula:archrules-joda:0.7.1=archRules,mainArchRulesRuntime,testArchRulesRuntime
8+
com.netflix.nebula:archrules-nullability:0.7.1=archRules,mainArchRulesRuntime,testArchRulesRuntime
9+
com.netflix.nebula:archrules-security:0.7.1=archRules,mainArchRulesRuntime,testArchRulesRuntime
10+
com.netflix.nebula:archrules-testing-frameworks:0.7.1=archRules,mainArchRulesRuntime,testArchRulesRuntime
11+
com.netflix.nebula:nebula-archrules-core:0.5.5=archRules,mainArchRulesRuntime
12+
com.netflix.nebula:nebula-archrules-core:0.7.0=testArchRulesRuntime,testCompileClasspath,testRuntimeClasspath
13+
com.tngtech.archunit:archunit:1.4.1=archRules,compileClasspath,mainArchRulesRuntime,runtimeClasspath,testArchRulesRuntime,testCompileClasspath,testRuntimeClasspath
14+
net.bytebuddy:byte-buddy:1.17.7=testArchRulesRuntime,testCompileClasspath,testRuntimeClasspath
15+
org.apiguardian:apiguardian-api:1.1.2=testCompileClasspath
16+
org.assertj:assertj-core:3.27.6=testArchRulesRuntime,testCompileClasspath,testRuntimeClasspath
17+
org.jetbrains.kotlin:kotlin-stdlib:2.2.0=testArchRulesRuntime,testCompileClasspath,testRuntimeClasspath
18+
org.jetbrains:annotations:13.0=testArchRulesRuntime,testCompileClasspath,testRuntimeClasspath
19+
org.jspecify:jspecify:1.0.0=archRules,compileClasspath,mainArchRulesRuntime,runtimeClasspath,testArchRulesRuntime,testCompileClasspath,testRuntimeClasspath
20+
org.junit.jupiter:junit-jupiter-api:5.12.2=testArchRulesRuntime,testCompileClasspath,testRuntimeClasspath
21+
org.junit.jupiter:junit-jupiter-engine:5.12.2=testArchRulesRuntime,testRuntimeClasspath
22+
org.junit.jupiter:junit-jupiter-params:5.12.2=testArchRulesRuntime,testCompileClasspath,testRuntimeClasspath
23+
org.junit.jupiter:junit-jupiter:5.12.2=testArchRulesRuntime,testCompileClasspath,testRuntimeClasspath
24+
org.junit.platform:junit-platform-commons:1.12.2=testArchRulesRuntime,testCompileClasspath,testRuntimeClasspath
25+
org.junit.platform:junit-platform-engine:1.12.2=testArchRulesRuntime,testRuntimeClasspath
26+
org.junit.platform:junit-platform-launcher:1.12.2=testArchRulesRuntime,testRuntimeClasspath
27+
org.junit:junit-bom:5.12.2=testArchRulesRuntime,testCompileClasspath,testRuntimeClasspath
28+
org.opentest4j:opentest4j:1.3.0=testArchRulesRuntime,testCompileClasspath,testRuntimeClasspath
29+
org.slf4j:slf4j-api:2.0.17=archRules,compileClasspath,mainArchRulesRuntime,runtimeClasspath,testArchRulesRuntime,testCompileClasspath,testRuntimeClasspath
30+
empty=annotationProcessor,testAnnotationProcessor
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.netflix.nebula.archrules.common;
2+
3+
import com.tngtech.archunit.base.DescribedPredicate;
4+
import org.jspecify.annotations.NullMarked;
5+
6+
import static com.tngtech.archunit.core.domain.properties.CanBeAnnotated.Predicates.annotatedWith;
7+
8+
@NullMarked
9+
public class CanBeAnnotated {
10+
public static class Predicates {
11+
12+
/**
13+
* Annotated with Java or Kotlin deprecation annotations
14+
*/
15+
public static DescribedPredicate<com.tngtech.archunit.core.domain.properties.CanBeAnnotated> deprecated() {
16+
return annotatedWith(Deprecated.class)
17+
.or(annotatedWith("kotlin.Deprecated"))
18+
.or(annotatedWith("kotlin.DeprecatedSinceKotlin"))
19+
.as("deprecated");
20+
}
21+
22+
/**
23+
* Annotated with Java deprecation annotation with the forRemoval property set to true
24+
*/
25+
public static DescribedPredicate<com.tngtech.archunit.core.domain.properties.CanBeAnnotated> deprecatedForRemoval() {
26+
return annotatedWith(JavaAnnotation.Predicates.deprecatedForRemoval())
27+
.as("deprecated for removal");
28+
}
29+
}
30+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.netflix.nebula.archrules.common;
2+
3+
import com.tngtech.archunit.base.DescribedPredicate;
4+
import org.jspecify.annotations.NullMarked;
5+
6+
@NullMarked
7+
public class Dependency {
8+
public static class Predicates {
9+
10+
/**
11+
* tests that a class and a dependency are in the same package
12+
*/
13+
public static DescribedPredicate<com.tngtech.archunit.core.domain.Dependency> resideInSamePackage() {
14+
return new DescribedPredicate<com.tngtech.archunit.core.domain.Dependency>("reside in same package") {
15+
@Override
16+
public boolean test(com.tngtech.archunit.core.domain.Dependency dependency) {
17+
return dependency.getOriginClass().getPackageName()
18+
.equals(dependency.getTargetClass().getPackageName());
19+
}
20+
};
21+
}
22+
}
23+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.netflix.nebula.archrules.common;
2+
3+
import com.tngtech.archunit.base.DescribedPredicate;
4+
import org.jspecify.annotations.NullMarked;
5+
6+
@NullMarked
7+
public class JavaAccess {
8+
public static class Predicates {
9+
10+
/**
11+
* tests that an access's origin and target are in the same package
12+
*/
13+
public static DescribedPredicate<com.tngtech.archunit.core.domain.JavaAccess<?>> targetHasOwnerInSamePackage() {
14+
return new DescribedPredicate<com.tngtech.archunit.core.domain.JavaAccess<?>>(
15+
"in the same package") {
16+
@Override
17+
public boolean test(com.tngtech.archunit.core.domain.JavaAccess javaAccess) {
18+
return javaAccess.getOriginOwner().getPackage()
19+
.equals(javaAccess.getTargetOwner().getPackage());
20+
}
21+
};
22+
}
23+
}
24+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.netflix.nebula.archrules.common;
2+
3+
import com.tngtech.archunit.base.DescribedPredicate;
4+
import org.jspecify.annotations.NullMarked;
5+
6+
@NullMarked
7+
public class JavaAnnotation {
8+
public static class Predicates {
9+
10+
/**
11+
* Java deprecation annotation with the forRemoval property set to true
12+
*/
13+
public static DescribedPredicate<com.tngtech.archunit.core.domain.JavaAnnotation<?>> deprecatedForRemoval() {
14+
return new DescribedPredicate<com.tngtech.archunit.core.domain.JavaAnnotation<?>>("@Deprecated(forRemoval=true)") {
15+
@Override
16+
public boolean test(com.tngtech.archunit.core.domain.JavaAnnotation<?> annotation) {
17+
if (!annotation.getRawType().isAssignableTo(Deprecated.class)) {
18+
return false;
19+
}
20+
return annotation.get("forRemoval")
21+
.filter(it -> it instanceof Boolean)
22+
.map(value -> (Boolean) value)
23+
.orElse(false);
24+
}
25+
};
26+
}
27+
}
28+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package com.netflix.nebula.archrules.common;
2+
3+
import com.tngtech.archunit.base.DescribedPredicate;
4+
import com.tngtech.archunit.core.domain.JavaMethod;
5+
import com.tngtech.archunit.core.domain.JavaModifier;
6+
import org.jspecify.annotations.NullMarked;
7+
8+
/**
9+
* Matches getter methods (getX(), isX()) that follow JavaBeans naming conventions.
10+
*/
11+
@NullMarked
12+
class JavaBeanGetterPredicate extends DescribedPredicate<JavaMethod> {
13+
14+
JavaBeanGetterPredicate() {
15+
super("getter");
16+
}
17+
18+
@Override
19+
public boolean test(JavaMethod input) {
20+
if (input.getModifiers().contains(JavaModifier.STATIC)) {
21+
return false;
22+
}
23+
if (!input.getParameters().isEmpty()) {
24+
return false;
25+
}
26+
if (input.getName().startsWith("get")) {
27+
return input.getName().length() >= 4 && !Character.isLowerCase(input.getName().charAt(3));
28+
}
29+
if (input.getName().startsWith("is")) {
30+
if (input.getRawReturnType().isAssignableTo(Boolean.class)) {
31+
return false;
32+
}
33+
return !Character.isLowerCase(input.getName().charAt(2));
34+
}
35+
return false;
36+
}
37+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package com.netflix.nebula.archrules.common;
2+
3+
import com.tngtech.archunit.base.DescribedPredicate;
4+
import com.tngtech.archunit.core.domain.Dependency;
5+
import com.tngtech.archunit.core.domain.JavaPackage;
6+
import com.tngtech.archunit.lang.ArchCondition;
7+
import com.tngtech.archunit.lang.conditions.NebulaAnyDependencyCondition;
8+
import org.jspecify.annotations.NullMarked;
9+
10+
import java.lang.annotation.Annotation;
11+
12+
import static com.tngtech.archunit.core.domain.JavaClass.Functions.GET_DIRECT_DEPENDENCIES_FROM_SELF;
13+
import static com.tngtech.archunit.core.domain.JavaClass.Functions.GET_PACKAGE;
14+
import static com.tngtech.archunit.core.domain.properties.CanBeAnnotated.Predicates.annotatedWith;
15+
import static com.tngtech.archunit.lang.conditions.ArchPredicates.is;
16+
17+
@NullMarked
18+
public class JavaClass {
19+
public static class Predicates {
20+
/**
21+
* evaluates the predicate on the class's package
22+
*/
23+
public static DescribedPredicate<com.tngtech.archunit.core.domain.JavaClass> resideInAPackageThat(
24+
DescribedPredicate<? super JavaPackage> condition) {
25+
return condition.onResultOf(GET_PACKAGE)
26+
.as("residing in package that %s", condition.getDescription());
27+
}
28+
29+
/**
30+
* checks if the class's package is annotated with a specific annotation
31+
*/
32+
public static DescribedPredicate<com.tngtech.archunit.core.domain.JavaClass> resideInPackageAnnotatedWith(
33+
Class<? extends Annotation> annotationClass
34+
) {
35+
return resideInAPackageThat(is(annotatedWith(annotationClass)));
36+
}
37+
}
38+
39+
public static class Conditions {
40+
/**
41+
* Can be removed once <a href="https://github.com/TNG/ArchUnit/pull/1580">haveAnyDependenciesThat</a> is merged.
42+
*/
43+
@Deprecated
44+
public static ArchCondition<com.tngtech.archunit.core.domain.JavaClass> haveAnyDependenciesThat(
45+
DescribedPredicate<? super Dependency> predicate) {
46+
return new NebulaAnyDependencyCondition(
47+
"have any dependencies that " + predicate.getDescription(),
48+
predicate,
49+
GET_DIRECT_DEPENDENCIES_FROM_SELF);
50+
}
51+
}
52+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.netflix.nebula.archrules.common;
2+
3+
import com.tngtech.archunit.base.DescribedPredicate;
4+
import org.jspecify.annotations.NullMarked;
5+
6+
@NullMarked
7+
public class JavaMethod {
8+
public static class Predicates {
9+
10+
/**
11+
* checks if a method is a getter according to JavaBean conventions
12+
*/
13+
public static DescribedPredicate<com.tngtech.archunit.core.domain.JavaMethod> aGetter() {
14+
return new JavaBeanGetterPredicate();
15+
}
16+
}
17+
}

0 commit comments

Comments
 (0)