org.soybeanMilk.SbmUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.soybeanMilk.SbmUtils.java

Source

/**
 * 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.soybeanMilk;

import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.soybeanMilk.core.Constants;
import org.soybeanMilk.core.bean.CustomGenericArrayType;
import org.soybeanMilk.core.bean.CustomParameterizedType;

/**
 * 
 * @author earthangry@gmail.com
 * @date 2010-12-31
 */
public class SbmUtils {
    /**
     * ?<code>Class</code>
     * @param type
     * @return
     * @date 2010-12-31
     */
    public static boolean isClassType(Type type) {
        return (type instanceof Class<?>);
    }

    /**
     * ?<code>Class</code>
     * @param type
     * @return
     * @date 2010-12-31
     */
    public static Class<?> narrowToClass(Type type) {
        return (Class<?>) type;
    }

    /**
     * ?
     * @param type
     * @return
     * @date 2010-12-31
     */
    public static boolean isPrimitive(Type type) {
        return type != null && isClassType(type) && narrowToClass(type).isPrimitive();
    }

    /**
     * ?
     * @param obj
     * @param type
     * @return
     * @date 2010-12-31
     */
    public static boolean isInstanceOf(Object obj, Type type) {
        if (obj == null) {
            if (type == null)
                return true;
            else if (isClassType(type) && narrowToClass(type).isPrimitive())
                return false;
            else
                return true;
        } else {
            if (isClassType(type))
                return narrowToClass(type).isInstance(obj);
            else
                return isAncestorType(type, obj.getClass());
        }
    }

    /**
     * ??
     * @param ancestor
     * @param descendant
     * @return
     * @date 2010-12-31
     */
    public static boolean isAncestorType(Type ancestor, Type descendant) {
        if (descendant == null) {
            return true;
        } else if (ancestor == null) {
            return false;
        } else if (isClassType(ancestor)) {
            Class<?> ancestorClass = narrowToClass(ancestor);

            if (isClassType(descendant)) {
                return ancestorClass.isAssignableFrom(narrowToClass(descendant));
            } else if (descendant instanceof ParameterizedType) {
                return ancestorClass.isAssignableFrom(narrowToClass(((ParameterizedType) descendant).getRawType()));
            } else if (descendant instanceof GenericArrayType) {
                if (!ancestorClass.isArray())
                    return false;
                else
                    return isAncestorType(ancestorClass.getComponentType(),
                            ((GenericArrayType) descendant).getGenericComponentType());
            } else if (descendant instanceof TypeVariable<?>) {
                return isAncestorType(ancestorClass, reify(descendant, null));
            } else if (descendant instanceof WildcardType) {
                return isAncestorType(ancestorClass, reify(descendant, null));
            } else
                return false;
        } else if (ancestor instanceof ParameterizedType) {
            return isAncestorType(((ParameterizedType) ancestor).getRawType(), descendant);
        } else if (ancestor instanceof GenericArrayType) {
            if (isClassType(descendant)) {
                Class<?> descendantClass = narrowToClass(descendant);

                if (!descendantClass.isArray())
                    return false;
                else
                    return isAncestorType(((GenericArrayType) ancestor).getGenericComponentType(),
                            descendantClass.getComponentType());
            } else if (descendant instanceof GenericArrayType) {
                return isAncestorType(((GenericArrayType) ancestor).getGenericComponentType(),
                        ((GenericArrayType) descendant).getGenericComponentType());
            } else
                return false;
        } else if (ancestor instanceof TypeVariable<?>) {
            return isAncestorType(reify(ancestor, null), descendant);
        } else if (ancestor instanceof WildcardType) {
            return isAncestorType(reify(ancestor, null), descendant);
        } else
            return false;
    }

    /**
     * ?<code>type</code>?
     * @param type
     * @return
     * @date 2010-12-31
     */
    public static Type wrapType(Type type) {
        if (!isClassType(type))
            return type;
        else if (!narrowToClass(type).isPrimitive())
            return type;
        else if (Byte.TYPE.equals(type))
            return Byte.class;
        else if (Short.TYPE.equals(type))
            return Short.class;
        else if (Integer.TYPE.equals(type))
            return Integer.class;
        else if (Long.TYPE.equals(type))
            return Long.class;
        else if (Float.TYPE.equals(type))
            return Float.class;
        else if (Double.TYPE.equals(type))
            return Double.class;
        else if (Boolean.TYPE.equals(type))
            return Boolean.class;
        else if (Character.TYPE.equals(type))
            return Character.class;
        else
            return type;
    }

