Base library for Apache Flink architecture tests that provides common ArchUnit extensions and utilities for validating architectural constraints in both production and test code
—
Utility methods that provide Java-only equivalents of standard ArchUnit rule definitions. Essential for mixed Java/Scala projects where ArchUnit's limited Scala support can cause analysis issues.
Provides equivalent functionality to ArchUnit's standard rule definitions but restricted to Java classes only.
/**
* Equivalent of ArchRuleDefinition.classes(), but only for Java classes
* @return ClassesThat builder for creating rules that apply only to Java classes
*/
public static ClassesThat<GivenClassesConjunction> javaClassesThat();
/**
* Equivalent of ArchRuleDefinition.classes() with predicate, but only for Java classes
* @param predicate Additional predicate to filter Java classes
* @return GivenClassesConjunction for building rules on filtered Java classes
*/
public static GivenClassesConjunction javaClassesThat(DescribedPredicate<JavaClass> predicate);Usage Examples:
import org.apache.flink.architecture.common.GivenJavaClasses;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes;
// Standard ArchUnit - may include Scala classes
ArchRule standardRule = classes()
.that().arePublic()
.should().haveSimpleNameNotContaining("Impl");
// Java-only equivalent - excludes Scala classes automatically
ArchRule javaOnlyRule = GivenJavaClasses.javaClassesThat()
.arePublic()
.should().haveSimpleNameNotContaining("Impl");
// With additional predicate
ArchRule serviceClassesRule = GivenJavaClasses.javaClassesThat(
clazz -> clazz.getSimpleName().endsWith("Service")
).should().notBeInterfaces();Provides "no classes" equivalents restricted to Java classes only.
/**
* Equivalent of ArchRuleDefinition.noClasses(), but only for Java classes
* @return ClassesThat builder for creating negative rules on Java classes
*/
public static ClassesThat<GivenClassesConjunction> noJavaClassesThat();
/**
* Equivalent of ArchRuleDefinition.noClasses() with predicate, but only for Java classes
* @param predicate Additional predicate to filter Java classes
* @return GivenClassesConjunction for building negative rules on filtered Java classes
*/
public static GivenClassesConjunction noJavaClassesThat(
DescribedPredicate<JavaClass> predicate);Usage Examples:
// Ensure no Java classes violate naming conventions
ArchRule noImplInPublicApi = GivenJavaClasses.noJavaClassesThat()
.arePublic()
.should().haveSimpleNameContaining("Impl");
// Ensure no service classes are in wrong package
ArchRule noServicesInUtil = GivenJavaClasses.noJavaClassesThat(
clazz -> clazz.getSimpleName().endsWith("Service")
).should().resideInAPackage("..util..");
// Complex negative rule
ArchRule noPublicInternalClasses = GivenJavaClasses.noJavaClassesThat()
.arePublic()
.and().resideInAPackage("..internal..")
.should().exist();// Problem: Standard ArchUnit may analyze Scala classes incorrectly
ArchRule problematicRule = classes()
.that().haveSimpleNameEndingWith("$") // Scala generates $ classes
.should().bePackagePrivate(); // May fail on Scala artifacts
// Solution: Use Java-only rules
ArchRule safeRule = GivenJavaClasses.javaClassesThat()
.haveSimpleNameNotContaining("$") // No Scala artifacts
.should().followCustomNamingConvention();import org.apache.flink.architecture.common.SourcePredicates;
// Double-layer protection against non-Java classes
ArchRule extraSafeRule = GivenJavaClasses.javaClassesThat(
SourcePredicates.areJavaClasses() // Additional Java-only filtering
).should().notAccessClassesThat().haveSimpleNameContaining("Scala");// Validate Java package organization
ArchRule packageStructureRule = GivenJavaClasses.javaClassesThat()
.resideInAPackage("org.apache.flink.api..")
.should().onlyAccessClassesThat()
.resideInAnyPackage(
"org.apache.flink.api..",
"org.apache.flink.util..",
"java..",
"javax.."
);
// Ensure internal packages are not accessed by public API
ArchRule internalAccessRule = GivenJavaClasses.noJavaClassesThat()
.resideInAPackage("org.apache.flink.api..")
.should().accessClassesThat()
.resideInAPackage("..internal..");// Validate abstract classes follow conventions
ArchRule abstractClassRule = GivenJavaClasses.javaClassesThat()
.areAbstract()
.and().areNotInterfaces()
.should().haveSimpleNameStartingWith("Abstract")
.orShould().haveSimpleNameEndingWith("Base");
// Validate interface naming
ArchRule interfaceNamingRule = GivenJavaClasses.javaClassesThat()
.areInterfaces()
.and().arePublic()
.should().haveSimpleNameNotEndingWith("Impl")
.andShould().haveSimpleNameNotStartingWith("I");// Validate deprecated classes are properly marked
ArchRule deprecatedClassRule = GivenJavaClasses.javaClassesThat()
.areAnnotatedWith(Deprecated.class)
.should().haveSimpleNameContaining("Deprecated")
.orShould().resideInAPackage("..deprecated..");
// Validate experimental features
ArchRule experimentalRule = GivenJavaClasses.javaClassesThat()
.areAnnotatedWith("org.apache.flink.annotation.Experimental")
.should().resideInAPackage("..experimental..")
.orShould().haveSimpleNameContaining("Experimental");// Validate service implementation hierarchy
ArchRule serviceHierarchyRule = GivenJavaClasses.javaClassesThat()
.haveSimpleNameEndingWith("ServiceImpl")
.should().implement("org.apache.flink.api.common.Service")
.andShould().bePackagePrivate();
// Validate utility classes are final
ArchRule utilityClassRule = GivenJavaClasses.javaClassesThat()
.haveSimpleNameEndingWith("Utils")
.should().beFinal()
.andShould().haveOnlyPrivateConstructors();// Validate layered architecture
ArchRule layeredArchitectureRule = GivenJavaClasses.javaClassesThat()
.resideInAPackage("..api..")
.should().onlyAccessClassesThat()
.resideInAnyPackage("..api..", "..spi..", "..util..", "java..")
.andShould().notAccessClassesThat()
.resideInAnyPackage("..internal..", "..impl..");
// Validate test utilities don't leak into production
ArchRule testUtilityRule = GivenJavaClasses.noJavaClassesThat()
.resideOutsideOfPackage("..test..")
.should().accessClassesThat()
.haveSimpleNameContaining("Test")
.orShould().accessClassesThat()
.resideInAPackage("..test..");// Memory-intensive: analyzes all classes including Scala artifacts
ArchRule memoryHeavyRule = classes()
.should().notAccessClassesThat().resideInAPackage("..internal..");
// Memory-optimized: analyzes only Java classes
ArchRule memoryOptimizedRule = GivenJavaClasses.javaClassesThat()
.should().notAccessClassesThat().resideInAPackage("..internal..");import org.apache.flink.architecture.common.ImportOptions;
// Complete Java-only analysis pipeline
JavaClasses javaOnlyClasses = new ClassFileImporter()
.withImportOption(new ImportOptions.ExcludeScalaImportOption())
.withImportOption(new ImportOptions.ExcludeShadedImportOption())
.importPackages("org.apache.flink");
// Apply Java-only rules to Java-only imports
ArchRule completeJavaRule = GivenJavaClasses.javaClassesThat()
.arePublic()
.should().onlyAccessClassesThat()
.areNotAnnotatedWith("org.apache.flink.annotation.Internal");
completeJavaRule.check(javaOnlyClasses);Install with Tessl CLI
npx tessl i tessl/maven-org-apache-flink--flink-architecture-tests-base