Мы проверяем архитектуру нашего программного обеспечения по некоторым правилам ArchUnit.
Один из них — тест для нашей многоуровневой архитектуры.
Это отлично работает для методов. Если мы получим доступ к методу слоя 3 из слоя 1, мы получим исключение.
Но если доступ к полю, объявленному в слое 3, из уровня 1, это не приведет к исключению.
.layer("layer1").definedBy("com.acme.layer1")
.layer("layer2").definedBy("com.acme.layer2")
.layer("layer3").definedBy("com.acme.layer3")
.whereLayer("layer3").mayNotBeAccessedByAnyLayer()
.whereLayer("layer2").mayOnlyAccessedByLayers("layer3")
.as("Respect the layered architecture");
Это не вызовет исключения, если мы импортируем поле из класса layer3 в класс layer1:
package com.acme.layer1
import static com.acme.layer3.SOME_LABEL
public class x {
...
}
Мы ожидаем, что доступ к полям из уровня 3 на любом другом уровне также вызовет исключение. Или есть другой способ проверить?
Мой ответ зависит от предположения, что com.acme.layer3.SOME_LABEL
является постоянное выражение, подобным public static final String SOME_LABEL = "..."
Константы времени компиляции встраиваются во время компиляции. Если ваш код выглядит как
String label = SharedConstants.SOME_LABEL;
тогда скомпилированный байт-код содержит точное значение из SharedConstants.SOME_LABEL
. В байт-коде не остается ссылки на это поле. (Статическая финальная встроенная ловушка)
ArchUnit собирает всю информацию, анализируя байт-код, см. также файл Руководство пользователя ArchUnit. Поскольку в байт-коде нет информации о SharedConstants.SOME_LABEL
, ArchUnit не знает об этом доступе.
Подводя итог: это ограничение ArchUnit и всех других библиотек, которые зависят только от байт-кода.