jOOR - Fluent Reflection in Java jOOR is a very simple fluent API that gives access to your Java Class structures in a more intuitive way. The JDK’s reflection APIs are hard and verbose to use. Other languages have much simpler constructs to access type meta information at runtime. Let us make Java reflection better. http://www.jooq.org/products
大意为:
jOOR提供了一种更为直观的方式来构建JDK原生的反射调用,因为JDK提供的反射API使用起来较冗长(它对包java.lang.reflect进行了简单封装,使得反射更加方便)。
compile'org.jooq:joor:0.9.6'
先看一个简单例子,对比JDK的反射API和jOOR的方法调用对比。
JDK的反射API:
/**
* 反射读取系统SystemProperties的属性值
* @param key
* @param defaultValue
* @return
*/
public static String getValue(String key, String defaultValue) {
String value = "";
try {
Class> cls = Class.forName("android.os.SystemProperties");
Method getMethod = cls.getDeclaredMethod("get", String.class, String.class);
getMethod.setAccessible(true);
return (String) getMethod.invoke(null, key, defaultValue);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return value;
}
jOOR的反射调用:
/**
* 反射读取系统SystemProperties的属性值
* @param key
* @param defaultValue
* @return
*/
public static String getValueEx(String key, String defaultValue) {
String value;
try {
value = Reflect.on("android.os.SystemProperties")
.call("get", key, defaultValue).get();
} catch (ReflectException e) {
e.printStackTrace();
value = "";
}
return value;
}
从上面的例子就可以看到jOOR明显的优势:
1、简化了反射冗长的异常处理。
2、简化了对Class、Method等反射类的实例化,改为统一Reflect替换。
3、支持private方法的调用,内部动态区分是否需要accessible()。
4、将反射调用封装为更流行的链式调用方式,代码更容易理解(类似Rxjava的封装方式)。
5、支持类型内部wrap转换(泛型实现)。
1、提供on()操作符对Class、对象(还包括方法、构造函数)进行统一实例化为Reflect对象,后续所有的反射操作基于改Reflect对象。
2、有功能调用方式均被封装成返回Reflect对象的链式结构,在使用上使得代码更加简洁。
3、对方法的签名匹配封装了更完善的匹配规则,包括精确匹配exactMethod()、近似匹配similarMethod()【对函数参数的近似匹配(int -> Integer)】和基类搜索等。
4、调用私有方法的不需要显示调用setAccessible(),内部动态读取public标记自动适配。
5、更加简洁的实现了对象构造函数的反射调用create()方法。
6、函数的调用call()方法组合成了可以拼接在Reflect的对象后面的链式方法。
7、额外增加了高级操作符as(),它实现了类的代理访问以及POJO对象的get/set/is方法实现。
//1、通过类名转换成一个Reflect对象:
public static Reflect on(String name);
public static Reflect on(String name, ClassLoader classLoader);
public static Reflect on(Class> clazz);
//2、将一个类对象转换成一个Reflect对象:
public static Reflect on(Object object);
//3、修改一个AccessibleObject类型的对象的访问权限:
public static T accessible(T accessible);
//4、返回Reflect对象具体包装的类型,类型为Class或者对象,由操作符on()的重载参数决定:
public T get();
//5、将name指定的field转换成一个Reflect对象,后续对field的操作变为对Reflect对象的操作:
public Reflect field(String name);
//6、返回当前Reflect对象的所有field属性,并转换成Reflect对象的map:
public Map fields();
//7、修改(获取)field属性值:
public Reflect set(String name, Object value);
public T get(String name);
//8、反射调用name指定的函数,此函数封装了对函数的签名的精准匹配和近似匹配:
public Reflect call(String name);
public Reflect call(String name, Object... args);
//9、反射调用指定类的构造函数,也封装了精准匹配和近似匹配:
public Reflect create();
public Reflect create(Object... args);
//10、返回当前Reflect对象封装的对象类型:
public Class> type();
//11、给封装对象创建一个代理访问,还实现了对POJO对象的setXX/getXX/isxx功能(此为Reflect对象的高级功能):
public P as(Class
proxyType);
method调用:
// Instance methods
// ----------------
final String value0 = Reflect.on((Object) "1234").call("substring", 0, 2).get(); //value0 = "12";
// Static methods
// ----------------
final String value1 = Reflect.on(String.class).call("valueOf", true).get(); //value1 = "true";
Field属性get/set操作:
// Instance methods
// ----------------
TestField testField = new TestField();
/**
* 修改final属性
*/
final Integer value0 = Reflect.on(testField).set("F_INT2", 1).get("F_INT2"); //value0 = 1;
/**
* 获取属性值
*/
final int value1 = Reflect.on(testField).field("F_INT2").get(); //value1 = 1;
/**
* 链式修改多个属性值
*/
Reflect.on(testField).set("F_INT1", 2).set("F_INT2", 2);
/**
* 复杂链式修改多个属性值
*/
Reflect.on(testField).set("I_DATA", Reflect.on(TestField.class).create())
.field("I_DATA").set("F_INT1", 3).set("F_INT2", 3);
// Static methods
// ----------------
/**
* 修改static final属性
*/
final int value2 = Reflect.on(TestField.class).set("SF_INT1", 4).get("SF_INT1"); //value2 = 4;
/**
* 获取静态属性值
*/
final int value3 = Reflect.on(TestField.class).field("SF_INT1").get(); //value3 = 4;
public static class TestField {
private static final int SF_INT1 = new Integer(0);
private static final Integer SF_INT2 = new Integer(0);
private final int F_INT1 = new Integer(0);
private final Integer F_INT2 = new Integer(0);
private TestField I_DATA;
}
代理调用、POJO对象支持:
/**
* 代理调用String
*/
final String value0 = Reflect.on((Object) "abc").as(Test6.class).substring(1, 2); //value0 = "b";
/**
* POJO对象的map代理
*/
class MyMap extends HashMap<String, Object> {
String baz;
public void setBaz(String baz) {
this.baz = "MyMap: " + baz;
}
public String getBaz() {
return baz;
}
}
Map<String, Object> map = new MyMap();
Reflect.on(map).as(Test6.class).setFoo("abc");
int size = map.size(); //size = 1;
final String value1 = (String) map.get("foo"); //value1 = "abc";
final String value2 = Reflect.on(map).as(Test6.class).getFoo(); //value2 = "abc";
Reflect.on(map).as(Test6.class).setBar(true);
size = map.size(); //size = 2;
final boolean value3 = Reflect.on(map).as(Test6.class).isBar(); //value3 = true;
Reflect.on(map).as(Test6.class).setBaz("baz-test");
size = map.size(); //size = 2;
final String value4 = (String) map.get("baz"); //value4 = null;
final String value5 = Reflect.on(map).as(Test6.class).getBaz(); //value5 = "MyMap: baz-test";
Reflect.on(map).as(Test6.class).testIgnore(); //crash
public interface Test6 {
void setFoo(String s);
void setBar(boolean b);
void setBaz(String baz);
void testIgnore();
String getFoo();
boolean isBar();
String getBaz();
String substring(int beginIndex, int endIndex);
}
在项目中需要较多地方使用反射时,可以采用jOOR的封装来简化反射的调用;后续需要进行反射优化时(比如对Class、Method、Field仅在首次调用时获取并缓存起来,后续仅仅调用缓存的invoke()),jOOR的统一封装对优化也提供了便利。