Skip to content

Commit 76c2987

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

38 files changed

Lines changed: 664 additions & 124 deletions

File tree

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: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.netflix.nebula.archrules.common;
2+
3+
import com.tngtech.archunit.base.DescribedPredicate;
4+
5+
public class Dependency {
6+
public static class Predicates {
7+
8+
/**
9+
* tests that a class and a dependency are in the same package
10+
*/
11+
public static DescribedPredicate<com.tngtech.archunit.core.domain.Dependency> resideInSamePackage() {
12+
return new DescribedPredicate<com.tngtech.archunit.core.domain.Dependency>("reside in same package") {
13+
@Override
14+
public boolean test(com.tngtech.archunit.core.domain.Dependency dependency) {
15+
return dependency.getOriginClass().getPackageName()
16+
.equals(dependency.getTargetClass().getPackageName());
17+
}
18+
};
19+
}
20+
}
21+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.netflix.nebula.archrules.common;
2+
3+
import com.tngtech.archunit.base.DescribedPredicate;
4+
5+
public class JavaAccess {
6+
public static class Predicates {
7+
8+
/**
9+
* tests that an access's origin and target are in the same package
10+
*/
11+
public static DescribedPredicate<com.tngtech.archunit.core.domain.JavaAccess<?>> inSamePackage() {
12+
return new DescribedPredicate<com.tngtech.archunit.core.domain.JavaAccess<?>>("in the same package") {
13+
@Override
14+
public boolean test(com.tngtech.archunit.core.domain.JavaAccess javaAccess) {
15+
return javaAccess.getOriginOwner().getPackage()
16+
.equals(javaAccess.getTargetOwner().getPackage());
17+
}
18+
};
19+
}
20+
}
21+
}
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: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
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+
7+
/**
8+
* Matches getter methods (getX(), isX()) that follow JavaBeans naming conventions.
9+
*/
10+
class JavaBeanGetterPredicate extends DescribedPredicate<JavaMethod> {
11+
12+
JavaBeanGetterPredicate() {
13+
super("getter");
14+
}
15+
16+
@Override
17+
public boolean test(JavaMethod input) {
18+
if (input.getModifiers().contains(JavaModifier.STATIC)) {
19+
return false;
20+
}
21+
if (!input.getParameters().isEmpty()) {
22+
return false;
23+
}
24+
if (input.getName().startsWith("get")) {
25+
return input.getName().length() >= 4 && !Character.isLowerCase(input.getName().charAt(3));
26+
}
27+
if (input.getName().startsWith("is")) {
28+
if (input.getRawReturnType().isAssignableTo(Boolean.class)) {
29+
return false;
30+
}
31+
return !Character.isLowerCase(input.getName().charAt(2));
32+
}
33+
return false;
34+
}
35+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
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.lang.ArchCondition;
6+
import com.tngtech.archunit.lang.conditions.NebulaAnyDependencyCondition;
7+
8+
import static com.tngtech.archunit.core.domain.JavaClass.Functions.GET_DIRECT_DEPENDENCIES_FROM_SELF;
9+
10+
public class JavaClass {
11+
/**
12+
* Can be removed once <a href="https://github.com/TNG/ArchUnit/pull/1580">haveDependenciesThat</a> is merged.
13+
*/
14+
@Deprecated
15+
public static ArchCondition<com.tngtech.archunit.core.domain.JavaClass> haveAnyDependenciesThat(
16+
DescribedPredicate<? super Dependency> predicate) {
17+
return new NebulaAnyDependencyCondition(
18+
"have any dependencies that " + predicate.getDescription(),
19+
predicate,
20+
GET_DIRECT_DEPENDENCIES_FROM_SELF);
21+
}
22+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.netflix.nebula.archrules.common;
2+
3+
import com.tngtech.archunit.base.DescribedPredicate;
4+
5+
public class JavaMethod {
6+
public static class Predicates {
7+
8+
/**
9+
* checks if a method is a getter according to JavaBean conventions
10+
*/
11+
public static DescribedPredicate<com.tngtech.archunit.core.domain.JavaMethod> aGetter() {
12+
return new JavaBeanGetterPredicate();
13+
}
14+
}
15+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package com.tngtech.archunit.lang.conditions;
2+
3+
4+
import com.tngtech.archunit.PublicAPI;
5+
import com.tngtech.archunit.base.DescribedPredicate;
6+
import com.tngtech.archunit.core.domain.Dependency;
7+
import com.tngtech.archunit.core.domain.JavaClass;
8+
import org.jspecify.annotations.NullMarked;
9+
10+
import java.util.Collection;
11+
import java.util.HashSet;
12+
import java.util.function.Function;
13+
14+
import static com.tngtech.archunit.PublicAPI.Usage.ACCESS;
15+
import static com.tngtech.archunit.base.DescribedPredicate.alwaysFalse;
16+
17+
/**
18+
* Duplicate of {@link AnyDependencyCondition}.
19+
* @deprecated Can be removed once <a href="https://github.com/TNG/ArchUnit/pull/1580">haveDependenciesThat</a> is merged.
20+
*/
21+
@Deprecated
22+
@NullMarked
23+
public final class NebulaAnyDependencyCondition extends AnyAttributeMatchesCondition<Dependency> {
24+
private final DescribedPredicate<? super Dependency> conditionPredicate;
25+
private final Function<JavaClass, ? extends Collection<Dependency>> javaClassToRelevantDependencies;
26+
private final DescribedPredicate<Dependency> ignorePredicate;
27+
28+
public NebulaAnyDependencyCondition(
29+
String description,
30+
DescribedPredicate<? super Dependency> predicate,
31+
Function<JavaClass, ? extends Collection<Dependency>> javaClassToRelevantDependencies) {
32+
33+
this(description, predicate, javaClassToRelevantDependencies, alwaysFalse());
34+
}
35+
36+
private NebulaAnyDependencyCondition(
37+
String description,
38+
DescribedPredicate<? super Dependency> conditionPredicate,
39+
Function<JavaClass, ? extends Collection<Dependency>> javaClassToRelevantDependencies,
40+
DescribedPredicate<Dependency> ignorePredicate) {
41+
42+
super(description, new DependencyCondition(conditionPredicate));
43+
this.conditionPredicate = conditionPredicate;
44+
this.javaClassToRelevantDependencies = javaClassToRelevantDependencies;
45+
this.ignorePredicate = ignorePredicate;
46+
}
47+
48+
@PublicAPI(usage = ACCESS)
49+
public NebulaAnyDependencyCondition ignoreDependency(DescribedPredicate<? super Dependency> ignorePredicate) {
50+
return new NebulaAnyDependencyCondition(getDescription(),
51+
conditionPredicate,
52+
javaClassToRelevantDependencies,
53+
this.ignorePredicate.or(ignorePredicate));
54+
}
55+
56+
@Override
57+
@PublicAPI(usage = ACCESS)
58+
public NebulaAnyDependencyCondition as(String description, Object... args) {
59+
return new NebulaAnyDependencyCondition(
60+
String.format(description, args),
61+
conditionPredicate,
62+
javaClassToRelevantDependencies,
63+
ignorePredicate);
64+
}
65+
66+
@Override
67+
Collection<Dependency> relevantAttributes(JavaClass javaClass) {
68+
Collection<Dependency> result = new HashSet<>();
69+
for (Dependency dependency : javaClassToRelevantDependencies.apply(javaClass)) {
70+
if (!ignorePredicate.test(dependency)) {
71+
result.add(dependency);
72+
}
73+
}
74+
return result;
75+
}
76+
}

0 commit comments

Comments
 (0)