1 16 package org.directwebremoting.extend; 17 18 import java.lang.reflect.Method ; 19 import java.util.ArrayList ; 20 import java.util.Iterator ; 21 import java.util.List ; 22 23 import org.directwebremoting.util.LocalUtil; 24 import org.directwebremoting.util.Logger; 25 26 31 public class TypeHintContext 32 { 33 39 public TypeHintContext(ConverterManager converterManager, Method method, int parameterNumber) 40 { 41 if (method == null) 42 { 43 throw new IllegalArgumentException ("The method can not be null"); 44 } 45 46 this.converterManager = converterManager; 47 this.method = method; 48 this.parameterNumber = parameterNumber; 49 50 Object [] types = (Object []) LocalUtil.invoke(method, getGenericParameterTypesMethod, new Object [0]); 52 53 if (types != null) 54 { 55 if (parameterNumber >= types.length) 56 { 57 throw new IllegalArgumentException ("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 (); 68 parameterTypeTree = new ArrayList (); 69 } 70 71 78 private TypeHintContext(ConverterManager manager, Method method, int parameterNumber, Object parameterType) 79 { 80 this.converterManager = manager; 81 this.method = method; 82 this.parameterNumber = parameterNumber; 83 this.parameterType = parameterType; 84 85 parameterNumberTree = new ArrayList (); 86 parameterTypeTree = new ArrayList (); 87 } 88 89 94 public TypeHintContext createChildContext(int newParameterNumber) 95 { 96 Object childType = null; 97 98 if (isGenericsSupported) 99 { 100 if (parameterizedTypeClass.isInstance(parameterType)) 102 { 103 Object ptype = parameterType; 104 Object [] actualTypeArguments = (Object []) LocalUtil.invoke(ptype, getActualTypeArgumentsMethod, new Object [0]); 106 107 if (newParameterNumber >= actualTypeArguments.length) 108 { 109 throw new IllegalArgumentException ("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 (newParameterNumber)); 120 121 child.parameterTypeTree.addAll(parameterTypeTree); 122 child.parameterTypeTree.add(parameterType); 123 124 return child; 125 } 126 127 132 public Class getExtraTypeInfo() 133 { 134 Class 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 (parameterizedTypeClass.isInstance(parameterType)) 150 { 151 Object ptype = parameterType; 152 Object rawType = LocalUtil.invoke(ptype, getRawTypeMethod, new Object [0]); 154 155 if (rawType instanceof Class ) 156 { 157 type = (Class ) 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 ) 163 { 164 type = (Class ) 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 .class; 172 } 173 174 177 public int hashCode() 178 { 179 return method.hashCode() + parameterNumber + parameterNumberTree.hashCode(); 180 } 181 182 185 public boolean equals(Object 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 220 public String toString() 221 { 222 if (cachedToString == null) 223 { 224 StringBuffer buffer = new StringBuffer (); 225 226 buffer.append(method.getName()); 227 buffer.append('('); 228 buffer.append(parameterNumber); 229 230 for (Iterator it = parameterNumberTree.iterator(); it.hasNext();) 231 { 232 buffer.append('<'); 233 buffer.append(it.next()); 234 } 235 for (Iterator 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 252 private ConverterManager converterManager; 253 254 257 private String cachedToString = null; 258 259 262 private final Method method; 263 264 267 private final int parameterNumber; 268 269 272 private final Object parameterType; 273 274 277 private final List parameterNumberTree; 278 279 282 private final List parameterTypeTree; 283 284 287 private static final Logger log = Logger.getLogger(TypeHintContext.class); 288 289 292 private static final Class parameterizedTypeClass; 293 294 297 private static final Method getGenericParameterTypesMethod; 298 299 302 private static final Method getActualTypeArgumentsMethod; 303 304 307 private static final Method getRawTypeMethod; 308 309 312 private static final boolean isGenericsSupported; 313 314 static 315 { 316 319 int failures = 0; 323 324 Class tempParameterizedTypeClass; 325 try 326 { 327 tempParameterizedTypeClass = LocalUtil.classForName("java.lang.reflect.ParameterizedType"); 328 log.debug("JDK1.5 reflection available."); 329 } 330 catch (Exception ex) 331 { 332 tempParameterizedTypeClass = null; 333 log.debug("JDK1.5 reflection not available. Generic parameters must use <signatures>."); 334 failures++; 335 } 336 337 Method tempGetGenericParameterTypesMethod = null; 338 try 339 { 340 tempGetGenericParameterTypesMethod = Method .class.getDeclaredMethod("getGenericParameterTypes", new Class [0]); 341 } 342 catch (Exception ex) 343 { 344 log.debug("Error finding Method.getGenericParameterTypes(): JDK1.5 reflection not available."); 345 failures++; 346 } 347 catch (Error er) 348 { 349 log.error("If you see this stack trace please report it to the DWR users mailing list", er); 351 } 352 353 Method tempGetActualTypeArgumentsMethod = null; 354 try 355 { 356 if (tempParameterizedTypeClass != null) 357 { 358 tempGetActualTypeArgumentsMethod = tempParameterizedTypeClass.getDeclaredMethod("getActualTypeArguments", new Class [0]); 359 } 360 } 361 catch (Exception ex) 362 { 363 log.debug("Error finding ParameterizedType.getActualTypeArguments(): JDK1.5 reflection not available."); 364 failures++; 365 } 366 367 Method tempGetRawTypeMethod = null; 368 try 369 { 370 if (tempParameterizedTypeClass != null) 371 { 372 tempGetRawTypeMethod = tempParameterizedTypeClass.getDeclaredMethod("getRawType", new Class [0]); 373 } 374 } 375 catch (Exception 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 |