2

I am currently developing Java/GWT-application which is hosted on a weblogic application server. I am using EJB3.0 with EclipseLink as persistence layer. Sadly my GWT has problems to deserialize persistent entities.

It might be helpful for you to know, that I

  • have the EclipseLink-Library in my classpath (including javax.persistence.Entity)
  • am not recieving the persistence objects from a database or persistence-manager - I am creating the objects with standard java code
  • use Eclipse IDE for Java EE Developers for development and deploying and I am compiling my GWT code with the GWT-Plugin (GWT 2.1.0) - my source code is split up in several projects
  • am pretty sure, that the problems occures on client side, since the HTTP response of my server is the same in my working and in my not working example
  • tried to patch javax.persistence.Entity and tried to include several libraries which included javax.persistence.Entity but nothing was helping
  • a minimal project with just this code works fine, but this code integrated in our project environment does not work

UPDATE: it looks like this whole topic is some problem with rpc.enhancedClasses. I added the interesting contents of my generated .gwt.rpc-files. It seems to be unnormal, that the data transfered over HTTP is the same, although these .rpc files differ. These links might be interesting: RemoteService.gwt.xml and the documentation for enhances classes

In my server provides a list of instances of class SerialClass; the interface looks like this:

public interface GreetingService extends RemoteService {
    List<SerialClass> greetServer();
}

My onModuleLoad()-Method gets those instances and creates a browser-popup with the information:

public void onModuleLoad() {
    GreetingServiceAsync server = (GreetingServiceAsync) GWT.create(GreetingService.class);
    server.greetServer(new AsyncCallback<List<SerialClass>>() {
        public void onFailure(Throwable caught) {
        }

        public void onSuccess(List<SerialClass> result) {

            String resultString = "";
            try {
                for (SerialClass serial : result) {
                    if (serial == null) {
                        resultString += "null ";
                    } else {
                        resultString += ">" + serial.id + "< ";
                    }
                }
            } catch (Throwable t) {
                Window.alert("failed to process");
            }

            Window.alert("success:" + resultString);
        }
    });

}

My server is looking like this:

public class GreetingServiceImpl extends RemoteServiceServlet implements GreetingService {
    public List<SerialClass> greetServer() throws IllegalArgumentException {
        List<SerialClass> list = new ArrayList<SerialClass>();
        for (int i = 0; i < 100; i++) {
            list.add(new SerialClass());
        }
        return list;
    }
}

Case 1 => everything works fine

I am using this SerialClass (either without any annotation, or with any annotation other than Entity - for example javax.persistence.PersistenceContext works fine):

//@Entity
public class SerialClass implements Serializable, IsSerializable {
    public int id = 4711;
}

The popup contains (as expected):

success:>4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711< >4711<

The data sent over HTTP looks like this:

//OK[4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,100,1,["java.util.ArrayList/3821976829","serial.shared.SerialClass/10650133"],0,6]

The generated .xml.rpc-file (4F138A4EA095EA4C468507AF3CA19D8F.gwt.rpc) contains:

