Solving a GWT deferred binding mystery

This morning at work, I was running our GWT application with some deferred binding logic in it, and all of a sudden I got this ridiculous message:

[ERROR] Class 'mycompany.rebind.HistoryResourceGenerator' must derive from 'com.google.gwt.core.ext.Generator'
[ERROR] Failure while parsing XML
com.google.gwt.core.ext.UnableToCompleteException: (see previous log entries)
at com.google.gwt.dev.cfg.ModuleDefSchema$ObjAttrCvt.convertToArg(ModuleDefSchema.java:729)
at com.google.gwt.dev.util.xml.HandlerArgs.convertToArg(HandlerArgs.java:64)
at com.google.gwt.dev.util.xml.HandlerMethod.invokeBegin(HandlerMethod.java:214)
at com.google.gwt.dev.util.xml.ReflectiveParser$Impl.startElement(ReflectiveParser.java:257)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.startElement(AbstractSAXParser.java:501)

It was running fine yesterday when I left work, and now it tells me that my generator isn’t a subclass of the GWT Generator??? Quickly pulled the source, and it’s as clear as day that my generator is properly written. Then what gives?

Searching for an explanation, I pulled the GWT’s source code, and opened com.google.gwt.dev.cfg.ModuleDefSchema and here’s the method in question:

    public Object convertToArg(Schema schema, int lineNumber, String elemName,
        String attrName, String attrValue) throws UnableToCompleteException {

      Object found = singletonsByName.get(attrValue);
      if (found != null) {
        // Found in the cache.
        //
        return found;
      }

      Class<?> foundClass = null;
      try {
        // Load the class.
        //
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        foundClass = cl.loadClass(attrValue);
        Class<? extends T> clazz = foundClass.asSubclass(fReqdSuperclass);

        T object = clazz.newInstance();
        singletonsByName.put(attrValue, object);
        return object;
      } catch (ClassCastException e) {
        Messages.INVALID_CLASS_DERIVATION.log(logger, foundClass,
            fReqdSuperclass, null);
        throw new UnableToCompleteException();
      } catch (ClassNotFoundException e) {
        Messages.UNABLE_TO_LOAD_CLASS.log(logger, attrValue, e);
        throw new UnableToCompleteException();
      } catch (InstantiationException e) {
        Messages.UNABLE_TO_CREATE_OBJECT.log(logger, attrValue, e);
        throw new UnableToCompleteException();
      } catch (IllegalAccessException e) {
        Messages.UNABLE_TO_CREATE_OBJECT.log(logger, attrValue, e);
        throw new UnableToCompleteException();
      }
    }
  }

Because the error message was from Messages.INVALID_CLASS_DERIVATION, I put a breakpoint on line 22:

Messages.INVALID_CLASS_DERIVATION.log(logger, foundClass, fReqdSuperclass, null);

and started my app in debug mode. The breakpoint hits, and I noticed that the exception object is reporting ClassCastException from JSONNull to JSONObject. I quickly clicked: The error is from the class that fetches some resource over the net and plugged in to the generator. Following this lead, I found that the server resource the class was fetching wasn’t available any more, which caused the fetcher class to fail, and consequently, the ClassCastException is propagated to the generator and eventually ModuleDefSchema.

The mysterious error message, however, has nothing to do with the real problem. I spent a lot of time thinking that my Generator is wrong, because that’s what the compiler says, but in fact, it’s not. I think the confusion can be avoided if the GWT compiler can log the actual exception object, instead of interpreting the exception for the user. That’s what they’re doing in the try/catch clause in the method shown above: the exception object “e” is not used in the case of ClassCastException…

Well, the take-home message is: don’t always trust the GWT compiler message. Also, adding log more logging to your generator classes that can be indicative to where the actual problem is.

Setting up a Clojure Project with Maven

In this blog post I’m going to record my recent experience in setting up a Clojure project using the clojure-maven-plugin.

Clojure-Maven-Plugin

First you need to compile the plugin from source:
git clone git://github.com/talios/clojure-maven-plugin.git
cd clojure-maven-plugin
mvn install
Of course, you will need to have Maven2 installed already.

After that, the compiled plugin jar will be in your maven local repository. Create a pom.xml file to use the plugin. I’m using the pom.xml from my project Programming Collective Intelligence as an example:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>pci</groupId>
    <artifactId>pci</artifactId>
    <name>Programming Collective Intelligence</name>
    <version>0.0.1-SNAPSHOT</version>

    <build>
        <plugins>
            <plugin>
                <groupId>com.theoryinpractise</groupId>
                <artifactId>clojure-maven-plugin</artifactId>
                <version>1.2-SNAPSHOT</version>
            </plugin>
        </plugins>
    </build>

</project>

Also, setting up clojure-lang and clojure-contrib (optional, but nice to have) as dependencies as follows:

    <dependencies>
        <dependency>
            <groupId>org.clojure</groupId>
            <artifactId>clojure-lang</artifactId>
            <version>1.1.0-alpha-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.clojure</groupId>
            <artifactId>clojure-contrib</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

Clojure builds haven’t reached Maven central repository yet, so you need to build Clojure from source, and install it into your local repository by using
mvn install:install-file -Dfile=clojure-lang.jar -DgroupId=org.clojure -DartifactId=clojure-lang -Dversion=1.1.0-alpha-SNAPSHOT -Dpackaging=jar

Do the same for clojure-contrib.

You can also create a directory in under your project root and have pom.xml looking for artifacts in that directory as well. I found this to be useful for artifacts that are not in the central repository. To do so, add repository definition in pom.xml:

    <repositories>
        <repository>
            <id>lib-repo</id>
            <name>lib-m2-repository</name>
            <url>file://${basedir}/lib-repo</url>
            <layout>legacy</layout>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
            <releases>
                <checksumPolicy>ignore</checksumPolicy>
            </releases>
        </repository>
    </repositories>

Afterwards, you need to setup your directory structure as follows:

${project_root}
-- lib-repo
    -- org.clojure
        -- jars
            * clojure-lang-1.1.0-alpha-SNAPSHOT.jar
            * clojure-contrib-1.1.0-alpha-SNAPSHOT.jar
        -- poms
            * clojure-lang-1.1.0-alpha-SNAPSHOT.pom
            * clojure-contrib-1.1.0-alpha-SNAPSHOT.pom

The pom files can be found in your local repository after you’ve done mvn install:install-file.

If you want to run clojure:repl goal, you’d better add jline to your dependency as well:

<dependencies>
  ...
        <dependency>
            <groupId>jline</groupId>
            <artifactId>jline</artifactId>
            <version>0.9.94</version>
        </dependency>

  ...
</dependencies>

By convention, the plugin compiles everything under ${project_root}/src/main/clojure and ${project_root}/src/test/clojure.

It’s hard to imagine working in a language like Clojure without automated unit tests. Fortunately, clojure-maven-plugin has the clojure:test goal which runs unit tests. All you need to do is telling the plugin where’s the entry point of your unit test. Add the following configuration in the build section:

    <build>
        <plugins>
            <plugin>
                <groupId>com.theoryinpractise</groupId>
                <artifactId>clojure-maven-plugin</artifactId>
                <version>1.2-SNAPSHOT</version>
                <configuration>
                    <testScript>src/test/clojure/pci/test.clj</testScript>
                </configuration>
            </plugin>
        </plugins>
    </build>

The test script looks like the following:

(ns my-namespace
  (:use clojure.contrib.test-is
          test-module-1
          test-module-2))
(run-tests 'test-module-n)

There you have it! The sample files can be found in my pci-clj project on GitHub.

Programming Collective Intelligence in Clojure

They say the best way to learn a new programming language is by programming in it. Therefore I’m starting this project converting algorithms in the book Programming Collective Intelligence into Clojure, while learning the best practices and language idioms during the process.

I’ve created a GitHub project for this. I’m not sure how far I’m able to go but let’s see.