21

I've been trying to grok the org.apache.commons.beanutils library for a method/idiom to evaluate for equality all properties between 2 instances i.e. a generic equals() method for beans.
Is there a simple way to do this usnig this library? Or am I going about this the wrong way? Thanks.

ysouter
  • 213
  • 1
  • 2
  • 4
  • The [xtendbeans library](http://stackoverflow.com/a/39222891/421602) could be of interest in this context; see [the full example over on this other SO question](http://stackoverflow.com/a/39222891/421602). – vorburger Aug 30 '16 at 08:54

4 Answers4

23

Try EqualsBuilder.reflectionEquals() of commons-lang. EqualsBuilder has a set of methods to include all fields, all non-transient fields and all but certain fields.

If all else fails, the code could serve as a good example how to implement this.

billc.cn
  • 7,187
  • 3
  • 39
  • 79
Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
  • 6
    Be warned that this isn't recursive - so if you have nested beans (i.e. a property of a bean is another bean), they need to implement equals themselves. `reflectionEquals` just calls `equals` on each property, it doesn't reflect into the class any further. – artbristol Oct 08 '12 at 10:01
  • 1
    @artbristol: +1 but be careful will recursive equals: You can easily get caught in a loop when beans form cycles. – Aaron Digulla Oct 08 '12 at 11:52
  • Also useful ReflectionDiffBuilder to find differences – Alexey Sviridov Jun 06 '19 at 09:57
8

To answer your question directly, you could use reflection to do equality checking of beans. There are a few snags you need to be aware of.

There are rules regarding the behaviour of equals() and hashcode(). These rules talk about symmetry, consitency and reflexiveness which may be hard to do when your equals method behaves dynamically based on the other object you're passing in.

Interesting read: http://www.geocities.com/technofundo/tech/java/equalhash.html

Generally speaking, I think you are better off creating your own hashcode and equals methods. There are a fwe good plugins which can automatically generate that code for you based on the class properties.

Having said all this, here are some (old style) methods for getting getters, setters and properties I wrote a long time ago:

private Map getPrivateFields(Class clazz, Map getters, Map setters) {
    Field[] fields = clazz.getDeclaredFields();
    Map m = new HashMap();
    for (int i = 0; i < fields.length; i++) {
        int modifiers = fields[i].getModifiers();
        if (Modifier.isPrivate(modifiers) && !Modifier.isStatic(modifiers) && !Modifier.isFinal(modifiers)) {
            String propName = fields[i].getName();
            if (getters.get(propName) != null && setters.get(propName) != null) {
                m.put(fields[i].getName(), fields[i]);
            }
        }
    }
    return m;
}

The Getters:

private Map getGetters(Class clazz) {
    Method[] methods = clazz.getMethods();
    Map m = new HashMap();
    for (int i = 0; i < methods.length; i++) {
        if (methods[i].getName().startsWith("get")) {
            int modifiers = methods[i].getModifiers();
            if (validAccessMethod(modifiers)) {
                m.put(getPropertyName(methods[i].getName()), methods[i]);
            }
        }
    }
    return m;
}

And the Setters:

private Map getSetters(Class clazz, Map getters) {
    Method[] methods = clazz.getMethods();
    Map m = new HashMap();
    for (int i = 0; i < methods.length; i++) {
        if (methods[i].getName().startsWith("set")) {
            int modifiers = methods[i].getModifiers();
            String propName = getPropertyName(methods[i].getName());
            Method getter = (Method) getters.get(propName);

            if (validAccessMethod(modifiers) && getter != null) {
                Class returnType = getter.getReturnType();
                Class setType = methods[i].getParameterTypes()[0];
                int numTypes = methods[i].getParameterTypes().length;

                if (returnType.equals(setType) && numTypes == 1) {
                    m.put(propName, methods[i]);
                }
            }
        }
    }
    return m;
}

Maybe you can use this to roll your own.

Edit: Ofcourse the reflectionbuilder in Aaron Digulla's answer is much better than my handywork.

Community
  • 1
  • 1
Rolf
  • 7,098
  • 5
  • 38
  • 55
2

As mentioned above, a reflection-based implementation will do what you want. I just wanted to warn you, that reflection is quite costly and such an implementation could be comparably slow. If you just need to do occasional comparisons, you will be fine. However, if you have huge datasets and frequent equality checks (e.g. filtering of big tables) you might get into trouble.

Rahel Lüthy
  • 6,837
  • 3
  • 36
  • 51
  • Good point indeed. jguru has a nice comparison online: http://www.jguru.com/faq/view.jsp?EID=246569 – Rolf Jan 23 '09 at 14:00
0

Or, although not a direct answer to your question, but it might be an answer to your problem (i.e. remove the effort of doing boilerplate code while being super fast)

if you use Eclipse, the following steps will auto generate the hashCode and equals for you:

Source > Generate hashCode and equals...

and then select the fields, it's super effective! :D

Cheers and I hope it helps whoever comes here with the purpose of cutting some time writing boilerplate.

PS: I'm sure other popular IDEs must have similar features.

João Antunes
  • 811
  • 9
  • 16
  • I would really like to know why this option got downvoted to -1. This is a very quick way to generate such methods. And most IDEs support it - it's not as costly as reflection - and this answer is still overall helpful - that's why I put it here.. and it's why I won't take it from here - I wish that it was mandatory to explain why one downvotes things – João Antunes Mar 28 '19 at 11:44
  • 1
    FWIW I think this answer is as least as relevant as the answer that warns that reflection can be slow. – Bampfer Jun 27 '19 at 18:11