Google Groups Home
Help | Sign in
extending RemoteServiceServlet
There are currently too many topics in this group that display first. To make this topic appear first, remove this option from another topic.
There was an error processing your request. Please try again.
flag
  4 messages - Collapse all
The group you are posting to is a Usenet group. Messages posted to this group will make your email address visible to anyone on the Internet.
Your reply message has not been sent.
Your post was successful
jdwy  
View profile
(1 user)  More options Feb 1 2007, 1:28 pm
From: "jdwy" <jdw...@gmail.com>
Date: Thu, 01 Feb 2007 18:28:32 -0000
Local: Thurs, Feb 1 2007 1:28 pm
Subject: extending RemoteServiceServlet
I've modified my ServerSerializationStreamWriter to help me escape
some of the curve balls that Hibernate throws. Basically it just
rewrites PersistentSet / CGLIB proxies and / Dates. It's a little
rough but it allowed me to delete all my old twisted
"makeThisObjectGWTSerializationSafe()" code and it works like a charm.

To plug my implementation in however I had to make my own
RemoteServiceServlet replacement, since the
ServerSerializationStreamWriter that it uses is coded right in there.

ServerSerializationStreamWriterWithHibernateEscaping streamWriter =
new
ServerSerializationStreamWriterWithHibernateEscaping(serializableTypeOracle );

Any help making RemoteServiceServlet more extensible/pluggable would
be lovely. I'd love to be able to just inject a streamWriter of my
choosing right in there.

public void serializeValue(Object value, Class type) throws
SerializationException {

                          if (type == boolean.class) {
                                  writeBoolean(((Boolean) value).booleanValue());
                          } else if (type == byte.class) {
                                  writeByte(((Byte) value).byteValue());
                          } else if (type == char.class) {
                                  writeChar(((Character) value).charValue());
                          } else if (type == double.class) {
                                  writeDouble(((Double) value).doubleValue());
                          } else if (type == float.class) {
                                  writeFloat(((Float) value).floatValue());
                          } else if (type == int.class) {
                                  writeInt(((Integer) value).intValue());
                          } else if (type == long.class) {
                                  writeLong(((Long) value).longValue());
                          } else if (type == short.class) {
                                  writeShort(((Short) value).shortValue());
                          } else if (type == String.class) {
                                  writeString((String) value);
                          }
                          /*
                           * make sure we dont return any java.sql.Timestamps
                           */
                          else if (type == java.util.Date.class) {
                                  writeObject(new
java.util.Date(((java.util.Date)value).getTime()));
                          }
                          /*
                           * convert org.collection.hibernate.PersistentSet to HashSet
                           */
                          else if (type == java.util.Set.class) {
                                  Set hashSet = new HashSet();
                                  if (value instanceof PersistentSet) {
                                          PersistentSet persSet = (PersistentSet) value;
                                          if(persSet.wasInitialized()){
                                                  hashSet.addAll(persSet);
                                          }
                                  } else{
                                          hashSet = (Set) value;
                                  }
                                  writeObject(hashSet);
                          }
                          /*
                           * if this is a CGLIB proxy object do clone it so that we ditch
the proxy.
                           * Using
                           * public interface ReallyCloneable {
                           *            public Object clone();
                           * }
                           * Because std Cloneable doesn't actually define .clone()
                           *
                           * NOTE: for polymorphic classes don't forget to
implement .clone() for each class
                           */
                          else if (value != null &&
value.getClass().getName().contains("CGLIB")) {

                                  if(Hibernate.isInitialized(value)){
                                          if(value instanceof ReallyCloneable){
                                                  System.out.println(value.getClass().getName()+" CGLIBBB!!
Cloning "+value);
                                                  writeObject(((ReallyCloneable)value).clone());
                                          }else{
                                                  throw new CouldntFixCGLIBException(value.getClass()+" must
implement ReallyCloneable if we're to fix it.");
                                          }
                                  }else{
                                          System.out.println("Uninitialized CGLIB");
                                          writeObject(null);
                                  }
                          }
                          else {
                                  writeObject(value);
                          }
          }


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Rob Jellinghaus  
View profile
 More options Feb 1 2007, 2:48 pm
From: "Rob Jellinghaus" <r...@unrealities.com>
Date: Thu, 01 Feb 2007 11:48:43 -0800
Local: Thurs, Feb 1 2007 2:48 pm
Subject: Re: extending RemoteServiceServlet
See issue 389 and the monster thread about it in this forum right
now :-)  It doesn't do exactly what you want (it doesn't have a
specific hook for overriding the streamwriter), but it does break the
code down enough that you should be able to override the new
RemoteServiceServlet in a more convenient way.  Let us know what you
think.

Cheers!
Rob


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
jdwy  
View profile
 More options Feb 2 2007, 1:41 pm
