/** * * Copyright 2014 The Darks ORM Project (Liu lihua) * * 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 darks.orm.util; import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.JarURLConnection; import java.net.URL; import java.net.URLDecoder; import java.sql.ResultSet; import java.util.ArrayList; import java.util.Enumeration; import java.util.LinkedList; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.jar.JarEntry; import java.util.jar.JarFile; import net.sf.cglib.reflect.FastClass; import net.sf.cglib.reflect.FastConstructor; import net.sf.cglib.reflect.FastMethod; import darks.orm.core.data.FastClassData; import darks.orm.core.factory.TransformFactory; import darks.orm.exceptions.ClassReflectException; import darks.orm.log.Logger; import darks.orm.log.LoggerFactory; public final class ReflectHelper { private static Logger log = LoggerFactory.getLogger(ReflectHelper.class); /** * ���������ݻ��漯�� */ private static final ConcurrentMap<Class<?>, FastClassData> fastClassMap = new ConcurrentHashMap<Class<?>, FastClassData>( 32); /** * ResultSetӳ��get���ٷ��� get����Ϊ���� */ private static final ConcurrentMap<String, FastMethod> fastResultStringMethodMap = new ConcurrentHashMap<String, FastMethod>( 32); /** * ResultSetӳ��get���ٷ��� get����Ϊ������ */ private static final ConcurrentMap<String, FastMethod> fastResultIndexMethodMap = new ConcurrentHashMap<String, FastMethod>( 32); private static FastClass fastClass; static { fastClass = FastClass.create(ResultSet.class); registerResultSetMethod(); } // private static Logger log = LoggerFactory.getLogger(ReflectHelper.class); private ReflectHelper() { } @SuppressWarnings("unchecked") public static <T> T newInstance(String className, Object... params) throws ClassReflectException { Constructor<T> ctor = null; boolean set = false; try { Class<T> cls = (Class<T>) Class.forName(className); if (cls == null) return null; ctor = cls.getDeclaredConstructor(); if (ctor == null) { return cls.newInstance(); } if (!ctor.isAccessible()) { ctor.setAccessible(true); set = true; } return ctor.newInstance(params); } catch (NoSuchMethodException e) { throw new ClassReflectException("Failed to find empty constructor for class: " + className, e); } catch (Exception e) { throw new ClassReflectException( "Failed to create new instance for class: " + className, e); } finally { if (ctor != null && set) { ctor.setAccessible(false); } } } @SuppressWarnings("unchecked") public static <T> T newInstance(Class<T> clazz) throws ClassReflectException { if (clazz == null) return null; FastClassData data = parseFastClass(clazz); boolean set = false; Constructor<T> ctor = null; try { ctor = (Constructor<T>) data.getConstructor(); if (ctor == null) { return clazz.newInstance(); } if (!ctor.isAccessible()) { ctor.setAccessible(true); set = true; } return ctor.newInstance(); } catch (Exception e) { throw new ClassReflectException("Failed to create new instance for class: " + clazz, e); } finally { if (ctor != null && set) { ctor.setAccessible(false); } } } /** * ������ͨ����ٴ������� * * @param clazz ��ͨ�� * @return ����ʵ�� * @throws ClassReflectException */ @SuppressWarnings("unchecked") public static <T> T newFastInstance(Class<T> clazz) throws ClassReflectException { if (clazz == null) return null; FastClassData data = parseFastClass(clazz); FastConstructor fc = data.getFastConstructor(); if (fc != null) { try { return (T) fc.newInstance(); } catch (InvocationTargetException e) { throw new ClassReflectException( "Failed to create new instance for class: " + clazz, e); } } FastClass fclass = data.getFastClass(); if (fclass != null) { try { return (T) fclass.newInstance(); } catch (InvocationTargetException e) { throw new ClassReflectException( "Failed to create new instance for class: " + clazz, e); } } return newInstance(clazz); } /** * ���������� * * @param clazz ԭʼ�� * @return */ public static FastClass getFastClass(Class<?> clazz) { return FastClass.create(clazz); } /** * �������ٷ��� * * @param fasrClazz ������ * @param method ԭʼ���� * @return */ public static FastMethod getFastMethod(FastClass fastClazz, Method method) { return fastClazz.getMethod(method); } /** * �������ٷ��� * * @param fasrClazz ������ * @param method ԭʼ���� * @return */ public static FastMethod getFastMethod(FastClass fastClazz, String methodName, Class<?>... methodTypes) throws SecurityException, NoSuchMethodException { Class<?> clazz = fastClazz.getJavaClass(); FastClassData data = parseFastClass(clazz); FastMethod fastMethod = data.getFastMethod(methodName); if (fastMethod == null) { Method method = clazz.getMethod(methodName, methodTypes); fastMethod = getFastMethod(data.getFastClass(), method); data.addFastMethod(method, fastMethod); } return fastMethod; } /** * �������ٷ��� * * @param fasrClazz ������ * @param method ԭʼ���� * @return */ public static FastMethod getFastMethod(Class<?> clazz, String methodName, Class<?>... methodTypes) throws SecurityException, NoSuchMethodException { FastClassData data = parseFastClass(clazz); FastMethod fastMethod = data.getFastMethod(methodName); if (fastMethod == null) { Method method = clazz.getMethod(methodName, methodTypes); fastMethod = getFastMethod(data.getFastClass(), method); data.addFastMethod(method, fastMethod); } return fastMethod; } /** * ������ͨ�����ɿ����� * * @param clazz ��ͨ�� */ public static FastClassData parseFastClass(Class<?> clazz) { FastClassData data = fastClassMap.get(clazz); if (data != null) return data; Constructor<?> constructor = null; FastConstructor fconstructor = null; data = new FastClassData(); FastClass fastClazz = getFastClass(clazz); data.setOriginalClass(clazz); data.setFastClass(fastClazz); try { constructor = clazz.getConstructor(); if (constructor != null) { fconstructor = fastClazz.getConstructor(constructor); data.setConstructor(constructor); data.setFastConstructor(fconstructor); } } catch (SecurityException e) { } catch (NoSuchMethodException e) { } fastClassMap.put(clazz, data); return data; } /** * ������ͨ�������ɿ��ٷ��� * * @param clazz ��ͨ�� * @param method ��ͨ���� */ public static void parseFastMethod(Class<?> clazz, Method method) { FastClassData data = parseFastClass(clazz); FastMethod fastMethod = getFastMethod(data.getFastClass(), method); data.addFastMethod(method, fastMethod); } /** * ������ͨ�������ɿ��ٷ��� * * @param clazz ��ͨ�� * @param methodName ��ͨ�������� * @param methodTypes ��ͨ������������ * @throws NoSuchMethodException * @throws SecurityException */ public static FastMethod parseFastMethod(Class<?> clazz, String methodName, Class<?>... methodTypes) throws SecurityException, NoSuchMethodException { FastClassData data = parseFastClass(clazz); FastMethod fastMethod = data.getFastMethod(methodName); if (fastMethod == null) { Method method = clazz.getMethod(methodName, methodTypes); fastMethod = getFastMethod(data.getFastClass(), method); data.addFastMethod(method, fastMethod); } return fastMethod; } /** * ��ȡ����������(�������и���) * * @param clazz * @param fieldName * @return */ public static Field getField(Class<?> clazz, String fieldName) throws NoSuchFieldException { for (; clazz != Object.class; clazz = clazz.getSuperclass()) { try { Field field = getAllField(clazz, fieldName);// clazz.getDeclaredField(fieldName); return field; } catch (Exception e) { continue; } } throw new NoSuchFieldException("con't find field '" + fieldName + "'"); } /** * ���������ַ���ֵ * * @param field ���� * @param obj ���� * @param value ֵ * @throws ClassReflectException */ public static void setFieldString(Field field, Object obj, String value) throws ClassReflectException { Class<?> typeClazz = field.getType(); Object val = null; if (typeClazz.equals(String.class)) { val = value; } else if ((value == null || "".equals(value))) { if (!typeClazz.equals(String.class)) val = 0; } else { if (typeClazz.equals(Integer.class) || typeClazz.equals(int.class)) { val = Integer.parseInt(value); } else if (typeClazz.equals(Short.class) || typeClazz.equals(short.class)) { val = Short.parseShort(value); } else if (typeClazz.equals(Float.class) || typeClazz.equals(float.class)) { val = Float.parseFloat(value); } else if (typeClazz.equals(Double.class) || typeClazz.equals(double.class)) { val = Double.parseDouble(value); } else if (typeClazz.equals(Long.class) || typeClazz.equals(long.class)) { val = Double.parseDouble(value); } else if (typeClazz.equals(Byte.class) || typeClazz.equals(byte.class)) { val = Byte.parseByte(value); } else if (typeClazz.equals(Boolean.class) || typeClazz.equals(boolean.class)) { val = Boolean.parseBoolean(value); } } setFieldValue(field, obj, val); } /** * ��������ֵ * * @param field ���� * @param obj ���� * @param value ֵ * @throws ClassReflectException */ public static void setFieldValue(Field field, Object obj, Object value) throws ClassReflectException { try { boolean acc = field.isAccessible(); field.setAccessible(true); field.set(obj, value); field.setAccessible(acc); } catch (Exception e) { e.printStackTrace(); throw new ClassReflectException("set field '" + field.getName() + "' is error", e); } } /** * ע��ResultSet setter,getter���� */ private static void registerResultSetMethod() { Class<ResultSet> clazz = ResultSet.class; Method[] mts = clazz.getDeclaredMethods(); for (Method mt : mts) { String name = mt.getName(); if (name.startsWith("get")) { FastMethod fastMethod = fastClass.getMethod(mt); Class<?>[] types = fastMethod.getParameterTypes(); if (types.length == 1) { if (types[0].equals(String.class)) fastResultStringMethodMap.put(name, fastMethod); if (types[0].equals(int.class)) fastResultIndexMethodMap.put(name, fastMethod); } } } } /** * ���ResultSetӳ����ٷ��� ����Ϊ���� * * @param methodName ������ * @return ���ٷ��� */ public static FastMethod getResultSetStringFastMethod(String methodName) { return fastResultStringMethodMap.get(methodName); } /** * ���ResultSetӳ����ٷ��� ����Ϊ������ * * @param methodName ������ * @return ���ٷ��� */ public static FastMethod getResultSetIndexFastMethod(String methodName) { return fastResultIndexMethodMap.get(methodName); } /** * �ж��Ƿ��ǽӿ��� * * @param clazz �� * @return */ public static boolean isInterfaceClass(Class<?> clazz) { return clazz.isInterface(); } /** * ��������ָ��������ֵ * * @param rs ����� * @param javaType ����JAVA���� * @param colnumIndex ������ * @return ֵ * @throws Exception */ public static final Object getResultSetValue(ResultSet rs, Class<?> javaType, int colnumIndex) throws ClassReflectException { String jdbcmt = TransformFactory.getInstance().getJdbcResultMethod(javaType); FastMethod method = ReflectHelper.getResultSetIndexFastMethod(jdbcmt); if (method == null) { Class<?> rsClass = rs.getClass(); Method m = null; try { m = rsClass.getMethod(jdbcmt, new Class[] { int.class }); return m.invoke(rs, colnumIndex); } catch (NoSuchMethodException e) { throw new ClassReflectException( "ReflectHelper::getResultSetValue happen NoSuchMethodException " + e.toString(), e); } catch (Exception e) { throw new ClassReflectException( "ReflectHelper::getResultSetValue happen Exception " + e.toString(), e); } } try { return method.invoke(rs, new Object[] { colnumIndex }); } catch (InvocationTargetException e) { throw new ClassReflectException( "ReflectHelper::getResultSetValue happen InvocationTargetException " + e.toString(), e); } } /** * ��������ָ������ֵ * * @param rs ����� * @param javaType ����JAVA���� * @param colnumName ���� * @return ֵ * @throws Exception */ public static final Object getResultSetValue(ResultSet rs, Class<?> javaType, String colnumName) throws Exception { String jdbcmt = TransformFactory.getInstance().getJdbcResultMethod(javaType); FastMethod method = ReflectHelper.getResultSetStringFastMethod(jdbcmt); if (method == null) { Class<?> rsClass = rs.getClass(); Method m = rsClass.getMethod(jdbcmt, new Class[] { String.class }); return m.invoke(rs, colnumName); } return method.invoke(rs, new Object[] { colnumName }); } public static Field getAllField(Class<?> clazz, String fieldName) { if (Object.class.equals(clazz)) throw new ClassReflectException("'" + fieldName + "' does not exists in " + clazz); Field result = null; try { result = clazz.getDeclaredField(fieldName); } catch (Exception e) { result = getAllField(clazz.getSuperclass(), fieldName); } return result; } public static Field[] getAllFields(Class<?> clazz) { List<Field> fields = new LinkedList<Field>(); getAllFields(fields, clazz); Field[] result = new Field[fields.size()]; fields.toArray(result); return result; } public static Object getFieldValue(Field field, Object target) { boolean isAccess = field.isAccessible(); if (!isAccess) field.setAccessible(true); try { return field.get(target); } catch (Exception e) { e.printStackTrace(); return null; } finally { if (!isAccess) field.setAccessible(isAccess); } } private static void getAllFields(List<Field> fields, Class<?> clazz) { if (Object.class.equals(clazz)) return; for (Field field : clazz.getDeclaredFields()) { fields.add(field); } getAllFields(fields, clazz.getSuperclass()); } public static Method getAllMethod(Class<?> clazz, String methodName, Class<?>... parameterTypes) { if (Object.class.equals(clazz)) throw new ClassReflectException("'" + methodName + "' does not exists in " + clazz); Method result = null; try { result = clazz.getDeclaredMethod(methodName, parameterTypes); } catch (Exception e) { result = getAllMethod(clazz.getSuperclass(), methodName); } return result; } public static Method[] getAllMethods(Class<?> clazz) { List<Method> methods = new LinkedList<Method>(); getAllMethods(methods, clazz); Method[] result = new Method[methods.size()]; methods.toArray(result); return result; } private static void getAllMethods(List<Method> methods, Class<?> clazz) { if (Object.class.equals(clazz)) return; for (Method method : clazz.getDeclaredMethods()) { methods.add(method); } getAllMethods(methods, clazz.getSuperclass()); } /** * Scan classes from package * * @param packageName Package name * @param recursive Whether scan sub directory * @return Classes list */ public static List<Class<?>> scanPackageClasses(String packageName, boolean recursive) { List<Class<?>> classes = new ArrayList<Class<?>>(); String packageDirName = packageName.replace('.', '/'); Enumeration<URL> dirs; try { dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName); while (dirs.hasMoreElements()) { URL url = dirs.nextElement(); String protocol = url.getProtocol(); if ("file".equals(protocol)) { String filePath = URLDecoder.decode(url.getFile(), "UTF-8"); scanPackageFromFile(packageName, filePath, recursive, classes); } else if ("jar".equals(protocol)) { try { JarFile jar = ((JarURLConnection) url.openConnection()).getJarFile(); scanJarPackageClass(classes, packageDirName, packageName, jar, recursive); } catch (IOException e) { log.error("Fail to scan jar package classes.Cause " + e.getMessage(), e); } } } } catch (IOException e) { log.error("Fail to scan package classes.Cause " + e.getMessage(), e); } return classes; } private static void scanJarPackageClass(List<Class<?>> classes, String packageDirName, String packageName, JarFile jar, boolean recursive) { Enumeration<JarEntry> entries = jar.entries(); while (entries.hasMoreElements()) { JarEntry entry = entries.nextElement(); String name = entry.getName(); if (name.charAt(0) == '/') { name = name.substring(1); } if (name.startsWith(packageDirName)) { int idx = name.lastIndexOf('/'); if (idx != -1) { packageName = name.substring(0, idx).replace('/', '.'); } if ((idx != -1) || recursive) { if (name.endsWith(".class") && !entry.isDirectory()) { String className = name.substring(packageName.length() + 1, name.length() - 6); try { classes.add(Class.forName(packageName + '.' + className)); } catch (ClassNotFoundException e) { e.printStackTrace(); } } } } } } /** * Scan classes from files * * @param packageName Package name * @param packagePath Package path * @param recursive Whether scan sub directory * @param classes Classes list */ public static void scanPackageFromFile(String packageName, String packagePath, final boolean recursive, List<Class<?>> classes) { File dir = new File(packagePath); if (!dir.exists() || !dir.isDirectory()) { return; } File[] dirfiles = dir.listFiles(new FileFilter() { public boolean accept(File file) { return (recursive && file.isDirectory()) || (file.getName().endsWith(".class")); } }); for (File file : dirfiles) { if (file.isDirectory()) { scanPackageFromFile(packageName + "." + file.getName(), file.getAbsolutePath(), recursive, classes); } else { String className = file.getName().substring(0, file.getName().length() - 6); try { classes.add(Class.forName(packageName + '.' + className)); } catch (ClassNotFoundException e) { log.error(e.getMessage(), e); } } } } }