我有一个自定义规则,我检查某个类是否仅用于@Repository
注释类。
这是规则:
@Rule(key = QueryInNonRepositoryCheck.KEY, priority = Priority.CRITICAL, name = QueryInNonRepositoryCheck.NAME, description = QueryInNonRepositoryCheck.DESCRIPTION)
public class QueryInNonRepositoryCheck extends BaseTreeVisitor implements JavaFileScanner {
public static final String REPOSITORY_ANNOTATION = "Repository";
public static final String QUERY_CLASS = "Query";
public static final String KEY = "queryInNonRepositoryCheck";
public static final String DESCRIPTION = "be.vaph.sparta.architectuur.common.persistence.query.Query can only be used in classes annotated with @Repository.";
public static final String MESSAGE = "Query can only be used in repository classes.";
private static final RuleKey RULE_KEY = RuleKey.of(JavaExtensionRulesRepository.REPOSITORY_KEY, KEY);
public static final String NAME = "Use Query only in @Repository annotated classes.";
private JavaFileScannerContext context;
private boolean repository;
@Override
public void scanFile(@Nonnull JavaFileScannerContext javaFileScannerContext) {
this.context = javaFileScannerContext;
scan(this.context.getTree());
}
@Override public void visitAnnotation(AnnotationTree annotationTree) {
if (annotationTree.annotationType().is(Tree.Kind.IDENTIFIER)) {
IdentifierTree identifierTree = (IdentifierTree) annotationTree.annotationType();
if (REPOSITORY_ANNOTATION.equals(identifierTree.name())) {
this.repository = true;
}
}
super.visitAnnotation(annotationTree);
}
@Override
public void visitMethodInvocation(MethodInvocationTree tree) {
ExpressionTree expressionTree = tree.methodSelect();
if (!this.repository) {
if (expressionTree.is(Tree.Kind.MEMBER_SELECT)) {
MemberSelectExpressionTree memberSelectExpressionTree = (MemberSelectExpressionTree) expressionTree;
ExpressionTree expression = memberSelectExpressionTree.expression();
String query = null;
if (expression.is(Tree.Kind.MEMBER_SELECT)) {
MemberSelectExpressionTree memberSelectExpressionTree1 = (MemberSelectExpressionTree) expression;
query = memberSelectExpressionTree1.identifier().name();
} else if (expression.is(Tree.Kind.IDENTIFIER)) {
IdentifierTree identifierTree = (IdentifierTree) expression;
query = identifierTree.name();
}
if (QUERY_CLASS.equals(query)) {
this.context.addIssue(tree, RULE_KEY, MESSAGE);
}
}
}
super.visitMethodInvocation(tree);
}
}
涵盖它的JUnit测试:
public class QueryInNonRepositoryCheckTest {
@Rule
public CheckMessagesVerifierRule checkMessagesVerifierRule = new CheckMessagesVerifierRule();
@Test
public void detected() throws URISyntaxException {
// Parse a known file and use an instance of the check under test to raise the issue.
File file = new File(getClass().getResource("/QueryInNonRepositoryTestClass.java").toURI());
VisitorsBridge visitorsBridge = new VisitorsBridge(new QueryInNonRepositoryCheck());
SourceFile sourceFile = JavaAstScanner.scanSingleFile(file, visitorsBridge);
// Check the message raised by the check
this.checkMessagesVerifierRule.verify(sourceFile.getCheckMessages())
.next().atLine(8).withMessage(QueryInNonRepositoryCheck.MESSAGE)
.next().atLine(13).withMessage(QueryInNonRepositoryCheck.MESSAGE)
.next().atLine(15).withMessage(QueryInNonRepositoryCheck.MESSAGE)
.next().atLine(17).withMessage(QueryInNonRepositoryCheck.MESSAGE)
;
}
@Test
public void notDetected() throws URISyntaxException {
// Parse a known file and use an instance of the check under test to raise the issue.
File file = new File(getClass().getResource("/QueryInRepositoryTestClass.java").toURI());
VisitorsBridge visitorsBridge = new VisitorsBridge(new QueryInNonRepositoryCheck());
SourceFile sourceFile = JavaAstScanner.scanSingleFile(file, visitorsBridge);
// Check the message raised by the check
Assert.assertFalse("Geen fouten verwacht", sourceFile.hasCheckMessages());
}
}
使用这两个测试文件:
public class QueryInNonRepositoryTestClass {
public Object aMethod() {
find(
Query
.query(getPersistentType())
.eq(Rekening.PROP_HOUDER, houder)
);
find(Query.query(getPersistentType()).eq(Rekening.PROP_HOUDER, houder));
be.vaph.sparta.architectuur.common.persistence.query.Query.criteria(Individu.class);
return Query.hql("from Individu");
}
}
和
@Repository("aRepository")
public class QueryInRepositoryTestClass {
public Object aMethod() {
find(
Query
.query(getPersistentType())
.eq(Rekening.PROP_HOUDER, houder)
);
find(Query.query(getPersistentType()).eq(Rekening.PROP_HOUDER, houder));
be.vaph.sparta.architectuur.common.persistence.query.Query.criteria(Individu.class);
return Query.hql("from Individu");
}
}
在Sonar构建之后,它会报告15个规则违规。在调查这些违规行为是有效的。但是,有一个有2个故意违反规则的课程不标记为此类。
@Service("rekeningService")
public class RekeningServiceImpl implements RekeningService {
[...]
public void sonarCheckTest() {
this.rekeningRepository.find(
Query.query(Rekening.class) // should be a violation but not detected
);
this.rekeningRepository.find(Query.query(Rekening.class)); // should be a violation but not detected
Logger.getLogger("DON'T DO THIS"); // other custom rule violation, correctly detected
}
}
我们有其他自定义规则,例如。一个在使用Logger
时发出警告的,并且正确触发了这些警告。
知道可能导致这种情况的原因吗?