]> WPIA git - gigi.git/blob - lib/jetty/org/eclipse/jetty/util/TypeUtil.java
updating jetty to jetty-9.2.16.v2016040
[gigi.git] / lib / jetty / org / eclipse / jetty / util / TypeUtil.java
1 //
2 //  ========================================================================
3 //  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
4 //  ------------------------------------------------------------------------
5 //  All rights reserved. This program and the accompanying materials
6 //  are made available under the terms of the Eclipse Public License v1.0
7 //  and Apache License v2.0 which accompanies this distribution.
8 //
9 //      The Eclipse Public License is available at
10 //      http://www.eclipse.org/legal/epl-v10.html
11 //
12 //      The Apache License v2.0 is available at
13 //      http://www.opensource.org/licenses/apache2.0.php
14 //
15 //  You may elect to redistribute this code under either of these licenses.
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  * TYPE Utilities.
41  * Provides various static utiltiy methods for manipulating types and their
42  * string representations.
43  *
44  * @since Jetty 4.1
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     /** Array to List.
174      * <p>
175      * Works like {@link Arrays#asList(Object...)}, but handles null arrays.
176      * @return a list backed by the array.
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     /** Class from a canonical name for a type.
187      * @param name A class or type name.
188      * @return A class , which may be a primitive TYPE field..
189      */
190     public static Class<?> fromName(String name)
191     {
192         return name2Class.get(name);
193     }
194
195     /* ------------------------------------------------------------ */
196     /** Canonical name for a type.
197      * @param type A class , which may be a primitive TYPE field.
198      * @return Canonical name.
199      */
200     public static String toName(Class<?> type)
201     {
202         return class2Name.get(type);
203     }
204
205     /* ------------------------------------------------------------ */
206     /** Convert String value to instance.
207      * @param type The class of the instance, which may be a primitive TYPE field.
208      * @param value The value as a string.
209      * @return The value as an Object.
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     /** Convert String value to instance.
244      * @param type classname or type (eg int)
245      * @param value The value as a string.
246      * @return The value as an Object.
247      */
248     public static Object valueOf(String type, String value)
249     {
250         return valueOf(fromName(type),value);
251     }
252
253     /* ------------------------------------------------------------ */
254     /** Parse an int from a substring.
255      * Negative numbers are not handled.
256      * @param s String
257      * @param offset Offset within string
258      * @param length Length of integer or -1 for remainder of string
259      * @param base base of the integer
260      * @return the parsed integer
261      * @throws NumberFormatException if the string cannot be parsed
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     /** Parse an int from a byte array of ascii characters.
285      * Negative numbers are not handled.
286      * @param b byte array
287      * @param offset Offset within string
288      * @param length Length of integer or -1 for remainder of string
289      * @param base base of the integer
290      * @return the parsed integer
291      * @throws NumberFormatException if the array cannot be parsed into an integer
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      * @param c An ASCII encoded character 0-9 a-f A-F
350      * @return The byte value of the character 0-16.
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      * @param c An ASCII encoded character 0-9 a-f A-F
363      * @return The byte value of the character 0-16.
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         // Lets just try all methods for now
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         // Lets look for a method with optional arguments
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                 // target has no annotations
571                 if ( parameterAnnotations == null || parameterAnnotations.length == 0 )
572                 {
573                     if (LOG.isDebugEnabled())
574                         LOG.debug("Target has no parameter annotations");
575                     return constructor.newInstance(arguments);
576                 }
577                 else
578                 {
579                    Object[] swizzled = new Object[arguments.length];
580                    
581                    int count = 0;
582                    for ( Annotation[] annotations : parameterAnnotations )
583                    {
584                        for ( Annotation annotation : annotations)
585                        {
586                            if ( annotation instanceof Name )
587                            {
588                                Name param = (Name)annotation;
589                                
590                                if (namedArgMap.containsKey(param.value()))
591                                {
592                                    if (LOG.isDebugEnabled())
593                                        LOG.debug("placing named {} in position {}", param.value(), count);
594                                    swizzled[count] = namedArgMap.get(param.value());
595                                }
596                                else
597                                {
598                                    if (LOG.isDebugEnabled())
599                                        LOG.debug("placing {} in position {}", arguments[count], count);
600                                    swizzled[count] = arguments[count];
601                                }
602                                ++count;
603                            }
604                            else
605                            {
606                                if (LOG.isDebugEnabled())
607                                    LOG.debug("passing on annotation {}", annotation);
608                            }
609                        }
610                    }
611                    
612                    return constructor.newInstance(swizzled);
613                 }
614                 
615             }
616             catch (InstantiationException | IllegalAccessException | IllegalArgumentException e)
617             {
618                 LOG.ignore(e);
619             }
620         }
621         throw new NoSuchMethodException("<init>");
622     }
623
624     /* ------------------------------------------------------------ */
625     /** 
626      * @param o Object to test for true
627      * @return True if passed object is not null and is either a Boolean with value true or evaluates to a string that evaluates to true.
628      */
629     public static boolean isTrue(Object o)
630     {
631         if (o==null)
632             return false;
633         if (o instanceof Boolean)
634             return ((Boolean)o).booleanValue();
635         return Boolean.parseBoolean(o.toString());
636     }
637
638     /* ------------------------------------------------------------ */
639     /** 
640      * @param o Object to test for false
641      * @return True if passed object is not null and is either a Boolean with value false or evaluates to a string that evaluates to false.
642      */
643     public static boolean isFalse(Object o)
644     {
645         if (o==null)
646             return false;
647         if (o instanceof Boolean)
648             return !((Boolean)o).booleanValue();
649         return "false".equalsIgnoreCase(o.toString());
650     }
651 }