Google App Engine Some JPA Gotchas


While porting an application to Google App Engine we encountered several issues. Most of them where related to persistence. We were using JPA for persistence in the application. One of the most common mistake we did was in issuing a JPA Query where one or more parameters are of type com.google.appengine.datastore.api.Key class. Key class has two String representations which lead to some confusion.

Let’s look at an example. There is a Department entity and its associated JpaDepartmentDAO data access object. This DAO has a method which returns a Department based on departmentKey which is of type com.google.appengine.datastore.api.Key.

@Entity
public class Department implements Serializable {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Key departmentKey;
	
	private String name;

	public String getName() {
		return name;
	}

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

	public Key getDepartmentKey() {
		return departmentKey;
	}

	public void setDepartmentKey(Key departmentKey) {
		this.departmentKey = departmentKey;
	}
}


and the JpaDepartDAO code listing:

@Transactional
public class JpaDepartmentDao extends JpaDaoSupport implements DepartmentDao {

	@PersistenceContext
	private EntityManager entityManager;

	
	@Override
	public Department findByKey(Key departmentKey) {
		String queryString = String.format("Select from Department where departmentKey = '%s'", departmentKey);
		Department department = (Department) getEntityManager().createQuery(queryString).getSingleResult();
		return department;
	}
	...
}

The method findByKey() in JpaDepartmentDao fails as it does not return any Department. The problem in the query is that we expect Key.toString() implementation to return the same value we expect to find in the datastore.

Key has two String representations. Key.toString() is human readable which is similar to what Object.toString() recommends. The second is the Key object translated to a protocol buffer and then base-64 encoded. The second one can be outputted by KeyFactory.keyToString() method in your application.

When to use Key.toString() and KeyFactory.keyToString() methods. Key.toString() outputs a string that is useful in logging and debugging, KeyFactory.keyToString() outputs a string that you can safely pass around in forms and urls.

Now for our JpaDepartmentDao to work correctly we can modify query to use KeyFactory.keyToString() string representation. Let’s look at code listing:

@Transactional
public class JpaDepartmentDao extends JpaDaoSupport implements DepartmentDao {

	@PersistenceContext
	private EntityManager entityManager;

	
	@Override
	public Department findByKey(Key departmentKey) {
		String queryString = String.format("Select from Department where departmentKey = '%s'", KeyFactory.keyToString(departmentKey));
		Department department = (Department) getEntityManager().createQuery(queryString).getSingleResult();
		return department;
	}
	...

}

or can use setParameter() methods to set key in the query, which will be something like this.

@Transactional
public class JpaDepartmentDao extends JpaDaoSupport implements DepartmentDao {

	@PersistenceContext
	private EntityManager entityManager;

	
	@Override
	public Department findByKey(Key departmentKey) {
		Department department = (Department) getEntityManager()
		.createQuery("Select From Department Where departmentKey = :departmentKey")
		.setParameter("departmentKey", departmentKey).getSingleResult();
		return department;
	}
	...

}

Two representation of com.google.appengine.datastore.api.Key class can lead to some confusion on their usage and it is important to know when to use Key.toString() and when to use KeyFactory.keyToString() method.

This entry was posted in Cloud, Java and tagged , . Bookmark the permalink.

2 Responses to Google App Engine Some JPA Gotchas

  1. Pingback: Google App Engine More JPA Gotchas « Inphina Thoughts

  2. Pingback: Pierre’s weblog » Blog Archive » Choix du framework (part 2)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s