-
Notifications
You must be signed in to change notification settings - Fork 329
Improve error messages for synthetic/anonymous class violations #1552
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Improve error messages for synthetic/anonymous class violations #1552
Conversation
|
@hankem @codecholeric When you have time, I would appreciate your review of this PR. No rush at all—I know maintaining this project takes considerable effort. Thank you for all your work on ArchUnit! 😃 |
|
Thank you so much for your contribution and understanding, and apologies for missing your ping on the other issue! |
|
@hankem The issue was that the hint message was using hardcoded I fixed this by changing the hint message from a static constant to a method that dynamically uses All tests pass locally and I've run the full test suite with |
|
Hi @hankem , just wanted to let you know that all checks are passing now! Personally, I believe that developers shouldn't need to understand the internal behavior of the Java compiler to use this library. They simply expect ArchUnit to verify naming conventions on their source code, just as the rules imply. However, I value your insight as the maintainer. I'm curious to hear if you agree that this abstraction is meaningful for the project. Looking forward to your review! |
|
One thing I want to look into (but didn't get to do yet): Does the added hint affect frozen violations? |
When ArchUnit rules fail on synthetic or anonymous classes generated by the compiler (e.g., from lambdas or enum switches), new users are often confused by error messages pointing to classes they didn't write (MyService$1). This commit enhances naming convention error messages to detect synthetic/ anonymous classes and provide a helpful hint directing users to exclude these classes using .doNotHaveModifier(JavaModifier.SYNTHETIC) or .areNotAnonymousClasses(). The implementation uses a custom ArchCondition that checks the failing object and appends the hint only when the condition fails on a synthetic or anonymous class, ensuring regular violations remain unchanged. Implementation details: - Checks both SYNTHETIC (compiler-generated, e.g., enum switch maps per JLS 13.1.7) and anonymous classes (both can cause unexpected naming violations) - Applies to haveSimpleNameStartingWith, haveSimpleNameContaining, and haveSimpleNameEndingWith methods - Fully compatible with Java 8-21 (all APIs available since Java 1.5) - Includes unit tests for anonymous classes and integration tests for synthetic classes Resolves: TNG#1509 Signed-off-by: chadongmin <cdm2883@naver.com>
The synthetic class hint message was using hardcoded \n line separators, which caused test failures on Windows CI. Windows uses \r\n as line separator, but the test framework splits violation messages using System.lineSeparator(). This mismatch prevented proper message parsing and matching in integration tests. Changed SYNTHETIC_CLASS_HINT_MESSAGE from a static constant with hardcoded \n to a dynamic method getSyntheticClassHintMessage() that uses System.lineSeparator(). This ensures the hint message uses the correct platform-specific line separator, allowing tests to pass on all platforms (macOS, Linux, and Windows). Signed-off-by: chadongmin <cdm2883@naver.com>
The hint messages added for synthetic/anonymous class violations could break existing frozen violation stores, since FuzzyViolationLineMatcher would treat violations with hints as different from violations without hints. This change makes FuzzyViolationLineMatcher ignore hint suffixes (text following line separator + line separator + "Hint:") when comparing violations, similar to how it already ignores line numbers and anonymous class numbers. Resolves: TNG#1509 Signed-off-by: chadongmin <cdm2883@naver.com>
6247703 to
5a11803
Compare
|
@hankem Thank you for your comment. I looked into the frozen violations concern you raised. I came up with two possible solutions to address this issue. The first option is to modify The second option is to make hints configurable via I chose the first option. I look forward to hearing your thoughts. |
Description
Improves error messages when ArchUnit rules fail on synthetic or anonymous classes generated by the compiler. New users are often confused when rules fail on classes like
MyService$1that they didn't write, with no clear guidance on how to resolve the issue.Problem
As reported in #1509 and #1019, users encounter confusing error messages like:
This happens when the Java compiler generates synthetic classes for:
Users spend significant time debugging these "violations" even though they aren't actual architectural issues in their source code.
Solution
This PR adds helpful hints to error messages when rules fail on synthetic or anonymous classes:
Before:
After:
The hint only appears when relevant—regular class violations remain unchanged.
Implementation Details
Why Check Both SYNTHETIC and Anonymous?
Synthetic classes: Compiler-generated (e.g., enum switch maps defined in JLS 13.1.7)
ACC_SYNTHETICflag in bytecodeMyClass$1from enum switchesAnonymous classes: Explicitly created in source but may violate naming rules
isAnonymousClass()new Runnable() {}SYNTHETICcheck doesn't work butareNotAnonymousClasses()doesChanges Made
Core Implementation (
ArchConditions.java):haveWithHint()method that creates customArchConditionwith hint supportisSyntheticOrAnonymous()helper to detect both synthetic and anonymous classeshaveWithHint():haveSimpleNameStartingWith()haveSimpleNameContaining()haveSimpleNameEndingWith()Unit Tests (
ClassesShouldTest.java):NestedClassWithSomeMoreClasses.getAnonymousClass()for testingIntegration Tests:
ExpectedNaming.javato handle hint messagesExamplesIntegrationTest.javato include expected hint linesUseCaseOneThreeController$1(synthetic class from enum switch)Compatibility
isAnonymousClass()available since Java 1.5JavaModifier.SYNTHETICavailable since Java 1.5./gradlew clean build -PallTests✅ passesTesting
Test Coverage
BUILD SUCCESSFULwith all testsTest Results
Related Issues
Resolves #1509
Relates to #1019
Checklist
./gradlew clean build -PallTests)git commit -s)