如何防止 ArchUnit 对某个 API(例如 Streaming API 或 Builder API)的通用使用?
How to prevent generic usage of a certain API (e.g Streaming API or Builder API) with ArchUnit?
给定一组 classes,其中不应禁止使用某些 APIs(无论出于何种原因)。
例如,禁止 Java 8 Streaming API,或调用 Builder 内部 class 因为你想强制使用特定的循环和构造函数 classes.
关键部分是你事先不知道 ownerName
并且没有 callMethod(methodName)
我可以粗粒度地禁止调用 stream()
或 build()
方法.
有什么想法吗?
您可以使用谓词而不是流利的 API 来编写功能强大的 ArchRule
;在你的情况下
.callMethodWhere(DescribedPredicate<? super JavaMethodCall> predicate)
.
要防止使用 someCollection.stream()
,您可以从 HasName.Predicates.
name
:
开始
noClasses().should().callMethodWhere(name("stream"))
为避免误报,规则可能应该更加具体。
ArchUnit 提供了许多有用的预定义谓词;您只需要找到它们(并可能通过 DescribedPredicate.forSubtype
处理它们的协变参数类型):
noClasses().should().callMethodWhere(target(
name("stream").<CodeUnitCallTarget>forSubtype().and(
owner(assignableTo(Collection.class)).<CodeUnitCallTarget>forSubtype().and(
rawParameterTypes(new Class[0])
)
)
))
我个人觉得定义自定义谓词更简单(例如使用
DescribedPredicate.
describe
):
noClasses().should().callMethodWhere(target(describe("is Collection.stream()",
target -> "stream".equals(target.getName()) &&
target.getOwner().isAssignableTo(Collection.class) &&
target.getParameterTypes().isEmpty()
)))
仅供参考:我的解决方案使用以下导入:
import static com.tngtech.archunit.base.DescribedPredicate.describe;
import static com.tngtech.archunit.core.domain.JavaCall.Predicates.target;
import static com.tngtech.archunit.core.domain.JavaClass.Predicates.assignableTo;
import static com.tngtech.archunit.core.domain.properties.HasName.Predicates.name;
import static com.tngtech.archunit.core.domain.properties.HasOwner.Predicates.With.owner;
import static com.tngtech.archunit.core.domain.properties.HasParameterTypes.Predicates.rawParameterTypes;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;
给定一组 classes,其中不应禁止使用某些 APIs(无论出于何种原因)。
例如,禁止 Java 8 Streaming API,或调用 Builder 内部 class 因为你想强制使用特定的循环和构造函数 classes.
关键部分是你事先不知道 ownerName
并且没有 callMethod(methodName)
我可以粗粒度地禁止调用 stream()
或 build()
方法.
有什么想法吗?
您可以使用谓词而不是流利的 API 来编写功能强大的 ArchRule
;在你的情况下
.callMethodWhere(DescribedPredicate<? super JavaMethodCall> predicate)
.
要防止使用 someCollection.stream()
,您可以从 HasName.Predicates.
name
:
noClasses().should().callMethodWhere(name("stream"))
为避免误报,规则可能应该更加具体。
ArchUnit 提供了许多有用的预定义谓词;您只需要找到它们(并可能通过 DescribedPredicate.forSubtype
处理它们的协变参数类型):
noClasses().should().callMethodWhere(target(
name("stream").<CodeUnitCallTarget>forSubtype().and(
owner(assignableTo(Collection.class)).<CodeUnitCallTarget>forSubtype().and(
rawParameterTypes(new Class[0])
)
)
))
我个人觉得定义自定义谓词更简单(例如使用
DescribedPredicate.
describe
):
noClasses().should().callMethodWhere(target(describe("is Collection.stream()",
target -> "stream".equals(target.getName()) &&
target.getOwner().isAssignableTo(Collection.class) &&
target.getParameterTypes().isEmpty()
)))
仅供参考:我的解决方案使用以下导入:
import static com.tngtech.archunit.base.DescribedPredicate.describe;
import static com.tngtech.archunit.core.domain.JavaCall.Predicates.target;
import static com.tngtech.archunit.core.domain.JavaClass.Predicates.assignableTo;
import static com.tngtech.archunit.core.domain.properties.HasName.Predicates.name;
import static com.tngtech.archunit.core.domain.properties.HasOwner.Predicates.With.owner;
import static com.tngtech.archunit.core.domain.properties.HasParameterTypes.Predicates.rawParameterTypes;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;