Hi Jeff. I was hoping to hear from You since I saw that You solved
some GAE issues on the hessian-interest list. I already posted the
issue on the hessian-interest list here:
http://maillist.caucho.com/pipermail/hessian-interest/2010-June/000908.html
I also posted several forum questions:
http://forum.caucho.com/showthread.php?t=9999
http://groups.google.com/group/google-appengine-java/browse_thread/thread/c4fb4f414c425ca1
And a few bug reports:
http://bugs.caucho.com/view.php?id=4061
http://code.google.com/p/googleappengine/issues/detail?id=3305
The posts actually describe two issues one with arraylist
serialization and the other with exception serialization. The posts
also include test projects with code that reproduces the issues. I
also managed to solve the issue today by using a custom serializer.
Here is how. First the Serializer:

public class ThrowableSerializer extends AbstractSerializer {
    @Override
    public void writeObject(Object obj, AbstractHessianOutput out)
throws IOException {
        if (obj != null) {
            final Class cl = obj.getClass();
            if (out.addRef(obj))
                return;
            int ref = out.writeObjectBegin(cl.getName());
            Throwable tr = (Throwable) obj;
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            try {
                oos.writeObject(tr);

                if (ref < -1) {
                    out.writeString("value");
                    out.writeBytes(bos.toByteArray());
                    out.writeMapEnd();
                } else {
                    if (ref == -1) {
                        out.writeInt(1);
                        out.writeString("value");
                        out.writeObjectBegin(cl.getName());
                    }
                    out.writeBytes(bos.toByteArray());
                }
            } finally {
                oos.close();
                bos.close();
            }
        } else
            out.writeNull();
    }
}

The other class we need is the Deserializer:
public class ThrowableDeserializer extends AbstractDeserializer {
    //private static final Logger l =
Logger.getLogger(ThrowableDeserializer.class.getName());

    @Override
    public Class getType() {
        return Throwable.class;
    }

    @Override
    public Object readMap(AbstractHessianInput in) throws IOException
{
        int ref = in.addRef(null);
        byte[] initValue = null;
        while (!in.isEnd()) {
            String key = in.readString();

            if (key.equals("value"))
                initValue = in.readBytes();
            else
                in.readString();
        }

        in.readMapEnd();
        ByteArrayInputStream bis = new
ByteArrayInputStream(initValue);
        ObjectInputStream ois = new ObjectInputStream(bis);
        try {
            Object value = ois.readObject();
            in.setRef(ref, value);
            return value;
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } finally {
            ois.close();
            bis.close();
        }
    }

    @Override
    public Object readObject(AbstractHessianInput in, Object[]
fieldNames)
            throws IOException {
        int ref = in.addRef(null);
        byte[] initValue = null;
        for (Object o : fieldNames) {
            if (o instanceof String) {
                final String key = (String) o;
                if (key.equals("value"))
                    initValue = in.readBytes();
                else
                    in.readObject();
            }
        }
        ByteArrayInputStream bis = new
ByteArrayInputStream(initValue);
        ObjectInputStream ois = new ObjectInputStream(bis);
        try {
            Object value = ois.readObject();
            in.setRef(ref, value);
            return value;
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } finally {
            ois.close();
            bis.close();
        }
    }
}
I'm not sure if the readMap part is actually needed since I rearranged
this code from another example. Also, a ThrowableSerializerFactory is
needed:
public class ThrowableSerializerFactory extends
AbstractSerializerFactory {
    @Override
    public Serializer getSerializer(Class cl) throws
HessianProtocolException {
        if (Throwable.class.isAssignableFrom(cl)) {
            return new ThrowableSerializer();
        }
        return null;
    }

    @Override
    public Deserializer getDeserializer(Class cl) throws
HessianProtocolException {
        if (Throwable.class.isAssignableFrom(cl)) {
            return new ThrowableDeserializer();
        }
        return null;
    }
}
What this code essentially does is take a Throwable (which implements
Serializable), serializes it to a byte[] and pushes it over to the
other side. This serialization does not use the problematic
setAccessible method (like com.caucho.hessian.io.ThrowableSerializer)
and works correctly on App engine (I tested it). The only part left to
do is to plug all this into the servlet and the client. Here is how to
do it on the servlet:
public class Service extends HessianServlet implements IService {
    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        getSerializerFactory().addFactory(new
ThrowableSerializerFactory());
    }
    // implement IService methods...
}

