Creating a “Simple” MongoDB + Groovy + Maven Project

Posted By Hoyt Summers Pittman

Currently, I am experimenting with writing a MOO (Programmable text based game). To facilitate the dynamic behavior I want to encourage, I decided to write it using Groovy and MongoDB with Maven[1] doing the actual building. However, the “real world” documentation of this combination has been rather lacking and thus, this post.

First let’s tackle Maven and Groovy. There are currently two Maven plugins for Groovy: GMaven and groovy-eclipse-compiler. GMaven generates .java stub files and tends to have a little bit better integration with Java. However, this leads to having lots of “weird”[2] errors which require a clean and build to fix. groovy-eclipse-compiler doesn’t generate stubs and works a little bit more smoothly in a mostly Groovy project, and that is the plugin I chose to use.

With that out of the way, let’s create the maven project.

mvn archetype:generate -DarchetypeGroupId=org.apache.maven.archetypes

For this example, I used “net.saga.blog” as my groupId and “GroovyMongoBlogPost” as my artifactId. If you choose to use different ones, make sure to update your package names accordingly.

Now let’s update the pom to include the groovy builders. First we have to add Groovy to our dependencies:

<dependency>
     <groupId>org.codehaus.groovy</groupId>
     <artifactId>groovy-all</artifactId>
     <version>1.8.5</version>
</dependency>

Next, let’s add the groovy-eclipse-compiler and our groovy source directories to our builders. Create a directory named “groovy” in both the src/main and src/test directories. Then add the following to your pom:

<plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>build-helper-maven-plugin</artifactId>
                <version>1.5</version>
                <executions>
                    <execution>
                        <id>add-source</id>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>add-source</goal>
                        </goals>
                        <configuration>
                            <sources>
                                <source>src/main/groovy</source>
                            </sources> 
                        </configuration>
                    </execution>
                    <execution>
                        <id>add-test-source</id>
                        <phase>generate-test-sources</phase>
                        <goals>
                            <goal>add-test-source</goal>
                        </goals>
                        <configuration>
                            <sources>
                                <source>src/test/groovy</source>
                            </sources>
                        </configuration>
                    </execution>    
                </executions>
            </plugin>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <compilerId>groovy-eclipse-compiler</compilerId>
                    <verbose>true</verbose>
                    <source>1.7</source>
                    <target>1.7</target>
                    <encoding>${project.build.sourceEncoding}</encoding>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>org.codehaus.groovy</groupId>
                        <artifactId>groovy-eclipse-compiler</artifactId>
                        <version>2.6.0-01</version>
                    </dependency>
                </dependencies>
            </plugin>

Perform a quick build and make sure everything is set up correctly so far, I’ll wait.

Now let’s add in our first test. Create in “src/test/groovy” a file:SimpleGroovyTest.groovy.

package net.saga.blog.groovy
/**
 *
 * @author summers
 */
class SimpleGroovyTest extends GroovyTestCase {
	
    void testPass() {
        assert false
    }
    
}

Now perform a build and ensure that the build fails. Once you have a failing build, change false to true and rebuild for the green bar. We now have a fully functional Groovy project being built with Maven.

One of the things I ran into was that JUnit Suites and Groovy don’t behave as much as I would like. Also, a lot of libraries for Java still work “better” in a Java source file. To get around this, I overrode Maven’s default and used JUnit 4.10 and create a class to setup my database and then run the Groovy tests.

First, we replace the JUnit dependency with the following:

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.10</version>
    <scope>test</scope>
</dependency>

Then we change our test class:

package net.saga.blog.groovymongoblogpost
import org.junit.Test
import com.gmongo.GMongo

/**
 *
 * @author summers
 */
class SimpleGroovyTest extends GroovyTestCase {
	
    @Test
    void testPass() {
        assert true
    }
}

Now we create a Java class in src/test/java/net/saga/blog/groovymongoblogpost directory.

package net.saga.blog.groovymongoblogpost;
import junit.framework.TestSuite;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
/**
 * Unit test for simple App.
 */
@RunWith(value = org.junit.runners.Suite.class)
@Suite.SuiteClasses({net.saga.blog.groovymongoblogpost.SimpleGroovyTest.class})
public class AppTestSuite
    extends TestSuite
{
    /**
     * Create the test case
     *
     * @param testName name of the test case
     */
    public AppTest( String testName )
    {
        super( testName );
    }
}

