上一篇文章最后提到,java 内省的原生 api 操作依旧不方便,比如参数类型的判断。用脚趾头都想得到,一定有人写了轮子。
可以使用 BeanUtils 来简化操作。spring 有一个 BeanUtils, apache-common 也有,这里使用 apache-common 的 BeanUtils 来测试。
存在如下 javaBean:
public class User {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
1. 自动类型判断。
public void test() throws Exception {
// init
Class<?> clazz = Class.forName(User.class.getName());
Object user = clazz.newInstance();
// set
for (Field field : clazz.getDeclaredFields()) {
if (field.getName().equalsIgnoreCase("name")) {
BeanUtils.setProperty(user, field.getName(), "chengfan");
} else {
BeanUtils.setProperty(user, field.getName(), 22);
}
}
// show
for (Field field : clazz.getDeclaredFields()) {
String property = BeanUtils.getProperty(user, field.getName());
System.out.println(property);
}
}
/*
chengfan
22
*/
可以看到,使用 BeanUtils.setProperty
方法,我们不需要关心是什么参数。
当然,该方法只能处理基本数据类型和 String, 自定义的类型依旧无法处理。当然,可以通过编写 convert 来解决这个问题。这个最后演示
2. map 转 java bean。
上面的代码还是很复杂,因为需要判断字段的名字,然后设定值,BeanUtils 可以直接将一个 map 转为 bean,当然 map 的 key 要和 bean 的字段名一样。
public void test2() throws Exception {
// init
Class<?> clazz = Class.forName(User.class.getName());
Object user = clazz.newInstance();
Map<String, Object> beanMap = new HashMap<String, Object>();
beanMap.put("name", "chengfan");
beanMap.put("age", 22);
// set
BeanUtils.populate(user, beanMap);
// show
for (Field field : clazz.getDeclaredFields()) {
String property = BeanUtils.getProperty(user, field.getName());
System.out.println(property);
}
}
/*
chengfan
22
*/
3. bean 转 map
2 的逆过程,不解释。
@Test
public void test3() throws Exception {
// init
Class<?> clazz = Class.forName(User.class.getName());
Object user = clazz.newInstance();
Map<String, Object> beanMap = new HashMap<String, Object>();
beanMap.put("name", "chengfan");
beanMap.put("age", 22);
// set
BeanUtils.populate(user, beanMap);
// trans
Map<String, String> describe = BeanUtils.describe(user);
for (Entry<String, String> entry : describe.entrySet()) {
System.out.println(String.format("%s -- %s", entry.getKey(), entry.getValue()));
}
}
/*
name -- chengfan
age -- 22
class -- class cn.fanhub.jysk.utilslearn.beanutils.User // 忽略它
*/
2 和 3 在哪里有应用呢?
- convertor 的用法
比如,我的字段是一个 Date 类型,并且按照 yyyy-MM-dd
格式化,正常情况下,BeanUtils 是解析不了的,所以需要做一些操作:
public class DateBean {
private Date date;
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
}
@Test
public void test4() throws Exception {
DateBean bean = new DateBean();
ConvertUtils.register(new Converter() {
public Object convert(Class aClass, Object o) {
String p = (String)o;
if(p== null || p.trim().length()==0){
return null;
}
try{
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
return df.parse(p.trim());
}
catch(Exception e){
return null;
}
}
}, java.util.Date.class);
BeanUtils.setProperty(bean, "date", "2018-04-18");
System.out.println(BeanUtils.getProperty(bean, "date"));
}
// Wed Apr 18 00:00:00 CST 2018
如果注释掉 ConvertUtils.register
会报错。