Problem serialising generated class - gwt

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).

Related

How to register custom Querydsl EntityPathResolver with Spring Data MongoRepositoryFactory?

I am using the Querydsl extension (QueryDslPredicateExecutor) to my CrudRepository.
To reliably exclude the generated Q classes from my test coverage measurements, they are generated into a dedicated querydsl subpackage of the respective domain classes (annotation processor option -Aquerydsl.packageSuffix=.querydsl).
Alas, this causes a ClassNotFoundException at application start up:
java.lang.IllegalArgumentException: Did not find a query class org.example.QDomain for domain class org.example.Domain!
at org.springframework.data.querydsl.SimpleEntityPathResolver.createPath(SimpleEntityPathResolver.java:63)
at org.springframework.data.mongodb.repository.support.QueryDslMongoRepository.<init>(QueryDslMongoRepository.java:85)
at org.springframework.data.mongodb.repository.support.QueryDslMongoRepository.<init>(QueryDslMongoRepository.java:67)
…
Caused by: java.lang.ClassNotFoundException: org.example.QDomain
…
I have already located the EntityPathResolver interface that supposedly would allow me to plug in my own domain class to Q class mapping that inserts the .querydsl package suffix, but I haven’t found a way to configure Spring Data’s MongoRepositoryFactory to pick my own EntityPathResolver.
Is this possible?
Currently, the only way is to create your own variant of the MongoRepositoryFactory because the instance of the EntityPathResolver is hard-wired into it.

Jackson (jersey) deserialize exception - (for id type 'Id.class'): no such class found

I have a REST web application based on Jersey and running in an OSGi container - Geronimo3. The service is returning results fine with Json POST data and able to marshal json output to java object. I have written a REST client and that too works fine with main method getting back the response object.
However, Rest client fails in one scenario - when called from Bundle Activator class in a OSGi web application. It gives below error in this case.
Also when the web application is fully initialized, the Rest client works fine in request scope. I am suspecting some issue with classloaders since OSGi classloading is different regular webapps (tomcat). Also the response class uses #JsonTypeInfo annotation to map Interface type to concrete class.
Caused by: java.lang.IllegalArgumentException: Invalid type id 'com.nnn.IContentValue$ContentText' (for id type 'Id.class'): no such class found
at org.codehaus.jackson.map.jsontype.impl.ClassNameIdResolver.typeFromId(ClassNameIdResolver.java:57)
at org.codehaus.jackson.map.jsontype.impl.TypeDeserializerBase._findDeserializer(TypeDeserializerBase.java:113)
at org.codehaus.jackson.map.jsontype.impl.AsPropertyTypeDeserializer.deserializeTypedFromObject(AsPropertyTypeDeserializer.java:82)
at org.codehaus.jackson.map.deser.AbstractDeserializer.deserializeWithType(AbstractDeserializer.java:52)
at org.codehaus.jackson.map.deser.std.MapDeserializer._readAndBind(MapDeserializer.java:321)
at org.codehaus.jackson.map.deser.std.MapDeserializer.deserialize(MapDeserializer.java:249)
at org.codehaus.jackson.map.deser.std.MapDeserializer.deserialize(MapDeserializer.java:33)
at org.codehaus.jackson.map.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:299)
at org.codehaus.jackson.map.deser.SettableBeanProperty$MethodProperty.deserializeAndSet(SettableBeanProperty.java:414)
at org.codehaus.jackson.map.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:697)
I found a workaround that I'm documenting.
It is caused due to org.codehaus.jackson.map.util.ClassUtil.findClass loading typeid class from org.eclipse.core.runtime.internal.adaptor.ContextFinder that is different from OSGi bundle classloader during bundle init phase.
I replaced the contextClassLoader using Thread.currentThread().setContextClassLoader(getClass().getClassLoader()) before making the jersey client call and reverting it to original one in finally block.

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.

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