Category Archives: Groovy

Guava: Testing equals(..) and hashcode(..)

PROBLEM

Let’s assume we want to test the following equals(..):-

public class Person {
    private String name;
    private int age;

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

        Person person = (Person) o;
        return Objects.equal(name, person.name);
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(name);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

A correctly implemented equals(..) must be reflexive, symmetric, transitive, consistent and handles null comparison.

In another word, you have to write test cases to pass at least these 5 rules. Anything less is pure bullshit.

SOLUTION

You can write these tests yourself… or you can leverage Guava’s EqualsTester. This library will test these 5 rules and ensure the generated hashcode matches too.

First, include the needed dependency:-

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava-testlib</artifactId>
    <version>18.0</version>
    <scope>test</scope>
</dependency>

Instead of writing JUnit tests, I’ll be writing Spock specs, which is essentially built on top of Groovy, because it allows me to write very clear and clean tests.

class PersonSpec extends Specification {

    def person = new Person(name: 'Mike', age: 10)

    def "equals - equal"() {
        when:
        new EqualsTester().
                addEqualityGroup(person,
                                 new Person(name: 'Mike', age: 10),
                                 new Person(name: 'Mike', age: 20)).
                testEquals()

        then:
        notThrown(AssertionFailedError.class)
    }

    def "equals - not equal"() {
        when:
        new EqualsTester().
                addEqualityGroup(person,
                                 new Person(name: 'Kurt', age: 10)).
                testEquals()

        then:
        thrown(AssertionFailedError.class)
    }
}

Oh… wait for it… BOOM!

Java + Groovy: Creating Immutable List

Java: Mutable List

// class java.util.Arrays$ArrayList
final List mutableList = Arrays.asList(1, 2, 3);

Java: Immutable List

// class java.util.Collections$UnmodifiableRandomAccessList
final List immutableList = Collections.unmodifiableList(Arrays.asList(1, 2, 3));

Java: Immutable List using Guava

// class com.google.common.collect.RegularImmutableList
final ImmutableList guavaImmutableList = ImmutableList.of(1, 2, 3);

Groovy: Immutable List

// class java.util.Collections$UnmodifiableRandomAccessList
final def groovyImmutableList = [1, 2, 3].asImmutable()

Comparing Disassembled Java Class From JVM Languages

All JVM languages come with some degrees of syntactic sugar to make the code easier to read and write.

To satisfy my curiosity, I decided to run javap command to disassemble the bytecode inside the class file generated from several JVM languages. The chosen languages are Java, Groovy, Scala, JRuby and Rhino. I left out Clojure because the syntax does not compute for me after having my heavy lunch.

JAVA

Source Code

public class JavaPerson {
    private String name;
    private int age;

