Following the method suggested in this blog post, I am trying to create an archunit rule that will enforce log statements to have contextual information. But the code mentioned in the example is not compiling:
public static ArchRule noInfoLoggingWithoutContext() {
ArchCondition<JavaClass> loggerWithOutContext =
callMethodWhere(
target(name("info"))
.and(target(owner(assignableTo(Logger.class))))
.and(target(rawParameterTypes(new DescribedPredicate<>("logger.info without context") {
@Override
public boolean test(List<JavaClass> methodParameters) {
return methodParameters.size() <= 1;
}
})))).as("use logger.info without context");
return noClasses().should(loggerWithOutContext);
}
The above mentioned code fails with the following error:
Required type: DescribedPredicate <? super AccessTarget>
Provided: DescribedPredicate<HasParameterTypes>
Any suggestions, how can we implement such a rule?
archunit version: 1.0.1
You probably picked the "wrong" static import
import static com.tngtech.archunit.core.domain.JavaAccess.Predicates.target;
(which returns a DescribedPredicate<JavaAccess<?>>
) instead of
import static com.tngtech.archunit.core.domain.JavaCall.Predicates.target;
(which returns a DescribedPredicate<JavaCall<?>>
).
As callMethodWhere
takes a DescribedPredicate<? super JavaMethodCall>
,
and as JavaMethodCall extends JavaCall
, which in turn extends JavaCodeUnitAccess
, which in turn extends JavaAccess
, the "wrong" target
method worked for callMethodWhere
, but its predicates could only operate on JavaAccess
, which has a name
and an owner
, but no rawParameterTypes
.
Unrelated to your question: I would simplify the entire rule to
import com.tngtech.archunit.junit.ArchTest;
import com.tngtech.archunit.lang.ArchRule;
import org.slf4j.Logger;
import static com.tngtech.archunit.base.DescribedPredicate.describe;
import static com.tngtech.archunit.core.domain.JavaCall.Predicates.target;
import static com.tngtech.archunit.lang.conditions.ArchConditions.callMethodWhere;
import static com.tngtech.archunit.lang.conditions.ArchPredicates.is;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;
public class StackOverflow76250573 {
@ArchTest
ArchRule noInfoLoggingWithoutContext =
noClasses().should(callMethodWhere(target(is(describe("logger.info without context",
target ->
target.getOwner().isAssignableTo(Logger.class)
&& target.getName().equals("info")
&& target.getRawParameterTypes().size() < 2
)))));
}