java常用工具方法2

来源:互联网 发布:淘宝 html5 编辑:程序博客网 时间:2024/05/17 01:08
/* * Copyright 2005 Joe Walker * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *     http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package org.directwebremoting.util;import java.io.IOException;import java.io.InputStream;import java.io.RandomAccessFile;import java.io.Reader;import java.lang.reflect.Field;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.net.URLDecoder;import java.util.ArrayList;import java.util.Arrays;import java.util.HashSet;import java.util.Iterator;import java.util.List;import java.util.Locale;import java.util.Map;import java.util.Set;import javax.servlet.ServletConfig;import javax.servlet.ServletContext;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import javax.xml.transform.TransformerFactoryConfigurationError;/** * 一些通用的方法 * Various utilities, mostly to make up for JDK 1.4 functionallity that is not * in JDK 1.3 * @author Joe Walker [joe at getahead dot ltd dot uk] */public final class LocalUtil{    /**     * splitInbound() returns the type info in this parameter     */    public static final int INBOUND_INDEX_TYPE = 0;    /**     * splitInbound() returns the value info in this parameter     */    public static final int INBOUND_INDEX_VALUE = 1;    /**     * Prevent instansiation     */    private LocalUtil()    {    }    /**     * Replacement for String#replaceAll(String, String) in JDK 1.4+     * @param text source text     * @param repl the stuff to get rid of     * @param with the stuff to replace it with     * @return replaced text or null if any args are null     */    public static String replace(String text, String repl, String with)    {        if (text == null || repl == null || with == null || repl.length() == 0)        {            return text;        }        StringBuffer buf = new StringBuffer(text.length());        int searchFrom = 0;        while (true)        {            int foundAt = text.indexOf(repl, searchFrom);            if (foundAt == -1)            {                break;            }            buf.append(text.substring(searchFrom, foundAt)).append(with);            searchFrom = foundAt + repl.length();        }        buf.append(text.substring(searchFrom));        return buf.toString();    }    /**     * 判断给定的字符串是否符合 Java 标识符的规范     *      * Determines if the specified string is permissible as a Java identifier.     * Returns true if the string is non-null, non-zero length with a Java     * identifier start as the first character and Java identifier parts in all     * remaining characters.     * @param test the string to be tested.     * @return true if the string is a Java identifier, false otherwise.     * @see java.lang.Character#isJavaIdentifierPart(char)     * @see java.lang.Character#isJavaIdentifierStart(char)     */    public static boolean isJavaIdentifier(String test)    {        if (test == null || test.length() == 0)        {            return false;        }        if (!Character.isJavaIdentifierStart(test.charAt(0)) && test.charAt(0) != '_')        {            return false;        }        for (int i = 1; i < test.length(); i++)        {            if (!Character.isJavaIdentifierPart(test.charAt(i)) && test.charAt(i) != '_')            {                return false;            }        }        return true;    }    /**     * Determines if the specified string contains only Unicode letters or     * digits as defined by {@link Character#isLetterOrDigit(char)}     * @param test The string to test     * @return true if the string is non-null, non-empty and contains only     * characters that are unicode letters or digits     * @see Character#isLetterOrDigit(char)     */    public static boolean isLetterOrDigitOrUnderline(String test)    {        if (test == null || test.length() == 0)        {            return false;        }        for (int i = 0; i < test.length(); i++)        {            if (!Character.isLetterOrDigit(test.charAt(i)) && test.charAt(i) != '_')            {                return false;            }        }        return true;    }    /**     * True if c1 is java.lang.Boolean and c2 is boolean, etc.     * @param c1 the first class to test     * @param c2 the second class to test     * @return true if the classes are equivalent     */    public static boolean isEquivalent(Class c1, Class c2)    {        if (c1 == Boolean.class || c1 == Boolean.TYPE)        {            return c2 == Boolean.class || c2 == Boolean.TYPE;        }        else if (c1 == Byte.class || c1 == Byte.TYPE)        {            return c2 == Byte.class || c2 == Byte.TYPE;        }        else if (c1 == Character.class || c1 == Character.TYPE)        {            return c2 == Character.class || c2 == Character.TYPE;        }        else if (c1 == Short.class || c1 == Short.TYPE)        {            return c2 == Short.class || c2 == Short.TYPE;        }        else if (c1 == Integer.class || c1 == Integer.TYPE)        {            return c2 == Integer.class || c2 == Integer.TYPE;        }        else if (c1 == Long.class || c1 == Long.TYPE)        {            return c2 == Long.class || c2 == Long.TYPE;        }        else if (c1 == Float.class || c1 == Float.TYPE)        {            return c2 == Float.class || c2 == Float.TYPE;        }        else if (c1 == Double.class || c1 == Double.TYPE)        {            return c2 == Double.class || c2 == Double.TYPE;        }        else if (c1 == Void.class || c1 == Void.TYPE)        {            return c2 == Void.class || c2 == Void.TYPE;        }        return false;    }    /**     * @param type The class to de-primitivize     * @return The non-privitive version of the class     */    public static Class getNonPrimitiveType(Class type)    {        if (!type.isPrimitive())        {            return type;        }        else if (type == Boolean.TYPE)        {            return Boolean.class;        }        else if (type == Byte.TYPE)        {            return Byte.class;        }        else if (type == Character.TYPE)        {            return Character.class;        }        else if (type == Short.TYPE)        {            return Short.class;        }        else if (type == Integer.TYPE)        {            return Integer.class;        }        else if (type == Long.TYPE)        {            return Long.class;        }        else if (type == Float.TYPE)        {            return Float.class;        }        else if (type == Double.TYPE)        {            return Double.class;        }        else if (type == Void.TYPE)        {            return Void.class;        }        return null;    }    /**     * Add headers to prevent browers and proxies from caching this reply.     * @param resp The response to add headers to     */    public static void addNoCacheHeaders(HttpServletResponse resp)    {        // Set standard HTTP/1.1 no-cache headers.        resp.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");        // Set IE extended HTTP/1.1 no-cache headers (use addHeader).        resp.addHeader("Cache-Control", "post-check=0, pre-check=0");        // Set standard HTTP/1.0 no-cache header.        resp.setHeader("Pragma", "no-cache");        // Set to expire far in the past. Prevents caching at the proxy server        resp.setHeader("Expires", "Sat, 6 May 1995 12:00:00 GMT");    }    /**     * Is this class one that we auto fill, so the user can ignore?     * @param paramType The type to test     * @return true if the type is a Servlet type     */    public static boolean isServletClass(Class paramType)    {        return paramType == HttpServletRequest.class ||               paramType == HttpServletResponse.class ||               paramType == ServletConfig.class ||               paramType == ServletContext.class ||               paramType == HttpSession.class;    }    /**     * URL decode a value. This method gets around the lack of a     * decode(String, String) method in JDK 1.3.     * @param value The string to decode     * @return The decoded string     */    public static String decode(String value)    {        if (!testedDecoder)        {            try            {                decode14 = URLDecoder.class.getMethod("decode", new Class[] { String.class, String.class });            }            catch (Exception ex)            {                if (!warn13)                {                    log.warn("URLDecoder.decode(String, String) is not available. Falling back to 1.3 variant.");                    warn13 = true;                }            }            testedDecoder = true;        }        if (decode14 != null)        {            try            {                return (String) decode14.invoke(null, new Object[] { value, "UTF-8" });            }            catch (Exception ex)            {                log.warn("Failed to use JDK 1.4 decoder", ex);            }        }        return URLDecoder.decode(value);    }    /**     * 用反射给对象设置属性集     *      * Set use reflection to set the setters on the object called by the keys     * in the params map with the corresponding values     * @param object The object to setup     * @param params The settings to use     * @param ignore List of keys to not warn about if they are not properties     *               Note only the warning is skipped, we still try the setter     */    public static void setParams(Object object, Map params, List ignore)    {        for (Iterator it = params.entrySet().iterator(); it.hasNext();)        {            Map.Entry entry = (Map.Entry) it.next();            String key = (String) entry.getKey();            Object value = entry.getValue();            try            {                setProperty(object, key, value);            }            catch (NoSuchMethodException ex)            {                if (ignore != null && !ignore.contains(key))                {                    log.warn("No property '" + key + "' on " + object.getClass().getName());                }            }            catch (InvocationTargetException ex)            {                log.warn("Error setting " + key + "=" + value + " on " + object.getClass().getName(), ex.getTargetException());            }            catch (Exception ex)            {                log.warn("Error setting " + key + "=" + value + " on " + object.getClass().getName(), ex);            }        }    }    /**     * 用反射给对象设置属性,通过给定的属性名。     *      * Set a property on an object using reflection     * @param object The object to call the setter on     * @param key The name of the property to set.     * @param value The new value to use for the property     * @throws NoSuchMethodException Passed on from reflection code     * @throws SecurityException Passed on from reflection code     * @throws IllegalAccessException Passed on from reflection code     * @throws IllegalArgumentException Passed on from reflection code     * @throws InvocationTargetException Passed on from reflection code     */    public static void setProperty(Object object, String key, Object value) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException    {        Class real = object.getClass();        String setterName = "set" + key.substring(0, 1).toUpperCase(Locale.ENGLISH) + key.substring(1);        try        {            // Can we work with whatever type we were given?            Method method = real.getMethod(setterName, new Class[] { value.getClass() });            method.invoke(object, new Object[] { value });            return;        }        catch (NoSuchMethodException ex)        {            // If it is a string then next we try to coerce it to the right type            // otherwise we give up.            if (!(value instanceof String))            {                throw ex;            }        }        Method[] methods = real.getMethods();        for (int i = 0; i < methods.length; i++)        {            Method setter = methods[i];            if (setter.getName().equals(setterName) && setter.getParameterTypes().length == 1)            {                Class propertyType = setter.getParameterTypes()[0];                try                {                    Object param = LocalUtil.simpleConvert((String) value, propertyType);                    setter.invoke(object, new Object[] { param });                    return;                }                catch (IllegalArgumentException ex)                {                    // The conversion failed - it was speculative anyway so we                    // don't worry now                }            }        }        throw new NoSuchMethodException("Failed to find a property called: " + key + " on " + object.getClass().getName());    }    /**     * Can the type be used in a call to {@link #simpleConvert(String, Class)}?     * @param paramType The type to test     * @return true if the type is acceptable to simpleConvert()     */    public static boolean isTypeSimplyConvertable(Class paramType)    {        return paramType == String.class ||            paramType == Integer.class ||            paramType == Integer.TYPE ||            paramType == Short.class ||            paramType == Short.TYPE ||            paramType == Byte.class ||            paramType == Byte.TYPE ||            paramType == Long.class ||            paramType == Long.TYPE ||            paramType == Float.class ||            paramType == Float.TYPE ||            paramType == Double.class ||            paramType == Double.TYPE ||            paramType == Character.class ||            paramType == Character.TYPE ||            paramType == Boolean.class ||            paramType == Boolean.TYPE;    }    /**     * A very simple conversion function for all the IoC style setup and     * reflection that we are doing.     * @param value The value to convert     * @param paramType The type to convert to. Currently ony primitive types and     * String are supported.     * @return The converted object.     */    public static Object simpleConvert(String value, Class paramType)    {        if (paramType == String.class)        {            return value;        }        if (paramType == Character.class || paramType == Character.TYPE)        {            if (value.length() == 1)            {                return new Character(value.charAt(0));            }            else            {                throw new IllegalArgumentException("Can't more than one character in string - can't convert to char: '" + value + "'");            }        }        String trimValue = value.trim();        if (paramType == Boolean.class)        {            if (trimValue.length() == 0)            {                return null;            }            return Boolean.valueOf(trimValue);        }        if (paramType == Boolean.TYPE)        {            return Boolean.valueOf(trimValue);        }        if (paramType == Integer.class)        {            if (trimValue.length() == 0)            {                return null;            }            return Integer.valueOf(trimValue);        }        if (paramType == Integer.TYPE)        {            if (trimValue.length() == 0)            {                return new Integer(0);            }            return Integer.valueOf(trimValue);        }        if (paramType == Short.class)        {            if (trimValue.length() == 0)            {                return null;            }            return Short.valueOf(trimValue);        }        if (paramType == Short.TYPE)        {            if (trimValue.length() == 0)            {                return new Short((short) 0);            }            return Short.valueOf(trimValue);        }        if (paramType == Byte.class)        {            if (trimValue.length() == 0)            {                return null;            }            return Byte.valueOf(trimValue);        }        if (paramType == Byte.TYPE)        {            if (trimValue.length() == 0)            {                return new Byte((byte) 0);            }            return Byte.valueOf(trimValue);        }        if (paramType == Long.class)        {            if (trimValue.length() == 0)            {                return null;            }            return Long.valueOf(trimValue);        }        if (paramType == Long.TYPE)        {            if (trimValue.length() == 0)            {                return new Long(0);            }            return Long.valueOf(trimValue);        }        if (paramType == Float.class)        {            if (trimValue.length() == 0)            {                return null;            }            return Float.valueOf(trimValue);        }        if (paramType == Float.TYPE)        {            if (trimValue.length() == 0)            {                return new Float(0);            }            return Float.valueOf(trimValue);        }        if (paramType == Double.class)        {            if (trimValue.length() == 0)            {                return null;            }            return Double.valueOf(trimValue);        }        if (paramType == Double.TYPE)        {            if (trimValue.length() == 0)            {                return new Double(0);            }            return Double.valueOf(trimValue);        }        throw new IllegalArgumentException("Unsupported conversion type: " + paramType.getName());    }    /**     * 得到除去包名的类名。     *      * Get the short class name (i.e. without the package part)     * @param clazz the class to get the short name of     * @return the class name of the class without the package name     */    public static String getShortClassName(Class clazz)    {        String className = clazz.getName();        char[] chars = className.toCharArray();        int lastDot = 0;        for (int i = 0; i < chars.length; i++)        {            if (chars[i] == '.')            {                lastDot = i + 1;            }            else if (chars[i] == '$')            {                chars[i] = '.';            }        }        // This might come up in scans for locale/charset issues. It's not an        // issue since we are talking about chars.        return new String(chars, lastDot, chars.length - lastDot);    }    /**     * Is this object property one that we can use in a JSON style or do we need     * to get fancy. i.e does it contain only letters and numbers with an     * initial letter.     * @param name The name to test for JSON compatibility     * @return true if the name is simple     */    public static boolean isSimpleName(String name)    {        if (name.length() == 0)        {            return false;        }        if (JavascriptUtil.isReservedWord(name))        {            return false;        }        boolean isSimple = Character.isLetter(name.charAt(0));        for (int i = 1; isSimple && i < name.length(); i++)        {            if (!Character.isLetterOrDigit(name.charAt(i)))            {                isSimple = false;            }        }        return isSimple;    }    /**     * Utility to essentially do Class forName and allow configurable     * Classloaders.     * <p>The initial implementation makes use of the context classloader for     * the current thread.     * @param className The class to create     * @return The class if it is safe or null otherwise.     * @throws ClassNotFoundException If <code>className</code> is not valid     */    public static Class classForName(String className) throws ClassNotFoundException    {        // Class.forName(className);        return Thread.currentThread().getContextClassLoader().loadClass(className);    }    /**     * Calling methods using reflection is useful for graceful fallback - this     * is a helper method to make this easy     * @param object The object to use as 'this'     * @param method The method to call, can be null in which case null is returned     * @param params The parameters to pass to the reflection call     * @return The results of calling method.invoke() or null     * @throws IllegalStateException If anything goes wrong     */    public static Object invoke(Object object, Method method, Object[] params) throws IllegalStateException    {        Object reply = null;        if (method != null)        {            try            {                reply = method.invoke(object, params);            }            catch (InvocationTargetException ex)            {                throw new IllegalStateException("InvocationTargetException calling " + method.getName() + ": " + ex.getTargetException().toString());            }            catch (Exception ex)            {                throw new IllegalStateException("Reflection error calling " + method.getName() + ": " + ex.toString());            }        }        return reply;    }    /**     * Utility to essentially do Class forName with the assumption that the     * environment expects failures for missing jar files and can carry on if     * this process fails.     * @param name The name for debugging purposes     * @param className The class to create     * @param impl The implementation class - what should className do?     * @return The class if it is safe or null otherwise.     */    public static Class classForName(String name, String className, Class impl)    {        Class clazz;        try        {            clazz = classForName(className);        }        catch (ClassNotFoundException ex)        {            // We expect this sometimes, hence debug            log.debug("Skipping '" + name + "' due to ClassNotFoundException on " + className + ". Cause: " + ex.getMessage());            return null;        }        catch (NoClassDefFoundError ex)        {            // We expect this sometimes, hence debug            log.debug("Skipping '" + name + "' due to NoClassDefFoundError on " + className + ". Cause: " + ex.getMessage());            return null;        }        catch (TransformerFactoryConfigurationError ex)        {            // We expect this sometimes, hence debug            log.debug("Skipping '" + name + "' due to TransformerFactoryConfigurationError on " + className + ". Cause: " + ex.getMessage());            log.debug("Maybe you need to add xalan.jar to your webserver?");            return null;        }        // Check it is of the right type        if (!impl.isAssignableFrom(clazz))        {            log.error("Class '" + clazz.getName() + "' does not implement '" + impl.getName() + "'.");            return null;        }        // Check we can create it        try        {            clazz.newInstance();        }        catch (InstantiationException ex)        {            log.error("InstantiationException for '" + name + "' failed:", ex);            return null;        }        catch (IllegalAccessException ex)        {            log.error("IllegalAccessException for '" + name + "' failed:", ex);            return null;        }        catch (NoClassDefFoundError ex)        {            // We expect this sometimes, hence debug            log.debug("Skipping '" + name + "' due to NoClassDefFoundError on " + className + ". Cause: " + ex.getMessage());            return null;        }        catch (TransformerFactoryConfigurationError ex)        {            // We expect this sometimes, hence debug            log.debug("Skipping '" + name + "' due to TransformerFactoryConfigurationError on " + className + ". Cause: " + ex.getMessage());            log.debug("Maybe you need to add xalan.jar to your webserver?");            return null;        }        catch (Exception ex)        {            // For some reason we can't catch this?            if (ex instanceof ClassNotFoundException)            {                // We expect this sometimes, hence debug                log.debug("Skipping '" + name + "' due to ClassNotFoundException on " + className + ". Cause: " + ex.getMessage());                return null;            }            else            {                log.error("Failed to load '" + name + "' (" + className + ")", ex);                return null;            }        }        return clazz;    }    /**     * Utility to essentially do Class forName and newInstance with the     * assumption that the environment expects failures for missing jar files     * and can carry on if this process fails.     * @param name The name for debugging purposes     * @param className The class to create     * @param impl The implementation class - what should className do?     * @return The new instance if it is safe or null otherwise.     */    public static Object classNewInstance(String name, String className, Class impl)    {        Class clazz;        try        {            clazz = LocalUtil.classForName(className);        }        catch (ClassNotFoundException ex)        {            // We expect this sometimes, hence debug            log.debug("Skipping '" + name + "' due to ClassNotFoundException on " + className + ". Cause: " + ex.getMessage());            return null;        }        catch (NoClassDefFoundError ex)        {            // We expect this sometimes, hence debug            log.debug("Skipping '" + name + "' due to NoClassDefFoundError on " + className + ". Cause: " + ex.getMessage());            return null;        }        catch (TransformerFactoryConfigurationError ex)        {            // We expect this sometimes, hence debug            log.debug("Skipping '" + name + "' due to TransformerFactoryConfigurationError on " + className + ". Cause: " + ex.getMessage());            return null;        }        // Check it is of the right type        if (!impl.isAssignableFrom(clazz))        {            log.error("Class '" + clazz.getName() + "' does not implement '" + impl.getName() + "'.");            return null;        }        // Check we can create it        try        {            return clazz.newInstance();        }        catch (InstantiationException ex)        {            log.error("InstantiationException for '" + name + "' failed:", ex);            return null;        }        catch (IllegalAccessException ex)        {            log.error("IllegalAccessException for '" + name + "' failed:", ex);            return null;        }        catch (TransformerFactoryConfigurationError ex)        {            log.error("TransformerFactoryConfigurationError for '" + name + "' failed:", ex);            return null;        }        catch (Exception ex)        {            log.error("Failed to load creator '" + name + "', classname=" + className + ": ", ex);            return null;        }    }    /**     * InputStream closer that can cope if the input stream is null.     * If anything goes wrong, the errors are logged and ignored.     * @param in The resource to close     */    public static void close(InputStream in)    {        if (in == null)        {            return;        }        try        {            in.close();        }        catch (IOException ex)        {            log.warn(ex.getMessage(), ex);        }    }    /**     * InputStream closer that can cope if the input stream is null.     * If anything goes wrong, the errors are logged and ignored.     * @param in The resource to close     */    public static void close(Reader in)    {        if (in == null)        {            return;        }        try        {            in.close();        }        catch (IOException ex)        {            log.warn(ex.getMessage(), ex);        }    }    /**     * InputStream closer that can cope if the input stream is null.     * If anything goes wrong, the errors are logged and ignored.     * @param in The resource to close     */    public static void close(RandomAccessFile in)    {        if (in == null)        {            return;        }        try        {            in.close();        }        catch (IOException ex)        {            log.warn(ex.getMessage(), ex);        }    }    /**     * Return a List of superclasses for the given class.     * @param clazz the class to look up     * @return the List of superclasses in order going up from this one     */    public static List getAllSuperclasses(Class clazz)    {        List classes = new ArrayList();        Class superclass = clazz.getSuperclass();        while (superclass != null)        {            classes.add(superclass);            superclass = superclass.getSuperclass();        }        return classes;    }    /**     * Return a list of all fields (whatever access status, and on whatever     * superclass they were defined) that can be found on this class.     * <p>This is like a union of {@link Class#getDeclaredFields()} which     * ignores and superclasses, and {@link Class#getFields()} which ignored     * non-pubic fields     * @param clazz The class to introspect     * @return The complete list of fields     */    public static Field[] getAllFields(Class clazz)    {        List classes = getAllSuperclasses(clazz);        classes.add(clazz);        return getAllFields(classes);    }    /**     * As {@link #getAllFields(Class)} but acts on a list of {@link Class}s and     * uses only {@link Class#getDeclaredFields()}.     * @param classes The list of classes to reflect on     * @return The complete list of fields     */    private static Field[] getAllFields(List classes)    {        Set fields = new HashSet();        for (Iterator it = classes.iterator(); it.hasNext();)        {            Class clazz = (Class) it.next();            fields.addAll(Arrays.asList(clazz.getDeclaredFields()));        }        return (Field[]) fields.toArray(new Field[fields.size()]);    }    /**     * The log stream     */    private static final Logger log = Logger.getLogger(LocalUtil.class);    /**     * Have we given a warning about URLDecoder.decode() in jdk 1.3     */    private static boolean warn13 = false;    /**     * Have we tested for the correct URLDecoder.decode()     */    private static boolean testedDecoder = false;    /**     * Are we using the jdk 1.4 version of URLDecoder.decode()     */    private static Method decode14 = null;}
0 0