commons-beanutils

內省(瞭解)

內省的目標是得到JavaBean屬性的讀、寫方法的反射對象,通過反射對JavaBean屬性進行操作的一組API。例如User類有名爲username的JavaBean屬性,通過兩個Method對象(一個是getUsenrmae(),一個是setUsername())來操作User對象。

如果你還不能理解內省是什麼,那麼我們通過一個問題來了解內省的作用。現在我們有一個Map,內容如下:

       Map<String,String> map = new HashMap<String,String>();

       map.put("username", "admin");

       map.put("password", "admin123");

public class User {

    private String username;

    private String password;

 

    public User(String username, String password) {

       this.username = username;

       this.password = password;

    }

    public User() {

    }

    public String getUsername() {

       return username;

    }

    public void setUsername(String username) {

       this.username = username;

    }

    public String getPassword() {

       return password;

    }

    public void setPassword(String password) {

       this.password = password;

    }

    public String toString() {

       return "User [username=" + username + ", password=" + password + "]";

    }

}

 

現在需要把map的數據封裝到一個User對象中!User類有兩個JavaBean屬性,一個叫username,另一個叫password。

你可能想到的是反射,通過map的key來查找User類的Field!這麼做是沒有問題的,但我們要知道類的成員變量是私有的,雖然也可以通過反射去訪問類的私有的成員變量,但我們也要清楚反射訪問私有的東西是有“危險”的,所以還是建議通過getUsername和setUsername來訪問JavaBean屬性。

 

2.1 內省之獲取BeanInfo

我們這裏不想去對JavaBean規範做過多的介紹,所以也就不在多介紹BeanInfo的“出身”了。你只需要知道如何得到它,以及BeanInfo有什麼。

通過java.beans.Introspector的getBeanInfo()方法來獲取java.beans.BeanInfo實例。

BeanInfo beanInfo = Introspector.getBeanInfo(User.class);

 

2.2 得到所有屬性描述符(PropertyDescriptor)

通過BeanInfo可以得到這個類的所有JavaBean屬性的PropertyDescriptor對象。然後就可以通過PropertyDescriptor對象得到這個屬性的getter/setter方法的Method對象了。

PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();

 

每個PropertyDescriptor對象對應一個JavaBean屬性:

  1. String getName():獲取JavaBean屬性名稱;
  2. Method getReadMethod:獲取屬性的讀方法;
  3. Method getWriteMethod:獲取屬性的寫方法。

 

2.3 完成Map數據封裝到User對象中

    public void fun1() throws Exception {

       Map<String,String> map = new HashMap<String,String>();

       map.put("username", "admin");

       map.put("password", "admin123");

      

       BeanInfo beanInfo = Introspector.getBeanInfo(User.class);[崔1] 

      

       PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();[崔2] 

      

       User user = new User();[崔3] 

       for(PropertyDescriptor pd : pds)[崔4]  {

           String name = pd.getName();[崔5] 

           String value = map.get(name);[崔6] 

           if(value != null)[崔7]  {

              Method writeMethod = pd.getWriteMethod();[崔8] 

              writeMethod.invoke(user, value);[崔9] 

           }

       }

      

       System.out.println(user);

    }

 

3 commons-beanutils

提到內省,不能不提commons-beanutils這個工具。它底層使用了內省,對內省進行了大量的簡化!

使用beanutils需要的jar包:

  1. commons-beanutils.jar;
  2. commons-logging.jar;

 

3.1 設置JavaBean屬性

       User user = new User();

      

       BeanUtils.setProperty(user, "username", "admin");[崔10] 

       BeanUtils.setProperty(user, "password", "admin123");[崔11] 

      

       System.out.println(user);

 

3.2 獲取JavaBean屬性

       User user = new User("admin", "admin123");

      

       String username = BeanUtils.getProperty(user, "username");[崔12] 

       String password = BeanUtils.getProperty(user, "password");[崔13] 

      

       System.out.println("username=" + username + ", password=" + password);

 

