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<Attribute> {
    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")) return n.substring("get".length());
    29              if (n.startsWith("is")) return n.substring("is".length());
    30              if (n.startsWith("has")) return n.substring("has".length());
    31              if (n.startsWith("uses")) return n.substring("uses".length());
    32
    33              return n;
    34          }
    35      }
    36
    37      private Attribute currObj;
    38      private MethodWrapper[] methodWrappers;
    39      private int position;
    40      private Node node;
    41
    42      private static Map<Class, MethodWrapper[]> methodCache = new HashMap<Class, MethodWrapper[]>();
    43
    44      public AttributeAxisIterator(Node contextNode) {
    45          this.node = contextNode;
    46          if (!methodCache.containsKey(contextNode.getClass())) {
    47              Method[] preFilter = contextNode.getClass().getMethods();
    48              List<MethodWrapper> postFilter = new ArrayList<MethodWrapper>();
    49              for (int i = 0; i < preFilter.length; i++) {
    50                  if (isAttributeAccessor(preFilter[i])) {
    51                      postFilter.add(new MethodWrapper(preFilter[i]));
    52                  }
    53              }
    54              methodCache.put(contextNode.getClass(), postFilter.toArray(new MethodWrapper[postFilter.size()]));
    55          }
    56          this.methodWrappers = methodCache.get(contextNode.getClass());
    57
    58          this.position = 0;
    59          this.currObj = getNextAttribute();
    60      }
    61
    62      public Attribute next() {
    63          if (currObj == null) {
    64              throw new IndexOutOfBoundsException();
    65          }
    66          Attribute ret = currObj;
    67          currObj = getNextAttribute();
    68          return ret;
    69      }
    70
    71      public boolean hasNext() {
    72          return currObj != null;
    73      }
    74
    75      public void remove() {
    76          throw new UnsupportedOperationException();
    77      }
    78
    79      private Attribute getNextAttribute() {
    80          if (position == methodWrappers.length) {
    81              return null;
    82          }
    83          MethodWrapper m = methodWrappers[position++];
    84          return new Attribute(node, m.name, m.method);
    85      }
    86
    87      protected boolean isAttributeAccessor(Method method) {
    88
    89      	String methodName = method.getName();
    90
    91          return (Integer.TYPE == method.getReturnType() || Boolean.TYPE == method.getReturnType() || String.class == method.getReturnType())
    92                  && (method.getParameterTypes().length == 0)
    93                  && (Void.TYPE != method.getReturnType())
    94                  && !methodName.startsWith("jjt")
    95                  && !methodName.equals("toString")
    96                  && !methodName.equals("getScope")
    97                  && !methodName.equals("getClass")
    98                  && !methodName.equals("getTypeNameNode")
    99                  && !methodName.equals("getImportedNameNode")
    100                 && !methodName.equals("hashCode");
    101     }
    102 }