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