Why does Scalatra give me a FlashMap casting error sometimes? - scala

When running Scalatra in code reload mode, if I load the page before the scalate engine has reinitialized I get a 500 error.
If I watch the terminal until it looks like the engine has fully reloaded, it works fine, but I think this happens when I load the page between a) successful compile, and b) the container restart.
This won't correct itself until I change something else and force a new compile and code reload.
I can't seem to find why this is happening, does anyone have any ideas?
Here is how I'm doing code reloading:
./sbt "container:start" "~ ;copy-resources;aux-compile"
Here is the error I see:
HTTP ERROR 500
Problem accessing /. Reason:
org.scalatra.FlashMap cannot be cast to org.scalatra.FlashMap
Caused by:
java.lang.ClassCastException: org.scalatra.FlashMap cannot be cast to org.scalatra.FlashMap
at org.scalatra.FlashMapSupport$$anonfun$org$scalatra$FlashMapSupport$$getFlash$2$$anonfun$1.apply(flashMap.scala:182)
at org.scalatra.FlashMapSupport$$anonfun$org$scalatra$FlashMapSupport$$getFlash$2$$anonfun$1.apply(flashMap.scala:182)
at scala.Option.map(Option.scala:145)
at org.scalatra.FlashMapSupport$$anonfun$org$scalatra$FlashMapSupport$$getFlash$2.apply(flashMap.scala:181)
at org.scalatra.FlashMapSupport$$anonfun$org$scalatra$FlashMapSupport$$getFlash$2.apply(flashMap.scala:180)
at scala.Option.getOrElse(Option.scala:120)
at org.scalatra.FlashMapSupport$class.org$scalatra$FlashMapSupport$$getFlash(flashMap.scala:180)
at org.scalatra.FlashMapSupport$class.flash(flashMap.scala:192)
at beekeeper.controllers.HomeServlet.flash(HomeServlet.scala:13)
at org.scalatra.FlashMapSupport$$anonfun$handle$1.apply$mcV$sp(flashMap.scala:137)
at org.scalatra.FlashMapSupport$$anonfun$handle$1.apply(flashMap.scala:136)
at org.scalatra.FlashMapSupport$$anonfun$handle$1.apply(flashMap.scala:136)
at scala.util.DynamicVariable.withValue(DynamicVariable.scala:57)
at org.scalatra.DynamicScope$class.withRequest(DynamicScope.scala:71)
at org.scalatra.ScalatraServlet.withRequest(ScalatraServlet.scala:49)
at org.scalatra.FlashMapSupport$class.handle(flashMap.scala:136)
at beekeeper.controllers.HomeServlet.handle(HomeServlet.scala:13)
at org.scalatra.ScalatraServlet.service(ScalatraServlet.scala:54)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:848)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:669)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:455)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:137)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:560)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:231)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1072)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:382)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:193)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1006)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:135)
at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:255)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:116)
at org.eclipse.jetty.server.Server.handle(Server.java:365)
at org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:485)
at org.eclipse.jetty.server.AbstractHttpConnection.headerComplete(AbstractHttpConnection.java:926)
at org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.headerComplete(AbstractHttpConnection.java:988)
at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:635)
at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:235)
at org.eclipse.jetty.server.AsyncHttpConnection.handle(AsyncHttpConnection.java:82)
at org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:628)
at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:52)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:608)
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:543)
at java.lang.Thread.run(Thread.java:744)

This error says that there are 2 instances of the same class, loaded by different class loaders. This behavior rooted in java: classes from different class loaders are not the same. Basically equals method for classes is the function of a class name and a class loader. Classes will not be the same in this case even if they come from the same jar or folder.
When container reloads code it creates a new class loader, while your session still holds instance of flash map loaded using old class loader. This most likely the cause of the issue.

In Java every class is identified by its fully qualified class name and the class loader that has loaded it, this implies that:
ClassLoader1.my.package.MyClass != ClassLoader2.my.package.MyClass
This signifiy that it is not possible to cast an object of class MyClass loaded in ClassLoader1 to type MyClass loaded from ClassLoader2. You can find more details on
http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-5.html
On the other hand, it is not possible to load the same class twice in the same class loader, so you need a new class loader, there is no way around it. While I never wrote code that performs class reloading, one can suppose that class reloading means in practice:
create a new class loader
reload the class
swap class loaders
Because of what described above, one needs to be careful when designing classes that are supposed to be reloaded: see http://tutorials.jenkov.com/java-reflection/dynamic-class-loading-reloading.html#designing

