如何使用“javax.lang.model.element.ElementVisitor”?

时间:2009-12-14 13:10:36

标签: java annotations

我尝试使用java注释处理器并尝试理解“javax.lang.model”中类的用法。对于我所阅读的内容,我认为ElementVisitor是作为使用该模型的主要方式。但我不明白如何正确使用它。

我知道访客模式。到目前为止,我已经用它来避免迭代元素的子元素(以及子元素的子元素......)并避免丑陋的“instanceof”测试。但这位访客似乎有所不同。如果我在模型元素上调用“accept”,它不会访问子元素,只会访问元素本身。

有人可以就如何使用API​​提供帮助吗?

我找到了以下链接:http://www.cs.bgu.ac.il/~gwiener/programming/visitors-galore/#more-113。但是在另一个内部使用另一个访客...只是感觉不对!?

修改:为了更容易理解问题,我从上面的链接中复制代码。以下代码似乎并不“正确”。我无法相信官方java API是以这种方式设计的。但是如何正确使用ElementVisitor?

tElem.accept(new SimpleElementVisitor6<Void, ...>() {
  public Void visitType(TypeElement e, ...) {
    for (Element tSubElem : e.getEnclosedElements()) {
      tSubElem.accept(new SimpleElementVisitor6<AssocEndSpec, ...>() {
        public AssocEndSpec visitExecutable(ExecutableElement ex, ...) {
          TypeMirror tRetTypeMirror = ex.getReturnType();
          tRetTypeMirror.accept(new SimpleTypeVisitor6<TypeElement, TypeElement>() {
            public TypeElement visitDeclared(DeclaredType t, TypeElement enclose) {
              for (TypeMirror tTypeArgMirror : t.getTypeArguments()) {
                tTypeArgMirror.accept(new SimpleTypeVisitor6<TypeElement, ...>() {
                  public TypeElement visitDeclared(DeclaredType t, TypeElement self) {
                    TypeElement tArgTypeElem = (TypeElement) t.asElement();
                    if (!self.equals(tArgTypeElem)) {
                      // found the little bugger!
                    }
                  }
                }, ...);
              }
            }
          }, ...);
        }
    }, ...);
  }
}, ...);

2 个答案:

答案 0 :(得分:4)

此代码是bollocks。

看看javax.lang.model.util.ElementKindVisitor6javax.lang.model.util.ElementScanner6,他们可能会做什么。无论如何,您应该能够获取他们的资源并根据您的需求进行调整。

NB:如果说,是的,我也会说ElementVisitor是一个相当奇怪的访问者实现。

答案 1 :(得分:0)

我遇到了同样的问题,javax.lang.model.util.ElementScanner9是我想要的。引用有关ElementScanner9(强调我的)的javdoc:

  

此类中的visitXYZ方法通过扫描其组成元素   对其周围的元素,参数等进行调用扫描,如下   在各个方法规范中指明

由于这些访问者实现的示例在互联网上都很稀少,因此,我编写了使其能够运行的代码(问题是获取给定类的所有字段):


import java.util.ArrayList;
import java.util.List;

import javax.lang.model.element.VariableElement;
import javax.lang.model.util.ElementScanner9;

/**
 * visitor which collects all the fields of a class
 * 
 * <pre>{@code
 *  TypeElement t = ...;
 *  List<VariableElement> fields = t.accept(new FieldElementVisitor(), null);
 * }</pre>
 *
 * @param <P>
 */
public class FieldElementVisitor<P> extends ElementScanner9<List<VariableElement>, P>{

    protected List<VariableElement> variables;

    public FieldElementVisitor() {
        super(new ArrayList<>());
        this.variables = this.DEFAULT_VALUE;
    }

    @Override
    public List<VariableElement> visitVariable(VariableElement e, P p) {
        if (isVariableAClassField(e)) { //to implement
            this.variables.add(e);
        }
        return this.variables;
    }

}

这是我使用它的代码:

TypeElement classElement = ...;
List<VariableElement> fields = new FieldElementVisitor<Void>().visit(classElement);

在上面的示例中,我并不需要它,但是您可以自定义visitXYZ方法,并且仍然可以通过调用visit来调用其子级的super.visitXYZ方法,就像javadoc一样说(强调我)。

  

当子类覆盖visitXYZ方法时,新方法可以   使包含的元素以默认方式被扫描   调用super.visitXYZ 。以这种方式,具体的访客可以   使用以下命令控制组成元素的遍历顺序   关于附加处理;