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