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.
9 // The Eclipse Public License is available at
10 // http://www.eclipse.org/legal/epl-v10.html
12 // The Apache License v2.0 is available at
13 // http://www.opensource.org/licenses/apache2.0.php
15 // You may elect to redistribute this code under either of these licenses.
16 // ========================================================================
19 package org.eclipse.jetty.util;
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;
33 import org.eclipse.jetty.util.annotation.Name;
34 import org.eclipse.jetty.util.log.Log;
35 import org.eclipse.jetty.util.log.Logger;
38 /* ------------------------------------------------------------ */
41 * Provides various static utiltiy methods for manipulating types and their
42 * string representations.
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';
53 /* ------------------------------------------------------------ */
54 private static final HashMap<String, Class<?>> name2Class=new HashMap<>();
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);
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);
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);
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);
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);
101 /* ------------------------------------------------------------ */
102 private static final HashMap<Class<?>, String> class2Name=new HashMap<>();
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");
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");
124 class2Name.put(null,"void");
125 class2Name.put(java.lang.String.class,"java.lang.String");
128 /* ------------------------------------------------------------ */
129 private static final HashMap<Class<?>, Method> class2Value=new HashMap<>();
134 Class<?>[] s ={java.lang.String.class};
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));
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));
172 /* ------------------------------------------------------------ */
175 * Works like {@link Arrays#asList(Object...)}, but handles null arrays.
176 * @return a list backed by the array.
178 public static <T> List<T> asList(T[] a)
181 return Collections.emptyList();
182 return Arrays.asList(a);
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..
190 public static Class<?> fromName(String name)
192 return name2Class.get(name);
195 /* ------------------------------------------------------------ */
196 /** Canonical name for a type.
197 * @param type A class , which may be a primitive TYPE field.
198 * @return Canonical name.
200 public static String toName(Class<?> type)
202 return class2Name.get(type);
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.
211 public static Object valueOf(Class<?> type, String value)
215 if (type.equals(java.lang.String.class))
218 Method m = class2Value.get(type);
220 return m.invoke(null, value);
222 if (type.equals(java.lang.Character.TYPE) ||
223 type.equals(java.lang.Character.class))
224 return value.charAt(0);
226 Constructor<?> c = type.getConstructor(java.lang.String.class);
227 return c.newInstance(value);
229 catch (NoSuchMethodException | IllegalAccessException | InstantiationException x)
233 catch (InvocationTargetException x)
235 if (x.getTargetException() instanceof Error)
236 throw (Error)x.getTargetException();
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.
248 public static Object valueOf(String type, String value)
250 return valueOf(fromName(type),value);
253 /* ------------------------------------------------------------ */
254 /** Parse an int from a substring.
255 * Negative numbers are not handled.
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
263 public static int parseInt(String s, int offset, int length, int base)
264 throws NumberFormatException
269 length=s.length()-offset;
271 for (int i=0;i<length;i++)
273 char c=s.charAt(offset+i);
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;
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
293 public static int parseInt(byte[] b, int offset, int length, int base)
294 throws NumberFormatException
299 length=b.length-offset;
301 for (int i=0;i<length;i++)
303 char c=(char)(0xff&b[offset+i]);
306 if (digit<0 || digit>=base || digit>=10)
309 if (digit<10 || digit>=base)
312 if (digit<0 || digit>=base)
313 throw new NumberFormatException(new String(b,offset,length));
314 value=value*base+digit;
319 /* ------------------------------------------------------------ */
320 public static byte[] parseBytes(String s, int base)
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);
328 /* ------------------------------------------------------------ */
329 public static String toString(byte[] bytes, int base)
331 StringBuilder buf = new StringBuilder();
335 int c='0'+(bi/base)%base;
344 return buf.toString();
347 /* ------------------------------------------------------------ */
349 * @param c An ASCII encoded character 0-9 a-f A-F
350 * @return The byte value of the character 0-16.
352 public static byte convertHexDigit( byte c )
354 byte b = (byte)((c & 0x1f) + ((c >> 6) * 0x19) - 0x10);
356 throw new NumberFormatException("!hex "+c);
360 /* ------------------------------------------------------------ */
362 * @param c An ASCII encoded character 0-9 a-f A-F
363 * @return The byte value of the character 0-16.
365 public static int convertHexDigit( int c )
367 int d= ((c & 0x1f) + ((c >> 6) * 0x19) - 0x10);
369 throw new NumberFormatException("!hex "+c);
373 /* ------------------------------------------------------------ */
374 public static void toHex(byte b,Appendable buf)
378 int d=0xf&((0xF0&b)>>4);
379 buf.append((char)((d>9?('A'-10):'0')+d));
381 buf.append((char)((d>9?('A'-10):'0')+d));
385 throw new RuntimeException(e);
389 /* ------------------------------------------------------------ */
390 public static void toHex(int value,Appendable buf) throws IOException
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));
407 buf.append((char)((d>9?('A'-10):'0')+d));
409 Integer.toString(0,36);
413 /* ------------------------------------------------------------ */
414 public static void toHex(long value,Appendable buf) throws IOException
416 toHex((int)(value>>32),buf);
417 toHex((int)value,buf);
420 /* ------------------------------------------------------------ */
421 public static String toHexString(byte b)
423 return toHexString(new byte[]{b}, 0, 1);
426 /* ------------------------------------------------------------ */
427 public static String toHexString(byte[] b)
429 return toHexString(b, 0, b.length);
432 /* ------------------------------------------------------------ */
433 public static String toHexString(byte[] b,int offset,int length)
435 StringBuilder buf = new StringBuilder();
436 for (int i=offset;i<offset+length;i++)
439 int c='0'+(bi/16)%16;
448 return buf.toString();
451 /* ------------------------------------------------------------ */
452 public static byte[] fromHexString(String s)
455 throw new IllegalArgumentException(s);
456 byte[] array = new byte[s.length()/2];
457 for (int i=0;i<array.length;i++)
459 int b = Integer.parseInt(s.substring(i*2,i*2+2),16);
460 array[i]=(byte)(0xff&b);
466 public static void dump(Class<?> c)
468 System.err.println("Dump: "+c);
469 dump(c.getClassLoader());
472 public static void dump(ClassLoader cl)
474 System.err.println("Dump Loaders:");
477 System.err.println(" loader "+cl);
483 public static Object call(Class<?> oClass, String methodName, Object obj, Object[] arg)
484 throws InvocationTargetException, NoSuchMethodException
486 // Lets just try all methods for now
487 for (Method method : oClass.getMethods())
489 if (!method.getName().equals(methodName))
491 if (method.getParameterTypes().length != arg.length)
493 if (Modifier.isStatic(method.getModifiers()) != (obj == null))
495 if ((obj == null) && method.getDeclaringClass() != oClass)
500 return method.invoke(obj, arg);
502 catch (IllegalAccessException | IllegalArgumentException e)
508 // Lets look for a method with optional arguments
509 Object[] args_with_opts=null;
511 for (Method method : oClass.getMethods())
513 if (!method.getName().equals(methodName))
515 if (method.getParameterTypes().length != arg.length+1)
517 if (!method.getParameterTypes()[arg.length].isArray())
519 if (Modifier.isStatic(method.getModifiers()) != (obj == null))
521 if ((obj == null) && method.getDeclaringClass() != oClass)
524 if (args_with_opts==null)
525 args_with_opts=ArrayUtil.addToArray(arg,new Object[]{},Object.class);
528 return method.invoke(obj, args_with_opts);
530 catch (IllegalAccessException | IllegalArgumentException e)
537 throw new NoSuchMethodException(methodName);
540 public static Object construct(Class<?> klass, Object[] arguments) throws InvocationTargetException, NoSuchMethodException
542 for (Constructor<?> constructor : klass.getConstructors())
544 if (constructor.getParameterTypes().length != arguments.length)
549 return constructor.newInstance(arguments);
551 catch (InstantiationException | IllegalAccessException | IllegalArgumentException e)
556 throw new NoSuchMethodException("<init>");
559 public static Object construct(Class<?> klass, Object[] arguments, Map<String, Object> namedArgMap) throws InvocationTargetException, NoSuchMethodException
561 for (Constructor<?> constructor : klass.getConstructors())
563 if (constructor.getParameterTypes().length != arguments.length)
568 Annotation[][] parameterAnnotations = constructor.getParameterAnnotations();
570 // target has no annotations
571 if ( parameterAnnotations == null || parameterAnnotations.length == 0 )
573 if (LOG.isDebugEnabled())
574 LOG.debug("Target has no parameter annotations");
575 return constructor.newInstance(arguments);
579 Object[] swizzled = new Object[arguments.length];
582 for ( Annotation[] annotations : parameterAnnotations )
584 for ( Annotation annotation : annotations)
586 if ( annotation instanceof Name )
588 Name param = (Name)annotation;
590 if (namedArgMap.containsKey(param.value()))
592 if (LOG.isDebugEnabled())
593 LOG.debug("placing named {} in position {}", param.value(), count);
594 swizzled[count] = namedArgMap.get(param.value());
598 if (LOG.isDebugEnabled())
599 LOG.debug("placing {} in position {}", arguments[count], count);
600 swizzled[count] = arguments[count];
606 if (LOG.isDebugEnabled())
607 LOG.debug("passing on annotation {}", annotation);
612 return constructor.newInstance(swizzled);
616 catch (InstantiationException | IllegalAccessException | IllegalArgumentException e)
621 throw new NoSuchMethodException("<init>");
624 /* ------------------------------------------------------------ */
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.
629 public static boolean isTrue(Object o)
633 if (o instanceof Boolean)
634 return ((Boolean)o).booleanValue();
635 return Boolean.parseBoolean(o.toString());
638 /* ------------------------------------------------------------ */
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.
643 public static boolean isFalse(Object o)
647 if (o instanceof Boolean)
648 return !((Boolean)o).booleanValue();
649 return "false".equalsIgnoreCase(o.toString());