Skip to content

[Enhancement] Improve Error Message for Failures on Synthetic/Anonymous Classes #1509

@chadongmin

Description

@chadongmin

New users of ArchUnit, including myself, are often confused when a seemingly correct rule fails on a class they didn't write, typically one ending with $1, $2, etc. (e.g., MyService$1).

As detailed in issue #1019, this problem occurs because the Java compiler generates synthetic or anonymous classes for certain language features like lambdas, switch expressions on enums, or try-with-resources statements.

The current error message is technically correct but unhelpful, as it points to a compiler artifact without any context:

java.lang.AssertionError: Architecture Violation [...]
Rule 'classes that reside in a package '..service..' should have simple name ending with 'Service'' was violated (1 times):
Class <com.app.archunittest.service.DummyService$1> does not have simple name ending with 'Service' in (DummyService.java:0)

This leads new users to spend significant time debugging an issue that isn't an actual architectural violation in their source code. The solution—adding .and().doNotHaveModifier(JavaModifier.SYNTHETIC) or .and().areNotAnonymousClasses()—is not immediately obvious.

Describe the solution you'd like
I propose enhancing the error message to detect when a failing class is synthetic or anonymous and provide a helpful hint to the user. This would guide them directly to the correct solution and dramatically improve the new user experience.

Here is an example of the proposed error message:

java.lang.AssertionError: Architecture Violation [...]
Rule 'classes that reside in a package '..service..' should have simple name ending with 'Service'' was violated (1 times):
Class <com.app.archunittest.service.DummyService$1> does not have simple name ending with 'Service' in (DummyService.java:0)

Hint: The failing class 'DummyService$1' appears to be a synthetic class generated by the compiler from a lambda or other language feature. To test only developer-written code, consider adding `.and().doNotHaveModifier(JavaModifier.SYNTHETIC)` or `.and().areNotAnonymousClasses()` to your rule.

Describe alternatives you've considered
The current alternative is for users to discover the solution through trial and error, or by finding existing GitHub issues like #1019. This is not an ideal user experience. Adding a proactive hint in the error message is a far more effective approach.

Here is a minimal reproducible example from issue #1019 that triggers the confusing error.

Code that causes the issue:

@Service
public class DummyService {
    private DummyEnum dummyEnum = DummyEnum.FIRST;

    public void dummyMethod() {
        Optional.ofNullable(dummyEnum)
                .ifPresent(de -> {
                    // This switch on an enum inside a lambda generates a synthetic class
                    switch(de) {
                        case FIRST: System.out.println("First"); break;
                        case SECOND: System.out.println("Second"); break;
                        case THIRD: System.out.println("Third"); break;
                    }
                });
    }
}

ArchUnit Test:

@AnalyzeClasses(packages = "com.app.archunittest")
public class NamingConventionTest {

    @ArchTest
    static ArchRule serviceShouldBeSuffixed = classes()
            .that()
            .resideInAPackage("..service..")
            .should()
            .haveSimpleNameEndingWith("Service");
}

Implementing this small improvement would make ArchUnit more intuitive and save developers time, reinforcing its role as a helpful tool rather than a source of confusion.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions