CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-apache-flink--flink-architecture-tests-base

Base library for Apache Flink architecture tests that provides common ArchUnit extensions and utilities for validating architectural constraints in both production and test code

Pending
Overview
Eval results
Files

java-only-rules.mddocs/

Java-Only Rules

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.

Capabilities

Java-Only Class Selection

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();

Java-Only Negative Rules

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();

Java vs Scala Filtering

Why Java-Only Rules are Necessary

// 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();

Integration with SourcePredicates

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");

Advanced Usage Patterns

Package Structure Validation

// 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..");

Class Type Validation

// 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");

Annotation-Based Rules

// 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");

Inheritance and Composition Rules

// 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();

Complex Architectural Rules

// 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..");

Performance and Memory Benefits

Reduced Analysis Scope

// 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..");

Integration with Import Options

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);

Design Principles

  • Scala Compatibility: Designed to handle mixed Java/Scala codebases safely
  • Drop-in Replacement: Provides exact equivalents to standard ArchUnit rule definitions
  • Performance: Reduces analysis scope by excluding non-Java classes
  • Composability: Works with all standard ArchUnit conditions and predicates
  • Safety: Provides additional layer of protection against Scala-related analysis issues

Install with Tessl CLI

npx tessl i tessl/maven-org-apache-flink--flink-architecture-tests-base

docs

field-analysis.md

general-predicates.md

import-control.md

index.md

java-only-rules.md

method-validation.md

source-predicates.md

tile.json