At the time I thought the issues were connected since they threw the same exception so I posted them together. So should I post the issue with exceptions again on the Caucho bug tracker? If this issue is solved I would recommend Hessian as the best RPC mechanism for GAE at this time. Apologies to other readers for the offtopic with bugs. D.
On Jun 15, 11:24 pm, Jeff Schnitzer <[email protected]> wrote: > I think you did yourself a disservice by wrapping these two issues > into a single message - it ends up being way too much text to read and > otherwise eager volunteers just skip it. > > The first issue looks like you're not detaching your entities before > serializing them. This is a JDO issue. I suggest dropping JDO and > using something simpler like Objectify ;-) > > The issue with exceptions looks more serious. This is something that > will need to be fixed in Hessian (or your custom serializer). If you > cut down your issue to just this, you might get better results from > Caucho. > > Jeff > > On Tue, Jun 15, 2010 at 1:55 PM, dilbert <[email protected]> wrote: > > 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/00090... > > I also posted several forum questions: > >http://forum.caucho.com/showthread.php?t=9999 > >http://groups.google.com/group/google-appengine-java/browse_thread/th... > > 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 <[email protected]> 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 <[email protected]> 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. > > ... > > read more » -- 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 [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/google-appengine-java?hl=en.
