Java tutorial
/* * JEF - Copyright 2009-2010 Jiyi (mr.jiyi@gmail.com) * * 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 jef.tools.reflect; import java.io.InputStream; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import javax.management.ReflectionException; import jef.common.log.LogUtil; import jef.tools.Assert; import jef.tools.StringUtils; import jef.tools.collection.CollectionUtil; import jef.tools.collection.IterableAccessor; import jef.tools.reflect.BeanUtils.SearchMode; import org.apache.commons.lang.ObjectUtils; /** * Class? * ??Class? * @author jiyi */ public class ClassEx { /** * Class */ private Class<?> cls; /** * */ private Type genericType; private ClassEx instanceClz; public ClassEx(Type type) { this.genericType = type; this.cls = GenericUtils.getRawClass(type); Assert.notNull(cls); } public ClassEx(Class<?> cls) { if (isCGLibProxy(cls)) { cls = cls.getSuperclass(); } this.genericType = cls; this.cls = cls; } /** * * * @return */ public Class<?> getWrappered() { return cls; } /** * * * @return */ public Type getGenericType() { return genericType; } /** * ?? * * @param params * @return * @throws ReflectionException */ public Object newInstance(Object... params) throws ReflectionException { return BeanUtils.newInstance(cls, params); } /** * ??null */ public Object newInstanceAnyway() throws ReflectionException { return BeanUtils.newInstanceAnyway(cls); } /** * ??? * * @param method * @param params * @return * @throws ReflectionException */ public Object invokeStaticMethod(String method, Object... params) throws ReflectionException { return innerInvoke(null, method, true, params); } /** * ???? * * @param method * @param params * @return * @throws ReflectionException */ public Object invokeWithNewInstance(String method, Object... params) throws ReflectionException { return innerInvoke(newInstanceAnyway(), method, false, params); } /* * obj method??isStatic??params:? */ Object innerInvoke(Object obj, String method, boolean isStatic, Object... params) throws ReflectionException { try { if (obj == null && !isStatic) obj = newInstance(); List<Class<?>> list = new ArrayList<Class<?>>(); for (Object pobj : params) { list.add(pobj.getClass()); } MethodEx me = BeanUtils.getCompatibleMethod(cls, method, list.toArray(new Class[list.size()])); if (me == null) { NoSuchMethodException e = new NoSuchMethodException("Method:[" + cls.getName() + "::" + method + "] not found with param count:" + params.length); throw new ReflectionException(e); } if (!Modifier.isPublic(me.getModifiers()) || !Modifier.isPublic(cls.getModifiers())) { try { me.setAccessible(true); } catch (SecurityException e) { System.out.println(me.toString() + "\n" + e.getMessage()); } } return me.invoke(obj, params); } catch (IllegalAccessException e) { throw new ReflectionException(e); } catch (SecurityException e) { throw new ReflectionException(e); } catch (IllegalArgumentException e) { throw new ReflectionException(e); } catch (InvocationTargetException e) { if (e.getCause() instanceof Exception) { throw new ReflectionException((Exception) e.getCause()); } else { throw new ReflectionException(e); } } } /** * ?? */ public static List<Class<?>> withSupers(Class<?> c) { List<Class<?>> supers = new ArrayList<Class<?>>(); supers.add(c); c = c.getSuperclass(); while (c != null) { supers.add(c); c = c.getSuperclass(); } return supers; } public FieldEx[] getDeclaredFields() { Field[] fields = cls.getDeclaredFields(); FieldEx[] result = new FieldEx[fields.length]; for (int i = 0; i < fields.length; i++) { result[i] = new FieldEx(fields[i], instanceClz == null ? this : instanceClz); } return result; } /** * Annotation */ public <T extends Annotation> T getAnnotation(Class<T> t) { return cls.getAnnotation(t); } /** * ?? * * @param method * @return */ public Type getMethodReturnType(Method method) { ClassEx cw = this; method = getRealMethod(method); if (method.getDeclaringClass() != this.cls) { Type type = GenericUtils.getSuperType(null, cls, method.getDeclaringClass()); cw = new ClassEx(type); } return BeanUtils.getBoundType(method.getGenericReturnType(), cw); } /** * ?? * * @param method * @param index * @return */ public Type getMethodParamType(Method method, int index) { ClassEx cw = this; method = getRealMethod(method); if (method.getDeclaringClass() != this.cls) { Type type = GenericUtils.getSuperType(null, cls, method.getDeclaringClass()); cw = new ClassEx(type); } Type[] types = method.getGenericParameterTypes(); if (index < 0 || index > types.length) { throw new IllegalArgumentException(StringUtils.concat("the method ", method.getName(), " has ", String.valueOf(types.length), " params, index=", String.valueOf(index), " is out of bound.")); } return BeanUtils.getBoundType(types[index], cw); } private Method getRealMethod(Method method) { Class<?> cls = method.getDeclaringClass(); if (isCGLibProxy(cls)) { try { return cls.getSuperclass().getMethod(method.getName(), method.getParameterTypes()); } catch (SecurityException e) { LogUtil.exception(e); } catch (NoSuchMethodException e) { LogUtil.exception(e); } } return method; } /** * ???? * * @param method * @return */ public Type[] getMethodParamTypes(Method method) { ClassEx cw = this; method = getRealMethod(method); if (method.getDeclaringClass() != this.cls) { Type type = GenericUtils.getSuperType(null, cls, method.getDeclaringClass()); cw = new ClassEx(type); } Type[] types = method.getGenericParameterTypes(); for (int i = 0; i < types.length; i++) { types[i] = BeanUtils.getBoundType(types[i], cw); } return types; } /** * CGLib?class * * @param clz * @return */ public static Class<?> getRealClass(Class<?> clz) { if (isCGLibProxy(clz)) { return clz.getSuperclass(); } return clz; } // ?CGLIB? private static boolean isCGLibProxy(Class<?> declaringClass) { return (declaringClass.getName().indexOf("$$EnhancerByCGLIB$$") > -1); } /** * ?? * * @param value * @param container * @param oldValue * @return */ @SuppressWarnings("rawtypes") public static Object toProperType(Object value, ClassEx container, Object oldValue) { if (value == null) return null; Class<?> clz = value.getClass(); if (container.isAssignableFrom(clz)) { if (container.isCollection()) { return checkAndConvertCollection((Collection) value, container); } else if (container.isMap()) { return checkAndConvertMap((Map) value, container); } else { return value; } } else if (CollectionUtil.isArrayOrCollection(clz)) { IterableAccessor<Object> accesor = new IterableAccessor<Object>(value); if (container.isArray()) { return BeanUtils.toProperArrayType(accesor, container, oldValue); } else if (container.isCollection()) { return BeanUtils.toProperCollectionType(accesor, container, oldValue); } else { BeanUtils.toProperType(accesor.toString(), container, oldValue); } } return BeanUtils.toProperType(ObjectUtils.toString(value), container, oldValue); } @SuppressWarnings({ "rawtypes", "unchecked" }) private static Object checkAndConvertMap(Map rawValue, ClassEx container) { Entry<Type, Type> types = GenericUtils.getMapTypes(container.genericType); boolean checkKey = types.getKey() != Object.class; boolean checkValue = types.getValue() != Object.class; if (!checkKey && !checkValue) return rawValue; ClassEx tk = new ClassEx(types.getKey()); ClassEx tv = new ClassEx(types.getValue()); Set<Map.Entry> es = rawValue.entrySet(); Map result; try { result = rawValue.getClass().newInstance(); } catch (InstantiationException e1) { throw new IllegalArgumentException(e1); } catch (IllegalAccessException e1) { throw new IllegalArgumentException(e1); } for (Map.Entry e : es) { Object key = e.getKey(); Object value = e.getValue(); if (key != null && checkKey) key = toProperType(key, tk, null); if (value != null && checkValue) value = toProperType(value, tv, null); result.put(key, value); } return result; } @SuppressWarnings({ "rawtypes", "unchecked" }) private static Object checkAndConvertCollection(Collection rawValue, ClassEx container) { Type type = GenericUtils.getCollectionType(container.genericType); if (type == Object.class) return rawValue; ClassEx t = new ClassEx(type); Collection result; try { result = rawValue.getClass().newInstance(); } catch (InstantiationException e1) { throw new IllegalArgumentException(e1); } catch (IllegalAccessException e1) { throw new IllegalArgumentException(e1); } for (Object e : rawValue) { e = toProperType(e, t, null); result.add(e); } return result; } /** * class * * @return */ public String getName() { return cls.getName(); } /** * class * * @return */ public String getSimpleName() { return cls.getSimpleName(); } /** * ?? * * @return */ public String getGenericName() { return genericType.toString(); } /** * * * @param name * @param params * @return */ public Method getPublicMethod(String name, Class<?>... params) { try { return cls.getMethod(name, params); } catch (SecurityException e) { throw new IllegalArgumentException(e.getMessage()); } catch (NoSuchMethodException e) { return null; } } /** * ????????? * * @param name * @return */ public MethodEx getMethodByName(String name) { MethodEx[] methods = BeanUtils.getMethodByName(this, name, 1, SearchMode.NOT_IN_SUPER_IF_FOUND); if (methods.length > 1) { throw new IllegalArgumentException( "There are more than 1 method match the name " + name + " in class " + cls.getName()); } if (methods.length == 0) return null; return methods[0]; } /** * gettersetterfield * * @return */ public FieldEx[] getFieldsWithGetterAndSetter() { return BeanUtils.getFieldsWithGetterAndSetter(this.cls, Object.class); } public FieldEx[] getFieldsWithGetter() { return BeanUtils.getFieldsWithGetter(this.cls, Object.class); } public FieldEx[] getFieldsWithSetter() { return BeanUtils.getFieldsWithSetter(this.cls, Object.class); } /** * field?? * * @return */ public String[] getFieldNames() { return BeanUtils.getFieldNames(this.cls, Object.class); } /** * Field * * @return */ public FieldEx[] getFields() { return BeanUtils.getFields(this.cls, Object.class, false, false); } /** * public * * @return */ public MethodEx[] getMethods() { return BeanUtils.getMethods(this.cls); } /** * * * @param name * @return */ public Class<?> getFieldType(String name) { return BeanUtils.getFieldType(cls, name); } /** * ?? * * @param name * @return */ public Type getFieldGenericType(String name) { return BeanUtils.getField(this, name).getGenericType(); } /** * ?? * * @param name * @return */ public Type getFieldGenericType(Field field) { Assert.notNull(field); ClassEx cw = this; if (field.getDeclaringClass() != this.cls) { Type type = GenericUtils.getSuperType(null, cls, field.getDeclaringClass()); cw = new ClassEx(type); } return BeanUtils.getBoundType(field.getGenericType(), cw); } /** * ? * * @param className * @param loder * @return * @throws ReflectionException */ public static final ClassEx getClassEx(String className, ClassLoader loder) throws ReflectionException { try { if (loder == null) loder = ClassEx.class.getClassLoader(); Class<?> c = loder.loadClass(className); return new ClassEx(c); } catch (ClassNotFoundException e) { throw new ReflectionException(e, "Class: " + className + " not found."); } } /** * * * @param className * @return * @throws ReflectionException */ public static final ClassEx getClassEx(String className) throws ReflectionException { return getClassEx(className, null); } /** * ???????? * * @param name * @return */ public MethodEx getFirstMethodByName(String name) { MethodEx[] methods = BeanUtils.getMethodByName(this, name, 1, SearchMode.NOT_IN_SUPER_IF_FOUND); if (methods.length > 0) return methods[0]; return null; } /* * ???? <p>Title: getImplType</p> <p>Description: </p> * * @param declaration * * @return * * @see * jef.tools.reflect.GenericProvider#getImplType(java.lang.reflect.TypeVariable * ) */ public Type getImplType(TypeVariable<?> declaration) { if (declaration.getGenericDeclaration() == this.cls && this.genericType instanceof ParameterizedType) { ParameterizedType pType = (ParameterizedType) genericType; int n = 0; for (TypeVariable<?> tv : cls.getTypeParameters()) { if (tv == declaration) break; n++; } return pType.getActualTypeArguments()[n]; } return null; } public FieldEx getField(String field) { return BeanUtils.getField(this, field); } public MethodEx getMethod(String name, Class<?>... parameterTypes) throws NoSuchMethodException { return new MethodEx(cls.getMethod(name, parameterTypes), this); } public MethodEx getMethodIfExist(String name, Class<?>... paramTypes) { try { Method method = cls.getMethod(name, paramTypes); return new MethodEx(method, this); } catch (SecurityException e) { LogUtil.exception(e); } catch (NoSuchMethodException e) { LogUtil.exception(e); } return null; } public boolean isInterface() { return cls.isInterface(); } public Class<?> getEnclosingClass() { return cls.getEnclosingClass(); } public int getModifiers() { return cls.getModifiers(); } public Object[] getEnumConstants() { return cls.getEnumConstants(); } public MethodEx getDeclaredMethod(String name, Class<?>... parameterTypes) throws SecurityException, NoSuchMethodException { Method m = cls.getDeclaredMethod(name, parameterTypes); return new MethodEx(m, instanceClz == null ? this : instanceClz); } /** * ?? * * @return */ public ClassEx getSuperclass() { Type s = cls.getGenericSuperclass(); if (s == null) return null; ClassEx result = new ClassEx(s); if (instanceClz != null) { result.instanceClz = instanceClz; } else { result.instanceClz = this; } if (Throwable.class == result.getWrappered()) { return null; } return result; } public MethodEx[] getDeclaredMethods() { Method[] methods = cls.getDeclaredMethods(); MethodEx[] result = new MethodEx[methods.length]; for (int i = 0; i < methods.length; i++) { result[i] = new MethodEx(methods[i], instanceClz == null ? this : instanceClz); } return result; } public FieldEx getDeclaredField(String name) throws SecurityException, NoSuchFieldException { return new FieldEx(cls.getDeclaredField(name), instanceClz == null ? this : instanceClz); } public Constructor<?> getDeclaredConstructor(Class<?>... params) throws SecurityException, NoSuchMethodException { return cls.getDeclaredConstructor(params); } @Override public int hashCode() { return genericType.hashCode(); } @Override public boolean equals(Object obj) { if (obj instanceof ClassEx) { return this.genericType.equals(((ClassEx) obj).genericType); } return false; } public Package getPackage() { return cls.getPackage(); } public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) { return cls.isAnnotationPresent(annotationClass); } @Override public String toString() { return genericType.toString(); } public InputStream getResourceAsStream(String string) { return cls.getResourceAsStream(string); } public ClassLoader getClassLoader() { return cls.getClassLoader(); } public String getPackageName() { String s = cls.getName(); int n = s.lastIndexOf('.'); if (n > -1) { return s.substring(0, n); } else { return ""; } } /** * ??class?Wrapper * * @param name * @return class??null */ public static ClassEx forName(String name) { Class<?> c = getClass(name); return c == null ? null : new ClassEx(c); } /** * ??class,null * * @param name * @return */ public static Class<?> getClass(String name) { try { return Class.forName(name); } catch (ClassNotFoundException e) { System.err.println("Class:" + name + " not found!"); return null; } } public boolean isAssignableFrom(Class<?> class1) { return cls.isAssignableFrom(class1); } public boolean isGeneric() { return !this.genericType.equals(cls); } public boolean isEnum() { return cls.isEnum(); } public boolean isArray() { return GenericUtils.isArray(genericType); } public boolean isCollection() { return CollectionUtil.isCollection(genericType); } public boolean isMap() { return Map.class.isAssignableFrom(cls); } public Type getComponentType() { return CollectionUtil.getComponentType(genericType); } /** * ? * * @return */ public Class<?>[] getInterfaces() { return cls.getInterfaces(); } /** * ????? * * @return */ public Class<?>[] getAllInterfaces() { LinkedHashSet<Class<?>> intf = new LinkedHashSet<Class<?>>(); Class<?> c = cls; while (c != Object.class) { for (Class<?> ic : c.getInterfaces()) { intf.add(ic); } c = c.getSuperclass(); } return intf.toArray(new Class<?>[intf.size()]); } }