3.3 封裝Map數據到JavaBean對象中

       Map<String,String> map = new HashMap<String,String>();

       map.put("username", "admin");

       map.put("password", "admin123");

      

       User user = new User();

 

       BeanUtils.populate(user, map);[崔14] 

      

       System.out.println(user);


 工具類:將Map直接封裝到Bean

public static <T> T toBean(Map map, Class<T> clazz) {
		try {
			/*
			 * 1. 創建指定類型的javabean對象
			 */
			T bean = clazz.newInstance();
			/*
			 * 2. 把數據封裝到javabean中
			 */
			BeanUtils.populate(bean, map);
			/*
			 * 返回javabean對象
			 */
			return bean;
		} catch(Exception e) {
			throw new RuntimeException(e);
		}
	}

測試:

public class Demo1 {
	@Test
	public void fun1() throws Exception {
		String className = "cn.itcast.domain.Person";
		Class clazz = Class.forName(className);
		Object bean = clazz.newInstance();
		
		BeanUtils.setProperty(bean, "name", "張三");
		BeanUtils.setProperty(bean, "age", "23");
		BeanUtils.setProperty(bean, "gender", "男");
		BeanUtils.setProperty(bean, "xxx", "XXX");
		
		String age = BeanUtils.getProperty(bean, "age");
		System.out.println(age);
		System.out.println(bean);
	}
	
	/*
	 * 把map中的屬性直接封裝到一個bean中 
	 * 
	 * Map: {"username":"zhangSan", "password","123"}
	 * 我們要把map的數據封裝到一個javabean中!要求map的key與bean的屬性名相同!
	 */
	@Test
	public void fun2() throws Exception {
		Map<String,String> map = new HashMap<String,String>();
		map.put("username", "zhangSan");
		map.put("password", "123");
		
		User user = new User();
		BeanUtils.populate(user, map);
		
		System.out.println(user);
	}
	
	@Test
	public void fun3() {
		Map<String,String> map = new HashMap<String,String>();
		map.put("username", "zhangSan");
		map.put("password", "123");
		
		/*
		 * request.getParameterMap();
		 */
		
		User user = CommonUtils.toBean(map, User.class);
		System.out.println(user);
	}

 

commons-beanutils是Apache開源組織提供的用於操作JAVA BEAN的工具包。使用commons-beanutils,我們可以很方便的對bean對象的屬性進行操作。今天爲大家介紹一下該包的常用方法。

在介紹常用類之前,我們先來 編寫一個用於測試的BEAN類:

package com.gujin.entity;

public class UserInfo
{
   private String userId;
   private String userName;

   public UserInfo()
   {
   }

   public UserInfo(String userId, String userName)
   {
      this.userId = userId;
      this.userName = userName;
   }

   public String getUserId()
   {
      return userId;
   }

   public void setUserId(String userId)
   {
      this.userId = userId;
   }

   public String getUserName()
   {
      return userName;
   }

   public void setUserName(String userName)
   {
      this.userName = userName;
   }

