2013-03-12 60 views
4

我正在使用BeanutilsBean.describe()方法來獲取審計跟蹤的數據。它工作得很好 - 這不是問題!Apache Commons BeanUtilsBean - 從describe中排除屬性()

但是有些特性不需要審計。這些在列表中記錄爲字符串。因此,例如,如果您有屬性DomainObject.myValue,該列表將包含"myValue",因此對DomainObject.getMyValue()的調用結果未包含在審計跟蹤中。

當前代碼從BeanutilsBean.describe()獲取所有屬性,然後遍歷它們以丟棄不需要的屬性。

我希望能夠做的是配置BeanUtilsBean實例的屬性名稱列表進行排除,以便它永遠不會調用這些方法。所以在我的例子中,DomainObject.getMyValue()根本不會被調用。

如果可以通過API或代碼查看,我無法解決。

回答

1

不,您正在進行過濾是最簡單的方法。該方法的來源不提供任何可配置的過濾。其實只有兩個選擇,同時使用BeanUtilsBean,我可以看到:

  • 呼叫describe(),然後過濾結果(你現在在做什麼)。你可以用一個靜態方法把它包裝起來,像public static Map<String, String> describeBean(Object bean, String... excludedProperties)
  • 滾動你自己的工具方法(簽名像上面那樣),複製describe()的實現,但是在初始迭代過程中進行過濾。這會更高效,因爲它不需要額外通過Map
4

這是我用來解決這個問題的代碼。

這是BeanUtilsBean.describe()的略微修改副本,它不會調用排除的屬性獲取器;它是ach's answer中的「滾動你自己」選項(第一個選項已經在現場代碼中使用了幾年,但它從來沒有和我一起坐過!)。

import java.beans.PropertyDescriptor; 
import java.lang.reflect.InvocationTargetException; 
import java.lang.reflect.Method; 
import java.util.HashMap; 
import java.util.Map; 
import java.util.Set; 

import org.apache.commons.beanutils.BeanUtilsBean; 
import org.apache.commons.beanutils.DynaBean; 
import org.apache.commons.beanutils.DynaProperty; 
import org.apache.commons.beanutils.MethodUtils; 

public class BeanUtilsBeanExtensions { 

    private static final BeanUtilsBean BEAN_UTILS_BEAN = BeanUtilsBean 
        .getInstance(); 

    public BeanUtilsBeanExtensions() { 
    } 

    /** 
    * Extends BeanUtilsBean.describe() so that it can be given a list of 
    * attributes to exclude. This avoids calling methods which might derive 
    * data which don't happen to be populated when the describe() call is made 
    * (and therefore could throw exceptions) as well as being more efficient 
    * than describing everything then discarding attributes which aren't 
    * required. 
    * 
    * @param bean 
    *   See BeanUtilsBean.describe() 
    * @param excludedAttributeNames 
    *   the attribute names which should not be described. 
    * @return See BeanUtilsBean.describe() 
    */ 
    public Map<String, String> describe(Object bean, 
        Set<String> excludedAttributeNames) 
        throws IllegalAccessException, 
        InvocationTargetException, NoSuchMethodException { 

     // This method is mostly just a copy/paste from BeanUtilsBean.describe() 
     // The only changes are: 
     // - Removal of reference to the (private) logger 
     // - Addition of Reference to a BeanUtilsBean instance 
     // - Addition of calls to excludedAttributeNames.contains(name) 
     // - Use of generics on the Collections 
     // - Calling of a copy of PropertyUtilsBean.getReadMethod() 

     if (bean == null) { 
      return (new java.util.HashMap<String, String>()); 
     } 

     Map<String, String> description = new HashMap<String, String>(); 
     if (bean instanceof DynaBean) { 
      DynaProperty[] descriptors = ((DynaBean) bean).getDynaClass() 
          .getDynaProperties(); 
      for (int i = 0; i < descriptors.length; i++) { 
       String name = descriptors[i].getName(); 
       if (!excludedAttributeNames.contains(name)) { 
        description.put(name, 
            BEAN_UTILS_BEAN.getProperty(bean, name)); 
       } 
      } 
     } 
     else { 
      PropertyDescriptor[] descriptors = BEAN_UTILS_BEAN 
          .getPropertyUtils().getPropertyDescriptors(bean); 
      Class<? extends Object> clazz = bean.getClass(); 
      for (int i = 0; i < descriptors.length; i++) { 
       String name = descriptors[i].getName(); 
       if (!excludedAttributeNames.contains(name) 
           && getReadMethod(clazz, descriptors[i]) != null) { 
        description.put(name, 
            BEAN_UTILS_BEAN.getProperty(bean, name)); 
       } 
      } 
     } 
     return description; 
    } 

    /* 
    * Copy of PropertyUtilsBean.getReadMethod() since that is package-private. 
    */ 
    private Method getReadMethod(Class<? extends Object> clazz, 
        PropertyDescriptor descriptor) { 
     return MethodUtils.getAccessibleMethod(clazz, 
         descriptor.getReadMethod()); 
    } 

} 
相關問題