这两天又看了看Rod Johnson的Expert one-on-one J2EE Without EJB。看到第七章是,看到bean属性动态赋值用到了java.beans.PropertyEditor觉得很想了解一下,于是通过重写一段原来的代码熟悉了java.beans API。感觉上这种实现方式规避了很多程序陷阱,而且可以让程序看起来更优雅。这里,我把重写的代码,跟对这种实现方式的看法表达出来。
首先说说需求。
根据类名生成一个实例我们现在叫他obj,一个Map(map中存储的是property key-value),把Map的值根据obj的property name赋给obj。
例如,obj有name,age两个属性并且曝露Javabean标准的存取属性的方法,map有 name=lh , age=11 两个键值对。
分析一下我们要做什么。
1,首先根据反射找出所有公开的存取方法,通过方法名跟map的key进行匹配,找出keyName。找出需要赋值的方法setMethod
2,根据setMethod的方法签名,找到接收参数的类型class.
3,把keyName的值keyValue得到,把keyValue转变成class类型。
4,调用setMethod。
下面是一段类型转换的代码。
static Object getValue(Object v, Class type) {
if (type.getName().equals(String.class.getName())) {
return v.toString();
} else if (type.getName().equals(Long.class.getName())) {
return new Long(v.toString());
} else if (type.getName().equals(Integer.class.getName())) {
return new Integer(v.toString());
} else if (type.getName().equals(Double.class.getName())) {
return new Double(v.toString());
} else if (type.getName().equals(Date.class.getName())) {
return java.sql.Date.valueOf(v.toString());
} else if (type.getName().equals(long.class.getName())) {
return new Long(v.toString());
} else if (type.getName().equals(int.class.getName())) {
return new Integer(v.toString());
} else if (type.getName().equals(double.class.getName())) {
return new Double(v.toString());
}else if (type.getName().equals(BigDecimal.class.getName())) {
return new BigDecimal(v.toString());
} else {
return null;
}
}
这段代码的问题一目了然,每加入一个需要转换的类型就要修改这段代码,但是通过用java.beans API可以解决这个问题。
package com.surekam.util.reflection;
import java.beans.BeanInfo;
import java.beans.Expression;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.beans.PropertyEditor;
import java.beans.PropertyEditorManager;
import java.lang.reflect.Method;
import java.util.Properties;
import com.surekam.model.record.TobacOrder;
import test.util.TestXML;
/**
* 类说明:通过反射为bean赋值。
*
* @author 李华
*
*/
//
public class Evaluate { /** * 参数说明:*className :要赋值的bean的type**po:要赋值的bean,如果po为空则创建一个**prop:属性名->值** @author 李华 * */
public static Object evaluatePo(String className, Object po, Properties prop) {
try {
Class poClass = Class.forName(className);
if (po == null) {
po = poClass.newInstance();
}
// Introspector相当beans这个架构的一个入口。类似于Hibernate的SessionFactory// 通过bean的类型获得bean的描述—》获得属性描述的集合
BeanInfo bi = Introspector.getBeanInfo(poClass);
PropertyDescriptor[] pd = bi.getPropertyDescriptors();
for (int i = 0; i < pd.length; i++) {
if (prop.getProperty(pd[i].getName()) != null) {
Object value = getPropValue(pd[i].getPropertyType(),
prop.getProperty(pd[i].getName()));
executeEvaluate(po, pd[i].getWriteMethod(), value);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return po;
}
// 这里是PropertyEditor 的使用,规避了if条件的使用。让代码的扩展性得到了很好的保证。这里使用的是依赖查找(DL)的方式。// 注册PropertyEditor 的步骤放在了bean容器当中 static Object getPropValue(Class clazz, String value)
throws InstantiationException, IllegalAccessException {
PropertyEditor pe = PropertyEditorManager.findEditor(clazz);
pe.setAsText(value);
return pe.getValue();
}
//调用赋值方法
static void executeEvaluate(Object dest, Method m, Object value)
throws Exception {
Expression e = new Expression(dest, m.getName(),
new Object[] { value });
e.execute();
}
}
总结一下PropertyEditor 的使用方式。 1,注册PropertyEditor 。通过PropertyEditorManager的registerEditor方法注册PropertyEditor。 2,查找PropertyEditor 。通过PropertyEditorManager的findEditor方法查找PropertyEditor。 3,转换值。调用PropertyEditor 的setAsText方法进行转换。用getValue方法获得值。 java.beans包是JDK对java reflection的封装。Expression 封装了方法调用的细节。BeanInfo ,PropertyDescriptor封装了查找属性的细节。规避了很多代码的陷阱,隐藏了很多reflection的实现细节。通过这个框架编写的代码,更加强壮,更加有扩展性。