From: "jdwy" <jdw...@gmail.com>
Date: Fri, 02 Feb 2007 18:41:37 -0000
Local: Fri, Feb 2 2007 1:41 pm
Subject: Re: extending RemoteServiceServlet
Hey Rob,
Thanks for introducing me to the "monster thread." I should've found
that.

I got a chance to look at the code and I do think that this will have
some nice results. For unit testing in particular.

Plugging in my little HibernateEscaping stream will be easier with
this structure. It looks like I'd subclass RemoteServiceServlet and
override processCall() with one that call my own RPC mechanism right?

The only further request I'd have is to make the RPC.java a bit easier
to extend since it's not so much that I want to replace the current
RPC imp as to extend it with my Hibernate filter. All I'd really need
is a public encodeResult(). Or perhaps a specific "filter" extension
point? I think that this a a really common result for anyone using ORM
software. The Hibernate folks are (with reason) absolutely aghast at
saying un-initialized == null, but sending lazy objects into the
presentation tier is a tricky thing to solve if you're allergic to
DTOs. In my personal opinion it's one of the real unsolved problems
with the current state of the art.

http://forum.hibernate.org/viewtopic.php?t=947299&highlight=bomb+lazy

If not I'll just end up duping this class and maintaining myself. I'd
understand if you think that this would be a bit dangerous to allow
people to fiddle with the RPC as they choose, but I think it might be
worth it.

ahh. I see it's a final class. sigh. sounds like I'm not going to win
this one :)  but do think about it for me would you? With clients as
powerful as GWT I just love being able to use my real domain objects
in the client, but there's a real sticking point here.

Thanks again,

-Jeff

On Feb 1, 2:48 pm, "Rob Jellinghaus" <r...@unrealities.com> wrote:


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Rob Jellinghaus  
View profile
 More options Feb 2 2007, 4:52 pm
From: "Rob Jellinghaus" <rjellingh...@gmail.com>
Date: Fri, 02 Feb 2007 21:52:47 -0000
Local: Fri, Feb 2 2007 4:52 pm
Subject: Re: extending RemoteServiceServlet
On Feb 2, 10:41 am, "jdwy" <jdw...@gmail.com> wrote:

> I got a chance to look at the code and I do think that this will have
> some nice results. For unit testing in particular.

Good to hear :-)

> Plugging in my little HibernateEscaping stream will be easier with
> this structure. It looks like I'd subclass RemoteServiceServlet and
> override processCall() with one that call my own RPC mechanism right?

Yes, absolutely.

> The only further request I'd have is to make the RPC.java a bit easier
> to extend since it's not so much that I want to replace the current
> RPC imp as to extend it with my Hibernate filter.

Well, actually, the RPC class is probably better thought of as a pile
of static helper methods.  So it's not really something you extend --
it's a collection of methods that you can use, or not, as you please.
In your case I'd just write my own encodeHibernateResponse method that
used your special serialization stream, and then override
RemoteServiceServlet.processCall (as you already did) to use
RPC.decodeRequest, invoke your method, and then use
MyRPC.encodeHibernateResponse.  Shouldn't be too much code.

We could conceivably add another overloading of encodeResponse,
something like RPC.encodeResult(Method method, Object result,
ServerSerializationStreamWriter writer), but I don't think it would be
all that great a win.  There are so many possible hooks once you go
down that road, sometimes it's simpler to just roll your own where
it's needed :-)  It's probably still a big win to be reusing the
majority of RemoteServiceServlet, and to get to use the
RPC.decodeRequest method exactly as is.  Just be careful with your
exception handling, so you are encoding expected exceptions (which
you'll probably have to serialize with your special writer as well).

> I think that this a a really common result for anyone using ORM
> software. The Hibernate folks are (with reason) absolutely aghast at
> saying un-initialized == null, but sending lazy objects into the
> presentation tier is a tricky thing to solve if you're allergic to
> DTOs. In my personal opinion it's one of the real unsolved problems
> with the current state of the art.

I hear you.  I'm going to be in exactly the same situation myself.
But I think that this is a case where it might be a little early to
introduce a standard hook into GWT.  In my own project I'll probably
just make the classes I'm using for this freely available through one
of the GWT sandbox projects, so at least the code is out there.  Once
the right pattern emerges then there can be a subsequent GWT patch to
adopt it.  In fact, would you consider submitting your Hibernate
serializer to one of the GWT-commons projects?  I'm sure there'll be
interest, especially once GWT 1.4 ships with the refactored RPC.
Maybe put up your HibernateRemoteServiceServlet class?

Anyway, it won't be a one-liner, but it'll be a lot less than it
was :-)
Cheers!
Rob


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
End of messages
« Back to Discussions « Newer topic     Older topic »

Create a group - Google Groups - Google Home - Terms of Service - Privacy Policy
©2008 Google