这段时间学习java的反射机制想实现一个功能:遍历一个Map,然后利用反射机制调用BO的set方法,完成BO属性的自动注入。这样设计的初衷是解决Excel数据导入问题中的Map数据填充BO这一过程。
下面是一个BO:
package com.handlewell.testOnly.persistence; import java.io.Serializable; import java.util.Date; public class StudentBO implements Serializable{ /** * */ private static final long serialVersionUID = 1L; private Long id; private String sname; private Integer age; private Date birthDate; public Long getId() { return id; } public void setId(Long id) { this.id = id; } . . . }
为了代码的复用性和做Excel文件处理时的灵活性决定使用Enum来指定文件中表头和BO中属性方法的对应关系,下面是使用的Enum类:
public enum ExclTableField { Sname("姓名"), Age("年龄"), BirthDate("生日"); private String description; private ExclTableField(String description){ this.description = description; } public String getDescription() { return description; } }
有了BO和Enum我们需要一个工具类来完成数据的填充,这个工具类必须能完成各种BO的填充,所以必须使用泛型和反射。
下面是工具类的代码:
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class Excle2EntityUtil<T> { private T entity; public Excle2EntityUtil(T entity){ this.entity = entity; } public void doInitEntity(String methodName , Object obj) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException{ //根据传入的属性名称构造属性的set方法名 methodName = "set"+methodName; System.out.println("Method Name --"+methodName); Method[] methods = entity.getClass().getMethods(); for(Method method:methods){ //如果方法同名则执行该方法(不能用于BO中有重载方法的情况) if(methodName.equals(method.getName())){ //这里如何做类型转换???????????* method.invoke(entity, obj); } } } }
在做测试的时候因从模拟的数据Map中得到的Age是一个String类型的,在反射的方法调用时这个set方法应该传入的是int类型的数据。所以会抛出java.lang.IllegalArgumentException: argument type mismatch这样的异常。
package com.handlewell.testOnly.services.impl; import java.util.Date; import java.util.LinkedHashMap; import java.util.Map; import com.handlewell.testOnly.persistence.StudentBO; import com.handlewell.testOnly.support.ExclTableField; import com.handlewell.testOnly.support.Excle2EntityUtil; public class InvokeMethodTest { public static void main(String[] args) { /**测试,手动构造一个Map,模拟从Excel中读出的数据Map----begin*/ Map<String, Object> studentMap = new LinkedHashMap<String, Object>(); studentMap.put("姓名", "gaojun"); String age = "24"; studentMap.put("年龄", age); Date date = new Date(); studentMap.put("生日", date); /**测试,手动构造一个Map,模拟从Excel中读出的数据Map----end*/ StudentBO student = new StudentBO(); //使用StudentBO构造一个数据填充工具实例 Excle2EntityUtil<StudentBO> studentEntityUtil = new Excle2EntityUtil<StudentBO>(student); for (ExclTableField tableField : ExclTableField.values()) { //根据Enum上属性名称拿到属性的值,这里所有的属性值都是一个Object类型。 Object obj = studentMap.get(tableField.getDescription()); try { //传入属性名和值,完成自动填充BO属性。 studentEntityUtil.doInitEntity(tableField.toString(), obj); } catch (Exception e) { e.printStackTrace(); } } System.out.println(student.getSname()); System.out.println(student.getAge()); System.out.println(student.getBirthDate()); } }
请问:这里要如何解决这个类型转换的问题呢?有没有什么方法可以让方法在执行时自动将Object类型转换为所需要的类型呢?
Excle2EntityUtil类的中方法改成这样试试,现在能想到的就是这样if..else if 一个一个遍历,这些对类的反射操作以及类型转换在BeanUtils都有,你可以用下,可以省很多时间,它里面都有一些常用的类型转换器,如果你的需求中用到自定义转换还可以继续它的接口实现
[code="java"]public void doInitEntity(String methodName, Object obj) throws Exception {
//
methodName = "set" + methodName;
Method[] methods = entity.getClass().getMethods();
for (Method method : methods) {
if (methodName.equals(method.getName())) {
Class<?>[] clazz = method.getParameterTypes();
String type = clazz[0].getName();
if(type.equals("java.lang.String")){
method.invoke(entity,(String)obj);
}
else if(type.equals("java.util.Date")){
method.invoke(entity, (Date)obj);
}
else if(type.equals("java.lang.Integer")){
method.invoke(entity, new Integer((String)obj));
}else{
//........
}
}
}
}[/code]
都是判断去比的.
就算是框架也一样.
只能是判断当前的obj 的class 是不是 你期望的类的class 如果一样就行.
如果你都是引用类型 用instanceof就可以了.
如果你希望支持 int 这种普通类型. 那你就要用class 比较.
如果你期望动态 那么你就把比较的信息通过配置文件配置. 来支持你的类型扩展.
从Excel中读出的数据Map,请问一下,这个是如何实现的呢?谢谢!
自动是不可能的,你可以看下Method有没有获得传入参数类型的方法,如果有的话,再把object转换成这个类型。反正就是这个思路
可以参考spring的converter
请使用Field来进行设置值.