英文:
Using archunit to enforce log context
问题
I'll provide the translation for the code and error message:
以下是代码的翻译和错误信息:
按照[这个][1]博客文章中建议的方法,我正在尝试创建一个ArchUnit规则,以强制要求日志记录语句具有上下文信息。但是示例中提到的代码无法编译:
```java
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);
}
上述提到的代码出现以下错误:
所需类型: DescribedPredicate<? super AccessTarget>
提供的类型: DescribedPredicate<HasParameterTypes>
有什么建议,我们如何实现这样的规则?
archunit版本: 1.0.1
请注意,这是您提供的代码和错误信息的翻译。如果需要进一步的帮助或解释,请随时提出。
<details>
<summary>英文:</summary>
Following the method suggested in [this][1] 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:
```java
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
答案1
得分: 1
你可能选择了错误的静态导入:
import static com.tngtech.archunit.core.domain.JavaAccess.Predicates.target;
(它返回一个 DescribedPredicate<JavaAccess<?>>)
而不是
import static com.tngtech.archunit.core.domain.JavaCall.Predicates.target;
(它返回一个 DescribedPredicate<JavaCall<?>>)。
因为 callMethodWhere 接受一个 DescribedPredicate<? super JavaMethodCall>,
而 JavaMethodCall 继承自 JavaCall,后者又继承自 JavaCodeUnitAccess,再者继承自 JavaAccess,
所以 "错误" 的 target 方法适用于 callMethodWhere,
但它的谓词只能操作 JavaAccess,它具有 name 和 owner,但没有 rawParameterTypes。
无关于你的问题:我建议将整个规则简化为:
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
)))));
}
英文:
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
)))));
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论