PropertyDescriptor描述Java Bean中經過一對存儲器方法(getter / setter)導出的一個屬性。咱們能夠經過該PropertyDescriptor對bean中的該屬性進行讀取和寫入操做,也能夠設置其getter / setter。java
public PropertyDescriptor(String name, Class<?> beanClass) throws IntrospectionException public PropertyDescriptor(String name, Class<?> beanClass, String getMethodName, String setMethodName) throws IntrospectionException public PropertyDescriptor(String name, Method readMethod, Method writeMethod) throws IntrospectionException public Class<?> getPropertyType() public Method getReadMethod() public Method getWriteMethod() public void setReadMethod(Method readMethod) throws IntrospectionException public void setWriteMethod(Method writeMethod) public boolean equals(Object o)
相關的PropertyDescriptor內部屬性以下:
Class<?> propertyType; //該屬性的類型
Method getMethod; //getter
Method setMethod; //setter
還有繼承自其父類FeatureDescriptor的功能,用於指定該屬性的編程名稱編程
現有Person類以下:bash
package com.cwind.property; public class Person { private String name ; private int age ; public Person(){ this.name = ""; this.age = 0; } public Person(String name, int age) { super(); this.name = name; this. age = 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; } public String getNameInUpperCase(){ return this .name .toUpperCase(); } public void setNameToLowerCase(String name){ this.name = name.toLowerCase(); } }
該類中除了name和age兩個屬性的標準getter和setter以外,還有增長了一個獲取大寫name的get方法和一個將name設置爲小寫的set方法。
在測試類中,首先得到這兩個方法對象。markdown
Class personClass = Class.forName("com.cwind.property.Person"); Method read = personClass.getMethod("getNameInUpperCase", null); Method write = personClass.getMethod("setNameToLowerCase", String.class ); //而後能夠經過兩種方式構造PropertyDescriptor PropertyDescriptor prop1 = new PropertyDescriptor( "name", Person.class ); //使用其標準getter和setter PropertyDescriptor prop2 = new PropertyDescriptor( "name", read, write); //使用read和write兩個方法對象所自定義的getter和setter //下面構建一個Person對象 Person person = new Person("Kobe" , 36); System. out.println(prop1.getReadMethod().invoke(person, null)); // --實際調用Person.getName(), result: Kobe System. out.println(prop2.getReadMethod().invoke(person, null)); // --實際調用Person.getNameInUpperCase(), result: KOBE prop1.getWriteMethod().invoke(person, "James"); // --實際調用Person.setName(), person.name被設置爲James prop2.getWriteMethod().invoke(person, "James"); // --實際調用Person.setNameToLowerCase(), person.name被設置爲james
構造函數1:函數
public PropertyDescriptor(String name, Class<?> beanClass) throws IntrospectionException { setName(name); //設置屬性編程名,本例中即'name' if (name.length() == 0){ throw new IntrospectionException("empty property name"); // 編程名爲空則拋出異常 } String caps = Character.toUpperCase(name.charAt(0)) + name.substring(1); // 標準getter應爲getName()或isName(), 先將首字母大寫 findMethods(beanClass, "is" + caps, "get" + caps, "set" + caps); // 參數依次爲:類類型,可能的getter函數名1,可能的getter函數名2,setter函數名 if (getMethod == null){ // findMethods()設置PropertyDescriptor的getMethod和setMethod屬性 throw new IntrospectionException( "Cannot find a is" + caps + " or get" + caps + " method"); } if (setMethod == null){ throw new IntrospectionException( "Cannot find a " + caps + " method" ); } propertyType = checkMethods(getMethod, setMethod); // checkMethods()函數用來檢測getMethod獲得的類型與setMethod的參數類型是否匹配,若匹配則置propertyType爲該類型 }
構造函數2:
public PropertyDescriptor(String name, Class源碼分析
private void findMethods(Class beanClass, String getMethodName1, String getMethodName2, String setMethodName) throws IntrospectionException { try { // 首先查找getMethodName1指定的getter (isXXX) if (getMethodName1 != null) { try { getMethod = beanClass.getMethod(getMethodName1, new Class[0]); } catch (NoSuchMethodException e) {} } // 若失敗,則查找getMethodName2指定的getter (getXXX) if (getMethod == null && getMethodName2 != null) { try { getMethod = beanClass.getMethod(getMethodName2, new Class[0]); } catch (NoSuchMethodException e) {} } if (setMethodName != null) { if (getMethod != null) { // 若是獲得了getMethod,則經過其返回值類型決定setMethod的參數類型 Class propertyType = getMethod.getReturnType(); if (propertyType == Void.TYPE) { // 若getter的返回值爲Void類型則拋出異常 String msg = "The property's read method has return type 'void'"; throw new IntrospectionException(msg); } Class[] setArgs = new Class[] { propertyType }; try { setMethod = beanClass.getMethod(setMethodName, setArgs); // 經過函數名和參數類型得到setMethod } catch (NoSuchMethodException e) {} } else if (getMethodName1 == null && getMethodName2 == null) { // getMethodName1和2均爲空,則此屬性爲只寫屬性,此時遍歷bean中的函數,返回第一個名稱與setMethodName一致且返回類型爲Void的單參數函數 Method[] methods = beanClass.getMethods(); for (int i = 0; i < methods.length; i++) { if (methods[i].getName().equals(setMethodName) && methods[i].getParameterTypes().length == 1 && methods[i].getReturnType() == Void.TYPE) { setMethod = methods[i]; break; } } } } } catch (SecurityException e) { String msg = "SecurityException thrown on attempt to access methods."; // 做者在糾結要不要修改異常類型 throw new IntrospectionException(msg); } }
checkMethods方法測試
private Class<?> checkMethods(Method readMethod, Method writeMethod) throws IntrospectionException { Class<?> newPropertyType = propertyType; // 合法的read方法應該無參同時帶有一個非空的返回值類型 if (readMethod != null) { if (readMethod.getParameterTypes().length > 0) { throw new IntrospectionException("read method has unexpected parameters"); } newPropertyType = readMethod.getReturnType(); if (newPropertyType == Void.TYPE) { throw new IntrospectionException("read method return type is void"); } } // 合法的write方法應該包含一個類型相同的參數 if (writeMethod != null) { if (writeMethod.getParameterTypes().length != 1) { // 參數不能超過一個 String msg = "write method does not have exactly one parameter" ; throw new IntrospectionException(msg); } if (readMethod == null) { // 若無read方法,屬性類型就應爲writeMethod的參數類型 newPropertyType = writeMethod.getParameterTypes()[0]; } else { // 檢查read方法的返回值類型是否與write方法的參數類型相匹配 if (newPropertyType != null && !newPropertyType.isAssignableFrom( writeMethod.getParameterTypes()[0])) { throw new IntrospectionException("read and write method are not compatible"); } } } return newPropertyType; }
最後提一句PropertyDescriptor.equals(), 只有當屬性類型、標誌、讀寫方法和PropertyEditorClass均相同時才認爲兩個PropertyDescriptor相等ui
return samePropertyType && sameFlags && sameReadMethod && sameWriteMethod && samePropertyEditorClass;
轉載自:http://cwind.iteye.com/blog/2028208?utm_source=tuicool this
參考:http://blog.csdn.net/z69183787/article/details/8443777spa