我有一个图层,调用它Service
,另一个调用Permission
. 我想知道我是否可以强制执行以下规则:
从 layer 内任何公共类的任何公共方法中,Service
其参数列表包含一个名为 的参数foo
,断言它从Permission
layer 调用一个方法(理想情况下,确保在Service
layer 内的任何其他东西之前调用它)。
ArchUnit 有可能吗?
我有一个图层,调用它Service
,另一个调用Permission
. 我想知道我是否可以强制执行以下规则:
从 layer 内任何公共类的任何公共方法中,Service
其参数列表包含一个名为 的参数foo
,断言它从Permission
layer 调用一个方法(理想情况下,确保在Service
layer 内的任何其他东西之前调用它)。
ArchUnit 有可能吗?
它不能开箱即用,但您可以通过以下解决方案实现该目标:
DescribedPredicate<JavaClass> isPermissionClass = JavaClass.Predicates
.resideInAnyPackage("..permission..");
classes()
.that().resideInAnyPackage("..service..")
.should(new ContainOnlyMethodsCallingPermissionClass(isPermissionClass));
ContainOnlyMethodsCallingPermissionClass
可以定义如下。它首先收集所有声明的方法,然后检查对权限类的传出方法调用是否覆盖所有收集的方法。
public static class ContainOnlyMethodsCallingPermissionClass extends ArchCondition<JavaClass> {
private final DescribedPredicate<JavaClass> isPermissionClass;
public ContainOnlyMethodsCallingPermissionClass(DescribedPredicate<JavaClass> isPermissionClass) {
super("only contain methods calling a permission class");
this.isPermissionClass = isPermissionClass;
}
@Override
public void check(JavaClass javaClass, ConditionEvents events) {
Set<String> methodIdentifiers = getMethodIdentifiersOfClass(javaClass);
methodIdentifiers.removeAll(collectMethodsCallingPermissionClass(javaClass));
for (String methodId : methodIdentifiers) {
events.add(new SimpleConditionEvent(javaClass, false, methodId));
}
}
private Set<String> collectMethodsCallingPermissionClass(JavaClass javaClass) {
Set<String> methodIdentifiers = new HashSet<>();
for (JavaAccess<?> access : javaClass.getAccessesFromSelf()) {
if (!isCallFromMethod(access)) {
continue;
}
if (isMethodCallToPermissionClass(access)) {
JavaMethod callingMethod = (JavaMethod) access.getOwner();
methodIdentifiers.remove(callingMethod.getFullName());
}
}
return methodIdentifiers;
}
private Set<String> getMethodIdentifiersOfClass(JavaClass javaClass) {
return javaClass.getMethods().stream().filter(method -> !method.isConstructor())
.map(method -> method.getFullName()).collect(Collectors.toSet());
}
private boolean isCallFromMethod(JavaAccess<?> access) {
return access.getOrigin() instanceof JavaMethod;
}
private boolean isMethodCallToPermissionClass(JavaAccess<?> access) {
return isPermissionClass.apply(access.getTargetOwner());
}
}
您还可以将操作JavaClass
es 的谓词更改为操作JavaMethodCall
s 的谓词,以便更准确地定位相关的权限方法。这还允许过滤掉服务层中不相关的方法(例如,toString()
方法)。