KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > directwebremoting > extend > TypeHintContext


1 /*
2  * Copyright 2005 Joe Walker
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.directwebremoting.extend;
17
18 import java.lang.reflect.Method JavaDoc;
19 import java.util.ArrayList JavaDoc;
20 import java.util.Iterator JavaDoc;
21 import java.util.List JavaDoc;
22
23 import org.directwebremoting.util.LocalUtil;
24 import org.directwebremoting.util.Logger;
25
26 /**
27  * Something to hold the method, paramNo and index together as an object
28  * that can be a key in a Map.
29  * @author Joe Walker [joe at getahead dot ltd dot uk]
30  */

31 public class TypeHintContext
32 {
33     /**
34      * External setup this object
35      * @param converterManager For when we can't work out the parameterized type info
36      * @param method The method to annotate
37      * @param parameterNumber The number of the parameter to edit (counts from 0)
38      */

39     public TypeHintContext(ConverterManager converterManager, Method JavaDoc method, int parameterNumber)
40     {
41         if (method == null)
42         {
43             throw new IllegalArgumentException JavaDoc("The method can not be null");
44         }
45
46         this.converterManager = converterManager;
47         this.method = method;
48         this.parameterNumber = parameterNumber;
49
50         // Type[] types = method.getGenericParameterTypes();
51
Object JavaDoc[] types = (Object JavaDoc[]) LocalUtil.invoke(method, getGenericParameterTypesMethod, new Object JavaDoc[0]);
52
53         if (types != null)
54         {
55             if (parameterNumber >= types.length)
56             {
57                 throw new IllegalArgumentException JavaDoc("parameterNumber=" + parameterNumber + " is too big when method=" + method.getName() + " returns genericParameterTypes.length=" + types.length);
58             }
59
60             this.parameterType = types[parameterNumber];
61         }
62         else
63         {
64             this.parameterType = null;
65         }
66
67         parameterNumberTree = new ArrayList JavaDoc();
68         parameterTypeTree = new ArrayList JavaDoc();
69     }
70
71     /**
72      * Internal setup for nested object
73      * @param manager For when we can't work out the parameterized type info
74      * @param method The method to annotate
75      * @param parameterNumber The number of the parameter to edit (counts from 0)
76      * @param parameterType The Type for this context
77      */

78     private TypeHintContext(ConverterManager manager, Method JavaDoc method, int parameterNumber, Object JavaDoc/*Type*/ parameterType)
79     {
80         this.converterManager = manager;
81         this.method = method;
82         this.parameterNumber = parameterNumber;
83         this.parameterType = parameterType;
84
85         parameterNumberTree = new ArrayList JavaDoc();
86         parameterTypeTree = new ArrayList JavaDoc();
87     }
88
89     /**
90      * Create a child TypeHintContext based on this one
91      * @param newParameterNumber The index of the item between < and >.
92      * @return a new TypeHintContext
93      */

94     public TypeHintContext createChildContext(int newParameterNumber)
95     {
96         Object JavaDoc/*Type*/ childType = null;
97
98         if (isGenericsSupported)
99         {
100             //if (parameterType instanceof ParameterizedType)
101
if (parameterizedTypeClass.isInstance(parameterType))
102             {
103                 Object JavaDoc/*Type*/ ptype = /*(Type)*/ parameterType;
104                 // Type[] rawParams = ptype.getActualTypeArguments();
105
Object JavaDoc[] actualTypeArguments = (Object JavaDoc[]) LocalUtil.invoke(ptype, getActualTypeArgumentsMethod, new Object JavaDoc[0]);
106
107                 if (newParameterNumber >= actualTypeArguments.length)
108                 {
109                     throw new IllegalArgumentException JavaDoc("newParameterNumber=" + newParameterNumber + " is too big when parameterType=" + parameterType + " give actualTypeArguments.length=" + actualTypeArguments.length);
110                 }
111
112                 childType = actualTypeArguments[newParameterNumber];
113             }
114         }
115
116         TypeHintContext child = new TypeHintContext(converterManager, this.method, this.parameterNumber, childType);
117
118         child.parameterNumberTree.addAll(this.parameterNumberTree);
119         child.parameterNumberTree.add(new Integer JavaDoc(newParameterNumber));
120
121         child.parameterTypeTree.addAll(parameterTypeTree);
122         child.parameterTypeTree.add(parameterType);
123
124         return child;
125     }
126
127     /**
128      * Find the parameterized type information for this parameter either using
129      * JDK5 introspection or
130      * @return The extra type information for this context
131      */

132     public Class JavaDoc getExtraTypeInfo()
133     {
134         Class JavaDoc type = null;
135
136         if (converterManager != null)
137         {
138             type = converterManager.getExtraTypeInfo(this);
139             if (type != null)
140             {
141                 log.debug("Using type info from <signature> " + toString() + " of " + type);
142                 return type;
143             }
144         }
145
146         if (isGenericsSupported)
147         {
148             //if (parameterType instanceof ParameterizedType)
149
if (parameterizedTypeClass.isInstance(parameterType))
150             {
151                 Object JavaDoc/*Type*/ ptype = /*(Type)*/ parameterType;
152                 // Type rawType = ptype.getRawType();
153
Object JavaDoc rawType = LocalUtil.invoke(ptype, getRawTypeMethod, new Object JavaDoc[0]);
154
155                 if (rawType instanceof Class JavaDoc)
156                 {
157                     type = (Class JavaDoc) rawType;
158                     log.debug("Using type info from JDK5 ParameterizedType of " + type.getName() + " for " + toString());
159                     return type;
160                 }
161             }
162             else if (parameterType instanceof Class JavaDoc)
163             {
164                 type = (Class JavaDoc) parameterType;
165                 log.debug("Using type info from JDK5 reflection of " + type.getName() + " for " + toString());
166                 return type;
167             }
168         }
169
170         log.warn("Missing type info for " + toString() + ". Assuming this is a map with String keys. Please add to <signatures> in dwr.xml");
171         return String JavaDoc.class;
172     }
173
174     /* (non-Javadoc)
175      * @see java.lang.Object#hashCode()
176      */

177     public int hashCode()
178     {
179         return method.hashCode() + parameterNumber + parameterNumberTree.hashCode();
180     }
181
182     /* (non-Javadoc)
183      * @see java.lang.Object#equals(java.lang.Object)
184      */

185     public boolean equals(Object JavaDoc obj)
186     {
187         if (obj == null)
188         {
189             return false;
190         }
191
192         if (!this.getClass().equals(obj.getClass()))
193         {
194             return false;
195         }
196
197         if (obj == this)
198         {
199             return true;
200         }
201
202         TypeHintContext that = (TypeHintContext) obj;
203
204         if (!this.method.equals(that.method))
205         {
206             return false;
207         }
208
209         if (this.parameterNumber != that.parameterNumber)
210         {
211             return false;
212         }
213
214         return this.parameterNumberTree.equals(that.parameterNumberTree);
215     }
216
217     /* (non-Javadoc)
218      * @see java.lang.Object#toString()
219      */

220     public String JavaDoc toString()
221     {
222         if (cachedToString == null)
223         {
224             StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
225
226             buffer.append(method.getName());
227             buffer.append('(');
228             buffer.append(parameterNumber);
229
230             for (Iterator JavaDoc it = parameterNumberTree.iterator(); it.hasNext();)
231             {
232                 buffer.append('<');
233                 buffer.append(it.next());
234             }
235             for (Iterator JavaDoc it = parameterNumberTree.iterator(); it.hasNext();)
236             {
237                 buffer.append('>');
238                 it.next();
239             }
240
241             buffer.append(')');
242
243             cachedToString = buffer.toString();
244         }
245
246         return cachedToString;
247     }
248
249     /**
250      * When we can't work out a parameterized type, then we can ask here
251      */

252     private ConverterManager converterManager;
253
254     /**
255      * Calculating toString could be costly, so we cache it
256      */

257     private String JavaDoc cachedToString = null;
258
259     /**
260      * The method that the conversion is happening for
261      */

262     private final Method JavaDoc method;
263
264     /**
265      * The parameter of the method that the conversion is happening for
266      */

267     private final int parameterNumber;
268
269     /**
270      * The type parameter of the method that the conversion is happening for
271      */

272     private final Object JavaDoc/*Type*/ parameterType;
273
274     /**
275      * The list of generic parameters that we have dug into
276      */

277     private final List JavaDoc parameterNumberTree;
278
279     /**
280      * The list of generic parameters that we have dug into
281      */

282     private final List JavaDoc parameterTypeTree;
283
284     /**
285      * The log stream
286      */

287     private static final Logger log = Logger.getLogger(TypeHintContext.class);
288
289     /**
290      * We have to use ParameterizedType through reflection since we work on JDK 1.3
291      */

292     private static final Class JavaDoc parameterizedTypeClass;
293
294     /**
295      * We have to execute getGenericParameterTypes() through reflection too
296      */

297     private static final Method JavaDoc getGenericParameterTypesMethod;
298
299     /**
300      * We have to execute getActualTypeArguments() through reflection too
301      */

302     private static final Method JavaDoc getActualTypeArgumentsMethod;
303
304     /**
305      * We have to execute getRawType() through reflection too
306      */

307     private static final Method JavaDoc getRawTypeMethod;
308
309     /**
310      * Can we use generic type info?
311      */

312     private static final boolean isGenericsSupported;
313
314     static
315     {
316         // This is one of those times when you really wish you were in a
317
// dynamic language ...
318

319         // This may seem like a lot of bother just to call Class forName() a
320
// couple of times, however it is complex because the fields are final
321
// so we can only set them once
322
int failures = 0;
323
324         Class JavaDoc tempParameterizedTypeClass;
325         try
326         {
327             tempParameterizedTypeClass = LocalUtil.classForName("java.lang.reflect.ParameterizedType");
328             log.debug("JDK1.5 reflection available.");
329         }
330         catch (Exception JavaDoc ex)
331         {
332             tempParameterizedTypeClass = null;
333             log.debug("JDK1.5 reflection not available. Generic parameters must use <signatures>.");
334             failures++;
335         }
336
337         Method JavaDoc tempGetGenericParameterTypesMethod = null;
338         try
339         {
340             tempGetGenericParameterTypesMethod = Method JavaDoc.class.getDeclaredMethod("getGenericParameterTypes", new Class JavaDoc[0]);
341         }
342         catch (Exception JavaDoc ex)
343         {
344             log.debug("Error finding Method.getGenericParameterTypes(): JDK1.5 reflection not available.");
345             failures++;
346         }
347         catch (Error JavaDoc er)
348         {
349             // TODO: remove this error trapping - it's just here to debug a WL issue
350
log.error("If you see this stack trace please report it to the DWR users mailing list", er);
351         }
352
353         Method JavaDoc tempGetActualTypeArgumentsMethod = null;
354         try
355         {
356             if (tempParameterizedTypeClass != null)
357             {
358                 tempGetActualTypeArgumentsMethod = tempParameterizedTypeClass.getDeclaredMethod("getActualTypeArguments", new Class JavaDoc[0]);
359             }
360         }
361         catch (Exception JavaDoc ex)
362         {
363             log.debug("Error finding ParameterizedType.getActualTypeArguments(): JDK1.5 reflection not available.");
364             failures++;
365         }
366
367         Method JavaDoc tempGetRawTypeMethod = null;
368         try
369         {
370             if (tempParameterizedTypeClass != null)
371             {
372                 tempGetRawTypeMethod = tempParameterizedTypeClass.getDeclaredMethod("getRawType", new Class JavaDoc[0]);
373             }
374         }
375         catch (Exception JavaDoc ex)
376         {
377             log.debug("Error finding ParameterizedType.getRawType(): JDK1.5 reflection not available.");
378             failures++;
379         }
380
381         if (failures == 0)
382         {
383             isGenericsSupported = true;
384
385             parameterizedTypeClass = tempParameterizedTypeClass;
386             getGenericParameterTypesMethod = tempGetGenericParameterTypesMethod;
387             getActualTypeArgumentsMethod = tempGetActualTypeArgumentsMethod;
388             getRawTypeMethod = tempGetRawTypeMethod;
389         }
390         else
391         {
392             isGenericsSupported = false;
393
394             parameterizedTypeClass = null;
395             getGenericParameterTypesMethod = null;
396             getActualTypeArgumentsMethod = null;
397             getRawTypeMethod = null;
398         }
399     }
400 }
401
Popular Tags