my.package.SerialClass, true, true, false, false, my.package.SerialClass/2805025871, 2805025871
[Lmy.package.SerialClass;, true, true, false, false, [Lmy.package.SerialClass;/600614154, 600614154

Case 2 => its not working at all

I am using this SerialClass:

@Entity
public class SerialClass implements Serializable, IsSerializable {
    public int id = 4711;
}

My popup contains (THIS IS MY PROBLEM):

success:>2< null >2< null >2< null >2< null >2< null >2< null >2< null >2< null >2< null >2< null >2< null >2< null >2< null >2< null >2< null >2< null >2< null >2< null >2< null >2< null >2< null >2< null >2< null >2< null >2< null >2< null >2< null >2< null >2< null >2< null >2< null >2< null >2< null >2< null >2< null >2< null >2< null >2< null >2< null >2< null >2< null >2< null >2< null >2< null >2< null >2< null >2< null >2< null >2< null >2< null 

The data sent over HTTP looks like this (exactly the same!):

//OK[4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,4711,2,100,1,["java.util.ArrayList/3821976829","serial.shared.SerialClass/10650133"],0,6]

The generated .xml.rpc-file (E81A9E44448F41D2EC63CD508632C10B.gwt.rpc) contains:

my.package.SerialClass, true, true, false, false, my.package.SerialClass/2805025871, 2805025871
@ClientFields,my.package.SerialClass,id
[Lmy.package.SerialClass;, true, true, false, false, [Lmy.package.SerialClass;/600614154, 600614154

There is no suspicious logging output - neither on server, nor on client. All HTTP-responses have return code 200.

My current workaround

I am going to try to create transfer objects as a copy of my SerialClass - those transfer objects will look exactly the same, but will not have the @Entity annotation.

Alternatively I could try to use the RequestFactory (thanks to @Hilbrand for the hint).

I really don't know how to solve that problem and I'm really thankful about any suggestions, hints, tips, links, etc.

slartidan
  • 20,403
  • 15
  • 83
  • 131
  • We just debugged through the gwt serializer and found out, that it could be a problem with our classpath. It seems like the servlets have to be in the same classloader as the `.gwt.rpc` files, otherwise it probably will switch to legacy mode and entities cannot be serialized anymore. I'm trying to change my classpaths and retry to run the application. – slartidan Mar 08 '11 at 13:56
  • The problem seems to be, that our code consists of several war files, that are deployed separately. The generated .gwt.rpc files are not available in the servlet context and therefore the legacy mode is used. We are testing a workaround with a patch of "RemoteServiceServlet" - although pathing the gwt-servlet.jar seems not to be a good way of doing things... – slartidan Mar 15 '11 at 11:56

6 Answers6

3

With GWT RPC you can't serialize any class that contains code that can't be compiled to JavaScript and as you suggest the way to go forward is creating transfer objects.

An alternative is to use the GWT 2.1 RequestFactory, see also this article http://blog.ltgt.net/gwt-211-requestfactory. But it's a different both on client/server side than RPC so you need to refactor the client/server side implementation, which could cost more time than writing transfer objects.

Thomas Broyer
  • 64,353
  • 7
  • 91
  • 164
Hilbrand Bouwkamp
  • 13,509
  • 1
  • 45
  • 52
  • Thanks for your answer. The RequestFactory could indeed be an alternative to the transfer objects. But I don't think, that GWT has a general problem with annotations - my example works fine if I use the `javax.persistence.PersistenceContext` annotation instead of `javax.persistence.Entity` (which is really weird, isn't it?) – slartidan Jan 11 '11 at 10:16
  • True, GWT has no problem with annotations just as you say. GWT uses annotations itself. But with annotations it's tricky because it's difficult to see how they depend on other classes. And as soon as a class or has no source available or uses code (like a stream) that can't be compiled into JavaScript it's a dead end. – Hilbrand Bouwkamp Jan 11 '11 at 15:03
  • I checked the annotation source file of `javax.persistence.Entity`, but it seams to have no critical import (just to annotation based things in `java.lang`). http://www.docjar.com/html/api/javax/persistence/Entity.java.html – slartidan Jan 12 '11 at 10:14
  • With GWT RPC you can't serialize any class that contains code that can't be compiled to JavaScript : yes, you can have annotations that cannot be compiled. – koma Dec 19 '11 at 09:05
1

I have mentioned how to use JPA 2.0 entities at GWT layer at my blog. And also, I have a created a eclipse project to simulate your scenario. You can download it by using this link . I have used GWT 2.2, if your gwt version is below 2.1 , then you should also add gwt-java-math to your project.

Gursel Koca
  • 20,940
  • 2
  • 24
  • 34
1

Ok, we found a solution! Thanks for everyone that helped me!

GWT was unable to serialize the objects of my annotated class, because the .gwt.rpc-files were not accessible via servlet context.

The solution was to create just one war file containing all javascript, html and rpc resources. This war file now also contains the servlet definitions (in the web.xml). Our java code is deployed in seperate modules (jar files), which are referenced by that war file.

slartidan
  • 20,403
  • 15
  • 83
  • 131
0

A work-a-round:

You need to provide sources of used annotations to be compiled by GWT compiler.

Just create special source directory, which will be used for GWT-compilation only, and copy there the sources of annotations.

Danubian Sailor
  • 1
  • 38
  • 145
  • 223
  • Thanks for your answer. I tried that before, but it didn't work. Just to be 100% sure I now tried it again: 1. I created a copy of `javax.persistence.Entity` and put the sources in the same source folder as my SerialClass 2. I double checked, that this source folder is in front of my libraries in my class path 3. I recompiled, redeployed, retested - but sadly without success. :| – slartidan Jan 11 '11 at 11:00
  • Do you have any error messages? I've seen such tricks in one project I was involved in. – Danubian Sailor Jan 11 '11 at 11:23
  • Sadly I don't have any error messages. All HTTP-Responses have return type 200, there is no suspecious logging output on the server and firebug is not logging anything unnormal. – slartidan Jan 11 '11 at 11:33
  • And you have successfully compiled class with your annotation using GWT compiler? – Danubian Sailor Jan 11 '11 at 11:43
  • Oh, I see another potential problem. If you take your entity from hibernate Session or whatever, you usually have proxy class, not class itself (or class contains proxies in place of collections). The entity must be detached from session, sometimes cleared by copying constructor or tool like Dozer. Log what class your server is really sending. – Danubian Sailor Jan 11 '11 at 11:49
  • Indeed this could also produce similar problems - but in my example I'm creating the objects with default java code. I'm calling `new SerialClass()` in `GreetingServiceImpl` and I don't have any collections (just that one field called "id"). The data sent to the browser is exactly the same in both cases - but somehow the deserialization in JavaScript is not working in the second case... Thanks for your patience, btw ;] – slartidan Jan 11 '11 at 11:54
0

There is no need to create copies of your value-objects. I encountered such problem before. I've uploaded a application skeleton to help you get started(minus libraries). Let me know if you cannot use SVN.

zawhtut
  • 8,335
  • 5
  • 52
  • 76
0

The way I had handled this was by creating DTO's or value objects. GWT requires source files on the client side. I Don't think there is any way around it.

allthenutsandbolts
  • 1,513
  • 1
  • 13
  • 34