BeanUtils工具的学习与引见

BeanUtils工具的学习与介绍

什么是javabean呢?

简单来说,就是存粹的java对象,每个属性都提供对应的setXxx,getXxx方法。

下面是apache common beanutils对javabean的解释

  • As a necessary consequence of having a no-arguments constructor, configuration of your bean's behavior must be accomplished separately from its instantiation. This is typically done by defining a set of properties of your bean, which can be used to modify its behavior or the data that the bean represents. The normal convention for property names is that they start with a lower case letter, and be comprised only of characters that are legal in a Java identifier.
  • Typically, each bean property will have a public getter and setter method that are used to retrieve or define the property's value, respectively. The JavaBeans Specification defines a design pattern for these names, using get or set as the prefix for the property name with it's first character capitalized
这里的意思就是:javabean需要一个无参构造器,每个属性,都有一个public 的setXxx、getXxx方法。

下面看看一个具体的列子
public class Employee {
	
	private String address;
	private String firstName;
	private String lastName;
	private Employee employee;
	private List<String> privilegeIdList;
	private Map<String, String> theMap;
	
	public Map<String, String> getTheMap() {
		return theMap;
	}

	public void setTheMap(Map<String, String> theMap) {
		this.theMap = theMap;
	}

	public List<String> getPrivilegeIdList() {
		return privilegeIdList;
	}

	public void setPrivilegeIdList(List<String> privilegeIdList) {
		this.privilegeIdList = privilegeIdList;
	}

	public Employee getEmployee() {
		return employee;
	}

	public void setEmployee(Employee employee) {
		this.employee = employee;
	}

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}

	public String getFirstName() {
		return firstName;
	}

	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	public String getLastName() {
		return lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}


	@Override
	public String toString() {
		return "Employee [address=" + address + ", firstName=" + firstName
				+ ", lastName=" + lastName + ", employee=" + employee
				+ ", privilegeIdList=" + privilegeIdList + ", theMap=" + theMap
				+ "]";
	}
}

所以在开发中,如果我们得到一个Class对象,就可以通过java的反射来得到这个Class对象的相关属性。通常来书,一个Class对象的属性就是:还有哪些属性,那些方法,那些构造器等内容。具体的大家可以查阅相关资料。
由于使用java的反射机制不容易使用,所以我们有必要使用开源技术来访问这些内容。下面介绍BeanUtils工具,先大概浏览下BeanUtils api,如下面截图
BeanUtils工具的学习与引见
通过截图,我们可以发现,这个类提供了多个静态方法来操作bean对象。这些方法主要有:

  • 设置一个对象的属性
  • 获取一个对象的属性
  • 复制一个对象属性给另外一个对象
  • 获取对象的描述信息
这个api接口极大简便了我们队java对象的操作能力。下面是具体的测试代码:
<span style="font-family:SimSun;font-size:18px;">/*
 * Licensed to Luohong Software.
 */
package embedding;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtils;

/**
 * how to use the BeanUtils to set property
 * in the web, we can get the property, and then put the parameter to a map.
 * at finally,put the property map to the obj by using BeanUtils.popualte()
 *  
 * */
public class Employee {
	
	private String address;
	private String firstName;
	private String lastName;
	private Employee employee;
	private List<String> privilegeIdList;
	private Map<String, String> theMap;
	
	public Map<String, String> getTheMap() {
		return theMap;
	}

	public void setTheMap(Map<String, String> theMap) {
		this.theMap = theMap;
	}

	public List<String> getPrivilegeIdList() {
		return privilegeIdList;
	}

	public void setPrivilegeIdList(List<String> privilegeIdList) {
		this.privilegeIdList = privilegeIdList;
	}

	public Employee getEmployee() {
		return employee;
	}

	public void setEmployee(Employee employee) {
		this.employee = employee;
	}

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}

	public String getFirstName() {
		return firstName;
	}

	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	public String getLastName() {
		return lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}


	@Override
	public String toString() {
		return "Employee [address=" + address + ", firstName=" + firstName
				+ ", lastName=" + lastName + ", employee=" + employee
				+ ", privilegeIdList=" + privilegeIdList + ", theMap=" + theMap
				+ "]";
	}

	public static void main(String[] args) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException, InstantiationException {
		Employee employee = new Employee();
		
		Map<String, Object> empMap = new HashMap<String, Object>();
		empMap.put("address", "广东河源龙川");
		empMap.put("firstName", "骆");
		empMap.put("lastName", "Hong");
		empMap.put("employee", new Employee());  //测试对象setXxx、getXxx
		
		List<String> privilegeIdList = new ArrayList<String>();
		privilegeIdList.add("hello");
		privilegeIdList.add("hello");
		privilegeIdList.add("hello");
		privilegeIdList.add("hello");
		empMap.put("privilegeIdList", privilegeIdList);  //测试属性为List的setXxx、getXxx
		
		Map<String, String> theMap = new HashMap<String, String>();
		theMap.put("hello", "value");
		theMap.put("hello12", "value");
		theMap.put("hello2", "value");
		theMap.put("hello3", "value");
		
		empMap.put("theMap", theMap);  //测试属性为map的setXxx、getXxx
		
		//将map里面的内容,set进对象里面,前提是属性名与key相同
		BeanUtils.populate(employee, empMap);
		
		//复制
		Employee copyEmployee = (Employee) BeanUtils.cloneBean(employee);  
		System.out.println(copyEmployee);//
		
		//测试复制方法使用的是浅度复制
		copyEmployee.getPrivilegeIdList().add("你好,世界");  
		String value = BeanUtils.getNestedProperty(copyEmployee, "theMap(hello12)");
		System.out.println(value);
        
		
		//获取一个bean的描述,使用map来存储
		Map<String,String> map = BeanUtils.describe(employee);
		System.out.println(map);
		
		
		System.out.println(employee);  
	}
}</span>

输出结果:
<span style="font-family:SimSun;font-size:18px;">Employee [address=广东河源龙川, firstName=骆, lastName=Hong, employee=Employee [address=null, firstName=null, lastName=null, employee=null, privilegeIdList=null, theMap=null], privilegeIdList=[hello, hello, hello, hello], theMap={hello=value, hello12=value, hello2=value, hello3=value}]
value
{lastName=Hong, address=广东河源龙川, class=class embedding.Employee, employee=Employee [address=null, firstName=null, lastName=null, employee=null, privilegeIdList=null, theMap=null], firstName=骆, privilegeIdList=hello, theMap={hello=value, hello12=value, hello2=value, hello3=value}}
Employee [address=广东河源龙川, firstName=骆, lastName=Hong, employee=Employee [address=null, firstName=null, lastName=null, employee=null, privilegeIdList=null, theMap=null], privilegeIdList=[hello, hello, hello, hello, 你好,世界], theMap={hello=value, hello12=value, hello2=value, hello3=value}]
</span>

通过BeanUtils源码,我们可以发现,BeanUtils使用了如下的框架,来实现这个复杂操作
BeanUtils工具的学习与引见
ConverUtils主要负责将值进行转换,PropertyUtils主要负责取出bean的相关属性。其中在Converter中,使用了策略设计模式来解决类型转换。

总结:通过学习和研究,其实开源源码的难度,有时候并没有我们想象中的那么困难。在研究他人代码时,我们不能囫囵吐枣的乱看,需要系统的,从高处抽象的看待。并且,对于类过多的情况,我们可以采用画UML等方式来组织。