diff --git a/modules/utils/pom.xml b/modules/utils/pom.xml
index b757135f..559df524 100644
--- a/modules/utils/pom.xml
+++ b/modules/utils/pom.xml
@@ -31,7 +31,7 @@
0.9.10
-
+
commons-codec
commons-codec
@@ -39,7 +39,7 @@
true
-
+
commons-beanutils
commons-beanutils
@@ -47,7 +47,7 @@
true
-
+
com.fasterxml.jackson.core
jackson-databind
@@ -55,7 +55,7 @@
true
-
+
ma.glasnost.orika
orika-core
diff --git a/modules/utils/src/main/java/org/springside/modules/utils/base/PropertiesUtil.java b/modules/utils/src/main/java/org/springside/modules/utils/base/SystemProperties.java
similarity index 99%
rename from modules/utils/src/main/java/org/springside/modules/utils/base/PropertiesUtil.java
rename to modules/utils/src/main/java/org/springside/modules/utils/base/SystemProperties.java
index 01c2de9c..3e7b3268 100644
--- a/modules/utils/src/main/java/org/springside/modules/utils/base/PropertiesUtil.java
+++ b/modules/utils/src/main/java/org/springside/modules/utils/base/SystemProperties.java
@@ -9,7 +9,7 @@ package org.springside.modules.utils.base;
*
* @author calvin
*/
-public class PropertiesUtil {
+public class SystemProperties {
/////////// Boolean.readBoolean()扩展 ///////////////
diff --git a/modules/utils/src/main/java/org/springside/modules/utils/reflect/Reflections.java b/modules/utils/src/main/java/org/springside/modules/utils/reflect/Reflections.java
index 4d1bfd47..b7563970 100644
--- a/modules/utils/src/main/java/org/springside/modules/utils/reflect/Reflections.java
+++ b/modules/utils/src/main/java/org/springside/modules/utils/reflect/Reflections.java
@@ -10,19 +10,27 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.annotations.Beta;
-
/**
* 反射工具类.
*
- * 提供调用getter/setter方法, 访问私有变量, 调用私有方法.
+ * 所有反射均无视modifier的范围限制,同时将反射的Checked异常转为UnChecked异常。
+ *
+ * 基于这两点要求,没有现有库满足,只能自写
+ *
+ * 1. 属性访问:a.调用getter/setter方法, b.直接访问变量, c.直接先尝试查找getter/setter,如果不存在则直接访问变量
+ *
+ * 2. 一次性调用方法,其中一个特色函数是invokeByName,不准确匹配参数类型,只取第一个名称符合的函数.
+ *
+ * 3. 多次调用方法,先用getAccessibleMethod()获得Method对象,然后多次调用Method对象
*/
-@Beta
+@SuppressWarnings("unchecked")
public class Reflections {
private static final String SETTER_PREFIX = "set";
@@ -30,26 +38,27 @@ public class Reflections {
private static Logger logger = LoggerFactory.getLogger(Reflections.class);
+ /////////// 属性相关函数///////////
/**
- * 调用Getter方法.
+ * 调用Getter方法,无视private/protected修饰符.
*/
- public static Object invokeGetter(Object obj, String propertyName) {
+ public static T invokeGetter(Object obj, String propertyName) {
String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(propertyName);
- return invokeMethod(obj, getterMethodName, new Class[] {}, new Object[] {});
+ return (T) invokeMethod(obj, getterMethodName);
}
/**
- * 调用Setter方法, 仅匹配方法名。
+ * 调用Setter方法, 无视private/protected修饰符, 按传入value的类型匹配函数.
*/
public static void invokeSetter(Object obj, String propertyName, Object value) {
String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(propertyName);
- invokeMethodByName(obj, setterMethodName, new Object[] { value });
+ invokeMethod(obj, setterMethodName, new Object[] { value });
}
/**
* 直接读取对象属性值, 无视private/protected修饰符, 不经过getter函数.
*/
- public static Object getFieldValue(final Object obj, final String fieldName) {
+ public static T getFieldValue(final Object obj, final String fieldName) {
Field field = getAccessibleField(obj, fieldName);
if (field == null) {
@@ -62,7 +71,7 @@ public class Reflections {
} catch (IllegalAccessException e) {
logger.error("不可能抛出的异常{}", e.getMessage());
}
- return result;
+ return (T) result;
}
/**
@@ -83,10 +92,63 @@ public class Reflections {
}
/**
- * 直接调用对象方法, 无视private/protected修饰符. 用于一次性调用的情况,否则应使用getAccessibleMethod()函数获得Method后反复调用. 同时匹配方法名+参数类型,
+ * 先尝试用Getter函数读取, 如果不存在则直接读取变量.
*/
- public static Object invokeMethod(final Object obj, final String methodName, final Class>[] parameterTypes,
- final Object[] args) {
+ public static T getProperty(Object obj, String propertyName) {
+ String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(propertyName);
+ Method method = getAccessibleMethod(obj, getterMethodName);
+ if (method != null) {
+ try {
+ return (T) method.invoke(obj, ArrayUtils.EMPTY_OBJECT_ARRAY);
+ } catch (Exception e) {
+ throw convertReflectionExceptionToUnchecked(e);
+ }
+ } else {
+ return (T) getFieldValue(obj, propertyName);
+ }
+ }
+
+ /**
+ * 先尝试用Setter函数写入, 如果不存在则直接写入变量, 按传入value的类型匹配函数.
+ */
+ public static void setProperty(Object obj, String propertyName, final Object value) {
+ String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(propertyName);
+ Method method = getAccessibleMethod(obj, setterMethodName, value.getClass());
+ if (method != null) {
+ try {
+ method.invoke(obj, value);
+ } catch (Exception e) {
+ throw convertReflectionExceptionToUnchecked(e);
+ }
+ } else {
+ setFieldValue(obj, propertyName, value);
+ }
+ }
+
+ ////////// 方法相关函数 //////
+
+ /**
+ * 直接调用对象方法, 无视private/protected修饰符.
+ *
+ * 根据传入参数的实际类型进行匹配
+ *
+ * 用于一次性调用的情况,否则应使用getAccessibleMethod()函数获得Method后反复调用.
+ */
+ public static T invokeMethod(Object obj, String methodName, Object... args) {
+ args = ArrayUtils.nullToEmpty(args);
+ final Class>[] parameterTypes = ClassUtils.toClass(args);
+ return (T) invokeMethod(obj, methodName, args, parameterTypes);
+ }
+
+ /**
+ * 直接调用对象方法, 无视private/protected修饰符.
+ *
+ * 根据定义的参数类型进行匹配,
+ *
+ * 用于一次性调用的情况,否则应使用getAccessibleMethod()函数获得Method后反复调用.
+ */
+ public static Object invokeMethod(final Object obj, final String methodName, final Object[] args,
+ final Class>[] parameterTypes) {
Method method = getAccessibleMethod(obj, methodName, parameterTypes);
if (method == null) {
throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]");
@@ -100,8 +162,11 @@ public class Reflections {
}
/**
- * 直接调用对象方法, 无视private/protected修饰符, 用于一次性调用的情况,否则应使用getAccessibleMethodByName()函数获得Method后反复调用.
- * 只匹配函数名,如果有多个同名函数调用第一个。
+ * 直接调用对象方法, 无视private/protected修饰符
+ *
+ * 只匹配函数名,如果有多个同名函数调用第一个. 用于确信只有一个同名函数, 但参数类型不好确定的情况
+ *
+ * 用于一次性调用的情况,否则应使用getAccessibleMethodByName()函数获得Method后反复调用.
*/
public static Object invokeMethodByName(final Object obj, final String methodName, final Object[] args) {
Method method = getAccessibleMethodByName(obj, methodName);
@@ -120,10 +185,12 @@ public class Reflections {
* 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问.
*
* 如向上转型到Object仍无法找到, 返回null.
+ *
+ * 因为class.getFiled(); 不能获取父类的private函数, 因此采用循环向上的getDeclaredField();
*/
public static Field getAccessibleField(final Object obj, final String fieldName) {
Validate.notNull(obj, "object can't be null");
- Validate.notBlank(fieldName, "fieldName can't be blank");
+ Validate.notEmpty(fieldName, "fieldName can't be blank");
for (Class> superClass = obj.getClass(); superClass != Object.class; superClass = superClass
.getSuperclass()) {
try {
@@ -138,14 +205,20 @@ public class Reflections {
}
/**
- * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问. 如向上转型到Object仍无法找到, 返回null. 匹配函数名+参数类型。
+ * 循环向上转型, 获取对象的DeclaredMethod, 并强制设置为可访问.
*
- * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
+ * 如向上转型到Object仍无法找到, 返回null.
+ *
+ * 匹配函数名+参数类型.
+ *
+ * 用于方法需要被多次调用的情况. 先使用本函数先取得Method, 然后调用Method.invoke(Object obj, Object... args)
+ *
+ * 因为class.getFiled() 不能获取父类的private函数, 因此采用循环向上的getDeclaredField();
*/
- public static Method getAccessibleMethod(final Object obj, final String methodName,
- final Class>... parameterTypes) {
+ public static Method getAccessibleMethod(final Object obj, final String methodName, Class>... parameterTypes) {
Validate.notNull(obj, "object can't be null");
- Validate.notBlank(methodName, "methodName can't be blank");
+ Validate.notEmpty(methodName, "methodName can't be blank");
+ parameterTypes = ArrayUtils.nullToEmpty(parameterTypes);
for (Class> searchType = obj.getClass(); searchType != Object.class; searchType = searchType
.getSuperclass()) {
@@ -161,13 +234,19 @@ public class Reflections {
}
/**
- * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问. 如向上转型到Object仍无法找到, 返回null. 只匹配函数名。
+ * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
+ *
+ * 如向上转型到Object仍无法找到, 返回null.
+ *
+ * 只匹配函数名, 如果有多个同名函数返回第一个
*
* 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
+ *
+ * 因为class.getMethods() 不能获取父类的private函数, 因此采用循环向上的getMethods();
*/
public static Method getAccessibleMethodByName(final Object obj, final String methodName) {
Validate.notNull(obj, "object can't be null");
- Validate.notBlank(methodName, "methodName can't be blank");
+ Validate.notEmpty(methodName, "methodName can't be blank");
for (Class> searchType = obj.getClass(); searchType != Object.class; searchType = searchType
.getSuperclass()) {
diff --git a/modules/utils/src/test/java/org/springside/modules/utils/reflect/ReflectionsTest.java b/modules/utils/src/test/java/org/springside/modules/utils/reflect/ReflectionsTest.java
index a27646a3..74e019ce 100644
--- a/modules/utils/src/test/java/org/springside/modules/utils/reflect/ReflectionsTest.java
+++ b/modules/utils/src/test/java/org/springside/modules/utils/reflect/ReflectionsTest.java
@@ -63,7 +63,7 @@ public class ReflectionsTest {
// 使用函数名+参数类型的匹配
assertThat(
Reflections
- .invokeMethod(bean, "privateMethod", new Class[] { String.class }, new Object[] { "calvin" }))
+ .invokeMethod(bean, "privateMethod", new Object[] { "calvin" }, new Class[] { String.class }))
.isEqualTo("hello calvin");
// 仅匹配函数名
@@ -72,7 +72,7 @@ public class ReflectionsTest {
// 函数名错
try {
- Reflections.invokeMethod(bean, "notExistMethod", new Class[] { String.class }, new Object[] { "calvin" });
+ Reflections.invokeMethod(bean, "notExistMethod", new Object[] { "calvin" }, new Class[] { String.class });
failBecauseExceptionWasNotThrown(IllegalArgumentException.class);
} catch (IllegalArgumentException e) {
@@ -80,7 +80,7 @@ public class ReflectionsTest {
// 参数类型错
try {
- Reflections.invokeMethod(bean, "privateMethod", new Class[] { Integer.class }, new Object[] { "calvin" });
+ Reflections.invokeMethod(bean, "privateMethod", new Object[] { "calvin" }, new Class[] { Integer.class });
failBecauseExceptionWasNotThrown(RuntimeException.class);
} catch (RuntimeException e) {