Monthly Archives: October 2013

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

Deleting Cached Web Page by URI in CodeIgniter

PROBLEM

CodeIgniter contains a wonderful feature that allows me to cache web pages to speed up the page loading. The problem is there’s no easy mechanism for me to delete specific cached web pages, especially after I have updated the page contents. I have sucky two choices:-

  • Wait for the cache to expire by itself, which can be an excruciating wait since I tend to cache my web pages for a month.
  • Delete all cached files under application/cache.

I always do the latter even though I hate this approach.

SOLUTION

After poking around the web, it looks like @danmurf had written an Core Output extension that allows me to delete the cache by URI, which is exactly what I want.

The installation is pretty straightforward. To test it out, I used @philsturgeon’s REST support to create a simple controller to do so:-

<?php if (!defined('BASEPATH')) exit('No direct script access allowed');

    require(APPPATH . 'libraries/REST_Controller.php');

    class Delete_cache extends REST_Controller
    {
        public function __construct()
        {
            parent::__construct();
        }

        public function index_post()
        {
            $uri = $this->post('uri');
            $statusCode = $this->output->clear_path_cache($uri) ? 200 : 404;
            $this->response(NULL, $statusCode);
        }
    }

When I do a POST on http://localhost:8888/api/delete_cache?uri=/meow-meow, I’ll get either a 200 if the cached file is successfully deleted, or a 404 if the cached file is not present.

Works like a charm.

Rotating Log Files on Apache HTTP Server

PROBLEM

Consider the following log configuration:-

ErrorLog "D:/logs/apache/error.log"

<IfModule log_config_module>
    ...
    CustomLog "D:/logs/apache/access.log" common
</IfModule>

At some point of time, both error.log and access.log are going to get insanely large.

SOLUTION

To fix this, the logs can be piped (by using |) to Apache HTTP Server’s built-in program called rotatelogs to rotate the log files. For example, the following configuration will create a daily rolling file appender for error.log and access.log.

ErrorLog "|D:/apps/apache/bin/rotatelogs.exe -l D:/logs/apache/error-%Y-%m-%d.log 86400"

<IfModule log_config_module>
    ...
    CustomLog "|D:/apps/apache/bin/rotatelogs.exe -l D:/logs/apache/access-%Y-%m-%d.log 86400" common
</IfModule>

Suppressing FindBugs Warnings

PROBLEM

FindBugs is one of the many great static code analysis tools that I use everyday. However, the generated report may usually contain a few false positives that forces me to weave through them whenever I rerun my build on Jenkins.

For example, I’m using Google Guava to construct my equals(...) and hashCode():-

public class Person {
    private String firstName;
    private String lastName;
    private Long age;

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

        Person other = (Person) o;

        return Objects.equal(firstName, other.firstName) &&
               Objects.equal(lastName, other.lastName);
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(firstName, lastName);
    }
		
    // getters and setters
}

FindBugs will produce a EQ_UNUSUAL warning with the following description:-

myproject.Person.equals(Object) is unusual

This class doesn't do any of the patterns we recognize for checking 
that the type of the argument is compatible with the type of the this 
object. There might not be anything wrong with this code, but it is 
worth reviewing. 

SOLUTION

There are 2 known ways that I know to suppress these warnings. One way is to create FindBugs filter files, which I find very tedious. The other way is to use FindBug’s annotations to do so, which is what I’m going to show here.

First, we need to include the neccessary dependency:-

<dependency>
    <groupId>net.sourceforge.findbugs</groupId>
    <artifactId>annotations</artifactId>
    <version>1.3.2</version>
</dependency>

Next, we annotation equals(...) to suppress that specific warning:-

public class Person {
    private String firstName;
    private String lastName;
    private Long age;

    @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "EQ_UNUSUAL", 
                                                      justification="Implemented using Google Guava")
    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }

        Person other = (Person) o;

        return Objects.equal(firstName, other.firstName) &&
               Objects.equal(lastName, other.lastName);
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(firstName, lastName);
    }

    // getters and setters
}

That’s it… it’s that simple.