    /**
     * ???<code>name</code>??
     * @param name
     * @return
     * @throws ClassNotFoundException
     * @date 2012-5-27
     */
    public static Type nameToType(String name) throws ClassNotFoundException {
        Type re = ClassShortNames.get(name);

        if (re == null) {
            re = Class.forName(name);
        }

        return re;
    }

    /**
     * ??????{@linkplain Class#forName(String)}?
     * @param type
     * @return
     * @date 2012-5-14
     */
    public static String getFullQualifiedClassName(Type type) {
        String re = null;

        if (isClassType(type)) {
            re = ((Class<?>) type).getName();
        } else if (type instanceof ParameterizedType) {
            re = getFullQualifiedClassName(((ParameterizedType) type).getRawType());
        } else if (type instanceof GenericArrayType) {
            re = getFullQualifiedClassName(((GenericArrayType) type).getGenericComponentType());

            if (re.startsWith("[L"))
                re = "[" + re;
            else
                re = "[L" + re + ";";
        } else if (type instanceof TypeVariable<?>) {
            re = getFullQualifiedClassName(reify(type, (Class<?>) null));
        } else if (type instanceof WildcardType) {
            re = getFullQualifiedClassName(reify(type, (Class<?>) null));
        } else
            throw new IllegalArgumentException("unknown type " + SbmUtils.toString(type));

        return re;
    }

    /**
     * <code>type</code>?{@linkplain TypeVariable}{@linkplain WildcardType}<code>ownerClass</code>?
     * <code>type</code>????
     * @param type ?
     * @param ownerClass <code>type</code>?
     * @return
     * @date 2012-5-14
     */
    public static Type reify(Type type, Class<?> ownerClass) {
        if (isClassType(type))
            return type;

        if (ownerClass == null) {
            return reifyInner(type, null);
        } else {
            Map<TypeVariable<?>, Type> variableTypesMap = getClassVarialbleTypesMap(ownerClass);

            return reifyInner(type, variableTypesMap);
        }
    }

    /**
     * 
     * @param type
     * @param variableTypesMap
     * @return
     * @date 2012-5-14
     */
    private static Type reifyInner(Type type, Map<TypeVariable<?>, Type> variableTypesMap) {
        Type result = null;

        if (type instanceof Class<?>) {
            result = type;
        } else if (type instanceof ParameterizedType) {
            ParameterizedType pt = (ParameterizedType) type;

            Type[] at = pt.getActualTypeArguments();
            Type[] cat = new Type[at.length];

            //pt?pt??
            boolean reified = true;
            for (int i = 0; i < at.length; i++) {
                cat[i] = reifyInner(at[i], variableTypesMap);

                if (cat[i] != at[i])
                    reified = false;
            }

            if (reified)
                result = pt;
            else
                result = new CustomParameterizedType(pt.getRawType(), pt.getOwnerType(), cat);
        } else if (type instanceof GenericArrayType) {
            GenericArrayType gap = (GenericArrayType) type;

            Type ct = gap.getGenericComponentType();
            Type cct = reifyInner(ct, variableTypesMap);

            if (cct == ct)
                result = gap;
            else
                result = new CustomGenericArrayType(cct);
        } else if (type instanceof TypeVariable<?>) {
            TypeVariable<?> tv = (TypeVariable<?>) type;

            if (variableTypesMap != null)
                result = variableTypesMap.get(tv);

            if (result == null) {
                Type[] bounds = tv.getBounds();

                if (bounds == null || bounds.length == 0)
                    result = Object.class;
                else
                    result = bounds[0];
            }

            result = reifyInner(result, variableTypesMap);
        } else if (type instanceof WildcardType) {
            WildcardType wt = (WildcardType) type;

            Type[] upperBounds = wt.getUpperBounds();

            Type upperType = (upperBounds != null && upperBounds.length > 0 ? upperBounds[0] : null);

            if (upperType == null)
                upperType = Object.class;

            result = reifyInner(upperType, variableTypesMap);
        } else
            result = type;

        return result;
    }

    /**
     * ?{@linkplain TypeVariable}
     * @param clazz
     * @return
     * @date 2012-5-16
     */
    private static Map<TypeVariable<?>, Type> getClassVarialbleTypesMap(Class<?> clazz) {
        Map<TypeVariable<?>, Type> re = classReifiedTypeMap.get(clazz);

        if (re == null) {
            re = new HashMap<TypeVariable<?>, Type>();
            extractTypeVariablesInType(clazz, re);

            classReifiedTypeMap.putIfAbsent(clazz, re);
        }

        return re;
    }

    /**{@linkplain TypeVariable}?*/
    private static ConcurrentHashMap<Class<?>, Map<TypeVariable<?>, Type>> classReifiedTypeMap = new ConcurrentHashMap<Class<?>, Map<TypeVariable<?>, Type>>();

    /**
     * ???
     * <pre>
     * class A&lt;T&gt;{}
     * class B extends A&lt;Integer&gt;{}
     * </pre>
     * <code>extractTypeVariablesInType(B.class, map)</code><code>map</code>
     * <pre>
     * T    -------&gt;    Integer
     * </pre>
     * @param source
     * @param container
     * @date 2012-5-14
     */
    private static void extractTypeVariablesInType(Type source, Map<TypeVariable<?>, Type> variableTypesMap) {
        if (source == null)
            return;
        else if (source instanceof Class<?>) {
            Class<?> clazz = (Class<?>) source;

            //?
            Type[] genericInterfaces = clazz.getGenericInterfaces();
            if (genericInterfaces != null) {
                for (Type t : genericInterfaces)
                    extractTypeVariablesInType(t, variableTypesMap);
            }

            //
            Type genericSuperType = clazz.getGenericSuperclass();
            Class<?> superClass = clazz.getSuperclass();
            while (superClass != null && !Object.class.equals(superClass)) {
                extractTypeVariablesInType(genericSuperType, variableTypesMap);

                genericSuperType = superClass.getGenericSuperclass();
                superClass = superClass.getSuperclass();
            }

            //
            Class<?> outerClass = clazz;
            while (outerClass.isMemberClass()) {
                Type genericOuterType = outerClass.getGenericSuperclass();
                extractTypeVariablesInType(genericOuterType, variableTypesMap);

                outerClass = outerClass.getEnclosingClass();
            }
        } else if (source instanceof ParameterizedType) {
            ParameterizedType pt = (ParameterizedType) source;

            if (isClassType(pt.getRawType())) {
                Type[] actualArgTypes = pt.getActualTypeArguments();
                TypeVariable<?>[] typeVariables = narrowToClass(pt.getRawType()).getTypeParameters();

                for (int i = 0; i < actualArgTypes.length; i++) {
                    TypeVariable<?> var = typeVariables[i];
                    Type value = actualArgTypes[i];

                    //????
                    if (value instanceof TypeVariable<?>) {
                        Type actual = variableTypesMap.get(value);

                        if (actual != null)
                            value = actual;
                    }

                    variableTypesMap.put(var, value);
                }
            }

            //??
            extractTypeVariablesInType(pt.getRawType(), variableTypesMap);
        }
    }

    /**
     * ?
     * @param obj
     * @return
     * @date 2012-2-28
     */
    public static String toString(Object obj) {
        if (obj == null)
            return null;

        if (obj instanceof Type) {
            if (obj instanceof Class<?>)
                return "'" + ((Class<?>) obj).getName() + "'";
            else
                return "'" + obj.toString() + "'";
        } else if (obj instanceof String) {
            return "\"" + obj + "\"";
        } else if (obj.getClass().isArray()) {
            int len = Array.getLength(obj);

            StringBuilder sb = new StringBuilder();
            sb.append('[');

            for (int i = 0; i < len; i++) {
                sb.append(toString(Array.get(obj, i)));

                if (i != len - 1)
                    sb.append(", ");
            }

            sb.append(']');

            return sb.toString();
        } else
            return obj.toString();
    }

    /**
     * ??Java
     * @param s
     * @return
     */
    public static String unEscape(String s) {
        if (s == null || s.length() == 0)
            return s;

        StringBuffer sb = new StringBuffer();

        int i = 0;
        int len = s.length();
        while (i < len) {
            char c = s.charAt(i);

            if (c == '\\') {
                if (i == len - 1)
                    throw new IllegalArgumentException("\"" + s + "\" must not be end with '\\' ");

                i += 1;

                char next = s.charAt(i);
                if (next == 'u') {
                    i += 1;
                    int end = i + 4;

                    if (end > len)
                        throw new IllegalArgumentException("illegal \\uxxxx encoding in \"" + s + "\"");

                    int v = 0;
                    for (; i < end; i++) {
                        next = s.charAt(i);
                        switch (next) {
                        case '0':
                        case '1':
                        case '2':
                        case '3':
                        case '4':
                        case '5':
                        case '6':
                        case '7':
                        case '8':
                        case '9':
                            v = (v << 4) + next - '0';
                            break;
                        case 'a':
                        case 'b':
                        case 'c':
                        case 'd':
                        case 'e':
                        case 'f':
                            v = (v << 4) + 10 + next - 'a';
                            break;
                        case 'A':
                        case 'B':
                        case 'C':
                        case 'D':
                        case 'E':
                        case 'F':
                            v = (v << 4) + 10 + next - 'A';
                            break;
                        default:
                            throw new IllegalArgumentException("illegal \\uxxxx encoding in \"" + s + "\"");
                        }
                    }

                    sb.append((char) v);
                } else {
                    if (next == 't')
                        sb.append('\t');
                    else if (next == 'r')
                        sb.append('\r');
                    else if (next == 'n')
                        sb.append('\n');
                    else if (next == '\'')
                        sb.append('\'');
                    else if (next == '\\')
                        sb.append('\\');
                    else if (next == '"')
                        sb.append('"');
                    else
                        throw new IllegalArgumentException("unknown escape character '\\" + next + "'");

                    i++;
                }
            } else {
                sb.append(c);
                i++;
            }
        }

        return sb.toString();
    }

