Inspector | Message | Severity | Location |
---|---|---|---|
Java Inspector 048 | Copyrights information should be present in each file. | 1 | |
Java Inspector 049 | Use a Collection instead of arrays Object[] | 2 | 22:9 |
Java Inspector 049 | Use a Collection instead of arrays Object[] | 2 | 88:25 |
Java Inspector 049 | Use a Collection instead of arrays Object[] | 2 | 89:27 |
Java Inspector 049 | Use a Collection instead of arrays Object[] | 2 | 123:26 |
Java Inspector 068 | Do not use System.out and System.err to output logging messages. Use loggers instead. | 2 | 164:35 |
Java Inspector 068 | Do not use System.out and System.err to output logging messages. Use loggers instead. | 2 | 174:35 |
Java Inspector 070-A | Cyclomatic complexity is too high: 20, maximum allowed is 12 | 2 | 81:9 |
Java Inspector 082 | Parenthesis are redundant. | 2 | 93:38 |
Java Inspector 082 | Parenthesis are redundant. | 2 | 98:45 |
Java Inspector 089 | Undocumented constructor | 2 | 27:9 |
Java Inspector 089 | Constructor is not properly documented | 2 | 40:9 |
Java Inspector 089 | Constructor is not properly documented | 2 | 48:9 |
Java Inspector 089 | Undocumented parameter trace | 2 | 57:9 |
Java Inspector 089 | Undocumented parameter parentMap | 2 | 57:9 |
Java Inspector 089 | Undocumented method | 2 | 65:9 |
Java Inspector 089 | Undocumented method | 2 | 81:9 |
Java Inspector 089 | Parameter field is not documented | 2 | 163:9 |
Java Inspector 089 | Parameter e is not documented | 2 | 163:9 |
Java Inspector 089 | Parameter method is not documented | 2 | 173:9 |
Java Inspector 089 | Parameter e is not documented | 2 | 173:9 |
Java Inspector 089 | Parameter child is not documented | 2 | 185:9 |
Java Inspector 089 | Method return value is not properly documented | 2 | 185:9 |
Java Inspector 089 | Method is not properly documented | 2 | 198:9 |
Java Inspector 089 | Undocumented parameter obj | 2 | 198:9 |
Java Inspector 089 | Method is not properly documented | 2 | 219:9 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 32:55 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 33:34 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 69:53 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 69:74 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 73:69 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 100:72 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 164:36 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 174:36 |
Java Inspector 051 | It is good practice to call in any case super() in a constructor. | 3 | 27:9 |
Java Inspector 051 | It is good practice to call in any case super() in a constructor. | 3 | 40:9 |
Java Inspector 051 | It is good practice to call in any case super() in a constructor. | 3 | 48:9 |
Java Inspector 051 | It is good practice to call in any case super() in a constructor. | 3 | 57:9 |
1package biz.hammurapi.util;
2
3import java.lang.reflect.Field;
4import java.lang.reflect.Method;
5import java.lang.reflect.Modifier;
6import java.util.Arrays;
7import java.util.Collection;
8import java.util.HashMap;
9import java.util.Iterator;
10import java.util.LinkedList;
11import java.util.Map;
12
13/**
14 * Wraps bean into visitable. Children are inferred from: <UL> <LI>getXXX methods which <UL><LI>Are declared in classes which belong to one of root packages or its sub-packages
15 * </LI><LI>Have return type either collection or class (including arrays) belonging to one of root packages or its subpackages.</LI></UL>
16 * <LI>Public fields of type belonging to one of root packages or subpackages (including arrays) or of collection type.</LI></UL>
17 * @author Pavel Vlasov
18 */
19public class BeanVisitable implements Visitable {
20
21 private Object bean;
22 private String[] rootPackages;
23 private Map trace;
24 private Map parentMap;
25 private Integer identity;
26
27 public BeanVisitable(Object bean) {
28 this(bean, packageName(bean.getClass()));
29 }
30
31 private static String packageName(Class clazz) {
32 int idx = clazz.getName().lastIndexOf(".");
33 return idx==-1 ? "" : clazz.getName().substring(0, idx);
34 }
35
36 /**
37 * @param bean Bean to visit
38 * @param rootPackage Package for child classes to visit.
39 */
40 public BeanVisitable(Object bean, String rootPackage) {
41 this(bean, new String[] {rootPackage});
42 }
43
44 /**
45 * @param bean Bean to visit
46 * @param rootPackages Packages for child classes to visit.
47 */
48 public BeanVisitable(Object bean, String[] rootPackages) {
49 this(bean, rootPackages, new HashMap(), new HashMap());
50 }
51
52 /**
53 * This constructor is used by BeanVisitable itself to wrap children into visitable.
54 * @param bean Bean to visit
55 * @param rootPackages Package for child classes to visit.
56 */
57 protected BeanVisitable(Object bean, String[] rootPackages, Map trace, Map parentMap) {
58 this.bean = bean;
59 this.rootPackages = rootPackages;
60 this.trace = trace;
61 this.parentMap = parentMap;
62 this.identity = new Integer(System.identityHashCode(bean));
63 }
64
65 protected boolean inTheRightPackage(Class clazz) {
66 String name = clazz.getName();
67 for (int i=0; i<rootPackages.length; ++i) {
68 if (clazz.isArray()) {
69 if (name.startsWith("[L"+rootPackages[i]+".")) {
70 return true;
71 }
72 } else {
73 if (name.startsWith(rootPackages[i]+".")) {
74 return true;
75 }
76 }
77 }
78 return false;
79 }
80
81 public boolean accept(Visitor visitor) {
82 if (trace.containsKey(identity)) {
83 return false;
84 }
85 trace.put(identity, bean);
86 if (visitor.visit(bean)) {
87 Class beanClass=bean.getClass();
88 final Object[] args = new Object[] {};
89 Method[] methods = beanClass.getMethods();
90 for (int i=0; i<methods.length; i++) {
91 // getXXX() methods. Object.getClass() is not included.
92 Method method = methods[i];
93 if (!(void.class.equals(method.getReturnType()))
94 && (inTheRightPackage(method.getReturnType()) || Collection.class.isAssignableFrom(method.getReturnType()))
95 && inTheRightPackage(method.getDeclaringClass())
96 && Modifier.isPublic(method.getModifiers())
97 && !Modifier.isAbstract(method.getModifiers())
98 && !(method.getDeclaringClass().equals(Object.class))
99 && !Modifier.isStatic(method.getModifiers())
100 && method.getName().startsWith("get")
101 && method.getParameterTypes().length==0) {
102 try {
103 Object value = method.invoke(bean, args);
104 if (value instanceof Collection) {
105 Iterator it = ((Collection) value).iterator();
106 while (it.hasNext()) {
107 wrap(it.next()).accept(visitor);
108 }
109 } else if (value.getClass().isArray()) {
110 Iterator it = (Arrays.asList((Object[]) value)).iterator();
111 while (it.hasNext()) {
112 wrap(it.next()).accept(visitor);
113 }
114 } else {
115 wrap(value).accept(visitor);
116 }
117 } catch (Exception e) {
118 handleAccessError(method, e);
119 }
120 }
121 }
122
123 Field[] fields = beanClass.getFields();
124 for (int i=0; i<fields.length; i++) {
125 Field field = fields[i];
126 if (!Modifier.isStatic(field.getModifiers())
127 && Modifier.isPublic(field.getModifiers())
128 && inTheRightPackage(field.getDeclaringClass())
129 && (inTheRightPackage(field.getType()) || Collection.class.isAssignableFrom(field.getType()))) {
130 try {
131 Object value = field.get(bean);
132 if (value instanceof Collection) {
133 Iterator it = ((Collection) value).iterator();
134 while (it.hasNext()) {
135 wrap(it.next()).accept(visitor);
136 }
137 } else if (value.getClass().isArray()) {
138 Iterator it = (Arrays.asList((Object[]) value)).iterator();
139 while (it.hasNext()) {
140 wrap(it.next()).accept(visitor);
141 }
142 } else {
143 wrap(value).accept(visitor);
144 }
145 } catch (Exception e) {
146 handleAccessError(fields[i], e);
147 }
148 }
149 }
150
151 if (visitor instanceof PoliteVisitor) {
152 ((PoliteVisitor) visitor).leave(bean);
153 }
154 }
155 return false;
156 }
157
158 /**
159 * Prints stack trace to System.err. Override if necessary
160 * @param field
161 * @param e
162 */
163 protected void handleAccessError(Field field, Exception e) {
164 System.err.println("Error accessing field "+field);
165 e.printStackTrace();
166 }
167
168 /**
169 * Prints stack trace to System.err. Override if necessary
170 * @param method
171 * @param e
172 */
173 protected void handleAccessError(Method method, Exception e) {
174 System.err.println("Error accessing method "+method);
175 e.printStackTrace();
176 }
177
178 /**
179 * Wraps child into Visitable and updates path.
180 * If child is already instance of Visitable it is returned as is and path is not
181 * updated.
182 * @param child
183 * @return
184 */
185 protected Visitable wrap(Object child) {
186 if (child instanceof Visitable) {
187 return (Visitable) child;
188 }
189
190 BeanVisitable ret = new BeanVisitable(child, rootPackages, trace, parentMap);
191 parentMap.put(ret.identity, identity);
192 return ret;
193 }
194
195 /**
196 * @return Path from given object to the root of the model, the given object included.
197 */
198 public Object[] getPath(Object obj) {
199 LinkedList path = new LinkedList();
200 fillPath(path, obj);
201 return path.toArray();
202 }
203
204 private void fillPath(LinkedList path, Object obj) {
205 path.addFirst(obj);
206 Object parentKey = parentMap.get(new Integer(System.identityHashCode(obj)));
207 if (parentKey!=null) {
208 Object parent = trace.get(parentKey);
209 if (parent!=null) {
210 fillPath(path, parent);
211 }
212 }
213
214 }
215
216 /**
217 * @return System hash code of underlying bean
218 */
219 public Integer getIdentity() {
220 return identity;
221 }
222
223}
224
225