View Javadoc

    1   /***
    2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
    3    */
    4   package net.sourceforge.pmd.jaxen;
    5
    6   import net.sourceforge.pmd.ast.Node;
    7
    8   import java.lang.reflect.Method;
    9   import java.util.ArrayList;
    10  import java.util.HashMap;
    11  import java.util.Iterator;
    12  import java.util.List;
    13  import java.util.Map;
    14
    15  public class AttributeAxisIterator implements Iterator {
    16
    17      private static class MethodWrapper {
    18          public Method method;
    19          public String name;
    20
    21          public MethodWrapper(Method m) {
    22              this.method = m;
    23              this.name = truncateMethodName(m.getName());
    24          }
    25
    26          private String truncateMethodName(String n) {
    27              // about 70% of the methods start with 'get', so this case goes first
    28              if (n.startsWith("get")) {
    29                  n = n.substring("get".length());
    30              } else if (n.startsWith("is")) {
    31                  n = n.substring("is".length());
    32              } else if (n.startsWith("has")) {
    33                  n = n.substring("has".length());
    34              } else if (n.startsWith("uses")) {
    35                  n = n.substring("uses".length());
    36              }
    37              return n;
    38          }
    39      }
    40
    41      private Object currObj;
    42      private MethodWrapper[] methodWrappers;
    43      private int position;
    44      private Node node;
    45
    46      private static Map methodCache = new HashMap();
    47
    48      public AttributeAxisIterator(Node contextNode) {
    49          this.node = contextNode;
    50          if (!methodCache.containsKey(contextNode.getClass())) {
    51              Method[] preFilter = contextNode.getClass().getMethods();
    52              List postFilter = new ArrayList();
    53              for (int i = 0; i < preFilter.length; i++) {
    54                  if (isAttribute(preFilter[i])) {
    55                      postFilter.add(new MethodWrapper(preFilter[i]));
    56                  }
    57              }
    58              methodCache.put(contextNode.getClass(), (MethodWrapper[]) postFilter.toArray(new MethodWrapper[postFilter.size()]));
    59          }
    60          this.methodWrappers = (MethodWrapper[]) methodCache.get(contextNode.getClass());
    61
    62          this.position = 0;
    63          this.currObj = getNextAttribute();
    64      }
    65
    66      public Object next() {
    67          if (currObj == null) {
    68              throw new IndexOutOfBoundsException();
    69          }
    70          Object ret = currObj;
    71          currObj = getNextAttribute();
    72          return ret;
    73      }
    74
    75      public boolean hasNext() {
    76          return currObj != null;
    77      }
    78
    79      public void remove() {
    80          throw new UnsupportedOperationException();
    81      }
    82
    83      private Attribute getNextAttribute() {
    84          if (position == methodWrappers.length) {
    85              return null;
    86          }
    87          MethodWrapper m = methodWrappers[position];
    88          position++;
    89          return new Attribute(node, m.name, m.method);
    90      }
    91
    92      protected boolean isAttribute(Method method) {
    93          return (Integer.TYPE == method.getReturnType() || Boolean.TYPE == method.getReturnType() || String.class == method.getReturnType())
    94                  && (method.getParameterTypes().length == 0)
    95                  && (Void.TYPE != method.getReturnType())
    96                  && !method.getName().startsWith("jjt")
    97                  && !method.getName().equals("toString")
    98                  && !method.getName().equals("getScope")
    99                  && !method.getName().equals("getClass")
    100                 && !method.getName().equals("getTypeNameNode")
    101                 && !method.getName().equals("getImportedNameNode")
    102                 && !method.getName().equals("hashCode");
    103     }
    104 }