PMD XPath规则,用于查找使用名称未提前知道的类字段的方法

时间:2013-02-04 21:00:31

标签: xpath pmd

我需要查找在其equals()方法中使用JPA ID属性的JPA持久化类。例如,以下类将触发PMD规则违规:

@Entity
public class Foo
{
   @Id
   private long id;

   public boolean equals(Object o)
   {
      if (o.getClass().equals(Foo.class)) {
         Foo other = (Foo) o;
         return o.id == id;
      }
      return false;
   }
}

我知道如何使这个查询的各个部分工作,但不知道如何将它组合在一起。所以,例如,我知道如何找到JPA持久化类(假设使用JPA注释):

//ClassOrInterfaceDeclaration/../Annotation/MarkerAnnotation/Name[@Image='Entity']

我知道如何找到使用JPA ID注释注释的字段的声明:

//FieldDeclaration[../Annotation/MarkerAnnotation/Name[@Image='Id']]

同样,我可以在equals()方法中找到一个引用名为'id'的字段的表达式:

//MethodDeclaration[
  ./MethodDeclarator[@Image='equals'] and
  ./MethodDeclarator/FormalParameters[1]/FormalParameter/Type/ReferenceType/ClassOrInterfaceType[@Image='Object']
]
/Block//PrimaryExpression/PrimaryPrefix/Name[@Image='id']

我遇到的麻烦是使用表达式查找用@Id注释标记的字段的名称,并在谓词中使用它来查找使用该字段的equals()方法中的行。

这是我对查询的最佳猜测,但它不返回任何节点:

//MethodDeclaration[
  ./MethodDeclarator[@Image='equals'] 
  and
  //MethodDeclarator[count(./FormalParameters)=1]
  and
  ./MethodDeclarator/FormalParameters[1]/FormalParameter/Type/ReferenceType/ClassOrInterfaceType[@Image='Object']
]
/Block//PrimaryExpression/Name[
  @Image=ancestor::ClassOrInterfaceDeclaration//FieldDeclaration[
  ../Annotation/MarkerAnnotation/Name/@Image='Id']/VariableDeclarator/VariableDeclaratorId/@Image
]

前7行返回所有名称为“equals”的MethodDeclarations,并采用单个“Object”参数。

下一部分选择该方法中的任何PrimaryExpressions,其Name等于使用“Id”注释注释的字段的名称。 有什么帮助吗?

1 个答案:

答案 0 :(得分:1)

好的,我已经弄清楚了......这是我提出的解决方案:

//MethodDeclaration[
  MethodDeclarator[
    count(FormalParameters/FormalParameter)=1 and
    @Image='equals' and
    FormalParameters/FormalParameter[1]/Type/ReferenceType/ClassOrInterfaceType[@Image='Object']
  ]
]
/Block//PrimaryExpression[
  PrimaryPrefix/@Image=
    ancestor::ClassOrInterfaceDeclaration//FieldDeclaration[
      ../Annotation/MarkerAnnotation/Name/@Image='Id'
    ] /VariableDeclarator/VariableDeclaratorId/@Image
  or
  PrimarySuffix/@Image=
    ancestor::ClassOrInterfaceDeclaration//FieldDeclaration[
      ../Annotation/MarkerAnnotation/Name/@Image='Id'
    ] /VariableDeclarator/VariableDeclaratorId/@Image
]

似乎有效。