Ray has a workaround, but it is less than ideal
http://timepedia.blogspot.com/2009/04/google-appengine-and-gwt-now-marriage.html
And you can always use a DTO, but I recall that Serializable was added
to GWT just so that you didn't need to do that.
So... I'm not really asking for a fix... I am more wondering what the
"official response" is. Is this something that you want to fix,
something that isn't safe to fix, or something that you don't want to
fix?
Thanks.
Rob
I copied persisted entities to non-persisted copies, and again, it
fails. I needed to create a separate class, with the same fields as
the model object, and then copy the data to that. It seems that any
class with the @Entity annotation is unable to be passed to the
client.
Too bad that Google has to launch AppEngine to discover that ORM is definitively a problem for GWT. I send a mail to Bruce in early summer 2007 about that issue. His answer (that I perfectly understand) was to use DTO.
The fact is that DTO is no more a recommended pattern when your domain model is pure Java/POJO and client and server are tightly coupled. According to Gavin Kind and Rod Johnson, “DTO are evil” (http://forum.springsource.org/archive/index.php/t-15538.html). There are many situations where DTO are useful, but in general they could be avoided.
There is no “clean” solution for this problem unfortunately. All the ORM tools provide the “dirty state checking” mechanism by enhancing the entities object (Hibernate uses javassist during the attach process, jdo pre-enhanced during the compilation step). The issue comes from the fact that most of enhancers rely on java specific classes that are not serializable (SessionImplementor for Hibernate, …). Sending any Lazy initialized POJO over the wire to a non Java Client (Soap, XML, Json, …) leads to the same problem.
The idea behind hibernate4gwt is to replace on the fly (before InvokeAndEncodeRequest()) the proxies/specific classes by their JavaScript counter-part (a hashmap containing all the lazy initialized fields). This mechanism is implemented either with a generator (the generator generates subclasses that holds the hashmap proxy fields/information) or with a “magic” super class (LightEntity) which holds the same map.
Whatever we do, the process is necessarily specific to the ORM implementation because the way you get back the JavaScriptObject and you convert it back in Java depends on the Proxy implementation. The only way to get rid of this problem is to provide a mechanism based on “adaptors” that would be plugged during the Serialization process for converting attached entities to detached javascript compliant entities. Those Hibernate Adaptors would be provided by the ORM providers (Hibernate, DataNucleus, OpenJPA, etc …) and would handle for us all the nasty under-the-cover conversions stuff.
This problem requires a big implication of all the actors (ORM providers and Google/Community). Without this big bang, all the solutions based on Dozer, BeanLib, protocolbuffer generator (as stated by Ray) and DTO conversion tools will be a pain (many of them do not handle circular reference, deep graphs, etc..) and will lead to poor performance.
I’m working with Bruno (hibernate4gwt) to try to move the adaptor mechanism in the custom serialization (ServerSerializationWriter/Reader) process. I know that those classes are not meant to be extended as they are internal implementation and will probably be removed in the next version. Is there any work on a kind of (real) pluggable serialization mechanism for GWT 2 ?
Sami
Absolutely Ray, PB violates DRY principles and could be easily handled as a specific adaptor in the whole extensibility model.
This idea is to agree on an extensibility pattern similar to the way one extend RPC processCall(). CFS (Custom Field Serializer) may be an answer but they are supposed to be removed in further versions.
Customizing the JDO enhancer certainly does the trick but responds to a global problem by a specific solution. The main ORM used today is Hibernate (thru JPA with annotations or XML files), DataNucleus will probably gain momentum with AppEngine but people are waiting responses in priority for their ORM implementation.
To finish on the Latency, this problem is not specific to GWT/ORM but to ORM in general. Anyone who uses ORM should take care of FetchGroup, EagerFetching, N+1 select and minimizing roundtrip.
The way Hibernate4GWT solves this problem should be a starting point of thinking IMHO. This Framework looks like complex because of the lack of extensibility model in the serialization process, it is up to us (or GWT team) to simplify this mechanism.
Hope (you would) help
Sami
So I like GWT and I like Google App Engine, all I want is a simple
recipe for getting the two to work without hitting too many big
problems.
I'm willing to use DTO, I'm willing to suffer whatever I have to do -
but I need to know what's the best current way to do it.
> GWT RPC does not preserve identity across the wire, and the GWT compiler
> needs the source of the classes at compile time.
>
> The only way I see it working would be to add a flag requiring preserving
> object identity across RPC, and the protocol would include an object ID with
> each object if that flag is set.
Actually, JDO has a concept called application identity where object
identity is handled by the application. This typically boils down to
the PrimaryKey being used as object identity.
> what happens for a persistent object created on the client that the server
> has never seen before?
Calling persist() on it would insert it rather than merge it.
> IMHO, blindly transferring your stored data across the wire is convenient
> but produces big, slow client code.
This I agree with, I've been drum beating on this for awhile. ORM +
RPC is the surest way to produce 10,000 messages in the newsgroup
about "why my RPC calls are so slow and I get slow script warnings"
For me, the issue is to find a middle ground, a way of using DTOs, a
pattern, a DSL, a utility, that gives you DTO semantics without
excessive boilerplate. First of all, in almost all cases of an ORM
object sent over RPC, lazy association fetching would be wrong
(resulting in excess roundtrips), but pre-emptive fetches would also
be wrong much of the time. JDO/JPA work on the paradigm that the
server controls fetch semantics, but often times, it is the client
that knows what it wants to pull down, not the server, and this is
especially true if the client and server are written by different
people. Explicit finder methods with explicit DTOs are rather self
documenting and obvious on their face, what it is they do and what's
being transferred, the downside is a multiplication of boilerplate and
house keeping code.
This is certainly an area where DSLs + generators, libraries, and
compilers can help. Consider how easy Guice + Warp-Persist makes ORM
finders.
public interface CustomerDAO {
@Finder("select c from Customer c where c.zipCode = :zipcode")
Customer findCustomerByZipCode(@Named("zipcode") String zip);
}
You inject this and everything is handled automatically, getting
persistent context, opening/closing transactions, setting up the
query. It makes things painless.
Now we just need to find an equivalent for DTOs.
-Ray
That's true, but what bothers me about this is that it seems brittle.
If I pull down a domain object, one that comes with fetch group A, and
pull down another domain object from fetch group B, and stick them in
a Collection together, and then someone else maps over this
collection, it can result in serious breakage. The assumption being
made is that people working with domain objects are usually the ones
calling the RPC method, and so have read the documentation that says
"This returns a Customer object, but does not fetch the
AccountRepresentative. Do not call
Customer.getAccountRepresentative()!" It true, from the context of an
AsyncCallback, you will usually know what restrictions are in effect
on the domain object returned, but this will be lost as it goes down
the stack chain.
Of course, you could document Customer.getAccountRepresentative() as
potentially returning null, but that's sorta brittle too, because if
null represents the non-existence of a representative, then other code
might just to assign one!
And given the asynchronous nature of RPC, you can't really fetch these
associations on demand, unless you make the getter method take an
AsyncCallback, another pollution of the interface.
I know you can make this work if you're careful, but it seems brittle
and subject to subtle breakage as the number of people on a project
increase.
-Ray
-Ray
On Tue, Apr 14, 2009 at 9:03 AM, John Tamplin <j...@google.com> wrote:
> The only way I see it working would be to add a flag requiring preservingActually, JDO has a concept called application identity where object
> object identity across RPC, and the protocol would include an object ID with
> each object if that flag is set.
identity is handled by the application. This typically boils down to
the PrimaryKey being used as object identity.
> what happens for a persistent object created on the client that the serverCalling persist() on it would insert it rather than merge it.
> has never seen before?
...Besides fixing GWT-RPC with GAE, it also allows me to trim data
that I don't really need on the client side.
The rest, like knowing when to persist vs merge an incoming object
from the client, is my problem to figure out.
Rob
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.
-Ray
I hope I am not being naive (or reiterating an existing post), but I
am not concerned with identity, nor concerned with expecting my ORM
solution to deal with entities created on the client.
I think all I need is a way to use an entity as a DTO without needing
a second set of model objects.
What about something as simple as keeping the existing semantics in
tact, with the ability to flag properties that are send-able to the
client (as opposed to using transient to flag the reverse behavior).
public class Data implements Serializable {
@GwtDto
private Long id;
@GwtDto
private String partA;
private String partB;
}
In this case the GWT compiler would create a serializer for the client
that only handled the id and partA properties, and ignore partB. The
partB property would simply be null on the client side.
On the server reflection would be used to only serialize the marked
properties, ignoring the rest. Besides ignoring partB it would also
ignore any fields added by enhancers.
Ray, I reread your post, and I think that perhaps I had thought that
this only applied to JDO, but seems to also apply to JPA as well,
correct?
I guess this works, but that leaves one outstanding issue for me. I
want to use detachable instances on the server-side, yet still have
unenhanced objects to send to the GWT client.
BRUNO> For information, Gilead provides the @ServerOnly annotation to prevent
BRUNO> sending sensible fields over the wire.
Thanks Bruno, I will need to check that out.
RAY> The RPC generator could implement this in a way, such that the
RAY> received object from the RPC call is not a Customer, but a
RAY> DetachableCustomerImpl (which extends Customer). This would be a
RAY> client side 'enhanced' version which does dirty bit tracking
I like this idea. It seems to solve a most(?) of the issues.
Rob
> Ray, I reread your post, and I think that perhaps I had thought that
> this only applied to JDO, but seems to also apply to JPA as well,
> correct?
AFAIK, JDO is a superset of JPA now, and DataNucleus implements JPA as
a facade around their JDO implementation. As the GAE ORM sample that
comes in the distribution shows, you can persist a JDO class in either
an EntityManager or PersistenceManager, and JPA/JDO annotations seem
rather interchangeable.
> I guess this works, but that leaves one outstanding issue for me. I
> want to use detachable instances on the server-side, yet still have
> unenhanced objects to send to the GWT client.
The best way this should be done is to modify the DataNucleus/JDO
enhancer to add @GwtTransient annotation to the jdoDetachedState
field. This will tell GWT RPC to ignore it, but Java RMI/Serialization
won't. Optionally, RemoteServiceServlet should have some kind of
callback like isPersistent(Field) and let the app decide if it wants,
teaching SerializabilityUtil about this delegation.
Keep in mind, if you design your application to "open transaction in
view/open session in view" you can keep the domain objects attached
all throughout the request. Detach only seems relevant if you're
sending objects through RPC, or sticking them in a JCache or something
that lives across requests.
> I've pretty much decided to go the DTO approach at this point as it is
> known to work 100%. I don't feel the current hacks are production
> worthy.
You have mentioned on your blog that you use protobufs for DTOs. Could
you please elaborate on that?
P.S. Can't wait for gwt sessions to be uploaded on youtube!
--
Best Regards,
Piotr Jaroszyński