   @Override
   public String toString()
   {
      return String.format("{userId:%s,userName:%s}", userId, userName);
   }
}

MethodUtils

MethodUtils通過反射訪問對象的方法並且執行方法。

方法摘要:

返回值 方法名 說明
static int clearCache() 清空方法緩存
static Method getAccessibleMethod(Class<?> clazz, Method method) 返回一個可訪問的方法
static Method getAccessibleMethod(Class<?> clazz, String methodName, Class<?> parameterType) 返回一個可訪問的方法
static Method getAccessibleMethod(Class<?> clazz, String methodName, Class<?>[] parameterTypes) 返回一個可訪問的方法
static Method getAccessibleMethod(Method method) 返回一個可訪問的方法
static Method getMatchingAccessibleMethod(Class<?> clazz, String methodName, Class<?>[] parameterTypes) 查找與方法名及參數匹配的可訪問方法
static Class<?> getPrimitiveType(Class<?> wrapperType) 獲得包裝類的基本數據類型
static Class<?> getPrimitiveWrapper(Class<?> primitiveType) 獲得基本數據類型的包裝類型
static Object invokeExactMethod(Object object, String methodName, Object arg) 執行方法
static Object invokeExactMethod(Object object, String methodName, Object[] args) 執行方法
static Object invokeExactMethod(Object object, String methodName, Object[] args, Class<?>[] parameterTypes) 執行方法
static Object invokeExactStaticMethod(Class<?> objectClass, String methodName, Object arg) 執行靜態方法
static Object invokeExactStaticMethod(Class<?> objectClass, String methodName, Object[] args) 執行靜態方法
static Object invokeExactStaticMethod(Class<?> objectClass, String methodName, Object[] args, Class<?>[] parameterTypes) 執行靜態方法
static Object invokeMethod(Object object, String methodName, Object arg) 執行方法
static Object invokeMethod(Object object, String methodName, Object[] args) 執行方法
static Object invokeMethod(Object object, String methodName, Object[] args, Class<?>[] parameterTypes) 執行方法
static Object invokeStaticMethod(Class<?> objectClass, String methodName, Object arg) 執行靜態方法
static Object invokeStaticMethod(Class<?> objectClass, String methodName, Object[] args) 執行靜態方法
static Object invokeStaticMethod(Class<?> objectClass, String methodName, Object[] args, Class<?>[] parameterTypes) 執行靜態方法
static boolean isAssignmentCompatible(Class<?> parameterType, Class<?> parameterization) 確定是否可以使用一個類型作爲方法調用參數
static void setCacheMethods(boolean cacheMethods) 設置緩存方法
static Class<?> toNonPrimitiveClass(Class<?> clazz) 如果是簡單數據類型則返回對應的包裝類,否則返回本身

使用示例:

package com.gujin.beanutils;

import java.lang.reflect.Method;

import org.apache.commons.beanutils.MethodUtils;
import org.junit.Test;

import com.gujin.entity.UserInfo;

public class MethodUtilsTest
{
   @Test
   public void test() throws Exception
   {
      UserInfo userInfo = new UserInfo();
      // 通過方法名和參數類型獲得可訪問方法
      Method method = MethodUtils.getAccessibleMethod(UserInfo.class,
            "setUserId", String.class);
      method.invoke(userInfo, "jianggujin");
      // 可以直接通過invokeMethod執行方法
      MethodUtils.invokeMethod(userInfo, "setUserName", "蔣固金");
      System.out.println(userInfo);
   }
}

運行結果:

{userId:jianggujin,userName:蔣固金}

ConstructorUtils

ConstructorUtils通過反射提供了構造方法相關的便捷操作方法。

方法摘要:

返回值 方法名 說明
static <T> Constructor<T> getAccessibleConstructor(Class<T> klass, Class<?> parameterType) 獲得含有一個形參的構造方法
static <T> Constructor<T> getAccessibleConstructor(Class<T> klass, Class<?>[] parameterTypes) 獲得含有指定類型形參的構造方法
static <T> Constructor<T> getAccessibleConstructor(Constructor<T> ctor) 獲得可訪問構造方法
static <T> T invokeConstructor(Class<T> klass, Object arg) 執行構造方法
static <T> T invokeConstructor(Class<T> klass, Object[] args) 執行構造方法
static <T> T invokeConstructor(Class<T> klass, Object[] args, Class<?>[] parameterTypes) 執行構造方法
static <T> T invokeExactConstructor(Class<T> klass, Object arg) 執行構造方法
static <T> T invokeExactConstructor(Class<T> klass, Object[] args) 執行構造方法
static <T> T invokeExactConstructor(Class<T> klass, Object[] args, Class<?>[] parameterTypes) 執行構造方法

使用示例:

package com.gujin.beanutils;

import java.lang.reflect.Constructor;

import org.apache.commons.beanutils.ConstructorUtils;
import org.junit.Test;

import com.gujin.entity.UserInfo;

public class ConstructorUtilsTest
{
   @Test
   public void test() throws Exception
   {
      Constructor<UserInfo> constructor = ConstructorUtils
            .getAccessibleConstructor(UserInfo.class, new Class[] {
                  String.class, String.class });
      System.out.println(constructor.newInstance("jianggujin", "蔣固金"));
      // 更簡潔的寫法
      UserInfo userInfo = ConstructorUtils.invokeConstructor(UserInfo.class,
            new String[] { "jianggujin", "蔣固金" });
      System.out.println(userInfo);
   }
}

運行結果:

{userId:jianggujin,userName:蔣固金} 
{userId:jianggujin,userName:蔣固金}

PropertyUtils

PropertyUtils通過反射提供了對象屬性的便捷操作方法。

方法摘要:

返回值 方法名 說明
static void addBeanIntrospector(BeanIntrospector introspector) 添加一個BeanIntrospector
static void clearDescriptors() 清空所有屬性描述信息
static void copyProperties(Object dest, Object orig) 複製屬性
static Map<String,Object> describe(Object bean) 屬性描述
static Object getIndexedProperty(Object bean, String name) 指定索引屬性值
static Object getIndexedProperty(Object bean, String name, int index) 指定索引屬性值
static Object getMappedProperty(Object bean, String name) 獲得Map屬性
static Object getMappedProperty(Object bean, String name, String key) 獲得Map屬性中指定鍵對應的值
static Object getNestedProperty(Object bean, String name) 獲得嵌套屬性
static Object getProperty(Object bean, String name) 獲得屬性
static PropertyDescriptor getPropertyDescriptor(Object bean, String name) 獲得屬性描述
static PropertyDescriptor[] getPropertyDescriptors(Class<?> beanClass) 獲得屬性描述
static PropertyDescriptor[] getPropertyDescriptors(Object bean) 獲得屬性描述
static Class<?> getPropertyType(Object bean, String name) 獲得屬性類型
static Method getReadMethod(PropertyDescriptor descriptor) 返回一個可訪問的屬性的getter方法
static Object getSimpleProperty(Object bean, String name) 返回屬性值
static Method getWriteMethod(PropertyDescriptor descriptor) 返回一個可訪問的屬性的setter方法
static boolean isReadable(Object bean, String name) 判斷是否爲可讀屬性
static boolean isWriteable(Object bean, String name) 判斷是否爲可寫屬性
static boolean removeBeanIntrospector(BeanIntrospector introspector) 移除BeanIntrospector
static void resetBeanIntrospectors() 重置BeanIntrospector
static void setIndexedProperty(Object bean, String name, int index, Object value) 設置指定索引屬性值
static void setIndexedProperty(Object bean, String name, Object value) 設置指定索引屬性值
static void setMappedProperty(Object bean, String name, Object value) 設置Map屬性的值
static void setMappedProperty(Object bean, String name, String key, Object value) 設置Map屬性指定鍵的值
static void setNestedProperty(Object bean, String name, Object value) 設置嵌套屬性的值
static void setProperty(Object bean, String name, Object value) 設置屬性值
static void setSimpleProperty(Object bean, String name, Object value) 設置屬性值

使用示例:

package com.gujin.beanutils;

import org.apache.commons.beanutils.PropertyUtils;
import org.junit.Test;

import com.gujin.entity.UserInfo;

public class PropertyUtilsTest
{
   @Test
   public void test() throws Exception
   {
      UserInfo userInfo = new UserInfo("jianggujin", "蔣固金");
      UserInfo copyed = new UserInfo();
      PropertyUtils.copyProperties(copyed, userInfo);
      System.out.println(copyed);
      System.out.println(PropertyUtils.describe(userInfo));
      PropertyUtils.setProperty(userInfo, "userId", "gjjiang");
      System.out.println(userInfo);
   }
}

運行結果:

{userId:jianggujin,userName:蔣固金} 
{userId=jianggujin, class=class com.gujin.entity.UserInfo, userName=蔣固金} 
{userId:gjjiang,userName:蔣固金}

BeanUtils

BeanUtils通過反射提供了Bean對象的便捷操作方法。

方法摘要:

返回值 方法名 說明
static Object cloneBean(Object bean) 克隆對象
static void copyProperties(Object dest, Object orig) 複製屬性
static void copyProperty(Object bean, String name, Object value) 複製屬性
static <K,V> Map<K,V> createCache() 創建緩存
static Map<String,String> describe(Object bean) 描述
static String[] getArrayProperty(Object bean, String name) 返回指定屬性的值,作爲字符串數組返回
static String getIndexedProperty(Object bean, String name) 獲取指定索引位置對象作爲字符串返回
static String getIndexedProperty(Object bean, String name, int index) 獲取指定索引位置對象作爲字符串返回
static String getMappedProperty(Object bean, String name) 獲得Map屬性值作爲字符串返回
static String getMappedProperty(Object bean, String name, String key) 獲得Map屬性中指定鍵的值作爲字符串返回
static String getNestedProperty(Object bean, String name) 獲得嵌套屬性作爲字符串返回
static String getProperty(Object bean, String name) 獲得屬性值作爲字符串返回
static String getSimpleProperty(Object bean, String name) 獲得屬性值作爲字符串返回
static void populate(Object bean, Map<String,? extends Object> properties) 將Map中的數據注入到Bean對象中
static void setProperty(Object bean, String name, Object value) 設置屬性值

使用示例:

package com.gujin.beanutils;

import java.util.HashMap;

import org.apache.commons.beanutils.BeanUtils;
import org.junit.Test;

import com.gujin.entity.UserInfo;

public class BeanUtilsTest
{
   @Test
   public void test() throws Exception
   {
      UserInfo userInfo = new UserInfo();
      HashMap<String, String> properties = new HashMap<String, String>();
      properties.put("userId", "jianggujin");
      properties.put("userName", "蔣固金");
      BeanUtils.populate(userInfo, properties);
      System.out.println(userInfo);
   }
}

運行結果:

{userId:jianggujin,userName:蔣固金}

ConvertUtils

ConvertUtils提供了數據類型相互轉換的方法。

方法摘要: 
方法摘要:

返回值 方法名 說明
static String convert(Object value) 將對象轉換爲字符串
static Object convert(Object value, Class<?> targetType) 將對象轉換爲指定數據類型對象
static Object convert(String[] values, Class<?> clazz) 將數組轉換爲指定數據類型對象
static Object convert(String value, Class<?> clazz) 將字符串轉換爲指定數據類型對象
static void deregister() 移除所有已經註冊的轉換器
static void deregister(Class<?> clazz) 移除指定類型的轉換器
static Converter lookup(Class<?> clazz) 查找指定類型的轉換器
static Converter lookup(Class<?> sourceType, Class<?> targetType) 查找將指定類型轉換爲另一種類型的轉換器
static void register(Converter converter, Class<?> clazz) 註冊轉換器

使用示例:

package com.gujin.beanutils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.Converter;
import org.junit.Test;

public class ConvertUtilsTest
{
   @Test
   public void test() throws Exception
   {
      ConvertUtils.register(new Converter()
      {

         @Override
         public <T> T convert(Class<T> arg0, Object arg1)
         {
            try
            {
               return (T) new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
                     .parse((String) arg1);
            }
            catch (ParseException e)
            {
               return null;
            }
         }
      }, Date.class);

      System.out.println(ConvertUtils
            .convert("2016-04-09 12:41:00", Date.class));
   }
}

運行結果:

Sat Apr 09 12:41:00 CST 2016

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章