Finally, we reconfigure surefire in build/plugins in the pom to only run app suites.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.11</version>
    <configuration>
        <includes>
            <include>**/*TestSuite.java</include>
        </includes>
    </configuration>
</plugin>

Now rebuild your application and make sure your test is run. Once you get that, let’s move on to actually using MongoDB.

Installing MongoDB is beyond the scope of this tutorial (sorry if you were waiting this long for that), but it is rather trivial on a majority of systems. Ubuntu users, for instance, can sudo apt-get install mongodb. Your mileage may vary, but there are plenty of resources. What IS important is that you have Mongo running on your box (at 127.0.0.1) on the default port (27017).

For my project, I have chosen GMongo as my Groovy Mongo driver. It wraps the Java driver and makes is slightly Groovy-er. You will notice the code you write looks much like the Javascript code in your Mongo shell.

Now, add GMongo to your dependencies in your POM:

<dependency>
    <groupId>com.gmongo</groupId>
    <artifactId>gmongo</artifactId>
    <version>0.9.3</version>
</dependency>

Now let’s write some Mongo code. We will create a file that will populate some seed data in our database. This file will be called from the java test suite class. In the groovy test directory (src/test/groovy) create the file TestSetup.groovy.

import com.gmongo.GMongo
assert System.properties.database_address
//assert System.properties.database_user
assert System.properties.database_name
//assert System.properties.database_password
def port = System.properties.database_port?:27017
def address = System.properties.database_address
//def userName = System.properties.database_user
def databaseName = System.properties.database_name
//def password = System.properties.database_password
def mongo = new GMongo(address, port)
assert mongo
// Get a db reference in the old fashion way
def db = mongo.getDB(databaseName)
db.users.insert([name:'jesse', password:'scherer']);
db.users.insert([name:'kim', password:'berly']);
assert db.users.find([name:'jesse', password:'scherer'])[0] != null

And now we need to call it from AppTestSuite

Add some imports:

import groovy.lang.Binding;
import groovy.util.GroovyScriptEngine;
import java.io.IOException;
import junit.framework.TestSuite;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;

Some static code:

private final static String[] roots = new String[]{"src/test/groovy/net/saga/blog/groovymongoblogpost"};
    private final static GroovyScriptEngine gse;
    
    static {
        System.setProperty("database_address", "127.0.0.1");
        System.setProperty("database_name", "Testing");
        try {
            gse = new GroovyScriptEngine(roots);
        } catch (IOException ex) {
            throw new RuntimeException("failed to start tests", ex);
        }
    }

And actually call the file:

    @BeforeClass
    public static void setUpSuite() throws Exception {
        Binding binding = new Binding();
        gse.run("TestSetup.groovy", binding);
    }

Now we can add a test to our SimpleTestCase file

    @Test
    void testSimpleMongoFetch() {
        def port = System.properties.database_port?:27017
        def address = System.properties.database_address
        def databaseName = System.properties.database_name
        
        def mongo = new GMongo(address, port)
        def db = mongo.getDB("Testing")
        
        def userResult = db.users.find([name:'jesse', password:'password'])[0]
        
        assertNotNull( userResult )
        assertEquals ('jesse', userResult.name)
    }

Now if we build out app we should see that we have records in out database AND that groovy can query them.

Asides/Footnotes:
[1]: I understand Gradle may be a better technology (lord knows it can’t be worse), but Maven works much better in Netbeans and that has some pretty powerful side effects.
[2]: Basically if you update your groovy code, the linking will fail and trying to run your tests using the IDE will get a error until you clean and build.

Jan 26th, 2012

2 Comments to 'Creating a “Simple” MongoDB + Groovy + Maven Project'

Subscribe to comments with RSS or TrackBack to 'Creating a “Simple” MongoDB + Groovy + Maven Project'.

  1. Sam said,

    in your testSimpleMongoFetch() method the line below is wrong:

    def userResult = db.users.find([name:’jesse’, password:’password’])[0]

    The password should be ‘scherer’

  2. Sam said,

    I want to thank you for the tutorial though. It is indeed an excellent tutorial.

    Thanks again :-)

:: Trackbacks/Pingbacks ::

No Trackbacks/Pingbacks

Leave a Reply