原则:
1. 在业务代码中尽量不要通过反射访问类型私有属性!
2. 在框架代码中尽量少用。
3. 在测试代码中可以灵活使用。
public class InvokeUtil {
private static Logger logger = LoggerFactory.getLogger(InvokeUtil.class);
private InvokeUtil() {
}
/**
* 执行一个私有函数
*
* @param clazz 待访问的类
* @param object 待访问的实例
* @param methodName 待访问的方法名
* @param argsType 入参类型,如果无入参,则argsType为长度为0的数组
* @param args 入参实例,如果无入参,则args为长度为0的数组、或不填
* @return 执行结果,如果为void,则返回null
*/
public static Object invokeMethod(
Class<?> clazz, Object object, String methodName, Class[] argsType, Object... args) {
Object result = null;
try {
Method method = clazz.getDeclaredMethod(methodName, argsType);
method.setAccessible(true);
result = method.invoke(object, args);
method.setAccessible(false);
} catch (InvocationTargetException | IllegalAccessException e) {
logger.error("", e);
} catch (NoSuchMethodException e) {
logger.trace(e.getMessage());/*这里属于正常,留在下面的if中打印*/
Class<?> superClazz = clazz.getSuperclass();
if (superClazz == null) {
logger.error(methodName, e);
} else {
result = invokeMethod(
superClazz, object, methodName, argsType, args);
}
}
return result;
}
/**
* 访问一个实例内的私有变量
*
* @param clazz 待访问的类
* @param object 待访问的实例
* @param fieldName 待访问的字段名
* @return 实例内的该字段对象
*/
public static Object invokeField(Class<?> clazz, Object object, String fieldName) {
Object result = null;
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
result = field.get(object);
field.setAccessible(false);
} catch (IllegalAccessException e) {
logger.error("", e);
} catch (NoSuchFieldException e) {
logger.trace(e.getMessage());/*这里属于正常,留在下面的if中打印*/
Class<?> superClazz = clazz.getSuperclass();
if (superClazz == null) {
logger.error(fieldName, e);
} else {
result = invokeField(superClazz, object, fieldName);
}
}
return result;
}
/**
* 给一个实例内的私有变量赋值
*
* @param clazz 待访问的类
* @param object 待访问的实例
* @param fieldName 待访问的字段名
* @param value 待赋的值
*/
public static void updateFieldValue(
Class<?> clazz, Object object, String fieldName, Object value) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(object, value);
field.setAccessible(false);
} catch (IllegalAccessException e) {
logger.error("", e);
} catch (NoSuchFieldException e) {
logger.trace(e.getMessage());/*这里属于正常,留在下面的if中打印*/
Class<?> superClazz = clazz.getSuperclass();
if (superClazz == null) {
logger.error(fieldName, e);
} else {
updateFieldValue(superClazz, object, fieldName, value);
}
}
}
/**
* 通过反射吗,往某个注解里,动态追加属性
*/
private void addJsonSubTypes() {
try {
JsonSubTypes jsonSubTypesFxe = FlexeChannelExtension.class.getAnnotation(JsonSubTypes.class);
InvocationHandler invocationHandlerFxe = Proxy.getInvocationHandler(jsonSubTypesFxe);
Field fieldFxe = invocationHandlerFxe.getClass().getDeclaredField("memberValues");
fieldFxe.setAccessible(true);
Map<String, Object> allValuesFxe = (Map<String, Object>) fieldFxe.get(invocationHandlerFxe);
JsonSubTypes.Type[] subTypesOrigFxe = (JsonSubTypes.Type[]) allValuesFxe.get("value");
JsonSubTypes jsonSubTypes = LinkExtension.class.getAnnotation(JsonSubTypes.class);
InvocationHandler invocationHandler = Proxy.getInvocationHandler(jsonSubTypes);
Field field = invocationHandler.getClass().getDeclaredField("memberValues");
field.setAccessible(true);
Map<String, Object> allValues = (Map<String, Object>) field.get(invocationHandler);
JsonSubTypes.Type[] subTypesOrig = (JsonSubTypes.Type[]) allValues.get("value");
// 汇聚
List<JsonSubTypes.Type> subTypesList = Lists.newArrayList(subTypesOrig);
subTypesList.add(subTypesOrigFxe[0]);
// 转数组并写入
JsonSubTypes.Type[] subTypesNew = new JsonSubTypes.Type[subTypesList.size()];
subTypesList.toArray(subTypesNew);
allValues.put("value", subTypesNew);
} catch (Exception e) {
logger.error("", e);
}
}