JDO, RequestFactory, String and PrimaryKey

190 views
Skip to first unread message

Micah Caldwell

unread,
Aug 10, 2011, 1:10:03 AM8/10/11
to google-we...@googlegroups.com
@PersistenceCapable
public class MyEntity extends EntityBase
{
    @PrimaryKey
    @Persistent
    private String mPrimaryKey;
}

com.google.web.bindery.requestfactory.server.UnexpectedException: The domain type javax.jdo.identity.StringIdentity cannot be sent to the client

Is there a known workaround for this?

The problem is that JDO stores the identifier as a StringIdentity rather than a String and when it comes time to transmit the object to the client via GWT RequestFactory it's the JDO version of the object that is being transmitted (so it appears) rather than the MyEntity that I defined.

This only occurs when I fetch the object from the datastore.  If I instantiate it on the server (new MyEntity() ...) it can be sent to the client and if I instantiate it on the client it can be sent to the server.

When I look at the results in a debugger immediately after:
List<MyEntity> lMyEntities = (List<MyEntity>) lQuery.execute();

I get the following for: StreamingQueryResult.lazyResult.entityTransformer.val$acmd.managedMembers
[<field name="mKey"
    persistence-modifier="persistent"
    primary-key="true"
    null-value="none"
    default-fetch-group="true"
    embedded="false"
    unique="false">
  <column name="mKey"/>
</field>]

Which is all fine but when I look at: StreamingQueryResult.lazyResult.entityTransformer.val$acmd.objectidClass
javax.jdo.identity.StringIdentity

Apparently when I return from the the server request and the collection of objects is marshaled back to the client, that objectidClass gets marshaled along with it and the exception is thrown.

Micah Caldwell

unread,
Aug 10, 2011, 1:13:38 AM8/10/11
to google-we...@googlegroups.com
I guess the question I have is really more a JDO/GAE question than a GWT question as I need to know how to convert the StreamingQueryResult into a regular collection.  However, if there is a way to work around marshaling the StringIdentity to the client that would work too.

Kayode Odeyemi

unread,
Aug 10, 2011, 6:57:04 AM8/10/11
to google-we...@googlegroups.com
Do this to your Entity

@PrimaryKey
  @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
  @Extension(vendorName = "datanucleus", key = "gae.encoded-pk", value = "true")
  private String mPrimaryKey;

On Wed, Aug 10, 2011 at 6:13 AM, Micah Caldwell <mic...@gmail.com> wrote:
I guess the question I have is really more a JDO/GAE question than a GWT question as I need to know how to convert the StreamingQueryResult into a regular collection.  However, if there is a way to work around marshaling the StringIdentity to the client that would work too.

--
You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.
To view this discussion on the web visit https://groups.google.com/d/msg/google-web-toolkit/-/wyT11sMQBugJ.

To post to this group, send email to google-we...@googlegroups.com.
To unsubscribe from this group, send email to google-web-tool...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/google-web-toolkit?hl=en.



--
Odeyemi 'Kayode O.
http://www.sinati.com. t: @charyorde

Micah Caldwell

unread,
Aug 10, 2011, 10:02:06 AM8/10/11
to google-we...@googlegroups.com
Making the change you have suggested results in:
Server Error: Invalid primary key for com.zoltu.jdo_requestfactory_test.server.MyEntity.  The primary key field is an encoded String but an unencoded value has been provided. If you want to set an unencoded value on this field you can either change its type to be an unencoded String (remove the "gae.encoded-pk" extension), change its type to be a com.google.appengine.api.datastore.Key and then set the Key's name field, or create a separate String field for the name component of your primary key and add the "gae.pk-name" extension.
 I should specify that I do want to be able to set the primary key manually.  I have a unique string identifier I would like to use as the primary key for MyEntity.  Also, attempting to use a Long results in the same problem.  http://www.datanucleus.org/products/accessplatform/jdo/primary_key.html shows that most of the basic types have special Identity classes, none of which can be sent to the client (client can only receive basic types according to http://code.google.com/webtoolkit/doc/latest/DevGuideRequestFactory.html#transportable).

Kayode Odeyemi

unread,
Aug 10, 2011, 10:06:57 AM8/10/11
to google-we...@googlegroups.com
Sorry I meant,

@PrimaryKey
  @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
  @Extension(vendorName = "datanucleus", key = "gae.encoded-pk", value = "true")
  private Key mPrimaryKey;

Make sure the Key class is from com.google.appengine.api.datastore.Key;

--
You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.

To post to this group, send email to google-we...@googlegroups.com.
To unsubscribe from this group, send email to google-web-tool...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/google-web-toolkit?hl=en.

Micah Caldwell

unread,
Aug 10, 2011, 11:43:21 AM8/10/11
to google-we...@googlegroups.com
Error in meta-data for com.zoltu.jdo_requestfactory_test.server.MyEntity.mKey: A field with the "gae.encoded-pk" extension can only be applied to a String primary key.

Alex Dobjanschi

unread,
Aug 10, 2011, 11:56:06 AM8/10/11
to google-we...@googlegroups.com
I'd suggest you first write a unit test that checks if your data types are actually valid (say, persist some, delete some, etc). This test will only run for 0.5-1s, so it's really fast.

Then, you should know that GWT cannot send everything through the wire (from server to client). The Key will not be serialized.
I suggest you use a Data Transfer Object, and provide mapping from domain objects to DTOs.

Micah Caldwell

