1 /** 2 * Copyright (c) 2005-2012 springside.org.cn 3 * <p> 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 */ 6 package com.zhouyy.netBank.util; 7 8 import org.slf4j.Logger; 9 import org.slf4j.LoggerFactory; 10 import org.springframework.util.Assert; 11 12 import java.lang.reflect.*; 13 import java.util.ArrayList; 14 import java.util.List; 15 16 /** 17 * 反射工具類. 18 * 提供調用getter/setter方法, 訪問私有變量, 調用私有方法, 獲取泛型類型Class, 被AOP過的真實類等工具函數. 19 * @author calvin 20 * @version 2013-01-15 21 */ 22 @SuppressWarnings("rawtypes") 23 public class Reflections { 24 25 private static final String SETTER_PREFIX = "set"; 26 27 private static final String GETTER_PREFIX = "get"; 28 29 private static final String CGLIB_CLASS_SEPARATOR = "$$"; 30 31 private static Logger logger = LoggerFactory.getLogger(Reflections.class); 32 33 /** 34 * 調用Getter方法. 35 * 支持多級,如:對象名.對象名.方法 36 */ 37 public static Object invokeGetter(Object obj, String propertyName) { 38 Object object = obj; 39 for (String name : StringUtils.split(propertyName, ".")) { 40 String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name); 41 object = invokeMethod(object, getterMethodName, new Class[]{}, new Object[]{}); 42 } 43 return object; 44 } 45 46 /** 47 * 調用Setter方法, 僅匹配方法名。 48 * 支持多級,如:對象名.對象名.方法 49 */ 50 public static void invokeSetter(Object obj, String propertyName, Object value) { 51 Object object = obj; 52 String[] names = StringUtils.split(propertyName, "."); 53 for (int i = 0; i < names.length; i++) { 54 if (i < names.length - 1) { 55 String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]); 56 object = invokeMethod(object, getterMethodName, new Class[]{}, new Object[]{}); 57 } else { 58 String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]); 59 invokeMethodByName(object, setterMethodName, new Object[]{value}); 60 } 61 } 62 } 63 64 /** 65 * 直接讀取對象屬性值, 無視private/protected修飾符, 不通過getter函數. 66 */ 67 public static Object getFieldValue(final Object obj, final String fieldName) { 68 Field field = getAccessibleField(obj, fieldName); 69 70 if (field == null) { 71 throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]"); 72 } 73 74 Object result = null; 75 try { 76 result = field.get(obj); 77 } catch (IllegalAccessException e) { 78 logger.error("不可能拋出的異常{}", e.getMessage()); 79 } 80 return result; 81 } 82 83 /** 84 * 直接設置對象屬性值, 無視private/protected修飾符, 不通過setter函數. 85 */ 86 public static void setFieldValue(final Object obj, final String fieldName, final Object value) { 87 Field field = getAccessibleField(obj, fieldName); 88 89 if (field == null) { 90 throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]"); 91 } 92 93 try { 94 field.set(obj, value); 95 } catch (IllegalAccessException e) { 96 logger.error("不可能拋出的異常:{}", e.getMessage()); 97 } 98 } 99 100 /** 101 * 直接調用對象方法, 無視private/protected修飾符. 102 * 用於一次性調用的狀況,不然應使用getAccessibleMethod()函數得到Method後反覆調用. 103 * 同時匹配方法名+參數類型, 104 */ 105 public static Object invokeMethod(final Object obj, final String methodName, final Class<?>[] parameterTypes, 106 final Object[] args) { 107 Method method = getAccessibleMethod(obj, methodName, parameterTypes); 108 if (method == null) { 109 throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]"); 110 } 111 112 try { 113 return method.invoke(obj, args); 114 } catch (Exception e) { 115 throw convertReflectionExceptionToUnchecked(e); 116 } 117 } 118 119 /** 120 * 直接調用對象方法, 無視private/protected修飾符, 121 * 用於一次性調用的狀況,不然應使用getAccessibleMethodByName()函數得到Method後反覆調用. 122 * 只匹配函數名,若是有多個同名函數調用第一個。 123 */ 124 public static Object invokeMethodByName(final Object obj, final String methodName, final Object[] args) { 125 Method method = getAccessibleMethodByName(obj, methodName); 126 if (method == null) { 127 throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]"); 128 } 129 130 try { 131 return method.invoke(obj, args); 132 } catch (Exception e) { 133 throw convertReflectionExceptionToUnchecked(e); 134 } 135 } 136 137 /** 138 * 循環向上轉型, 獲取對象的DeclaredField, 並強制設置爲可訪問. 139 * 140 * 如向上轉型到Object仍沒法找到, 返回null. 141 */ 142 public static Field getAccessibleField(final Object obj, final String fieldName) { 143 Assert.notNull(obj, "object can't be null"); 144 Assert.hasText(fieldName, "fieldName can't be blank"); 145 for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) { 146 try { 147 Field field = superClass.getDeclaredField(fieldName); 148 makeAccessible(field); 149 return field; 150 } catch (NoSuchFieldException e) {//NOSONAR 151 // Field不在當前類定義,繼續向上轉型 152 try { 153 Field field = obj.getClass().getField(fieldName); 154 makeAccessible(field); 155 return field; 156 } catch (NoSuchFieldException e1) { 157 continue;// new add 158 } 159 } 160 } 161 return null; 162 } 163 164 /** 165 * 循環向上轉型, 獲取對象的DeclaredMethod,並強制設置爲可訪問. 166 * 如向上轉型到Object仍沒法找到, 返回null. 167 * 匹配函數名+參數類型。 168 * 169 * 用於方法須要被屢次調用的狀況. 先使用本函數先取得Method,而後調用Method.invoke(Object obj, Object... args) 170 */ 171 public static Method getAccessibleMethod(final Object obj, final String methodName, 172 final Class<?>... parameterTypes) { 173 Assert.notNull(obj, "object can't be null"); 174 Assert.hasText(methodName, "methodName can't be blank"); 175 176 for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) { 177 try { 178 Method method = searchType.getDeclaredMethod(methodName, parameterTypes); 179 makeAccessible(method); 180 return method; 181 } catch (NoSuchMethodException e) { 182 // Method不在當前類定義,繼續向上轉型 183 continue;// new add 184 } 185 } 186 return null; 187 } 188 189 /** 190 * 循環向上轉型, 獲取對象的DeclaredMethod,並強制設置爲可訪問. 191 * 如向上轉型到Object仍沒法找到, 返回null. 192 * 只匹配函數名。 193 * 194 * 用於方法須要被屢次調用的狀況. 先使用本函數先取得Method,而後調用Method.invoke(Object obj, Object... args) 195 */ 196 public static Method getAccessibleMethodByName(final Object obj, final String methodName) { 197 Assert.notNull(obj, "object can't be null"); 198 Assert.hasText(methodName, "methodName can't be blank"); 199 200 for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) { 201 Method[] methods = searchType.getDeclaredMethods(); 202 for (Method method : methods) { 203 if (method.getName().equals(methodName)) { 204 makeAccessible(method); 205 return method; 206 } 207 } 208 } 209 return null; 210 } 211 212 /** 213 * 改變private/protected的方法爲public,儘可能不調用實際改動的語句,避免JDK的SecurityManager抱怨。 214 */ 215 public static void makeAccessible(Method method) { 216 if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers())) 217 && !method.isAccessible()) { 218 method.setAccessible(true); 219 } 220 } 221 222 /** 223 * 改變private/protected的成員變量爲public,儘可能不調用實際改動的語句,避免JDK的SecurityManager抱怨。 224 */ 225 public static void makeAccessible(Field field) { 226 if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers()) || Modifier 227 .isFinal(field.getModifiers())) && !field.isAccessible()) { 228 field.setAccessible(true); 229 } 230 } 231 232 /** 233 * 經過反射, 得到Class定義中聲明的泛型參數的類型, 注意泛型必須定義在父類處 234 * 如沒法找到, 返回Object.class. 235 * eg. 236 * public UserDao extends HibernateDao<User> 237 * 238 * @param clazz The class to introspect 239 * @return the first generic declaration, or Object.class if cannot be determined 240 */ 241 @SuppressWarnings("unchecked") 242 public static <T> Class<T> getClassGenricType(final Class clazz) { 243 return getClassGenricType(clazz, 0); 244 } 245 246 /** 247 * 經過反射, 得到Class定義中聲明的父類的泛型參數的類型. 248 * 如沒法找到, 返回Object.class. 249 * 250 * 如public UserDao extends HibernateDao<User,Long> 251 * 252 * @param clazz clazz The class to introspect 253 * @param index the Index of the generic ddeclaration,start from 0. 254 * @return the index generic declaration, or Object.class if cannot be determined 255 */ 256 public static Class getClassGenricType(final Class clazz, final int index) { 257 258 Type genType = clazz.getGenericSuperclass(); 259 if (!(genType instanceof ParameterizedType)) { 260 logger.warn(clazz.getName() + "'s superclass not ParameterizedType"); 261 return Object.class; 262 } 263 264 Type[] params = ((ParameterizedType) genType).getActualTypeArguments(); 265 266 if (index >= params.length || index < 0) { 267 logger.warn("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: " 268 + params.length); 269 return Object.class; 270 } 271 if (!(params[index] instanceof Class)) { 272 logger.warn(clazz.getName() + " not set the actual class on superclass generic parameter"); 273 return Object.class; 274 } 275 276 return (Class) params[index]; 277 } 278 279 public static Class<?> getUserClass(Object instance) { 280 Assert.notNull(instance, "Instance must not be null"); 281 Class clazz = instance.getClass(); 282 if (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR)) { 283 Class<?> superClass = clazz.getSuperclass(); 284 if (superClass != null && !Object.class.equals(superClass)) { 285 return superClass; 286 } 287 } 288 return clazz; 289 290 } 291 292 /** 293 * 將反射時的checked exception轉換爲unchecked exception. 294 */ 295 public static RuntimeException convertReflectionExceptionToUnchecked(Exception e) { 296 if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException 297 || e instanceof NoSuchMethodException) { 298 return new IllegalArgumentException(e); 299 } else if (e instanceof InvocationTargetException) { 300 return new RuntimeException(((InvocationTargetException) e).getTargetException()); 301 } else if (e instanceof RuntimeException) { 302 return (RuntimeException) e; 303 } 304 return new RuntimeException("Unexpected Checked Exception.", e); 305 } 306 307 308 public static List<Field> fields(Class clzz) { 309 List<Field> result = new ArrayList<Field>(); 310 Field[] fields = clzz.getDeclaredFields(); 311 for (Field field : fields) { 312 result.add(field); 313 } 314 return result; 315 } 316 317 public static List<Field> fields(Class clzz, Class annotation) { 318 List<Field> result = new ArrayList<Field>(); 319 Field[] fields = clzz.getDeclaredFields(); 320 for (Field field : fields) { 321 if (field.isAnnotationPresent(annotation)) { 322 result.add(field); 323 } 324 } 325 return result; 326 } 327 328 public static Field findField(Class clzz, String fieldName) { 329 Field field = null; 330 try { 331 field = clzz.getDeclaredField(fieldName); 332 } catch (Exception e) { 333 if (clzz.getSuperclass() != null) { 334 field = findField(clzz.getSuperclass(), fieldName); 335 } 336 } 337 return field; 338 } 339 340 public static Object field(Class obj, String fieldName) throws Exception { 341 Field field = findField(obj.getClass(), fieldName); 342 field.setAccessible(true); 343 return field.get(obj); 344 } 345 }