Yes, I know there’s this ugly FindBugs dependency in my code. However, I’ll take that anyday so that I’m getting a cleaner report from FindBugs. I can also be absolutely sure that I have reviewed the generated warnings and decided that they are safe to be ignored.

How to Unit Test Spring MVC Controller

SCENARIO

Let’s assume we have the following controller that needs to be tested:-

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

    private PersonService personService;

    @Autowired
    public PersonController(PersonService personService) {
        this.personService = personService;
    }

    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    public String getPerson(@PathVariable Long id, Model model) {
        model.addAttribute("personData", personService.getPerson(id));
        return "personPage";
    }
}

SOLUTION 1: “Works but It Won’t Get You the Promotion”

This working solution relies on:-

  • JUnit – General unit test framework.
  • Mockito – To mock PersonService.

public class PersonControllerTest {

    @Test
    public void testGetPerson() {

        PersonService personService = mock(PersonService.class);

        when(personService.getPerson(1L)).thenReturn(new Person(1L, "Chuck"));

        PersonController controller = new PersonController(personService);

        Model model = new ExtendedModelMap();

        String view = controller.getPerson(1L, model);

        assertEquals("View name", "personPage", view);

        Person actualPerson = (Person) model.asMap().get("personData");

        assertEquals("matching ID", Long.valueOf(1), actualPerson.getId());
        assertEquals("matching Name", "Chuck", actualPerson.getName());
    }
}

While this solution works, but it has a few problems. This test case strictly tests the actual controller API, but it completely disregards the URI and request method (GET, POST, PUT, DELETE, etc). For instance:-

  • What if the URI has a typo ( /persn/1 ) or it is not properly constructed ( /person/donkey-kong )?
  • What if the request method should be a POST but we accidentally used a GET?

SOLUTION 2: “A Mind Blowing Solution that Still Won’t Get You the Promotion but You Feel So Invincible That You Feel Compelled to Flip a Table Over”

This better solution relies on:-

  • JUnit – General unit test framework.
  • Mockito – To mock PersonService.
  • Spring MVC Test Framework – To properly test the controller.
  • Hamcrest – To clean way to assert the actual result is correct.

@RunWith(SpringJUnit4ClassRunner.class)
// This XML configuration basically enable component scanning.
// You could have used @Configuration and @ComponentScan to do the same thing.
@ContextConfiguration({"classpath*:spring-test.xml"})
public class PersonControllerTest {

    @Mock
    private PersonService personService;

    @InjectMocks
    private PersonController personController;

    private MockMvc mockMvc;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
        mockMvc = MockMvcBuilders.standaloneSetup(personController).build();
    }

    @Test
    public void testGetPerson() throws Exception {
        when(personService.getPerson(1L)).thenReturn(new Person(1L, "Chuck"));

        mockMvc.perform(get("/person/{id}", 1L))
                .andExpect(status().isOk())
                .andExpect(view().name("personPage"))
                .andExpect(model().attribute("personData",
                                             allOf(hasProperty("id", is(1L)),
                                                   hasProperty("name", is("Chuck")))));
    }
}

Basically object that is annotated with @Mock will get injected into object that is annotated with InjectMocks. Then, we rely on Spring MVC Test Framework’s MockMvc to test our controller in a very clean and detailed fashion.

Okay, you may flip a table over now…

By the way…

You need at least Spring 3.2 to use MockMvc.

<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-test</artifactId>
	<version>3.2.4.RELEASE</version>
	<scope>test</scope>
</dependency>

If you are using an older Mockito version, you will get this error:-

