Skip to content

Commit

Permalink
Fix UseConstantAsMetricName rule - from XPath to Java
Browse files Browse the repository at this point in the history
  • Loading branch information
dykov committed Aug 21, 2024
1 parent f4ff01c commit 8f86832
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 23 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package io.github.dgroup.arch4u.pmd;

import net.sourceforge.pmd.lang.java.ast.ASTAnnotation;
import net.sourceforge.pmd.lang.java.ast.ASTMemberValuePair;
import net.sourceforge.pmd.lang.java.ast.ASTStringLiteral;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
import net.sourceforge.pmd.lang.java.types.TypeTestUtil;
import net.sourceforge.pmd.properties.PropertyDescriptor;
import net.sourceforge.pmd.properties.PropertyFactory;

import java.util.List;

public class UseConstantAsMetricName extends AbstractJavaRule {

private static final PropertyDescriptor<List<String>> METRIC_ANNOTATIONS_DESCRIPTOR =
PropertyFactory.stringListProperty("metricAnnotations")
.desc("List of the metric annotations.")
.defaultValues("io.micrometer.core.annotation.Timed")
.build();

private final List<String> metricAnnotations;

public UseConstantAsMetricName() {
definePropertyDescriptor(METRIC_ANNOTATIONS_DESCRIPTOR);
metricAnnotations = getProperty(METRIC_ANNOTATIONS_DESCRIPTOR);
}

@Override
public Object visit(ASTAnnotation annotation, Object data) {
if (isMetricAnnotation(annotation)) {
annotation.getMembers()
.map(ASTMemberValuePair::getValue)
.filter(val -> val instanceof ASTStringLiteral)
.forEach(val -> asCtx(data).addViolation(val));
}
return super.visit(annotation, data);
}

private boolean isMetricAnnotation(ASTAnnotation node) {
return metricAnnotations.stream().anyMatch(annot -> TypeTestUtil.isExactlyA(annot, node));
}
}
27 changes: 7 additions & 20 deletions src/main/resources/io/github/dgroup/arch4u/pmd/arch4u-ruleset.xml
Original file line number Diff line number Diff line change
Expand Up @@ -158,15 +158,15 @@
<priority>3</priority>
<properties>
<property name="restAnnotations"
description="List of the REST endpoint method annotations"
description="List of the REST endpoint method annotations. Use a comma (,) as a delimiter."
value="org.springframework.web.bind.annotation.GetMapping,
org.springframework.web.bind.annotation.DeleteMapping,
org.springframework.web.bind.annotation.PatchMapping,
org.springframework.web.bind.annotation.PostMapping,
org.springframework.web.bind.annotation.PutMapping,
org.springframework.web.bind.annotation.RequestMapping"/>
<property name="mandatoryAnnotations"
description="List of the mandatory metric method annotations"
description="List of the mandatory metric method annotations. Use a comma (,) as a delimiter."
value="io.micrometer.core.annotation.Timed"/>
</properties>
<example>
Expand All @@ -191,35 +191,22 @@
}
]]>
</example>
</rule><!--
</rule>

<rule name="UseConstantAsMetricName"
since="0.1.0"
language="java"
externalInfoUrl="https://github.com/dgroup/arch4u-pmd/discussions/75"
message="Use constant for metric name instead of hardcoded string literals: https://github.com/dgroup/arch4u-pmd/discussions/75"
class="net.sourceforge.pmd.lang.rule.xpath.XPathRule">
class="io.github.dgroup.arch4u.pmd.UseConstantAsMetricName">
<description>
The monitoring metric name should be provided into annotation @Timed by constant, not a hardcoded string.
</description>
<priority>3</priority>
<properties>
<property name="metricAnnotations" type="List[String]" delimiter="|"
description="List of the metric annotations"
<property name="metricAnnotations"
description="List of the metric annotations. Use a comma (,) as a delimiter."
value="io.micrometer.core.annotation.Timed"/>
<property name="version" value="2.0"/>
<property name="xpath">
<value>
<![CDATA[
//Annotation[some $annotation in $metricAnnotations satisfies pmd-java:typeIsExactly($annotation)]
[
SingleMemberAnnotation/MemberValue/PrimaryExpression/PrimaryPrefix/Literal
or
NormalAnnotation/MemberValuePairs/MemberValuePair[@Image='value']/MemberValue/PrimaryExpression/PrimaryPrefix/Literal
]
]]>
</value>
</property>
</properties>
<example>
<![CDATA[
Expand All @@ -240,7 +227,7 @@
}
]]>
</example>
</rule> -->
</rule>


<!-- Rules related to error handling --> <!--
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,15 @@
import net.sourceforge.pmd.test.SimpleAggregatorTst;

/**
* Test case for {@code UseConstantForMetricAnnotation} rule.
* Test case for {@link UseConstantAsMetricName} rule.
*
* @since 0.1.0
*/
@SuppressWarnings({"PMD.TestClassWithoutTestCases", "PMD.JUnit4TestShouldUseBeforeAnnotation"})
public final class UseConstantAsMetricNameTest extends SimpleAggregatorTst {

/*@Override
@Override
public void setUp() {
addRule("io/github/dgroup/arch4u/pmd/arch4u-ruleset.xml", "UseConstantAsMetricName");
}
*/}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,38 @@ public class Foo {
]]></code>
</test-code>

<test-code>
<description>[OK]: default annotation value</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
import io.micrometer.core.annotation.Timed;
public class Foo {
@Timed
public void bar() {
}
@Timed()
public void foo() {
}
}
]]></code>
</test-code>

<test-code>
<description>[OK]: the annotation has several params</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
import io.micrometer.core.annotation.Timed;
public class Foo {
String METRIC = "value";
@Timed(histogram=false, longTask=true, value=METRIC)
public void foo() {
}
}
]]></code>
</test-code>

</test-data>

0 comments on commit 8f86832

Please sign in to comment.