Правило PMD XPath, которое находит методы, использующие поле класса, имя которого заранее неизвестно.

У меня есть требование искать постоянные классы JPA, которые используют атрибут JPA ID в своем методе equals(). Например, следующий класс вызовет нарушение правила 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 строк возвращают все объявления методов с именем «равно» и принимают один аргумент «объект».

В следующем разделе выбираются любые PrimaryExpressions внутри этого метода, имя которых равно имени поля, помеченного аннотацией «Id». Любая помощь?


person mjeffw    schedule 04.02.2013    source источник


Ответы (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
]

Кажется, это работает.

person mjeffw    schedule 05.02.2013