And here is how to do it on the client:
String url = "http://whatever.appspot.com/service";;
HessianProxyFactory factory = new HessianProxyFactory();
factory.getSerializerFactory().addFactory(new
ThrowableSerializerFactory());
IService service = (IService) factory.create(IService.class, url);

I would like to hear your opinion on this solution. Do You see any
problems with it? Also, when could we expect to see a solution in
Hessian? If You need any other information please ask. Thank You for
Your time.

D.
On Jun 15, 7:34 pm, Jeff Schnitzer <j...@infohazard.org> wrote:
> Perhaps try posting the stacktrace to the hessian-interest list?
> Someone (possibly me) might be able to fix this issue.
>
> Jeff
>
> On Thu, Jun 10, 2010 at 9:13 AM, dilbert <dilbert.elbo...@gmail.com> wrote:
> > First I'd like to explain what I mean by RPC. I'd like to be able to
> > write interfaces like this (simple Java interface):
>
> > public interface EchoService {
> >  String echo(String message);
> > }
>
> > The framework would allow the creation of client classes that would
> > handle the serialization from/to the RPC service. Of course the
> > framework should support the serialization of ArrayLists, HashMaps and
> > other collections and should also support the serialization of objects
> > marked with the "java.io.Serializable" interface (or some other
> > interface).
> > We would create the RPC Client this way:
>
> > EchoService echoService =
> > RpcClientFactory.createInstance(EchoService.class,"http://bla.com/
> > smartApp/echo");
>
> > And of course use it this way:
>
> > String echoMessage = echoService.echo("The message !!!");
>
> > The server side servlet would implement the previously mentioned
> > interface.
> > public class Service extends WhateverServlet implements EchoService {
> >   �...@override
> >    String echo(String message) {
> >        return "server sends:" + message;
> >    }
> > }
>
> > A few additional nice features to have would be:
> > -support for asynchronous calls (where the developer would provide a
> > callback for handling the result, similar to GWT RPC)
> > -the developers should be able to access the RPC client somehow to be
> > able to handle Cookies or other http headers.
> > -the client side should be usable from Android.
>
> > After a long search I have found that the framework that most closely
> > matches these requirements is Hessian (http://hessian.caucho.com/). It
> > uses a binary protocol so it should be very fast and it works on
> > Android. AFAIK it does not support async calls. However, not all is
> > well. The current Hessian implementation does not handle exceptions
> > well. It throws a SecurityException like this:
>
> > java.lang.SecurityException: java.lang.IllegalAccessException:
> > Reflection is not allowed on private java.lang.Throwable
> > java.lang.Throwable.cause
>
> > I considered GWT RPC for a while but it does not have a proper Java
> > client or I could not find one. So I wanted to ask is there any other
> > library that could be used in this case? Could the App engine team
> > write such a library and add it to the SDK. Any suggestions?
>
> > --
> > You received this message because you are subscribed to the Google Groups 
> > "Google App Engine for Java" group.
> > To post to this group, send email to google-appengine-j...@googlegroups.com.
> > To unsubscribe from this group, send email to 
> > google-appengine-java+unsubscr...@googlegroups.com.
> > For more options, visit this group 
> > athttp://groups.google.com/group/google-appengine-java?hl=en.
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"Google App Engine for Java" group.
To post to this group, send email to google-appengine-j...@googlegroups.com.
To unsubscribe from this group, send email to 
google-appengine-java+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/google-appengine-java?hl=en.

Reply via email to