1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.util;
20
21 import java.io.IOException;
22 import java.lang.annotation.Annotation;
23 import java.lang.reflect.Constructor;
24 import java.lang.reflect.InvocationTargetException;
25 import java.lang.reflect.Method;
26 import java.lang.reflect.Modifier;
27 import java.util.Arrays;
28 import java.util.Collections;
29 import java.util.HashMap;
30 import java.util.List;
31 import java.util.Map;
32
33 import org.eclipse.jetty.util.annotation.Name;
34 import org.eclipse.jetty.util.log.Log;
35 import org.eclipse.jetty.util.log.Logger;
36
37
38
39
40
41
42
43
44
45
46 public class TypeUtil
47 {
48 private static final Logger LOG = Log.getLogger(TypeUtil.class);
49 public static final Class<?>[] NO_ARGS = new Class[]{};
50 public static final int CR = '\015';
51 public static final int LF = '\012';
52
53
54 private static final HashMap<String, Class<?>> name2Class=new HashMap<>();
55 static
56 {
57 name2Class.put("boolean",java.lang.Boolean.TYPE);
58 name2Class.put("byte",java.lang.Byte.TYPE);
59 name2Class.put("char",java.lang.Character.TYPE);
60 name2Class.put("double",java.lang.Double.TYPE);
61 name2Class.put("float",java.lang.Float.TYPE);
62 name2Class.put("int",java.lang.Integer.TYPE);
63 name2Class.put("long",java.lang.Long.TYPE);
64 name2Class.put("short",java.lang.Short.TYPE);
65 name2Class.put("void",java.lang.Void.TYPE);
66
67 name2Class.put("java.lang.Boolean.TYPE",java.lang.Boolean.TYPE);
68 name2Class.put("java.lang.Byte.TYPE",java.lang.Byte.TYPE);
69 name2Class.put("java.lang.Character.TYPE",java.lang.Character.TYPE);
70 name2Class.put("java.lang.Double.TYPE",java.lang.Double.TYPE);
71 name2Class.put("java.lang.Float.TYPE",java.lang.Float.TYPE);
72 name2Class.put("java.lang.Integer.TYPE",java.lang.Integer.TYPE);
73 name2Class.put("java.lang.Long.TYPE",java.lang.Long.TYPE);
74 name2Class.put("java.lang.Short.TYPE",java.lang.Short.TYPE);
75 name2Class.put("java.lang.Void.TYPE",java.lang.Void.TYPE);
76
77 name2Class.put("java.lang.Boolean",java.lang.Boolean.class);
78 name2Class.put("java.lang.Byte",java.lang.Byte.class);
79 name2Class.put("java.lang.Character",java.lang.Character.class);
80 name2Class.put("java.lang.Double",java.lang.Double.class);
81 name2Class.put("java.lang.Float",java.lang.Float.class);
82 name2Class.put("java.lang.Integer",java.lang.Integer.class);
83 name2Class.put("java.lang.Long",java.lang.Long.class);
84 name2Class.put("java.lang.Short",java.lang.Short.class);
85
86 name2Class.put("Boolean",java.lang.Boolean.class);
87 name2Class.put("Byte",java.lang.Byte.class);
88 name2Class.put("Character",java.lang.Character.class);
89 name2Class.put("Double",java.lang.Double.class);
90 name2Class.put("Float",java.lang.Float.class);
91 name2Class.put("Integer",java.lang.Integer.class);
92 name2Class.put("Long",java.lang.Long.class);
93 name2Class.put("Short",java.lang.Short.class);
94
95 name2Class.put(null,java.lang.Void.TYPE);
96 name2Class.put("string",java.lang.String.class);
97 name2Class.put("String",java.lang.String.class);
98 name2Class.put("java.lang.String",java.lang.String.class);
99 }
100
101
102 private static final HashMap<Class<?>, String> class2Name=new HashMap<>();
103 static
104 {
105 class2Name.put(java.lang.Boolean.TYPE,"boolean");
106 class2Name.put(java.lang.Byte.TYPE,"byte");
107 class2Name.put(java.lang.Character.TYPE,"char");
108 class2Name.put(java.lang.Double.TYPE,"double");
109 class2Name.put(java.lang.Float.TYPE,"float");
110 class2Name.put(java.lang.Integer.TYPE,"int");
111 class2Name.put(java.lang.Long.TYPE,"long");
112 class2Name.put(java.lang.Short.TYPE,"short");
113 class2Name.put(java.lang.Void.TYPE,"void");
114
115 class2Name.put(java.lang.Boolean.class,"java.lang.Boolean");
116 class2Name.put(java.lang.Byte.class,"java.lang.Byte");
117 class2Name.put(java.lang.Character.class,"java.lang.Character");
118 class2Name.put(java.lang.Double.class,"java.lang.Double");
119 class2Name.put(java.lang.Float.class,"java.lang.Float");
120 class2Name.put(java.lang.Integer.class,"java.lang.Integer");
121 class2Name.put(java.lang.Long.class,"java.lang.Long");
122 class2Name.put(java.lang.Short.class,"java.lang.Short");
123
124 class2Name.put(null,"void");
125 class2Name.put(java.lang.String.class,"java.lang.String");
126 }
127
128
129 private static final HashMap<Class<?>, Method> class2Value=new HashMap<>();
130 static
131 {
132 try
133 {
134 Class<?>[] s ={java.lang.String.class};
135
136 class2Value.put(java.lang.Boolean.TYPE,
137 java.lang.Boolean.class.getMethod("valueOf",s));
138 class2Value.put(java.lang.Byte.TYPE,
139 java.lang.Byte.class.getMethod("valueOf",s));
140 class2Value.put(java.lang.Double.TYPE,
141 java.lang.Double.class.getMethod("valueOf",s));
142 class2Value.put(java.lang.Float.TYPE,
143 java.lang.Float.class.getMethod("valueOf",s));
144 class2Value.put(java.lang.Integer.TYPE,
145 java.lang.Integer.class.getMethod("valueOf",s));
146 class2Value.put(java.lang.Long.TYPE,
147 java.lang.Long.class.getMethod("valueOf",s));
148 class2Value.put(java.lang.Short.TYPE,
149 java.lang.Short.class.getMethod("valueOf",s));
150
151 class2Value.put(java.lang.Boolean.class,
152 java.lang.Boolean.class.getMethod("valueOf",s));
153 class2Value.put(java.lang.Byte.class,
154 java.lang.Byte.class.getMethod("valueOf",s));
155 class2Value.put(java.lang.Double.class,
156 java.lang.Double.class.getMethod("valueOf",s));
157 class2Value.put(java.lang.Float.class,
158 java.lang.Float.class.getMethod("valueOf",s));
159 class2Value.put(java.lang.Integer.class,
160 java.lang.Integer.class.getMethod("valueOf",s));
161 class2Value.put(java.lang.Long.class,
162 java.lang.Long.class.getMethod("valueOf",s));
163 class2Value.put(java.lang.Short.class,
164 java.lang.Short.class.getMethod("valueOf",s));
165 }
166 catch(Exception e)
167 {
168 throw new Error(e);
169 }
170 }
171
172
173
174
175
176
177
178 public static <T> List<T> asList(T[] a)
179 {
180 if (a==null)
181 return Collections.emptyList();
182 return Arrays.asList(a);
183 }
184
185
186
187
188
189
190 public static Class<?> fromName(String name)
191 {
192 return name2Class.get(name);
193 }
194
195
196
197
198
199
200 public static String toName(Class<?> type)
201 {
202 return class2Name.get(type);
203 }
204
205
206
207
208
209
210
211 public static Object valueOf(Class<?> type, String value)
212 {
213 try
214 {
215 if (type.equals(java.lang.String.class))
216 return value;
217
218 Method m = class2Value.get(type);
219 if (m!=null)
220 return m.invoke(null, value);
221
222 if (type.equals(java.lang.Character.TYPE) ||
223 type.equals(java.lang.Character.class))
224 return value.charAt(0);
225
226 Constructor<?> c = type.getConstructor(java.lang.String.class);
227 return c.newInstance(value);
228 }
229 catch (NoSuchMethodException | IllegalAccessException | InstantiationException x)
230 {
231 LOG.ignore(x);
232 }
233 catch (InvocationTargetException x)
234 {
235 if (x.getTargetException() instanceof Error)
236 throw (Error)x.getTargetException();
237 LOG.ignore(x);
238 }
239 return null;
240 }
241
242
243
244
245
246
247
248 public static Object valueOf(String type, String value)
249 {
250 return valueOf(fromName(type),value);
251 }
252
253
254
255
256
257
258
259
260
261
262
263 public static int parseInt(String s, int offset, int length, int base)
264 throws NumberFormatException
265 {
266 int value=0;
267
268 if (length<0)
269 length=s.length()-offset;
270
271 for (int i=0;i<length;i++)
272 {
273 char c=s.charAt(offset+i);
274
275 int digit=convertHexDigit((int)c);
276 if (digit<0 || digit>=base)
277 throw new NumberFormatException(s.substring(offset,offset+length));
278 value=value*base+digit;
279 }
280 return value;
281 }
282
283
284
285
286
287
288
289
290
291
292
293 public static int parseInt(byte[] b, int offset, int length, int base)
294 throws NumberFormatException
295 {
296 int value=0;
297
298 if (length<0)
299 length=b.length-offset;
300
301 for (int i=0;i<length;i++)
302 {
303 char c=(char)(0xff&b[offset+i]);
304
305 int digit=c-'0';
306 if (digit<0 || digit>=base || digit>=10)
307 {
308 digit=10+c-'A';
309 if (digit<10 || digit>=base)
310 digit=10+c-'a';
311 }
312 if (digit<0 || digit>=base)
313 throw new NumberFormatException(new String(b,offset,length));
314 value=value*base+digit;
315 }
316 return value;
317 }
318
319
320 public static byte[] parseBytes(String s, int base)
321 {
322 byte[] bytes=new byte[s.length()/2];
323 for (int i=0;i<s.length();i+=2)
324 bytes[i/2]=(byte)TypeUtil.parseInt(s,i,2,base);
325 return bytes;
326 }
327
328
329 public static String toString(byte[] bytes, int base)
330 {
331 StringBuilder buf = new StringBuilder();
332 for (byte b : bytes)
333 {
334 int bi=0xff&b;
335 int c='0'+(bi/base)%base;
336 if (c>'9')
337 c= 'a'+(c-'0'-10);
338 buf.append((char)c);
339 c='0'+bi%base;
340 if (c>'9')
341 c= 'a'+(c-'0'-10);
342 buf.append((char)c);
343 }
344 return buf.toString();
345 }
346
347
348
349
350
351
352 public static byte convertHexDigit( byte c )
353 {
354 byte b = (byte)((c & 0x1f) + ((c >> 6) * 0x19) - 0x10);
355 if (b<0 || b>15)
356 throw new NumberFormatException("!hex "+c);
357 return b;
358 }
359
360
361
362
363
364
365 public static int convertHexDigit( int c )
366 {
367 int d= ((c & 0x1f) + ((c >> 6) * 0x19) - 0x10);
368 if (d<0 || d>15)
369 throw new NumberFormatException("!hex "+c);
370 return d;
371 }
372
373
374 public static void toHex(byte b,Appendable buf)
375 {
376 try
377 {
378 int d=0xf&((0xF0&b)>>4);
379 buf.append((char)((d>9?('A'-10):'0')+d));
380 d=0xf&b;
381 buf.append((char)((d>9?('A'-10):'0')+d));
382 }
383 catch(IOException e)
384 {
385 throw new RuntimeException(e);
386 }
387 }
388
389
390 public static void toHex(int value,Appendable buf) throws IOException
391 {
392 int d=0xf&((0xF0000000&value)>>28);
393 buf.append((char)((d>9?('A'-10):'0')+d));
394 d=0xf&((0x0F000000&value)>>24);
395 buf.append((char)((d>9?('A'-10):'0')+d));
396 d=0xf&((0x00F00000&value)>>20);
397 buf.append((char)((d>9?('A'-10):'0')+d));
398 d=0xf&((0x000F0000&value)>>16);
399 buf.append((char)((d>9?('A'-10):'0')+d));
400 d=0xf&((0x0000F000&value)>>12);
401 buf.append((char)((d>9?('A'-10):'0')+d));
402 d=0xf&((0x00000F00&value)>>8);
403 buf.append((char)((d>9?('A'-10):'0')+d));
404 d=0xf&((0x000000F0&value)>>4);
405 buf.append((char)((d>9?('A'-10):'0')+d));
406 d=0xf&value;
407 buf.append((char)((d>9?('A'-10):'0')+d));
408
409 Integer.toString(0,36);
410 }
411
412
413
414 public static void toHex(long value,Appendable buf) throws IOException
415 {
416 toHex((int)(value>>32),buf);
417 toHex((int)value,buf);
418 }
419
420
421 public static String toHexString(byte b)
422 {
423 return toHexString(new byte[]{b}, 0, 1);
424 }
425
426
427 public static String toHexString(byte[] b)
428 {
429 return toHexString(b, 0, b.length);
430 }
431
432
433 public static String toHexString(byte[] b,int offset,int length)
434 {
435 StringBuilder buf = new StringBuilder();
436 for (int i=offset;i<offset+length;i++)
437 {
438 int bi=0xff&b[i];
439 int c='0'+(bi/16)%16;
440 if (c>'9')
441 c= 'A'+(c-'0'-10);
442 buf.append((char)c);
443 c='0'+bi%16;
444 if (c>'9')
445 c= 'a'+(c-'0'-10);
446 buf.append((char)c);
447 }
448 return buf.toString();
449 }
450
451
452 public static byte[] fromHexString(String s)
453 {
454 if (s.length()%2!=0)
455 throw new IllegalArgumentException(s);
456 byte[] array = new byte[s.length()/2];
457 for (int i=0;i<array.length;i++)
458 {
459 int b = Integer.parseInt(s.substring(i*2,i*2+2),16);
460 array[i]=(byte)(0xff&b);
461 }
462 return array;
463 }
464
465
466 public static void dump(Class<?> c)
467 {
468 System.err.println("Dump: "+c);
469 dump(c.getClassLoader());
470 }
471
472 public static void dump(ClassLoader cl)
473 {
474 System.err.println("Dump Loaders:");
475 while(cl!=null)
476 {
477 System.err.println(" loader "+cl);
478 cl = cl.getParent();
479 }
480 }
481
482
483 public static Object call(Class<?> oClass, String methodName, Object obj, Object[] arg)
484 throws InvocationTargetException, NoSuchMethodException
485 {
486
487 for (Method method : oClass.getMethods())
488 {
489 if (!method.getName().equals(methodName))
490 continue;
491 if (method.getParameterTypes().length != arg.length)
492 continue;
493 if (Modifier.isStatic(method.getModifiers()) != (obj == null))
494 continue;
495 if ((obj == null) && method.getDeclaringClass() != oClass)
496 continue;
497
498 try
499 {
500 return method.invoke(obj, arg);
501 }
502 catch (IllegalAccessException | IllegalArgumentException e)
503 {
504 LOG.ignore(e);
505 }
506 }
507
508
509 Object[] args_with_opts=null;
510
511 for (Method method : oClass.getMethods())
512 {
513 if (!method.getName().equals(methodName))
514 continue;
515 if (method.getParameterTypes().length != arg.length+1)
516 continue;
517 if (!method.getParameterTypes()[arg.length].isArray())
518 continue;
519 if (Modifier.isStatic(method.getModifiers()) != (obj == null))
520 continue;
521 if ((obj == null) && method.getDeclaringClass() != oClass)
522 continue;
523
524 if (args_with_opts==null)
525 args_with_opts=ArrayUtil.addToArray(arg,new Object[]{},Object.class);
526 try
527 {
528 return method.invoke(obj, args_with_opts);
529 }
530 catch (IllegalAccessException | IllegalArgumentException e)
531 {
532 LOG.ignore(e);
533 }
534 }
535
536
537 throw new NoSuchMethodException(methodName);
538 }
539
540 public static Object construct(Class<?> klass, Object[] arguments) throws InvocationTargetException, NoSuchMethodException
541 {
542 for (Constructor<?> constructor : klass.getConstructors())
543 {
544 if (constructor.getParameterTypes().length != arguments.length)
545 continue;
546
547 try
548 {
549 return constructor.newInstance(arguments);
550 }
551 catch (InstantiationException | IllegalAccessException | IllegalArgumentException e)
552 {
553 LOG.ignore(e);
554 }
555 }
556 throw new NoSuchMethodException("<init>");
557 }
558
559 public static Object construct(Class<?> klass, Object[] arguments, Map<String, Object> namedArgMap) throws InvocationTargetException, NoSuchMethodException
560 {
561 for (Constructor<?> constructor : klass.getConstructors())
562 {
563 if (constructor.getParameterTypes().length != arguments.length)
564 continue;
565
566 try
567 {
568 Annotation[][] parameterAnnotations = constructor.getParameterAnnotations();
569
570
571 if ( parameterAnnotations == null || parameterAnnotations.length == 0 )
572 {
573 LOG.debug("Target has no parameter annotations");
574 return constructor.newInstance(arguments);
575 }
576 else
577 {
578 Object[] swizzled = new Object[arguments.length];
579
580 int count = 0;
581 for ( Annotation[] annotations : parameterAnnotations )
582 {
583 for ( Annotation annotation : annotations)
584 {
585 if ( annotation instanceof Name )
586 {
587 Name param = (Name)annotation;
588
589 if (namedArgMap.containsKey(param.value()))
590 {
591 LOG.debug("placing named {} in position {}", param.value(), count);
592 swizzled[count] = namedArgMap.get(param.value());
593 }
594 else
595 {
596 LOG.debug("placing {} in position {}", arguments[count], count);
597 swizzled[count] = arguments[count];
598 }
599 ++count;
600 }
601 else
602 {
603 LOG.debug("passing on annotation {}", annotation);
604 }
605 }
606 }
607
608 return constructor.newInstance(swizzled);
609 }
610
611 }
612 catch (InstantiationException | IllegalAccessException | IllegalArgumentException e)
613 {
614 LOG.ignore(e);
615 }
616 }
617 throw new NoSuchMethodException("<init>");
618 }
619 }