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 }