如何正确使用Apache Common BeanUtil的BeanComparator来获取内省?

时间:2014-11-25 16:23:25

标签: java javabeans apache-commons introspection apache-commons-beanutils

我搜索了SOF,但没有找到与BeanUtil使用相关的基本问题。

我有一个POJO类,例如UserPojo,其类代码为:

public class UserPojo{

    private String name;
    private int    gender;
    private int    size;

    //Setters
    public void setName(String name) {this.name  =name;}
    public void setGender(int gender){this.gender=gender;}
    public void setSize(int size)    {this.size  =size;}

    //getters
    public String getName()  {return this.name;}
    public int    getGender(){return this.gender;}
    public int    getSize()  {return this.size;}
}

我的问题是,如何使用BeanUtil自动比较这个bean的两个实例?

我试过了:

final BeanComparator<UserPojo> comparator = new BeanComparator<UserPojo>();
final int comparison = comparator.compare(expectedPojo, receivedPojo);

但它以下列错误结束:

java.lang.ClassCastException : UserPojo cannot be cast to java.lang.Comparable

我理解我的Pojo应该实现标准的Comparable接口,但这种比较不依赖于内省,而且BeanUtil的导入似乎没用......

那么,如何正确使用呢?

2 个答案:

答案 0 :(得分:0)

你必须看看那里的各种构造函数:

BeanComparator(String property)

  • 为bean构造一个基于属性的比较器。

BeanComparator(String property, Comparator comparator)

  • 为bean构造一个基于属性的比较器。

这是前者的javadoc(第二段是你的答案):

  

为bean构造一个基于属性的比较器。这比较两个   bean属性参数中指定的属性。这个   构造函数创建一个使用ComparableComparator的BeanComparator   比较属性值。

     

将“null”传递给此构造函数将导致BeanComparator   比较基于自然顺序的对象,即java.lang.Comparable。

正如您所期望的那样,您正在调用的构造函数就是这样:

this(null);

为了比较多个属性,您可以使用第二个变体

Collections.sort(collection, 
  new BeanComparator("property1", 
    new BeanComparator("property2", 
      new BeanComparator("property3")))); 

我个人认为Apache Commons CompareToBuilderGoogle Guava’s ComparisonChain是更好的选择。

答案 1 :(得分:0)

我终于放弃了并编码了这个。 它没有回答这个问题,但这是解决这个问题的方法:

import org.apache.commons.beanutils.BeanUtils;

public static void assertBeansEqual(final Object expected, final Object given) {
    try {
        final Map<String, String> expectedDescription = BeanUtils.describe(expected);
        final Map<String, String> givenDescription = BeanUtils.describe(given);

        // if the two bean don't share the same attributes.
        if (!(expectedDescription.keySet().containsAll(givenDescription.keySet()))) {
            final Set<String> keySet = givenDescription.keySet();
            keySet.removeAll(expectedDescription.keySet());
            fail("The expected bean has not the same attributes than the given bean, the followings fields are not present in the expected bean :" + keySet);
        }
        if (!(givenDescription.keySet().containsAll(expectedDescription.keySet()))) {
            final Set<String> keySet = expectedDescription.keySet();
            keySet.removeAll(givenDescription.keySet());
            fail("The expected bean has not the same attributes than the given bean, the followings fields are not present in the given bean :" + keySet);
        }

        final List<String> differences = new LinkedList<String>();
        for (final String key : expectedDescription.keySet()) {
            if (isNull(expectedDescription.get(key))) {
                // if the bean1 value is null and not the other -> not equal. This test is
                // required to avoid NPE attributes values are null. (null object dot not have
                // equals method).
                if (!isNull(givenDescription.get(key))) {
                    differences.add(key);
                }
            }
            else {
                // if two attributes don't share an attributes value.
                if (!expectedDescription.get(key).equals(givenDescription.get(key))) {
                    differences.add(key);
                }
            }
        }
        if (!differences.isEmpty()) {
            String attributes = "";
            for (final String attr : differences) {
                attributes = attributes + "|" + attr;
            }
            fail("Assertion fail, the expected bean and the given bean attributes values differ for the followings attributes : " + attributes + "|");
        }
    }
    catch (final Exception e) {
        e.printStackTrace();
        fail(e.getMessage());
    }
}