我们已经解决了解析XML文件的问题,并把所有数据都封装到了我们所需要的类中,接下来,我们需要根据actionName找到相对应的class , 例如LoginAction, 通过反射实例化(创建对象)
据parameters中的数据,调用对象的setter方法, 例如parameters中的数据是
(“name”=”test” , “password”=”1234”) , 那就应该调用setName和setPassword方法。
要想能调用set方法,首先得实例化我们所需要的JavaBean,然后调用实例化JavaBean内部的Set方法,把我们想要传进去的数据封装到这个JavaBean内部,我们自己做得javaBean如下:
package com.coderising.litestruts;
public class LoginAction{
private String name ;
private String password;
private String message;
public String getName() {
return name;
}
public String getPassword() {
return password;
}
public String execute(){
if("test".equals(name) && "1234".equals(password)){
this.message = "login successful";
return "success";
}
this.message = "login failed,please check your user/pwd";
return "fail";
}
public void setName(String name){
this.name = name;
}
public void setPassword(String password){
this.password = password;
}
public String getMessage(){
return this.message;
}
}
我们可以编写测试用例,测试用我们的方法能否获得set方法
public void testGetSetterMethod() throws Exception {
String name = "com.coderising.litestruts.LoginAction";
Class<?> clz = Class.forName(name);
List<Method> methods = ReflectionUtil.getSetterMethods(clz);
Assert.assertEquals(2, methods.size());
List<String> expectedNames = new ArrayList<>();
expectedNames.add("setName");
expectedNames.add("setPassword");
Set<String> acctualNames = new HashSet<>();
for(Method m : methods){
acctualNames.add(m.getName());
}
Assert.assertTrue(acctualNames.containsAll(expectedNames));
}
在测试用例的驱动下,我们编写的第一个方法如下,这样我们就实现了获取set的方法:
public static List<Method> getSetterMethods(Class clz) {
return getMethods(clz,"set");
}
private static List<Method> getMethods(Class<?> clz, String startWithName){
List<Method> methods = new ArrayList<>();
for(Method m : clz.getDeclaredMethods()){
//判断方法是否以指定的字幕开始
if(m.getName().startsWith(startWith
Name)){
methods.add(m);
}
}
return met
ho
ds;
}
紧接着,我们就需要将我们的name和password封装到对应的类,这样的话,我们可以继续编写一个测试用例,测试能否通过我们的方法,将目标值封装起来:
public void testSetParameters() throws Exception{
String name = "com.coderising.litestruts.LoginAction";
Class<?> clz = Class.forName(name);
Object o = clz.newInstance();
Map<String,String> params = new HashMap<String,String>();
params.put("name","test");
params.put("password","1234");
ReflectionUtil.setParameters(o,params);
//实例化域,将需要的域反射到f这个对象中
Field f = clz.getDeclaredField("name");
//由于JDK的安全检查耗时较多.所以通过setAccessible(true)的方式关闭安全检查就可以达到提升反射速度的目的
f.setAccessible(true);
//其值为obj域的当前值
ssert.assertEquals("test", f.get(o));
f = clz.getDeclaredField("password");
f.setAccs ible(true);
Assert.assertEquals("1234", f.get(o));
}
这样,我们就可以集中编写setParameter这个方法,通过这个方法,实现将我们的数据封装到实例化的类中。
public static void setParameters(Object o, Map<String, String> params) {
//将所有的setmethod方法放到一个集合中
List<Method> methods = getSetterMethods(o.getClass());
//遍历传入的map,获取所有的key值
for(String name : params.keySet() ){
//获得method方法名称
String methodName = "set" + name;
//遍历所有的方法
for(Method m: methods){
//判断遍历的方法名称是否与设置的方法名称一致
if(m.getName().equalsIgnoreCase(methodName)){
try {
//如果一致,则调用该方法,并把值传入
m.invoke(o, params.get(name));
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
}
set方法测试好了,接下来需要我们测试get方法,首先需要满足的测试用例是:
public void testGetGetterMethod() throws Exception{
String name = "com.coderising.litestruts.LoginAction";
Class<?> clz = Class.forName(name);
List<Method> methods = ReflectionUtil.getGetterMethods(clz);
Assert.assertEquals(3, methods.size());
List<String> expectedNames = new ArrayList<>();
expectedNames.add("getMessage");
expectedNames.add("getName");
expectedNames.add("getPassword");
Set<String> acctualNames = new HashSet<>();
for(Method m : methods){
acctualNames.add(m.getName());
}
Assert.assertTrue(acctualNames.containsAll(expectedNames));
}
跟获得set方法的名称一样,调用getMethods方法即可:
public static List<Method> getGetterMethods(Class<?> clz) {
return getMethods(clz,"get");
}
然后设计测试用例,取得我们想要的值,通过反射找到对象的所有getter方法(例如 getMessage),
通过反射来调用, 把值和属性形成一个HashMap , 例如 {“message”: “登录成功”} ,
放到View对象的parameters:
public void testGetParamters() throws Exception{
String name = "com.coderising.litestruts.LoginAction";
Class<?> clz = Class.forName(name);
LoginAction action = (LoginAction)clz.newInstance();
action.setName("test");
action.setPassword("123456");
Map<String,Object> params = ReflectionUtil.getParamterMap(action);
Assert.assertEquals(3, params.size());
Assert.assertEquals(null, params.get("messaage") );
Assert.assertEquals("test", params.get("name") );
Assert.assertEquals("123456", params.get("password") );
}
接下来,我们编写实现这个测试的工具类:
public static Map<String, Object> getParamterMap(Object o) {
Map<String ,Object> params = new HashMap<>();
//将javabean所有的get方法形成一个集合
List<Method> methods = getGetterMethods(o.getClass());
//遍历所有的方法
for(Method m : methods){
//定义方法名
String methodName = m.getName();
//去掉get方法前的get,形成name
String name = methodName.replaceFirst("get", "").toLowerCase();
try {
//调用这个方法
Object value = m.invoke(o);
//形成键值对,返回我们封装的数据
params.put(name, value);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
e.printStackTrace();
}
}
return params;
}