// ======================================================================== // Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 // and Apache License v2.0 which accompanies this distribution. // The Eclipse Public License is available at // http://www.eclipse.org/legal/epl-v10.html // The Apache License v2.0 is available at // http://www.opensource.org/licenses/apache2.0.php // You may elect to redistribute this code under either of these licenses. // ======================================================================== package net.hasor.rsf.json; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.net.URL; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; /* ------------------------------------------------------------ */ /** * TYPE Utilities. * Provides various static utiltiy methods for manipulating types and their * string representations. * * @since Jetty 4.1 */ class TypeUtil { protected final static Logger logger = LoggerFactory.getLogger(TypeUtil.class); public static int CR = '\015'; public static int LF = '\012'; /* ------------------------------------------------------------ */ private static final HashMap<String, Class<?>> name2Class = new HashMap<String, Class<?>>(); static { name2Class.put("boolean", Boolean.TYPE); name2Class.put("byte", Byte.TYPE); name2Class.put("char", Character.TYPE); name2Class.put("double", Double.TYPE); name2Class.put("float", Float.TYPE); name2Class.put("int", Integer.TYPE); name2Class.put("long", Long.TYPE); name2Class.put("short", Short.TYPE); name2Class.put("void", Void.TYPE); name2Class.put("java.lang.Boolean.TYPE", Boolean.TYPE); name2Class.put("java.lang.Byte.TYPE", Byte.TYPE); name2Class.put("java.lang.Character.TYPE", Character.TYPE); name2Class.put("java.lang.Double.TYPE", Double.TYPE); name2Class.put("java.lang.Float.TYPE", Float.TYPE); name2Class.put("java.lang.Integer.TYPE", Integer.TYPE); name2Class.put("java.lang.Long.TYPE", Long.TYPE); name2Class.put("java.lang.Short.TYPE", Short.TYPE); name2Class.put("java.lang.Void.TYPE", Void.TYPE); name2Class.put("java.lang.Boolean", Boolean.class); name2Class.put("java.lang.Byte", Byte.class); name2Class.put("java.lang.Character", Character.class); name2Class.put("java.lang.Double", Double.class); name2Class.put("java.lang.Float", Float.class); name2Class.put("java.lang.Integer", Integer.class); name2Class.put("java.lang.Long", Long.class); name2Class.put("java.lang.Short", Short.class); name2Class.put("Boolean", Boolean.class); name2Class.put("Byte", Byte.class); name2Class.put("Character", Character.class); name2Class.put("Double", Double.class); name2Class.put("Float", Float.class); name2Class.put("Integer", Integer.class); name2Class.put("Long", Long.class); name2Class.put("Short", Short.class); name2Class.put(null, Void.TYPE); name2Class.put("string", String.class); name2Class.put("String", String.class); name2Class.put("java.lang.String", String.class); } /* ------------------------------------------------------------ */ private static final HashMap<Class<?>, String> class2Name = new HashMap<Class<?>, String>(); static { class2Name.put(Boolean.TYPE, "boolean"); class2Name.put(Byte.TYPE, "byte"); class2Name.put(Character.TYPE, "char"); class2Name.put(Double.TYPE, "double"); class2Name.put(Float.TYPE, "float"); class2Name.put(Integer.TYPE, "int"); class2Name.put(Long.TYPE, "long"); class2Name.put(Short.TYPE, "short"); class2Name.put(Void.TYPE, "void"); class2Name.put(Boolean.class, "java.lang.Boolean"); class2Name.put(Byte.class, "java.lang.Byte"); class2Name.put(Character.class, "java.lang.Character"); class2Name.put(Double.class, "java.lang.Double"); class2Name.put(Float.class, "java.lang.Float"); class2Name.put(Integer.class, "java.lang.Integer"); class2Name.put(Long.class, "java.lang.Long"); class2Name.put(Short.class, "java.lang.Short"); class2Name.put(null, "void"); class2Name.put(String.class, "java.lang.String"); } /* ------------------------------------------------------------ */ private static final HashMap<Class<?>, Method> class2Value = new HashMap<Class<?>, Method>(); static { try { Class<?>[] s = { String.class }; class2Value.put(Boolean.TYPE, Boolean.class.getMethod("valueOf", s)); class2Value.put(Byte.TYPE, Byte.class.getMethod("valueOf", s)); class2Value.put(Double.TYPE, Double.class.getMethod("valueOf", s)); class2Value.put(Float.TYPE, Float.class.getMethod("valueOf", s)); class2Value.put(Integer.TYPE, Integer.class.getMethod("valueOf", s)); class2Value.put(Long.TYPE, Long.class.getMethod("valueOf", s)); class2Value.put(Short.TYPE, Short.class.getMethod("valueOf", s)); class2Value.put(Boolean.class, Boolean.class.getMethod("valueOf", s)); class2Value.put(Byte.class, Byte.class.getMethod("valueOf", s)); class2Value.put(Double.class, Double.class.getMethod("valueOf", s)); class2Value.put(Float.class, Float.class.getMethod("valueOf", s)); class2Value.put(Integer.class, Integer.class.getMethod("valueOf", s)); class2Value.put(Long.class, Long.class.getMethod("valueOf", s)); class2Value.put(Short.class, Short.class.getMethod("valueOf", s)); } catch (Exception e) { throw new Error(e); } } /* ------------------------------------------------------------ */ /** Array to List. * <p> * Works like {@link Arrays#asList(Object...)}, but handles null arrays. * @return a list backed by the array. */ public static <T> List<T> asList(T[] a) { if (a == null) return Collections.emptyList(); return Arrays.asList(a); } /* ------------------------------------------------------------ */ /** Class from a canonical name for a type. * @param name A class or type name. * @return A class , which may be a primitive TYPE field.. */ public static Class<?> fromName(String name) { return name2Class.get(name); } /* ------------------------------------------------------------ */ /** Canonical name for a type. * @param type A class , which may be a primitive TYPE field. * @return Canonical name. */ public static String toName(Class<?> type) { return class2Name.get(type); } /* ------------------------------------------------------------ */ /** Convert String value to instance. * @param type The class of the instance, which may be a primitive TYPE field. * @param value The value as a string. * @return The value as an Object. */ public static Object valueOf(Class<?> type, String value) { try { if (type.equals(String.class)) return value; Method m = class2Value.get(type); if (m != null) return m.invoke(null, value); if (type.equals(Character.TYPE) || type.equals(Character.class)) return new Character(value.charAt(0)); Constructor<?> c = type.getConstructor(String.class); return c.newInstance(value); } catch (NoSuchMethodException e) { // LogSupport.ignore(log,e); } catch (IllegalAccessException e) { // LogSupport.ignore(log,e); } catch (InstantiationException e) { // LogSupport.ignore(log,e); } catch (InvocationTargetException e) { if (e.getTargetException() instanceof Error) throw (Error) (e.getTargetException()); // LogSupport.ignore(log,e); } return null; } /* ------------------------------------------------------------ */ /** Convert String value to instance. * @param type classname or type (eg int) * @param value The value as a string. * @return The value as an Object. */ public static Object valueOf(String type, String value) { return valueOf(fromName(type), value); } /* ------------------------------------------------------------ */ /** Parse an int from a substring. * Negative numbers are not handled. * @param s String * @param offset Offset within string * @param length Length of integer or -1 for remainder of string * @param base base of the integer * @return the parsed integer * @throws NumberFormatException if the string cannot be parsed */ public static int parseInt(String s, int offset, int length, int base) throws NumberFormatException { int value = 0; if (length < 0) length = s.length() - offset; for (int i = 0; i < length; i++) { char c = s.charAt(offset + i); int digit = c - '0'; if (digit < 0 || digit >= base || digit >= 10) { digit = 10 + c - 'A'; if (digit < 10 || digit >= base) digit = 10 + c - 'a'; } if (digit < 0 || digit >= base) throw new NumberFormatException(s.substring(offset, offset + length)); value = value * base + digit; } return value; } /* ------------------------------------------------------------ */ /** Parse an int from a byte array of ascii characters. * Negative numbers are not handled. * @param b byte array * @param offset Offset within string * @param length Length of integer or -1 for remainder of string * @param base base of the integer * @return the parsed integer * @throws NumberFormatException if the array cannot be parsed into an integer */ public static int parseInt(byte[] b, int offset, int length, int base) throws NumberFormatException { int value = 0; if (length < 0) length = b.length - offset; for (int i = 0; i < length; i++) { char c = (char) (0xff & b[offset + i]); int digit = c - '0'; if (digit < 0 || digit >= base || digit >= 10) { digit = 10 + c - 'A'; if (digit < 10 || digit >= base) digit = 10 + c - 'a'; } if (digit < 0 || digit >= base) throw new NumberFormatException(new String(b, offset, length)); value = value * base + digit; } return value; } /* ------------------------------------------------------------ */ public static byte[] parseBytes(String s, int base) { byte[] bytes = new byte[s.length() / 2]; for (int i = 0; i < s.length(); i += 2) bytes[i / 2] = (byte) TypeUtil.parseInt(s, i, 2, base); return bytes; } /* ------------------------------------------------------------ */ public static String toString(byte[] bytes, int base) { StringBuilder buf = new StringBuilder(); for (byte b : bytes) { int bi = 0xff & b; int c = '0' + (bi / base) % base; if (c > '9') c = 'a' + (c - '0' - 10); buf.append((char) c); c = '0' + bi % base; if (c > '9') c = 'a' + (c - '0' - 10); buf.append((char) c); } return buf.toString(); } /* ------------------------------------------------------------ */ /** * @param b An ASCII encoded character 0-9 a-f A-F * @return The byte value of the character 0-16. */ public static byte convertHexDigit(byte b) { if ((b >= '0') && (b <= '9')) return (byte) (b - '0'); if ((b >= 'a') && (b <= 'f')) return (byte) (b - 'a' + 10); if ((b >= 'A') && (b <= 'F')) return (byte) (b - 'A' + 10); throw new IllegalArgumentException("!hex:" + Integer.toHexString(0xff & b)); } /* ------------------------------------------------------------ */ public static void toHex(byte b, Appendable buf) { try { int bi = 0xff & b; int c = '0' + (bi / 16) % 16; if (c > '9') c = 'A' + (c - '0' - 10); buf.append((char) c); c = '0' + bi % 16; if (c > '9') c = 'A' + (c - '0' - 10); buf.append((char) c); } catch (IOException e) { throw new RuntimeException(e); } } /* ------------------------------------------------------------ */ public static String toHexString(byte b) { return toHexString(new byte[] { b }, 0, 1); } /* ------------------------------------------------------------ */ public static String toHexString(byte[] b) { return toHexString(b, 0, b.length); } /* ------------------------------------------------------------ */ public static String toHexString(byte[] b, int offset, int length) { StringBuilder buf = new StringBuilder(); for (int i = offset; i < offset + length; i++) { int bi = 0xff & b[i]; int c = '0' + (bi / 16) % 16; if (c > '9') c = 'A' + (c - '0' - 10); buf.append((char) c); c = '0' + bi % 16; if (c > '9') c = 'a' + (c - '0' - 10); buf.append((char) c); } return buf.toString(); } /* ------------------------------------------------------------ */ public static byte[] fromHexString(String s) { if (s.length() % 2 != 0) throw new IllegalArgumentException(s); byte[] array = new byte[s.length() / 2]; for (int i = 0; i < array.length; i++) { int b = Integer.parseInt(s.substring(i * 2, i * 2 + 2), 16); array[i] = (byte) (0xff & b); } return array; } public static void dump(Class<?> c) { System.err.println("Dump: " + c); dump(c.getClassLoader()); } public static void dump(ClassLoader cl) { System.err.println("Dump Loaders:"); while (cl != null) { System.err.println(" loader " + cl); cl = cl.getParent(); } } /* ------------------------------------------------------------ */ public static byte[] readLine(InputStream in) throws IOException { byte[] buf = new byte[256]; int i = 0; int loops = 0; int ch = 0; while (true) { ch = in.read(); if (ch < 0) break; loops++; // skip a leading LF's if (loops == 1 && ch == LF) continue; if (ch == CR || ch == LF) break; if (i >= buf.length) { byte[] old_buf = buf; buf = new byte[old_buf.length + 256]; System.arraycopy(old_buf, 0, buf, 0, old_buf.length); } buf[i++] = (byte) ch; } if (ch == -1 && i == 0) return null; // skip a trailing LF if it exists if (ch == CR && in.available() >= 1 && in.markSupported()) { in.mark(1); ch = in.read(); if (ch != LF) in.reset(); } byte[] old_buf = buf; buf = new byte[i]; System.arraycopy(old_buf, 0, buf, 0, i); return buf; } public static URL jarFor(String className) { try { className = className.replace('.', '/') + ".class"; // hack to discover jstl libraries URL url = Loader.getResource(null, className, false); String s = url.toString(); if (s.startsWith("jar:file:")) return new URL(s.substring(4, s.indexOf("!/"))); } catch (Exception e) { logger.debug(e.getMessage(), e); } return null; } public static Object call(Class<?> oClass, String method, Object obj, Object[] arg) throws InvocationTargetException, NoSuchMethodException { // Lets just try all methods for now Method[] methods = oClass.getMethods(); for (int c = 0; methods != null && c < methods.length; c++) { if (!methods[c].getName().equals(method)) continue; if (methods[c].getParameterTypes().length != arg.length) continue; if (Modifier.isStatic(methods[c].getModifiers()) != (obj == null)) continue; if ((obj == null) && methods[c].getDeclaringClass() != oClass) continue; try { return methods[c].invoke(obj, arg); } catch (IllegalAccessException e) { logger.debug(e.getMessage(), e); } catch (IllegalArgumentException e) { logger.debug(e.getMessage(), e); } } throw new NoSuchMethodException(method); } }