Related

ClassNotFoundException when Loading Custom Class

So there's a lot of questions and examples around of reading external .class files using a ClassLoader but I'm struggling to see where I'm going wrong.
val folderUrl: URL = new File("D:/tmp/").toURI.toURL //file:/D:/tmp/
val cl: URLClassLoader = new URLClassLoader(Array(folderUrl), this.getClass.getClassLoader)
cl.loadClass("my.package.MyClassName")
The last line throws a ClassNotFoundException
The folder D:/tmp/ contains a class file "MyClassName.class".
The class has the package "my.package"
The class is called "MyClassName"
I can't understand what I'm doing wrong?
EDIT:
The two closest question which relate are:
Scala - Dynamic object/class loading
How do I call a Scala Object method using reflection?
But these both do not have my problem however, they both get further than I have done where they successfully load the class before running into issues.
So the issue was the fact that the folder structure did not match the package name.
So my folder structure was
D:/tmp/MyClassName.class
The full class name was
my.package.MyClassName
The class loader requires that the folder structure be
D:/tmp/my/package/MyClassName.class

How to use GWT SerializationStreamFactory

I am trying to serialize a object in GWT using SerializationFactory, but I am not able to get it working. Here is the sample code of my POC:
import com.google.gwt.user.client.rpc.SerializationException;
import com.google.gwt.user.client.rpc.SerializationStreamFactory;
import com.google.gwt.user.client.rpc.SerializationStreamReader;
import com.google.gwt.user.client.rpc.SerializationStreamWriter;
...........
Some code here....
.........
......
SerializationStreamFactory factory = (SerializationStreamFactory) GWT.create(MyClass.class);
SerializationStreamWriter writer = factory.createStreamWriter();
try {
writer.writeObject(new MyClass("anirudh"));
String value = writer.toString();
SerializationStreamReader reader = factory.createStreamReader(value);
MyClass myObj = (MyClass) reader.readObject();
System.out.println(myObj.getName());
} catch (SerializationException e) {
e.printStackTrace();
}
It gave me the following exception
Caused by: java.lang.RuntimeException: Deferred binding failed for 'com.anirudh..client.MyClass' (did you forget to inherit a required module?)
also in my code the class whose object I am trying to serialize implements IsSerializable
MyClass implements IsSerializable
I don't want to use GWT Auto-Bean framework because it does not fit my use case. Also I am not using GWT-RPC framework and right now I am quite adamant about using SerializationStreamFactory :D because I seriously want to know how this thing works.
Can anyone share a working example of SerializationStreamFactory or help me out pointing any mistake(s) I did.
Thanks in advance
SerializationStreamFactory factory = (SerializationStreamFactory) GWT.create(MyClass.class);
What are you expecting this line to do? GWT will attempt to find a replace-with or generate-with rule that matches this class (either when-type-assignable or when-type-is), or failing that will attempt to invoke a zero-arg constructor on MyClass, effectively new MyClass(). Is this what you are expecting?
The selected exception you've pasted suggests that MyClass may not be on the source path that GWT has been given to compile from, but the full error log will provide more information.
It looks as though you are trying to mimic the generated RPC code, where a *Async rpc interface would be implemented by code that extends from com.google.gwt.user.client.rpc.impl.RemoteServiceProxy (which implements SerializationStreamFactory). That base implementation is extended further to initialize several fields such as the com.google.gwt.user.client.rpc.impl.Serializer instance, actually responsible for serializing and deserializing object streams.
Serializers are created (by default) from the base class of com.google.gwt.user.client.rpc.impl.SerializerBase, through the rebind class com.google.gwt.user.rebind.rpc.TypeSerializerCreator. If you've build your own generator for MyClass, you should be kicking this off to get the work done as ProxyCreator already should be doing.
Remember when building your own serialization/deserialization mechanism that you need to decide which types can be marshalled within this system - if you open it to all types, then you will need to generate FieldSerializer types for all possible objects on the source path. This will greatly expand the size of your compiled code.
If your main goal is learning how this 'magic' works, dig into the generators and associated code that live in the com.google.gwt.user.rebind.rpc package. There are other libraries that leverage these ideas such as the gwt-atmosphere project (see https://github.com/Atmosphere/atmosphere to get started). Also review the generated code that GWT creates when it builds a 'tradition' RPC interface.

GWT Deferred binding issue

I am running into an issue with GWT :
The exception stack looks like :
Caused by: java.lang.RuntimeException: Deferred binding failed for 'com.cme.reg.fltrs.common.service.AnnouncementService' (did you forget to inherit a required module?)
at com.google.gwt.dev.shell.GWTBridgeImpl.create(GWTBridgeImpl.java:53)
at com.google.gwt.core.client.GWT.create(GWT.java:98)
at com.cme.reg.fltrs.client.sharedui.utils.ServiceFactory.getAnnouncementService(ServiceFactory.java:117)
at com.cme.reg.fltrs.client.announcement.AddMaintainAnnouncementModel.saveAnnouncement(AddMaintainAnnouncementModel.java:36)
at com.cme.reg.fltrs.client.announcement.AddMaintainAnnouncementPanel.save(AddMaintainAnnouncementPanel.java:260)
at com.cme.reg.fltrs.client.announcement.AddMaintainAnnouncementPanel$6.onClick(AddMaintainAnnouncementPanel.java:168)
at com.cme.libs.gwt.client.widgets.events.CMEClickListener.onEvent(CMEClickListener.java:10)
at com.cme.libs.gwt.client.widgets.events.CMEListenerCollection.fireEvent(CMEListenerCollection.java:51)
at com.cme.libs.gwt.client.widgets.CMEButton$1.onClick(CMEButton.java:30)
at com.google.gwt.event.dom.client.ClickEvent.dispatch(ClickEvent.java:54)
at com.google.gwt.event.dom.client.ClickEvent.dispatch(ClickEvent.java:1)
at com.google.gwt.event.shared.GwtEvent.dispatch(GwtEvent.java:1)
at com.google.web.bindery.event.shared.SimpleEventBus.doFire(SimpleEventBus.java:193)
at com.google.web.bindery.event.shared.SimpleEventBus.fireEvent(SimpleEventBus.java:88)
at com.google.gwt.event.shared.HandlerManager.fireEvent(HandlerManager.java:127)
Its failing at : announcementService = GWT.create(AnnouncementService.class);
Notes:
I have my service class : AnnouncementService
#RemoteServiceRelativePath( "announcement.srvc" ) has been added to AnnouncementService.
Async service class: AnnouncementServiceAsync
Configurations.xml :
entry key="**/announcement.srvc" value-ref="announcementServiceServlet"
Any help, where I am doing wrong or missing anything ?
Thanks Thomas.
Few The things to be checked:
1.Service must have a matching ServiceAsync class
2. Make sure all types used in Service implement IsSerializable
I was missing these two condition at few places.
If you're getting a deferred binding error with your RPC, then in addition to checking there is a matching Async interface, another thing to check is to make sure that you have the same methods in the following 3 places:
Synchronous interface
Asynchronous interface
Service implementation class
I got a similar "deferred binding" error when I accidentally had an extra method in my Synchronous (regular) interface that was missing in the Async interface and implementation class, but my IDE (IntelliJ IDEA 12) did not flag any files as having errors. When I finally remembered that I had recently removed a method from my service, I went into the Synchronous interface and saw that I had forgotten to remove that method's signature from the synchronous interface. Removing it so that the signatures matched in all three files fixed the Deferred binding error.

Problem serialising generated class

I am using GWT 2.3 for my application. I created a generator to generate classes and add behaviour to them.
My generator works fine and I can call GWT.create(MyClass.class) on the client. This does return a MyClassImpl object with the correct fields/methods. When I try to serialise the object to send it back to the server I have a SerializationException.
After debugging it appears that the RPC generator cannot find the class definition for MyClassImpl.
Is there a way of fixing this? I assumed the class definition generated by my own generator would be available to the RPC generator unless this one is run before my generator?
Thank you in advance for your help.
Farid
Hello and thank you for you quick answer,
My generated class is as follows:
- it has a public no arg constructor
- it implements Serializable (and to be sure I tried all combinations of Serializable and IsSerializable)
- is is generated (by my generator when I call GWT.create() ) in a shared package
- All its attributes are "Simple" (primitive or String)
It looks like this (where TestClass is my marker interface for the generator):
package com.test.shared;
import com.test.shared.TestClass;
public class TestClass_Impl implements TestClass, Serializable {
private String testString = "TestString";
public TestClass_Impl() {}
public String getTestString() {
return testString;
}
}
I can call GWT.create(TestClass.class) on the client. I get a instance of TestClass_Impl but as soon as I try to send it over the network to teh server through a GWT RPC call I get an exception:
com.test.server.TestServiceServlet-29927840: An IncompatibleRemoteServiceException was thrown while processing this call.
com.google.gwt.user.client.rpc.IncompatibleRemoteServiceException: java.lang.ClassNotFoundException: com.test.shared.TestClass_Impl
at com.google.gwt.user.server.rpc.RPC.decodeRequest(RPC.java:315)
at com.google.gwt.user.server.rpc.RemoteServiceServlet.processCall(RemoteServiceServlet.java:206)
at com.google.gwt.user.server.rpc.RemoteServiceServlet.processPost(RemoteServiceServlet.java:248)
at com.google.gwt.user.server.rpc.AbstractRemoteServiceServlet.doPost(AbstractRemoteServiceServlet.java:62)
....
Caused by: com.google.gwt.user.client.rpc.SerializationException: java.lang.ClassNotFoundException: com.test.shared.TestClass_Impl
at com.google.gwt.user.server.rpc.impl.ServerSerializationStreamReader.deserialize(ServerSerializationStreamReader.java:573)
at com.google.gwt.user.client.rpc.impl.AbstractSerializationStreamReader.readObject(AbstractSerializationStreamReader.java:119)
...
Caused by: java.lang.ClassNotFoundException: com.test.shared.TestClass_Impl
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at org.mortbay.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:366)
at org.mortbay.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:337)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:247)
at com.google.gwt.user.server.rpc.impl.ServerSerializationStreamReader.deserialize(ServerSerializationStreamReader.java:543)
It looks like GWT RPC cannot find the class TestClass_Impl on the server when it tries to instantiate it.
Any idea?
Thanks,
farid
Thank you Jusio. That is exactly what was going on. GWT seems to generate the java source only for the purpose of cross-compiling it into javascript and then discards the generated java files. There is a compiler option to keep the generated java code in a specific folder but the resulting .java file is not compiled with the build.
It is possible, although very convoluted and clumsy, to change the build process to pick up source files generated by my generator and include them in the build path so they can be compiled and available at runtime.
I have instead created a separate class to generate my java source code. This class is used by the generator to generate the java source to be cross-compiled by GWT. The same class is then used by my application to dynamically generate and load these java classes into the VM. They are then available at runtime and all seems to be working fine.
Thank you again for your help and if anyone needs more information about this workaround I will be happy to send it to them.
I believe the problem is, that generated class should exist on both client and server. That's why you get this error. As far as i know generators don't work on the server side. May be there is a way to make them work, but I don't know about it. Possible solution - launch compiler with -gen option to save generated classes to the disk, compile them to *.class and copy to the server class path. Or don't use GWT-RPC =)
Ensure that your generator makes the generated class IsSerializable (i.e., implements the IsSerializable interface).

Hibernate, Gilead and GWT

I'm experiencing some problems with GWT and Gilead/Hibernate
I did my code according to the tutorial but it fails with
com.google.gwt.user.client.rpc.SerializationException: Type 'ru.atamur.entity.UserEntity_gilead_15' was not included in the set of types which can be serialized by this SerializationPolicy or its Class object could not be loaded. For security purposes, this type will not be serialized.: instance = ru.atamur.entity.UserEntity_gilead_15#133fa82
Looking at the source code I can see that Gilead transformed my UserEntity into UserEntity_gilead_15 inside GileadRPCHelper.parseReturnValue(returnValue, _beanManager)
I can see that this was deliberately done by ProxyClassMapper (I'm trying to use proxy mode), so I was wondering where Gilead was expecting to tell GWT Serilization mechanism about this new proxy class it introduced ...
Can you share your code ?
before that I want to say that SerializationException is thrown when your class doesn't implement isSerializable interface that you send it to the server.
Every class that you send to the server should implement isSerializable interface