org.mockito.exceptions.base.MockitoException: Field 'personController' annotated with @InjectMocks is null.
Please make sure the instance is created *before* MockitoAnnotations.initMocks();
Example of correct usage:
   class SomeTest {
      @InjectMocks private Foo foo = new Foo();
      
      @Before public void setUp() {
         MockitoAnnotations.initMock(this);

Upgrading Mockito to the latest version will fix this error:-

<dependency>
	<groupId>org.mockito</groupId>
	<artifactId>mockito-core</artifactId>
	<version>1.9.5</version>
	<scope>test</scope>
</dependency>

Hibernate: Migrating from XML-Based Configuration to Annotation-Based Configuration

Overview

At some point of time, as your project scope grows, the Hibernate mapping XML files are going to get to a point where it becomes very difficult to maintain. This is where the annotation-based configuration comes in. It took me a few years to convince myself that annotation-based configuration is the way to go. Change is hard, yet necessary.

This tutorial covers the following:-

  • Upgrade Hibernate from 3.x to 4.x.
  • Configure Spring-Hibernate integration to replace XML-based configuration with annotation-based configuration.
  • Configure Joda-Time to work properly in Hibernate 4.
  • Activate @Transactional instead of relying on AOP-based transaction.

Maven Dependencies

Change the Hibernate dependency version from 3.x to 4.x. On top of that, add org.jadira.usertype:usertype.core:[version] dependency to get Joda-Time to work properly with Hibernate 4.

Hibernate 3.x

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>3.6.9.Final</version>
</dependency>
<dependency>
    <groupId>joda-time</groupId>
    <artifactId>joda-time</artifactId>
    <version>2.3</version>
</dependency>
<dependency>
	<groupId>joda-time</groupId>
	<artifactId>joda-time-hibernate</artifactId>
	<version>1.3</version>
</dependency>

Hibernate 4.x

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>4.2.6.Final</version>
</dependency>
<dependency>
    <groupId>joda-time</groupId>
    <artifactId>joda-time</artifactId>
    <version>2.3</version>
</dependency>
<dependency>
	<groupId>joda-time</groupId>
	<artifactId>joda-time-hibernate</artifactId>
	<version>1.3</version>
</dependency>
<dependency>
    <groupId>org.jadira.usertype</groupId>
    <artifactId>usertype.core</artifactId>
    <version>3.1.0.CR8</version>
</dependency>

By the way, if you don’t know what Joda-Time is or haven’t use it by now, then you should be spanked by the Date God. With that added dependency, the @Type for date field will look a little different ( see here for more info ):-

@Entity
@Table(name = "MrMeow")
public class MrMeow implements Ideable, Serializable {
	...
	
	@Column
	@Type(type = "org.jadira.usertype.dateandtime.joda.PersistentLocalDate")
	private LocalDate whenMeowed;
}

Spring Integration

Hibernate 3.x

This configuration uses Hibernate XML mapping files to configure mappings between the domain objects and the database tables. Further, AOP is used to configure the transaction.

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="configLocation" value="classpath:hibernate.cfg.xml"/>
</bean>

<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory"/>
</bean>

<tx:advice id="txAdvice">
    <tx:attributes>
        <tx:method name="*" propagation="REQUIRED"/>
    </tx:attributes>
</tx:advice>

<aop:config proxy-target-class="true">
    <aop:advisor pointcut="execution(* myproject..*.*(..))" advice-ref="txAdvice"/>
</aop:config>

Hibernate 4.x

This configuration scans myproject.domain package, which contains all Hibernate annotated domain classes. Further, it activates @Transactional so that you can place it in your code to manage the transaction.

<tx:annotation-driven transaction-manager="transactionManager"/>

<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory"/>
</bean>

<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>

    <property name="hibernateProperties">
        <props>
			<!-- Configure your Hibernate dialect  -->
            <prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>
            <prop key="hibernate.show_sql">false</prop>
        </props>
    </property>
    <property name="packagesToScan">
        <list>
			<!-- Configure your domain package -->
            <value>myproject.domain</value>
        </list>
    </property>
</bean>

web.xml

Change filter class for OpenSessionInViewFilter.

Hibernate 3.x

<filter>
    <filter-name>hibernateFilter</filter-name>
	<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>hibernateFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Hibernate 4.x

<filter>
    <filter-name>hibernateFilter</filter-name>
    <filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>hibernateFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Domain Classes

Finally, time to annotate your Hibernate domain classes!

Helpful Note

Please make sure you don’t have JPA 1.x in your classpath in the first place. Read java.lang.NoSuchMethodError: javax/persistence/OneToMany.orphanRemoval()Z for more information.

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.