Apache Commons BeanUtilsBean - 从describe()中排除属性

时间:2013-03-12 17:32:36

标签: java apache-commons-beanutils

我正在使用BeanutilsBean.describe()方法来获取审计跟踪的数据。它运作得很好 - 这不是问题!

但是,某些属性不需要审核。这些在列表中记录为字符串。因此,例如,如果您有一个属性DomainObject.myValue,则列表将包含"myValue",以便调用DomainObject.getMyValue()的调用结果不会包含在审计跟踪中。

目前,代码从BeanutilsBean.describe()获取所有属性,然后遍历它们以丢弃不需要的属性。

我希望能够做的是将BeanUtilsBean实例配置为要排除的属性名称列表,以便它不会调用这些方法。所以在我的例子中,根本就没有调用DomainObject.getMyValue()。

如果可以通过API或代码查看,我无法解决。

2 个答案:

答案 0 :(得分:4)

这是我用来解决这个问题的代码。

这是BeanUtilsBean.describe()的略微修改的副本,它不会调用被排除的属性getter;这是来自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());
    }

}

答案 1 :(得分:1)

不,你正在做的过滤是最简单的方法。该方法的来源不提供任何类型的可配置过滤。使用BeanUtilsBean时,我只能看到两个选项:

  • 调用describe(),然后过滤结果(您现在正在做的事情)。您可以使用带有public static Map<String, String> describeBean(Object bean, String... excludedProperties)
  • 之类签名的静态方法将其包装起来
  • 滚动您自己的实用程序方法(如上所述的签名),复制describe()的实现,但在初始迭代期间执行过滤。这样可以提高性能,因为它不需要额外通过Map