Home > Articles > Programming > Java

Java Reference Guide

Hosted by

Toggle Open Guide Table of ContentsGuide Contents

Close Table of ContentsGuide Contents

Close Table of Contents

Morphia, Part 1

Last updated Mar 14, 2003.

Morphia is a library, hosted by Google Code, that provides an ORM-like interface to working with MongoDB. Specifically, instead of thinking about building JSON documents from your Java objects, you think about your Java objects themselves and their relationships &;#8212; Morphia handles all the persistence logic for you.

In order to use Morphia, you perform the following steps:

  • Add the MongoDB Java driver to your project (or as a dependency in you POM if you're using Maven)
  • Add the Morphia dependency to your project (and you'll need to add a reference to the Google code Maven repository if you're using Maven)
  • Annotate your model classes with the Morphia annotations: in this article we're going to setup a simple example that uses the Entity, Embedded, and Id annotations
  • Create a Mongo instance that points to your MongoDB instance
  • Create a Morphia instance
  • Map your model classes to Morphia
  • Create a Datasource from the Morphia object, passing it the Mongo instance
  • Use the Morphia Datasource class to insert, remove, update, and query for your model objects

The sample project has two entities: a User that has an embedded Address, and demonstrates how to insert a new User, query for all users, and delete a user from MongoDB using Morphia.

Listing 1 shows the Maven POM file for our sample project.

Listing 1. pom.xml

<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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.geekcap.informit</groupId>
  <artifactId>mongodb-morphia-example</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>mongodb-morphia-example</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

      <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.0.2</version>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <classpathPrefix>lib/</classpathPrefix>
                            <mainClass>com.geekcap.informit.mongodb.morphiaexample.MorphiaExample</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
                        <id>copy</id>
                        <phase>install</phase>
                        <goals>
                            <goal>copy-dependencies</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${project.build.directory}/lib</outputDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

        </plugins>
    </build>

  <dependencies>

   <!-- Include the MongoDB Java driver -->
   <dependency>
    <groupId>org.mongodb</groupId>
    <artifactId>mongo-java-driver</artifactId>
    <version>2.5.3</version>
   </dependency>

   <!-- Include the Morphia library -->
   <dependency>
    <groupId>com.google.code.morphia</groupId>
    <artifactId>morphia</artifactId>
    <version>0.99</version>
   </dependency>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.6</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

<!-- http://morphia.googlecode.com/svn/mavenrepo/ -->

    <repositories>
        <repository>
            <id>morphia-repo</id>
            <url>http://morphia.googlecode.com/svn/mavenrepo/</url>
        </repository>
    </repositories>

</project>

The POM file begins by adding plug-ins to force compilation to Java 6, compile an executable JAR file that executes the main() method in the com.geekcap.informit.mongodb.morphiaexample.MorphiaExample class, and includes all of the dependencies (MongoDB Java driver and Morphia) in the final deployment. It then adds dependencies for the latest version of the MongoDB Java driver (2.5.3) and Morphia (0.99). I found this challenging because the latest version available in public Maven repositories is 0.91, which did not have support for the Morphia annotations. So instead I tracked down the Google Code Maven repository (at the bottom of the POM) and added the latest version, which also happened to be in a different package than 0.91. If you copy the repository entry from this POM it should work for you.

Listing 2 shows the User class, which is the entity that represents the user and has an embedded Address.

Listing 2. User.java

package com.geekcap.informit.mongodb.morphiaexample.model;

import org.bson.types.ObjectId;
import com.google.code.morphia.annotations.Entity;
import com.google.code.morphia.annotations.Embedded;
import com.google.code.morphia.annotations.Id;


/**
 * Represents a User object
 * 
 * @author shaines
 */
@Entity
public class User
{
    @Id
    private ObjectId id;
    private String firstName;
    private String lastName;
    private int age;
    
    @Embedded
    private Address address;

    public User()
    {
    }

    public User( String firstName, String lastName, int age )
    {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
    }

    public ObjectId getId()
    {
        return id;
    }

    public void setId( ObjectId id )
    {
        this.id = id;
    }

    public int getAge()
    {
        return age;
    }

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

    public String getFirstName()
    {
        return firstName;
    }

    public void setFirstName( String firstName )
    {
        this.firstName = firstName;
    }

    public String getLastName()
    {
        return lastName;
    }

    public void setLastName( String lastName )
    {
        this.lastName = lastName;
    }

    public Address getAddress()
    {
        return address;
    }

    public void setAddress( Address address )
    {
        this.address = address;
    }

    public String toString()
    {
        return firstName + " " + lastName + " is " + age + " years old";
    }
}

The first thing to note about the User class is that the class is annotated with Morphia's @Entity annotation. All of your entities should be annotated with the annotation so that Morphia knows to persist them. The id attribute is of type ObjectId, which is a MongoDB type, but required if you want the MongoDB driver to automatically generate keys for you, and is annotated by the @Id annotation. All other attributes will be added to the JSON object inserted into MongoDB [md] if there are attributes that you do not want persisted to MongoDB then annotate them with the @Transient annotation. Finally, the Address object is annotated with the @Embedded annotation. This annotation means that the Address object should be embedded inside the User object in the MongoDB document. The other option is to use @Reference if you want Morphia to store the objects in their own collections and create a reference (DBRef) between them.

Listing 3 shows the source code for the Address class.

Listing 3. Address.java

package com.geekcap.informit.mongodb.morphiaexample.model;

import org.bson.types.ObjectId;
import com.google.code.morphia.annotations.Embedded;

@Embedded
public class Address
{
    private ObjectId id;
    private String street;
    private String city;
    private String state;
    private String zipcode;

    public Address()
    {
    }

    public ObjectId getId()
    {
        return id;
    }

    public void setId( ObjectId id )
    {
        this.id = id;
    }

    public String getCity()
    {
        return city;
    }

    public void setCity( String city )
    {
        this.city = city;
    }

    public String getState()
    {
        return state;
    }

    public void setState( String state )
    {
        this.state = state;
    }

    public String getStreet()
    {
        return street;
    }

    public void setStreet( String street )
    {
        this.street = street;
    }

    public String getZipcode()
    {
        return zipcode;
    }

    public void setZipcode( String zipcode )
    {
        this.zipcode = zipcode;
    }
}

The Address class is annotated with the @Embedded annotation to inform Morphia that Address instances should be embedded inside other documents. The rest of the class is just a POJO.

Listing 4 presents a sample class that creates the Morphia object and persists users to and from MongoDB through Morphia.

Listing 4. MorphiaExample.java

package com.geekcap.informit.mongodb.morphiaexample;

import com.geekcap.informit.mongodb.morphiaexample.model.Address;
import com.geekcap.informit.mongodb.morphiaexample.model.User;
import com.google.code.morphia.Datastore;
import com.google.code.morphia.Morphia;
import com.mongodb.Mongo;
import java.util.List;

/**
 *
 * @author shaines
 */
public class MorphiaExample
{
    public static void main( String[] args )
    {
        try
        {
            // Create a Mongo instance that points to the MongoDB running on local host
            Mongo mongo = new Mongo( "localhost" );

            // Create a Morphia object and map our model classes
            Morphia morphia = new Morphia();
            morphia.map( User.class ).map( Address.class );

            // Create a data store
            Datastore ds = morphia.createDatastore( mongo, "morphiaexample" );

            // Query for all users in the database
            System.out.println( "Users before we start:" );
            Query<User> users = ds.find( User.class );
            for( User u : users.fetch() )
            {
                System.out.println( "User: " + u );
            }

            // Create an object to persist to the database
            Address address = new Address();
            address.setStreet( "123 Some Street" );
            address.setCity( "My City" );
            address.setState( "ST" );
            address.setZipcode( "12345" );

            User user = new User();
            user.setFirstName( "Steven" );
            user.setLastName( "Haines" );
            user.setAge( 39 );
            user.setAddress( address );

            // Insert the user into the database
            ds.save( user );

            // Query for all users in the database
            System.out.println( "Users after save:" );
            users = ds.find( User.class );
            for( User u : users.fetch() )
            {
                System.out.println( "User: " + u );
            }

            // Remove our users
            Query<User> q = ds.createQuery( User.class );
            ds.delete( q );

            // Re-show, to verify that the users have been deleted
            System.out.println( "Users after delete:" );
            users = ds.find( User.class );
            for( User u : users.fetch() )
            {
                System.out.println( "User: " + u );
            }
    }
}

Listing 4 begins by creating a Mongo instance pointed to localhost. Next it creates a Morphia instance and then invokes its map() method to tell Morphia to persist the User and Address classes.

Next it uses the Morphia instances to create a new Datastore pointed to the local MongoDB instance with the database named “morphiaexample”. The Datastore object provides Morphia's data persistence methods, including save(), find(), and delete(), which are illustrated in the latter half of the class.

Listing 4 then creates a User instance, including the embedded Address instance, and then invokes the Datastore's save() method. This is equivalent to invoking the DBCollection's save method to insert or update a document based on its id. In this example the id is null, so it knows to generate a new id and insert the document into the database.

In order to prove that the insertion is working, listing 4 executes the Datastore's find() method three times: before we start, after the insert, and after the delete. The find method is passed the User class, which asks Morphia to return all User instances (there are other find methods that accept queries for you to narrow down the results.) The response is a Query object that, through generics, contains User objects. The Query class has a fetch() method that returns an iterator that can be used to retrieve the results.

In addition to the find() method, listing 4 also demonstrates how to delete objects using the delete() method. The delete() method accepts a Query object that can be constructed with matching criteria to narrow the documents that will be deleted. This example creates a new Query object that matches all User documents.