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.

[sourcecode language=”java”]
@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;
}
}
[/sourcecode]

and the JpaDepartDAO code listing:

[sourcecode language=”java”]
@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;
}

}
[/sourcecode]

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:

[sourcecode language=”java”]
@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;
}

}
[/sourcecode]

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

[sourcecode language=”java”]
@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;
}

}
[/sourcecode]

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.

2 thoughts on “Google App Engine Some JPA Gotchas

Leave a Reply

%d bloggers like this: