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