    public JavaPerson(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

Disassembled Java Class

public class com.choonchernlim.epicapp.JavaPerson {
  public com.choonchernlim.epicapp.JavaPerson(java.lang.String, int);
  public java.lang.String getName();
  public int getAge();
}

GROOVY

Source Code

class GroovyPerson {
    String name
    int age
}

Disassembled Java Class

public class com.choonchernlim.epicapp.GroovyPerson implements groovy.lang.GroovyObject {
  public static transient boolean __$stMC;
  public static long __timeStamp;
  public static long __timeStamp__239_neverHappen1395328777863;
  public com.choonchernlim.epicapp.GroovyPerson();
  public java.lang.Object this$dist$invoke$1(java.lang.String, java.lang.Object);
  public void this$dist$set$1(java.lang.String, java.lang.Object);
  public java.lang.Object this$dist$get$1(java.lang.String);
  protected groovy.lang.MetaClass $getStaticMetaClass();
  public groovy.lang.MetaClass getMetaClass();
  public void setMetaClass(groovy.lang.MetaClass);
  public java.lang.Object invokeMethod(java.lang.String, java.lang.Object);
  public java.lang.Object getProperty(java.lang.String);
  public void setProperty(java.lang.String, java.lang.Object);
  public static void __$swapInit();
  static {};
  public java.lang.String getName();
  public void setName(java.lang.String);
  public int getAge();
  public void setAge(int);
  public void super$1$wait();
  public java.lang.String super$1$toString();
  public void super$1$wait(long);
  public void super$1$wait(long, int);
  public void super$1$notify();
  public void super$1$notifyAll();
  public java.lang.Class super$1$getClass();
  public java.lang.Object super$1$clone();
  public boolean super$1$equals(java.lang.Object);
  public int super$1$hashCode();
  public void super$1$finalize();
  static java.lang.Class class$(java.lang.String);
}

SCALA

Source Code

class ScalaPerson(val name: String, val age: Int) {
}

Disassembled Java Class

public class ScalaPerson {
  public java.lang.String name();
  public int age();
  public ScalaPerson(java.lang.String, int);
}

JRUBY

Source Code

require 'java'

class JRubyPerson
  java_signature 'JRubyPerson(String, int)'
  def initialize (name, age)
    @name= name
    @age = age
  end

  java_signature 'String getName()'
  def name;
      @name
  end

  java_signature 'int getAge()'
  def age;
    @age
  end
end

Disassembled Java Class

public class JRubyPerson extends org.jruby.RubyObject {
  public static org.jruby.runtime.builtin.IRubyObject __allocate__(org.jruby.Ruby, org.jruby.RubyClass);
  public JRubyPerson(java.lang.String, int);
  public java.lang.String getName();
  public int getAge();
  static {};
}

RHINO

Source Code

function RhinoPerson( name, age ) {
    this.name = name;
    this.age = age;

    this.getName = function () {
        return this.name;
    };

    this.getAge = function () {
        return this.age;
    };
}

Disassembled Java Class

public class RhinoPerson extends org.mozilla.javascript.NativeFunction implements org.mozilla.javascript.Script {
  public RhinoPerson(org.mozilla.javascript.Scriptable, org.mozilla.javascript.Context, int);
  public RhinoPerson();
  public static void main(java.lang.String[]);
  public final java.lang.Object exec(org.mozilla.javascript.Context, org.mozilla.javascript.Scriptable);
  public final java.lang.Object call(org.mozilla.javascript.Context, org.mozilla.javascript.Scriptable, org.mozilla.javascript.Scriptable, java.lang.Object[]);
  public int getLanguageVersion();
  public java.lang.String getFunctionName();
  public int getParamCount();
  public int getParamAndVarCount();
  public java.lang.String getParamOrVarName(int);
  public java.lang.String getEncodedSource();
  public boolean getParamOrVarConst(int);
}

Java: Programmatically Compile and Unit Test Generated Groovy Source Code

My previous post shows how you can programmatically compile and unit test the generated Java source code. In this example, we will programmatically compile and unit test the generated Groovy source code.

Let’s assume we have the following service class that generates Groovy source code as one big String:-

public class GroovyCodeGeneratorService {
    public String generate(String packageName, String className) {
        return "package " + packageName +
               "\nclass " + className + " {" +
               "\n    boolean isOne(Integer i) {" +
               "\n      return i == 1" +
               "\n    }" +
               "\n}";
    }
}

To unit test the generated Groovy code, it is much simpler than Java:-

package com.choonchernlim.epicapp;

import groovy.lang.GroovyClassLoader;
import groovy.lang.GroovyObject;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
import org.junit.Test;

public class GroovyCodeGeneratorServiceTest {

    GroovyCodeGeneratorService groovyCodeGeneratorService = new GroovyCodeGeneratorService();

    @Test
    public void testGeneratedCode() throws Exception {
        String packageName = "com.choonchernlim.epicapp.service.impl";
        String className = "HelloWorld";

        String groovySource = groovyCodeGeneratorService.generate(packageName, className);

        ClassLoader parent = getClass().getClassLoader();
        GroovyClassLoader loader = new GroovyClassLoader(parent);

        Class groovyClass = loader.parseClass(groovySource);

        assertThat(invokeMethod(groovyClass, 1), is(true));
        assertThat(invokeMethod(groovyClass, 2), is(false));
        assertThat(invokeMethod(groovyClass, 0), is(false));
        assertThat(invokeMethod(groovyClass, -1), is(false));
    }

    private boolean invokeMethod(Class groovyClass, Integer input) throws Exception {
        GroovyObject groovyObject = (GroovyObject) groovyClass.newInstance();
        return (Boolean) groovyObject.invokeMethod("isOne", input);
    }
}

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

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)
    }
}

java.lang.OutOfMemoryError: PermGen space When Running Maven on IntelliJ

NOTE

This is not a Groovy related problem, but I’m using it to illustrate my problem and solution here.

PROBLEM

I recently tried mixing some Groovy code into my existing JEE project. I created a simple POGO that looks as sophisticated as this:-

class GroovyStuff {
	String name
}

Then, I configured one of my controllers to invoke that POGO:-

@Controller
@RequestMapping(value = "/")
public class HomeController {

    @RequestMapping(method = RequestMethod.GET)
    public String main() {
        GroovyStuff stuff = new GroovyStuff();
        stuff.setName("Hello Groovy");
        System.out.println(stuff.getName());
        return "home";
    }
}

After starting up Jetty, I hit that controller from the web and I get this infamous exception:-

