DuckConverterFactory.java
biz/hammurapi/convert/DuckConverterFactory.java
Violations
Inspector |
Message |
Severity |
Location |
Java Inspector 048 |
Copyrights information should be present in each file. |
1 |
|
Java Inspector 086 |
Use equals() instead of == or != to compare objects. |
1 |
260:58
|
Java Inspector 086 |
Use equals() instead of == or != to compare objects. |
1 |
265:58
|
Java Inspector 049 |
Use a Collection instead of arrays Object[] |
2 |
47:17
|
Java Inspector 049 |
Use a Collection instead of arrays Object[] |
2 |
100:39
|
Java Inspector 049 |
Use a Collection instead of arrays Object[] |
2 |
101:39
|
Java Inspector 049 |
Use a Collection instead of arrays Object[] |
2 |
176:54
|
Java Inspector 049 |
Use a Collection instead of arrays Object[] |
2 |
177:54
|
Java Inspector 049 |
Use a Collection instead of arrays Object[] |
2 |
186:62
|
Java Inspector 070-A |
Cyclomatic complexity is too high: 16, maximum allowed is 12 |
2 |
141:9
|
Java Inspector 081 |
Avoid static collections, they can grow in size over time. |
2 |
36:9
|
Java Inspector 089 |
Undocumented method |
2 |
27:17
|
Java Inspector 089 |
Undocumented constructor |
2 |
51:17
|
Java Inspector 089 |
Undocumented method |
2 |
57:17
|
Java Inspector 089 |
Undocumented method |
2 |
61:33
|
Java Inspector 089 |
Undocumented method |
2 |
66:33
|
Java Inspector 089 |
Method is not properly documented |
2 |
84:9
|
Java Inspector 089 |
Parameter sourceClass is not documented |
2 |
84:9
|
Java Inspector 089 |
Parameter targetInterface is not documented |
2 |
84:9
|
Java Inspector 089 |
Undocumented parameter theInterface |
2 |
129:9
|
Java Inspector 089 |
Undocumented parameter theClass |
2 |
129:9
|
Java Inspector 089 |
Javadoc contains tag for non-existent parameter interfaceMethods |
2 |
129:9
|
Java Inspector 089 |
Javadoc contains tag for non-existent parameter classMethods |
2 |
129:9
|
Java Inspector 089 |
Parameter subClass is not documented |
2 |
226:9
|
Java Inspector 089 |
Parameter superClass is not documented |
2 |
226:9
|
Java Inspector 089 |
Undocumented method |
2 |
231:33
|
Java Inspector 089 |
Method is not properly documented |
2 |
252:9
|
Java Inspector 089 |
Parameter cl1 is not documented |
2 |
252:9
|
Java Inspector 089 |
Parameter cl2 is not documented |
2 |
252:9
|
Java Inspector 005 |
Classes, interfaces, methods, and variables should be named according to Sun's naming conventions. |
3 |
25:9
|
Java Inspector 051 |
It is good practice to call in any case super() in a constructor. |
3 |
51:17
|
1package biz.hammurapi.convert;
2
3import java.lang.reflect.InvocationHandler;
4import java.lang.reflect.Method;
5import java.lang.reflect.Proxy;
6import java.util.ArrayList;
7import java.util.Collection;
8import java.util.HashMap;
9import java.util.Map;
10
11import biz.hammurapi.util.ClassHierarchyVisitable;
12import biz.hammurapi.util.Visitor;
13
14
15
16
17
18
19
20public class DuckConverterFactory {
21
22
23
24
25 private static ConverterClosure ZERO_CONVERTER = new ConverterClosure() {
26
27 public Object convert(Object source) {
28 return source;
29 }
30
31 };
32
33
34
35
36 private static Map converterMap = new HashMap();
37
38 private static class ProxyConverter implements ConverterClosure {
39
40
41
42
43
44
45 private Map methodMap;
46
47 private Class[] targetInterfaces;
48
49 private ClassLoader classLoader;
50
51 public ProxyConverter(Class targetInterface, Map methodMap, ClassLoader classLoader) {
52 this.methodMap = methodMap;
53 this.targetInterfaces = new Class[] {targetInterface};
54 this.classLoader = classLoader;
55 }
56
57 public Object convert(final Object source) {
58
59 InvocationHandler ih = new FilterInvocationHandler() {
60
61 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
62 Method sourceMethod = (Method) (methodMap==null ? null : methodMap.get(method));
63 return sourceMethod==null ? method.invoke(source, args) : sourceMethod.invoke(source, args);
64 }
65
66 public Object getMaster() {
67 return source;
68 }
69
70 };
71
72 return Proxy.newProxyInstance(classLoader, targetInterfaces, ih);
73 }
74
75 }
76
77
78
79
80
81
82
83
84 public static ConverterClosure getConverter(Class sourceClass, Class targetInterface, boolean lenient) {
85 if (targetInterface.isAssignableFrom(sourceClass)) {
86 return ZERO_CONVERTER;
87 }
88
89 Collection key=new ArrayList();
90 key.add(sourceClass);
91 key.add(targetInterface);
92 key.add(lenient ? Boolean.TRUE : Boolean.FALSE);
93 synchronized (converterMap) {
94 Object value = converterMap.get(key);
95 if (Boolean.FALSE.equals(value)) {
96 return null;
97 }
98
99 if (value==null) {
100 Method[] targetMethods = targetInterface.getMethods();
101 Method[] sourceMethods = sourceClass.getMethods();
102 Map methodMap = new HashMap();
103
104 if (!(duckMap(targetMethods, sourceMethods, methodMap) || lenient)) {
105 converterMap.put(key, Boolean.FALSE);
106 return null;
107 }
108
109 ClassLoader cl = getChildClassLoader(sourceClass.getClassLoader(), targetInterface.getClassLoader());
110 if (cl==null) {
111 converterMap.put(key, Boolean.FALSE);
112 return null;
113 }
114
115 value = new ProxyConverter(targetInterface, methodMap.isEmpty() ? null : methodMap, cl);
116 converterMap.put(key, value);
117 }
118 return (ConverterClosure) value;
119 }
120 }
121
122
123
124
125
126
127
128
129 public static boolean duckMap(Class theInterface, Class theClass, Map methodMap) {
130 return duckMap(theInterface.getMethods(), theClass.getMethods(), methodMap);
131 }
132
133
134
135
136
137
138
139
140
141 public static boolean duckMap(Method[] interfaceMethods, Method[] classMethods, Map methodMap) {
142 boolean ret = true;
143
144 Z:
145 for (int i=0, l=interfaceMethods.length; i<l; ++i) {
146 if (interfaceMethods[i] == null) {
147 continue;
148 }
149
150 if (Object.class.equals(interfaceMethods[i].getDeclaringClass())) {
151 continue;
152 }
153
154 Method targetMethod = interfaceMethods[i];
155 int candidateIndex=-1;
156 Method candidateMethod = null;
157
158 Y:
159 for (int j=0, m=classMethods.length; j<m; ++j) {
160 Method sourceMethod = classMethods[j];
161 if (sourceMethod!=null) {
162 if (targetMethod.equals(sourceMethod)) {
163 continue Z;
164 }
165
166 if (targetMethod.getName().equals(sourceMethod.getName())
167 && targetMethod.getParameterTypes().length == sourceMethod.getParameterTypes().length) {
168
169
170
171 if (!(targetMethod.getReturnType().isAssignableFrom(sourceMethod.getReturnType())
172 || void.class.equals(targetMethod.getReturnType()))) {
173 continue;
174 }
175
176 Class[] targetParameterTypes = targetMethod.getParameterTypes();
177 Class[] sourceParameterTypes = sourceMethod.getParameterTypes();
178 for (int k=0, n=targetParameterTypes.length; k<n; ++k) {
179 if (!sourceParameterTypes[k].isAssignableFrom(targetParameterTypes[k])) {
180 continue Y;
181 }
182 }
183
184 if (candidateMethod!=null) {
185
186 Class[] candidateParameterTypes = candidateMethod.getParameterTypes();
187 for (int k=0, n=sourceParameterTypes.length; k<n; ++k) {
188 Integer oldAffinity = classAffinity(targetParameterTypes[k], candidateParameterTypes[k]);
189 Integer newAffinity = classAffinity(targetParameterTypes[k], sourceParameterTypes[k]);
190 if (oldAffinity!=null && (newAffinity==null || oldAffinity.intValue()<newAffinity.intValue())) {
191 continue Y;
192 }
193 }
194
195 Integer oldAffinity = classAffinity(candidateMethod.getReturnType(), targetMethod.getReturnType());
196 Integer newAffinity = classAffinity(sourceMethod.getReturnType(), targetMethod.getReturnType());
197 if (oldAffinity!=null && (newAffinity==null || oldAffinity.intValue()<newAffinity.intValue())) {
198 continue;
199 }
200
201 classMethods[candidateIndex] = candidateMethod;
202 }
203
204 candidateMethod=sourceMethod;
205 candidateIndex=j;
206 }
207 }
208 }
209
210 ret = false;
211 if (candidateMethod!=null) {
212 methodMap.put(targetMethod, candidateMethod);
213 interfaceMethods[i] = null;
214 }
215
216 }
217 return ret;
218 }
219
220
221
222
223
224
225
226 public static Integer classAffinity(Class subClass, final Class superClass) {
227 if (superClass.isAssignableFrom(subClass)) {
228 final int[] caffinity={0};
229 new ClassHierarchyVisitable(subClass).accept(new Visitor() {
230
231 public boolean visit(Object target) {
232 if (target.equals(superClass)) {
233 return false;
234 }
235
236 caffinity[0]++;
237 return true;
238 }
239
240 });
241 return new Integer(caffinity[0]);
242 }
243
244 return null;
245 }
246
247
248
249
250
251
252 public static ClassLoader getChildClassLoader(ClassLoader cl1, ClassLoader cl2) {
253
254 if (cl1==null) {
255 return cl2;
256 }
257 if (cl2==null) {
258 return cl1;
259 }
260 for (ClassLoader cl = cl1; cl!=null && cl!=cl.getParent(); cl=cl.getParent()) {
261 if (cl2.equals(cl)) {
262 return cl1;
263 }
264 }
265 for (ClassLoader cl = cl2; cl!=null && cl!=cl.getParent(); cl=cl.getParent()) {
266 if (cl1.equals(cl)) {
267 return cl2;
268 }
269 }
270 return null;
271 }
272
273}
274