unread,
Aug 10, 2011, 12:35:16 PM8/10/11
to google-we...@googlegroups.com
The app I have been working on to test this is as small of an app that I can figure out how to write that utilizes RequestFactory and JDO at the same time (since it's the interplay between them that is the problem).  Currently it only does 4 things to test this functionality:
  • generate an entity on the client and send it to the server for saving in the datastore
  • generate a new entity on the server, save it in the datastore and send the new entity back to the client
  • count the number of entities in the datastore and send the count to the client
  • send a list of all entities in the datastore to the client
All but the last work fine.  It's only when I try to get an entity out of the datastore and send it to the client that the problem presents itself.  In fact, I have commented out the code for the first 3 tests just to make sure there wasn't a problem with with the interaction of the different tests.

Can you extrapolate on what you mean by using a DTO in this situation?  Are you suggesting that I do not use the same object for client-server transfer as I do for server-datastore transfer?  This method seems to be contrary to the method outlined at http://code.google.com/webtoolkit/doc/latest/DevGuideRequestFactory.html where the JDO and RequestFactory objects are one and the same.
[RequestFactory] is designed to be used with an ORM layer like JDO or JPA on the server, although this is not required.

Kayode Odeyemi

unread,
Aug 10, 2011, 12:40:47 PM8/10/11
to google-we...@googlegroups.com
The fact that you are using RequestFactory eliminates the need for DTO.

You might want to see this project sample: listwidget - GWT+GAE sample app that tracks informal lists of ...

HTH

--
You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.

To post to this group, send email to google-we...@googlegroups.com.
To unsubscribe from this group, send email to google-web-tool...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/google-web-toolkit?hl=en.

Micah Caldwell

unread,
Aug 10, 2011, 12:51:51 PM8/10/11
to google-we...@googlegroups.com
The project you linked to uses Objectify rather than JDO for persistence.  Unfortunately, all examples of RequestFactory that I have been able to find use something other than JDO for persistence.  I assumed that JDO would work with request factory since it is mentioned in the RequestFactory documentation but am I incorrect in this assumption that the two are compatible?  Is my best course of action to just change persistence engines to something that I can find working samples of (such as Objectify)?

Kayode Odeyemi

unread,
Aug 10, 2011, 12:57:45 PM8/10/11
to google-we...@googlegroups.com
Yes I know. But you will find RF usage sample in there which shows in details how you
can pass your entity to the client using RF. 

Be it Objectify or not, the concept is the same. I particularly use JDO and it works.

On Wed, Aug 10, 2011 at 5:51 PM, Micah Caldwell <mic...@gmail.com> wrote:
The project you linked to uses Objectify rather than JDO for persistence.  Unfortunately, all examples of RequestFactory that I have been able to find use something other than JDO for persistence.  I assumed that JDO would work with request factory since it is mentioned in the RequestFactory documentation but am I incorrect in this assumption that the two are compatible?  Is my best course of action to just change persistence engines to something that I can find working samples of (such as Objectify)?

--
You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.

To post to this group, send email to google-we...@googlegroups.com.
To unsubscribe from this group, send email to google-web-tool...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/google-web-toolkit?hl=en.

Micah Caldwell

unread,
Aug 10, 2011, 1:19:35 PM8/10/11
to google-we...@googlegroups.com
The RequestFactory code I have is all working great.  I am able to transfer objects back and forth between the server and the client without trouble.  It's only when I try to return the results of a JDO query that I run into trouble.

The JDO side of things is working great.  I can query the datastore from the server with JDO and "do stuff" with those results on the server, except sending those results to the client.

The RequestFactory + JDO interaction is working great with the exception of query results.  I can successfully save JDO objects created on both the server and the client (via RequestFactory).  I can also successfully return aggregate JDO query results to the client (such as count).

Again, my only problem lies with sending entity query results to the client.  Everything else done with RequestFactory and JDO works great.

In case anyone wants to see my test app (Eclipse project):

Do you send JDO query results (javax.jdo.Query) to the client in your application where the query returns a JDO & RequestFactory enabled object?

This is how I am executing the query.  This is in a RequestFactory method called by the client through a RequestContext meaning that the list returned by this method will be packed up by the RequestFactory and shipped off to the client for unpacking (it's the packing step that throws the exception).
Query lQuery = MyPersistenceManagerFactory.fGet().newQuery(MyEntity.class);
try
{
List<MyEntity> lMyEntities = (List<MyEntity>) lQuery.execute();
return lMyEntities;
}
finally
{
lQuery.closeAll();
}

Kayode Odeyemi

unread,
Aug 10, 2011, 1:42:42 PM8/10/11
to google-we...@googlegroups.com
You will have to go through a Proxy[1] to hand that over to the client.

--
You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.

To post to this group, send email to google-we...@googlegroups.com.
To unsubscribe from this group, send email to google-web-tool...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/google-web-toolkit?hl=en.

Micah Caldwell

unread,
Aug 10, 2011, 1:49:01 PM8/10/11
to google-we...@googlegroups.com
MyEntity is a JDO enabled object with a proxy called MyEntityProxy:
@ProxyFor(value = MyEntity.class, locator = MyEntity.Locator.class)
public interface MyEntityProxy extends EntityProxy
{
public String getKey();
public void setKey(String pKey);
}
As I understand it, that query should return a List<MyEntity> which is a transportable type (http://code.google.com/webtoolkit/doc/latest/DevGuideRequestFactory.html#transportable). 
Reply all
Reply to author
Forward
0 new messages