java.lang.OutOfMemoryError: PermGen space
    at java.lang.ClassLoader.findBootstrapClass(Native Method)
    at java.lang.ClassLoader.findBootstrapClassOrNull(ClassLoader.java:926)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:297)
    at org.codehaus.plexus.classworlds.realm.ClassRealm.loadClass(ClassRealm.java:239)
    at org.codehaus.plexus.classworlds.realm.ClassRealm.loadClass(ClassRealm.java:230)
    at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:407)
    at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:383)
    at java.lang.Class.getDeclaredMethods0(Native Method)
    at java.lang.Class.privateGetDeclaredMethods(Class.java:2475)
    at java.lang.Class.getDeclaredMethods(Class.java:1818)
    at org.codehaus.groovy.reflection.CachedClass$3$1.run(CachedClass.java:84)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.codehaus.groovy.reflection.CachedClass$3.initValue(CachedClass.java:81)
    at org.codehaus.groovy.reflection.CachedClass$3.initValue(CachedClass.java:79)
    at org.codehaus.groovy.util.LazyReference.getLocked(LazyReference.java:46)
    at org.codehaus.groovy.util.LazyReference.get(LazyReference.java:33)
    at org.codehaus.groovy.reflection.CachedClass.getMethods(CachedClass.java:250)
    at org.codehaus.groovy.runtime.m12n.SimpleExtensionModule.createMetaMethods(SimpleExtensionModule.java:111)
    at org.codehaus.groovy.runtime.m12n.SimpleExtensionModule.getMetaMethods(SimpleExtensionModule.java:93)
    at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.registerExtensionModuleFromProperties(MetaClassRegistryImpl.java:192)
    at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.registerExtensionModuleFromMetaInf(MetaClassRegistryImpl.java:174)
    at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.registerClasspathModules(MetaClassRegistryImpl.java:156)
    at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.<init>(MetaClassRegistryImpl.java:111)
    at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.<init>(MetaClassRegistryImpl.java:73)
    at groovy.lang.GroovySystem.<clinit>(GroovySystem.java:33)
    at org.codehaus.groovy.reflection.ClassInfo.getMetaClassUnderLock(ClassInfo.java:162)
    at org.codehaus.groovy.reflection.ClassInfo.getMetaClass(ClassInfo.java:192)
    at myproject.bean.GroovyStuff.$getStaticMetaClass(Stuff.groovy)
    at myproject.bean.GroovyStuff.<init>(Stuff.groovy)
    at myproject.controller.HomeController.main(HomeController.java:14)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)

I tried both GMaven Plugin and Groovy-Eclipse Compiler Plugin, and both gave me the same problem.

I checked my MAVEN_OPTS variable, and I have set a rather big max perm size, but it doesn’t fix the problem.

export MAVEN_OPTS="-Xms2048m -Xmx2048m -XX:PermSize=256m -XX:MaxPermSize=512m"

Then, I rebooted my laptop since that’s what most tech supports in the world would tell me to do when they encounter a problem… but it doesn’t fix the problem.

When I commented out the Groovy calls from the controller, everything works fine:-

@Controller
@RequestMapping(value = "/")
public class HomeController {

    @RequestMapping(method = RequestMethod.GET)
    public String main() {
        //GroovyStuff stuff = new GroovyStuff();
        //stuff.setName("Hello Groovy");
        //System.out.println(stuff.getName());
        return "home";
    }
}

After venting my frustration at the ping pong table and cursing at the laptop for many hours both at work and at home, I decided to run Jetty directly from the command line:-

mvn clean jetty:run

I was rather surprised that I no longer see the error.

SOLUTION

After poking around, I realized that IntelliJ doesn’t seem to honor my MAVEN_OPTS setting. When I run jetty:run goal from IntelliJ, I see the following output in the console:-

/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/bin/java 
-Dmaven.home=/usr/local/apache-maven-3.0.3 -Dclassworlds.conf=/usr/local/apache-maven-3.0.3/bin/m2.conf 
-Didea.launcher.port=7533 "-Didea.launcher.bin.path=/Applications/IntelliJ IDEA 12.app/bin" 
-Dfile.encoding=UTF-8 -classpath "/usr/local/apache-maven-3.0.3/boot/plexus-classworlds-2.4.jar:/Applications/IntelliJ IDEA 12.app/lib/idea_rt.jar" 
com.intellij.rt.execution.application.AppMain org.codehaus.classworlds.Launcher --fail-fast --strict-checksums 
org.mortbay.jetty:jetty-maven-plugin:8.1.8.v20121106:run

So, I went to IntelliJ’s Preferences... -> Maven -> Runner and set my MAVEN_OPTS values under VM Options:-

IntelliJ's Maven VM Options

When I run jetty:run goal from IntelliJ again, now I see the following output in the console:-

/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/bin/java 
-Xms2048m -Xmx2048m -XX:PermSize=256m -XX:MaxPermSize=512m 
-Dmaven.home=/usr/local/apache-maven-3.0.3 -Dclassworlds.conf=/usr/local/apache-maven-3.0.3/bin/m2.conf 
-Didea.launcher.port=7534 "-Didea.launcher.bin.path=/Applications/IntelliJ IDEA 12.app/bin" 
-Dfile.encoding=UTF-8 -classpath "/usr/local/apache-maven-3.0.3/boot/plexus-classworlds-2.4.jar:/Applications/IntelliJ IDEA 12.app/lib/idea_rt.jar" 
com.intellij.rt.execution.application.AppMain org.codehaus.classworlds.Launcher --fail-fast --strict-checksums 
org.mortbay.jetty:jetty-maven-plugin:8.1.8.v20121106:run

Now, when I hit my controller again, the error went away.

The moral of the story is… if you still cannot fix your coding problem after spending many hours, go play ping pong.