ArchUnit
ArchUnit copied to clipboard
Remove accesses to synthetic enum SwitchMap fields when checking classes accessability
Hi,
I'm using ArchUnit 1.0.1 with Java 17 and have a similar problem as described in #570 resolved by PR https://github.com/TNG/ArchUnit/pull/895
I have this enum:
public enum ExampleEnum {
FOO,
BAR
}
and mapper
public class ExampleEnumMapper {
public static String failingExample1(final ExampleEnum exampleEnum) {
return switch (exampleEnum) {
case FOO -> "foo";
case BAR -> "bar";
};
}
}
When I'm executing this test:
private static final JavaClasses MODULE_CLASSES = new ClassFileImporter().importPath("build/classes/java")
def "should mappers be public"() {
given: "a rule"
ArchRule rule = classes()
.should()
.bePublic()
expect: "rule is not broken"
rule.check(MODULE_CLASSES)
}
I'm getting this error:
java.lang.AssertionError: Architecture Violation [Priority: MEDIUM] - Rule 'classes should be public' was violated (1 times):
Class <com.example.ExampleEnumMapper$1> does not have modifier PUBLIC in (ExampleEnumMapper.java:0)
Yes, I tried to be as little invasive as possible, because removing the whole class is a bigger impact. For now you can just adjust the rule to
classes()
.that().doNotHaveModifier(JavaModifier.SYNTHETIC)
.should()
.bePublic();
That should exclude your cases, right?
That should exclude your cases, right?
Thanks, it is working. But should I close this Issue? For me, it looks like a workaround, not a final solution,.
The problem is that I'm not sure if there is a general rule to deal with synthetic code. And once excluded there will be no way anymore for users to interact with it at all. I'm just thinking about dependency cases, where the source code actually results in a synthetic class (or method) being created where the compiled source code then lives. If the synthetic code is just ignored we suddenly don't have any traces more of the dependencies that were in the original source code.
I once experimented quite a lot to remove all synthetic members in #87 and I couldn't figure out a way to make it work without losing information in some place.
If we talk about dependencies, then it's still better to see Class <a.b.Magic$synthetic$123> calls method <a.b.Foo.bar()>... than not having any trace anymore at all even though it's in the source code :thinking: In particular, if things like the Kotlin compiler are also taken into consideration.