Embracing the Messiness in Search of Epic Solutions

Groovy: java.lang.StackOverflowError When Implementing equals()

Posted

in

PROBLEM

While migrating a portion of my Java code to Groovy code, I got bitten by the Groovy operator loading feature that I should have known better… and my pride hurts, but hey, I admit I write shitty code.

Consider this simple POGO with custom equals() and hashCode(), both implemented using Google Guava libraries:-

@Canonical
class Person {
    String firstName
    String lastName
    String email

    @Override
    boolean equals(Object o) {
        if (this == o) {
            return true
        }
        if (o == null || getClass() != o.getClass()) {
            return false
        }

        final Person other = (Person) o

        return Objects.equal(email, other.email)
    }

    @Override
    int hashCode() {
        return Objects.hashCode(email)
    }
}

What is wrong with the above code? Well, if you are mostly a Java developer like me, this look pretty much correct. However, when I perform an equality check, I get java.lang.StackOverflowError exception. I tend to see this exception when I write my too-smart-for-production recursion API that couldn’t seem find its way to end the recursion, causing the JVM stack to blow up.

SOLUTION

The reason we are getting java.lang.StackOverflowError exception is because Groovy overloads == with equals(). So, if (this == o) { … } becomes if (this.equals(o)) { … }. When we perform an equality check, it will call itself again and again until it chokes itself and dies.

To fix this, we have to use if (this.is(o)) { … } to perform an identity check:-

@Canonical
class Person {
    String firstName
    String lastName
    String email

    @Override
    boolean equals(Object o) {
        if (this.is(o)) {
            return true
        }
        if (o == null || getClass() != o.getClass()) {
            return false
        }

        final Person other = (Person) o

        return Objects.equal(email, other.email)
    }

    @Override
    int hashCode() {
        return Objects.hashCode(email)
    }
}

Tags:

Comments

2 responses to “Groovy: java.lang.StackOverflowError When Implementing equals()”

  1. Vasumathi Sundaram Avatar
    Vasumathi Sundaram

    Thanks for the solution, helped me save lot of time debugging the stackoverflowerror

  2. selimok Avatar

    Thank you for your blog entry. It inspired me to finding solution for my problem.

    I got the same StackOverflowError while calling hashCode of my entity class. I used guava Objects’ hashCode implementation. The hashCode method itself is generated by eclipse guava plugin and the method call includes a class member which is recursively reference the class itself again. In this case hashCode implementation go through this cyclic dependency and calls again and again itself. So I learned, i must be careful using auto generated hashCode or toString methods, especially by entity objects which reference another object with reference back to this entity.

Leave a Reply