GAE (Google App Engine) allows you to use an ORM library to map your noSQL data. In my test I’ve used JPA v.1.
To expose data I’ve implemented a REST API using Jersey. In this short article I don’t want to explain how to implement the complete application but how to solve the following Error
java.lang.IllegalArgumentException: app s~<yourappname> cannot access app <yourappname>'s data at com.google.appengine.api.datastore.DatastoreApiHelper.translateError(DatastoreApiHelper.java:36) at com.google.appengine.api.datastore.DatastoreApiHelper$1.convertException(DatastoreApiHelper.java:76) at com.google.appengine.api.utils.FutureWrapper.get(FutureWrapper.java:106) at com.google.appengine.api.datastore.FutureHelper$CumulativeAggregateFuture.get(FutureHelper.java:145) at com.google.appengine.api.utils.FutureWrapper.get(FutureWrapper.java:90) at com.google.appengine.api.datastore.FutureHelper.getInternal(FutureHelper.java:72) at com.google.appengine.api.datastore.FutureHelper.quietGet(FutureHelper.java:33) at com.google.appengine.api.datastore.DatastoreServiceImpl$2.runInternal(DatastoreServiceImpl.java:113) at com.google.appengine.api.datastore.DatastoreServiceImpl$2.runInternal(DatastoreServiceImpl.java:110) at com.google.appengine.api.datastore.TransactionRunner.runInTransaction(TransactionRunner.java:31) at com.google.appengine.api.datastore.DatastoreServiceImpl.put(DatastoreServiceImpl.java:110) <continued in next message>
This Error occurs only when you use the application on GAE and not when you debug locally.
In my experience the error is related to the Entity Key.
If you try to create a new Entity forcing the Key you have this error. Why you may incur in this? Because you are copy another Entity! So remember to clear the Entity Key in the copy constructor.
Another way to face this problem is using REST: if you are creating a new Entity and in the JSON posted you force the Key GAE log this error.
This is the example. The Entity
public interface BasicEntity<T> { public void createVersion(); public void updateVersion(T old); public boolean isRemoved(); public String getUUID(); } @Entity public class Utente implements Serializable, BasicEntity<Utente> { /** * */ private static final long serialVersionUID = -6565127229887272677L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @JsonIgnore private Key key; public Key getKey() { return key; } public void setKey(Key key) { this.key = key; } // server @Transient @JsonProperty("uuid") private String UUID; public String getUUID() { UUID = KeyFactory.keyToString(key); return UUID; } public void setUUID(String UUID) { this.UUID = UUID; key = KeyFactory.stringToKey(UUID); } // vecchio id private String id; // id generato dal client private String clientUUID; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getClientUUID() { return clientUUID; } public void setClientUUID(String clientUUID) { this.clientUUID = clientUUID; } @Basic private Long versione; // fields @Basic private String email; @Basic @JsonIgnore private String encryptedPwd; @Basic private String nome; @Basic private String azienda; @Basic private Boolean abilitato; public String getEmail() { return email; } public void setEmail(String eMail) { this.email = eMail; } public String getEncryptedPwd() { return encryptedPwd; } public void setEncryptedPwd(String encryptedPwd) { this.encryptedPwd = encryptedPwd; } public String getNome() { return nome; } public void setNome(String nome) { this.nome = nome; } public String getAzienda() { return azienda; } public void setAzienda(String azienda) { this.azienda = azienda; } public Boolean getAbilitato() { return abilitato; } public void setAbilitato(Boolean abilitato) { this.abilitato = abilitato; } @Override public void updateVersion(Utente old) { // TODO Auto-generated method stub } @Override public void createVersion() { // TODO Auto-generated method stub } public Long getVersione() { return versione; } public void setVersione(Long versione) { this.versione = versione; } private boolean removed; @Override public boolean isRemoved() { return removed; } public void setRemoved(boolean removed) { this.removed = removed; } }
DAO
public abstract class BasicDAO<T extends BasicEntity<T>> { private EntityManager em; protected abstract String getClassName(); protected abstract Class<?> getClassType(); public BasicDAO() { startTransaction(); } public void startTransaction() { setEm(EMF.get().createEntityManager()); } public void endTransaction() { getEm().close(); } public EntityManager getEm() { return em; } public void setEm(EntityManager em) { this.em = em; } @SuppressWarnings("unchecked") protected T get(String id) { return (T) getEm().find(getClassType(), id); } protected T insert(T myObject) { myObject.createVersion(); getEm().persist(myObject); getEm().refresh(myObject); return myObject; } protected T update(T myObject, String uuid) { if (myObject.getUUID() != null && myObject.getUUID().equalsIgnoreCase(uuid)) { T old = get(uuid); if (old != null) { myObject.updateVersion(old); getEm().persist(myObject); getEm().refresh(myObject); } return myObject; } return null; } protected boolean delete(String id) { boolean ok = false; Object myObject = get(id); if (myObject != null) { getEm().remove(myObject); ok = true; } return ok; } protected abstract T reattach(T myObject); @SuppressWarnings("unchecked") protected List<T> gets() { return (List<T>) getEm().createQuery("Select from " + getClassName()) .getResultList(); } } public class UtenteDAO extends BasicDAO<Utente> { public Utente getUtente(String id) { return get(id); } public void insertUtente(Utente utente) { insert(utente); } public void updateUtente(Utente utente, String id) { updateUtente(utente, id); } public List<Utente> getUtenti() { return gets(); } @Override protected String getClassName() { return "Utente"; } @Override protected Class<?> getClassType() { return Utente.class; } @Override protected Utente reattach(Utente myObject) { // TODO Auto-generated method stub return null; } }
Jersey REST mapping
@Produces(MediaType.APPLICATION_JSON) @Path("/utenti") public class UtenteResource { @GET @Path("/") public List<Utente> getUtentu() { UtenteDAO dao = new UtenteDAO(); return dao.getUtenti(); } @GET @Path("/{id}") public Utente getPraticaById(@PathParam("id") String id) { UtenteDAO dao = new UtenteDAO(); return dao.getUtente(id); } @POST @Path("/{id}") @Consumes(MediaType.APPLICATION_JSON) public void updateUtente(@Context HttpServletRequest Req, Utente utente, @PathParam("id") String id) { UtenteDAO dao = new UtenteDAO(); dao.updateUtente(utente, id); } @POST @Path("/new") @Consumes(MediaType.APPLICATION_JSON) public void insertUtente(@Context HttpServletRequest Req, Utente utente) { UtenteDAO dao = new UtenteDAO(); dao.insertUtente(utente); } }
The JSON posted that give you the error
curl -H “Content-Type: application/json” -X POST –data @jsontest/new_user.json http://localhost:8888/rest/utenti/new
{ "uuid": "agxpbGVnYWxlY2xvdWRyGwsSB1ByYXRpY2EYlAIMCxIGVXRlbnRlGJYCDA", "id": null, "clientUUID": null, "versione": null, "email": "giulio.roggero@gmail.com", "encryptedPwd": "adskasdhkasjhjakshd832329y", "nome": "Giulio Roggero", "azienda": "Isola Software", "abilitato": true }
remove uuid and you can create a new user
{ "id": null, "clientUUID": null, "versione": null, "email": "giulio.roggero@gmail.com", "encryptedPwd": "adskasdhkasjhjakshd832329y", "nome": "Giulio Roggero", "azienda": "Isola Software", "abilitato": true }