Java tutorial
/** * 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<T>{} * class B extends A<Integer>{} * </pre> * <code>extractTypeVariablesInType(B.class, map)</code><code>map</code> * <pre> * T -------> 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); } } }