tags:

views:

1443

answers:

5

I've just started learning Google Web Toolkit and finished writing the Stock Watcher tutorial app.

Is my thinking correct that if one wants to persist a business object (like a Stock) using JDO and send it back and forth to/from the client over RPC then one has to create two separate classes for that object: One with the JDO annotations for persisting it on the server and another which is serialisable and used over RPC?

I notice the Stock Watcher has separate classes and I can theorise why:

  • Otherwise the gwt compiler would try to generate javascript for everything the persisted class referenced like JDO and com.google.blah.users.User, etc
  • Also there may be logic on the server-side class which doesn't apply to the client and vice-versa.

I just want to make sure I'm understanding this correctly. I don't want to have to create two versions of all my business object classes which I want to use over RPC if I don't have to.

A: 

You don't have to create separate instances at all, in fact your better off not doing it. Your JDO objects should be plain POJO's anyway, and should never contain business logic, that's for your business layer, not your persistent objects themselves.

All you need to do is include the source for the annotations you are using and GWT should compile your class just fine. Also you want to avoid using libraries that GWT can't compile (like things that use reflection, etc) but in all the projects I've done this has never been a problem.

rustyshelf
The problem isn't that he has business logic in his JDOs, it's the JDO annotations that are causing problems (because GWT does not have access to the source, as you point out). This is a big problem in GWT+GAE, and I wish Google would articulate a proper solution.
Caffeine Coma
+2  A: 

Your assessment is correct. JDO replaces instances of Collections with their own implementations, in order to sniff when the object graph changes, I suppose. These implementations are not known by the GWT compiler, so it will not be able to serialize them. This happens often for classes that are composed of otherwise GWT compliant types, but with JDO annotations, especially if some of the object properties are Collections.

For a detailed explanation and a workaround, check out this pretty influential essay on the topic: http://timepedia.blogspot.com/2009/04/google-appengine-and-gwt-now-marriage.html

silvio
JDO does not replace Collections by its own implementations. DataNucleus, for example, has an option to do just that, but the default is to use java.util.* classes so we don't impose on the user to have DataNucleus present on client-side.
DataNucleus
+3  A: 

The short answer is: you don't need to create duplicate classes.

I recommend that you take a look from the following google groups discussion on the gwt-contributors list:

http://groups.google.com/group/google-web-toolkit-contributors/browse_thread/thread/3c768d8d33bfb1dc/5a38aa812c0ac52b

Here is an interesting excerpt:

If this is all you're interested in, I described a way to make GAE and GWT-RPC work together "out of the box". Just declare your entities as: @PersistenceCapable(identityType = IdentityType.APPLICATION, detachable = "false") public class MyPojo implements Serializable { }

and everything will work, but you'll have to manually deal with re-attachment when sending objects from the client back to the server.

You can use this option, and you will not need a mirror (DTO) class. You can also try gilead (former hibernate4gwt), which takes care of some details within the problems of serializing enhanced objects.

Miguel Ping
A: 

You do not have to create two versions of the domain model.

Here are two tips:

Use a String encoded key, not the Appengine Key class.

pojo = pm.detachCopy(pojo) ...will remove all the JDO enhancements.

nick
A: 

User: DataNucleus replied:

JDO does not replace Collections by its own implementations. DataNucleus, for example, has an option to do just that, but the default is to use java.util.* classes so we don't impose on the user to have DataNucleus present on client-side. – DataNucleus Jun 30 '09 at 7:07

I am finding the opposite. For some reason all my java.util collections are being replaced by DataNuclues collections. Even when setting the property: datanucleus.cache.collections to false.

DataNucleus, could you please explain how I can stop this from happening?