    /**
     * {@linkplain Constants#ACCESSOR }???{@linkplain Constants#ACCESSOR }?1
     * ?2?
     * @param str
     * @return
     * @date 2010-12-30
     */
    public static String[] splitByFirstAccessor(String str) {
        String[] re = null;

        int idx = str.indexOf(Constants.ACCESSOR);

        if (idx < 0)
            re = new String[] { str };
        else if (idx == 0)
            re = new String[] { "", str };
        else if (idx == str.length() - 1)
            re = new String[] { str, "" };
        else
            re = new String[] { str.substring(0, idx), str.substring(idx + 1) };

        return re;
    }

    /**
     * ?{@linkplain Constants#ACCESSOR }
     * @param accessExpression
     * @return
     * @date 2012-2-21
     */
    public static String[] splitAccessExpression(String accessExpression) {
        if (accessExpression == null)
            return null;

        String[] propertyArray = split(accessExpression, Constants.ACCESSOR);

        if (propertyArray == null || propertyArray.length == 0)
            propertyArray = new String[] { accessExpression };

        return propertyArray;
    }

    /**
     * ?
     * @param str
     * @param separatorChar 
     * @return
     * @date 2011-4-20
     */
    public static String[] split(String str, char separatorChar) {
        boolean preserveAllTokens = false;

        //org.apache.commons.lang.StringUtils.splitWorker(String, char, boolean)

        if (str == null) {
            return null;
        }
        int len = str.length();
        if (len == 0) {
            return null;//return ArrayUtils.EMPTY_STRING_ARRAY;
        }
        List<String> list = new ArrayList<String>();//List list = new ArrayList();
        int i = 0, start = 0;
        boolean match = false;
        boolean lastMatch = false;
        while (i < len) {
            if (str.charAt(i) == separatorChar) {
                if (match || preserveAllTokens) {
                    list.add(str.substring(start, i));
                    match = false;
                    lastMatch = true;
                }
                start = ++i;
                continue;
            }
            lastMatch = false;
            match = true;
            i++;
        }
        if (match || (preserveAllTokens && lastMatch)) {
            list.add(str.substring(start, i));
        }

        return list.toArray(new String[list.size()]);//return (String[]) list.toArray(new String[list.size()]);
    }

    /**
     * ????
     * @author earthangry@gmail.com
     * @date 2010-12-31
     */
    protected static class ClassShortNames {
        private static Class<?>[] simpleNameClasses = new Class<?>[] { boolean.class, boolean[].class,
                Boolean.class, Boolean[].class, byte.class, byte[].class, Byte.class, Byte[].class, char.class,
                char[].class, Character.class, Character[].class, double.class, double[].class, Double.class,
                Double[].class, float.class, float[].class, Float.class, Float[].class, int.class, int[].class,
                Integer.class, Integer[].class, long.class, long[].class, Long.class, Long[].class, short.class,
                short[].class, Short.class, Short[].class, String.class, String[].class, BigDecimal.class,
                BigDecimal[].class, BigInteger.class, BigInteger[].class, Date.class, Date[].class };

        private static Class<?>[] canonicalNameClasses = new Class<?>[] { java.sql.Date.class,
                java.sql.Date[].class, java.sql.Time.class, java.sql.Time[].class, java.sql.Timestamp.class,
                java.sql.Timestamp[].class };

        private static Map<String, Class<?>> nameMaps = new HashMap<String, Class<?>>();
        static {
            for (Class<?> c : simpleNameClasses)
                nameMaps.put(c.getSimpleName(), c);

            for (Class<?> c : canonicalNameClasses)
                nameMaps.put(c.getCanonicalName(), c);
        }

        /**
         * ?
         * @param shortName
         * @return
         */
        public static Class<?> get(String shortName) {
            if (shortName == null || shortName.length() == 0)
                return null;

            return nameMaps.get(shortName);
        }
    }
}