Reputation: 779
Given a set of classes where it should not be forbidden to use certain APIs (for whatever reason).
For example, prohibiting Java 8 Streaming API, or calling a Builder inner class because you want to force the usage of loops and constructors for particular classes.
The critical part is that you do not know the ownerName
beforehand and there is no callMethod(methodName)
where I could coarse-grainy disallow calling stream()
or build()
methods.
Any ideas?
Upvotes: 0
Views: 315
Reputation: 3142
You can compose powerful ArchRule
s using predicates instead of the fluent API; in your case with
.callMethodWhere(DescribedPredicate<? super JavaMethodCall> predicate)
.
To prevent the usage of someCollection.stream()
, you could start with HasName.Predicates.
name
:
noClasses().should().callMethodWhere(name("stream"))
To avoid false-positives, the rule should probably become more specific.
ArchUnit ships lots of useful pre-defined predicates; you just need to find them (and possibly deal with their covariant parameter types via DescribedPredicate.forSubtype
):
noClasses().should().callMethodWhere(target(
name("stream").<CodeUnitCallTarget>forSubtype().and(
owner(assignableTo(Collection.class)).<CodeUnitCallTarget>forSubtype().and(
rawParameterTypes(new Class[0])
)
)
))
I personally find it simpler to define a custom predicate instead (e.g. using
DescribedPredicate.
describe
):
noClasses().should().callMethodWhere(target(describe("is Collection.stream()",
target -> "stream".equals(target.getName()) &&
target.getOwner().isAssignableTo(Collection.class) &&
target.getParameterTypes().isEmpty()
)))
FYI: My solution uses the following imports:
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;
Upvotes: 2