【相关类库】org.apache.commons.beanutils.BeanUtils,提供对Java反射和自省API的包装,其中底层使用到了Java的内省方法。
【内省的一般应用形式】通过类Introspector 来获取某个对象的 BeanInfo 信息,然后通过 BeanInfo 来获取属性的描述器(PropertyDescriptor),通过这个属性描述器就可以获取某个属性对应的 getter/setter方法,然后我们就可以通过反射机制来调用这些方法。
【代码使用】Introspector.getBeanInfo(Class<?> beanClass);拿BeanInfo对象。
【例子】例如一个price属性,

1、定义 private Long price; // 价格
2、set方法

public void setPrice(Long price) {

this.price = price;

}
3、get方法

public String getPrice() {

return null == price ? null : StringUtil.priceToStr(price);

}
则通过内省只会拿到get方法。

【原理和注意事项】getBeanInfo()方法(返回GenericBeanInfo),其中有getTargetPropertyInfo(),会通过getPublicDeclaredMethods(beanClass);找出所有的get、set方法以PropertyDescriptor存储在list(通常长度为2),然后通过hashmap(属性名,list)暂存;
然后通过processPropertyDescriptors()进行筛选和合并,
(这个方法官方注释 Populates the property descriptor table by merging the lists of Property descriptors.)
其中会判断get方法的返回值和set方法的参数类型是否assignable,若不一致则以get方法为准,认为只有get方法符合要求。
然后存储在Introspector的properties当中,供GenericBeanInfo的构造方法调用。
之后BeanInfo对外暴露getPropertyDescriptors(),取其中的properties。

注:java.beans.Introspector当中,Introspector是public的,还有一个

GenericBeanInfo是包级可见的类(带蓝三角)。

官方注释

* Package private implementation support class for Introspector's
* internal use.
* <p>
* Mostly this is used as a placeholder for the descriptors.

大概不使用内部类的原因,是因为GenericBeanInfo基本上为Introspector所使用但又保留了给java.beans其他类使用的可能?这块的组织形式个人感觉比较别扭。

【最佳实践】
模型向视图对象vo转换时,vo属性设置为传给前端的类型,保持set、get方法类型一致,调用BeanUtils.copyProperties(dest, orig);通过org.apache.commons.beanutils.Converter转换器进行转换,而不要设置不同类型的get、set方法。

附:自定义类型转换器,注意这里Converter()的类型起名依据是转换后的类型,里面处理的是不同类型转换为转换后的类型的情况。

ConvertUtils.register(new XXXConverter(), java.lang.XXX.class);
BeanUtils.copyProperties(dest, orig);

Converter例子:

class DateConverter implements Converter {
@Override
public Object convert(Class type, Object value) {
if (value == null) {
return null;
}
if (value instanceof Date) {
return value;
}
if (value instanceof Long) {
Long longValue = (Long) value;
return new Date(longValue.longValue());
}
try {
return DateUtils.parseDate(value.toString(), new String[] { "yyyy-MM-dd HH:mm:ss.SSS",
"yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM-dd" });
} catch (Exception e) {
throw new ConversionException(e);
}
}
}

最新文章

  1. WebLogic中的一些基本概念
  2. MySQL 配置文件中忘配置default-character-set引发的乱码问题
  3. struts之动态方法调用使用通配符
  4. 根据 字数 确定 UI控件高度
  5. HTTP Post请求过程详解
  6. Linux串口调试
  7. Socket解决粘包问题1
  8. linux最大文件句柄数量总结
  9. 格而知之4:寻找EXC_BAD_ACCESS
  10. 转://ORA-00603,ORA-27501,ORA-27300,ORA-27301,ORA-27302故障案例一则
  11. XVIII Open Cup named after E.V. Pankratiev. GP of Urals
  12. MapReduce处理HBase出错:XXX.jar is not a valid DFS filename
  13. MySQL 5.7 时间显示修改(log_timestamps UTC)
  14. Go 程序执行顺序
  15. Understanding the difficulty of training deep feedforward neural networks
  16. iteritems()
  17. JSP乱码(小记)
  18. 「日常训练」 Fire!(UVA-11624)
  19. python 库 、包 、模块
  20. Django_MTV模型

热门文章

  1. 控制执行流程之ForEach语法
  2. 初入计算机专业,学习c语言的第一周作业问答
  3. DataGuard开启failover
  4. FPipe端口转发
  5. windows环境下搭建python虚拟环境及离线移植
  6. mybatis 配置之&lt;typeAliases&gt;别名配置元素设置
  7. SpringBootSecurity学习(13)前后端分离版之JWT
  8. 利用python爬虫关键词批量下载高清大图
  9. Disruptor—核心概念及体验
  10. request.getPathInfo()的作用