1

I'm trying to use JPA with GWT.

My serviceImpl calls

UserDAO.exists(user);

When I run a test case, which calls the same method, with the same parameters, it runs ok. When I do the RPC call, if fails horribly (error at the end).

When I rename persistence.xml to someothername.xml, I get the SAME error, so I'm inclined to think that GWT (in development mode BTW), is NOT reading my persistence.xml.

The error:

Starting Jetty on port 8888
   [WARN] Exception while dispatching incoming RPC call
com.google.gwt.user.server.rpc.UnexpectedException: Service method 'public abstract hobarrera.client.dto.main.UserRegDTO hobarrera.client.services.AuthService.selfRegisterUser(java.lang.String,java.lang.String,java.lang.String,java.lang.String) throws hobarrera.client.exceptions.MyCustomizedException' threw an unexpected exception: java.lang.ExceptionInInitializerError
 at com.google.gwt.user.server.rpc.RPC.encodeResponseForFailure(RPC.java:378)
 at com.google.gwt.user.server.rpc.RPC.invokeAndEncodeResponse(RPC.java:581)
 at com.google.gwt.user.server.rpc.RemoteServiceServlet.processCall(RemoteServiceServlet.java:188)
 at com.google.gwt.user.server.rpc.RemoteServiceServlet.processPost(RemoteServiceServlet.java:224)
 at com.google.gwt.user.server.rpc.AbstractRemoteServiceServlet.doPost(AbstractRemoteServiceServlet.java:62)
 at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
 at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
 at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
 at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:362)
 at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
 at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
 at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:729)
 at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:405)
 at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
 at org.mortbay.jetty.handler.RequestLogHandler.handle(RequestLogHandler.java:49)
 at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
 at org.mortbay.jetty.Server.handle(Server.java:324)
 at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:505)
 at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:843)
 at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:647)
 at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:211)
 at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:380)
 at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:395)
 at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:488)
Caused by: java.lang.ExceptionInInitializerError
 at hobarrera.server.DAO.EntityManagerFactory.createEntityManager(EntityManagerFactory.java:13)
 at hobarrera.server.DAO.UsuarioDAO.userNameExists(UsuarioDAO.java:52)
 at hobarrera.server.services.AuthServiceImpl.selfRegisterUser(AuthServiceImpl.java:60)
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
 at java.lang.reflect.Method.invoke(Method.java:616)
 at com.google.gwt.user.server.rpc.RPC.invokeAndEncodeResponse(RPC.java:562)
 ... 22 more
Caused by: javax.persistence.PersistenceException: No resource files named META-INF/services/javax.persistence.spi.PersistenceProvider were found. Please make sure that the persistence provider jar file is in your classpath.
 at javax.persistence.Persistence.findAllProviders(Persistence.java:167)
 at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:103)
 at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:83)
 at hobarrera.server.DAO.EntityManagerFactory$RealEntityManagerFactoryContainer.<clinit>(EntityManagerFactory.java:9)
 ... 30 more
[ERROR] 500 - POST /desarrollonew/greet (0:0:0:0:0:0:0:1) 57 bytes
   Request headers
      Host: localhost:8888
      User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.8) Gecko/20100216 Fedora/3.5.8-1.fc12 Firefox/3.5.8
      Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
      Accept-Language: en-us,en;q=0.5
      Accept-Encoding: gzip,deflate
      Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
      Keep-Alive: 300
      Connection: keep-alive
      Referer: http://localhost:8888/desarrollonew/hosted.html?desarrollonew
      Cache-Control: no-cache
      X-GWT-Permutation: HostedMode
      X-GWT-Module-Base: http://localhost:8888/desarrollonew/
      Content-Type: text/x-gwt-rpc; charset=utf-8
      Content-Length: 187
      Pragma: no-cache
   Response headers
      Content-Type: text/plain

[edit]
It seems GWT has it's own persistence.xml file somewhere (for internal use I guess). That's why renaming my persistence.xml to somethingelse.xml still gave the same error: The persistence.xml file which was being read was GWT's all the time.

So now my question is: How do I override it, force the usage of another one, or live without it?

WhyNotHugo
  • 9,423
  • 6
  • 62
  • 70

4 Answers4

2

Do you have the DataNucleus jars in WEB-INF/lib?

Pascal Thivent
  • 562,542
  • 136
  • 1,062
  • 1,124
  • Yes, as are their dependencies. It seems the problem resides elsewhere (edited my original post, so see there, plase). – WhyNotHugo Mar 06 '10 at 23:42
  • @Hugo Is this a GAE/J project or just GWT? – Pascal Thivent Mar 06 '10 at 23:53
  • It's just plain GWT with DataNucleus as a JPA implementation. – WhyNotHugo Mar 07 '10 at 00:51
  • I was unaware that all jars had to be in WEB-INF/lib but NOT in sub-folders. I had everything extremely tide as is: WEB-INF/lib/*, WEB-INF/lib/datanucleus/*, WEB-INF/lib/datanucleus/dependencies/*, etc... Moving everything to WEB-INF/lib/*. Subfolders should be usable. Helps keep thing tidy. Anyway, it was just ignorance on my part; thanks both who tried to help. – WhyNotHugo Mar 07 '10 at 02:26
0

You didn't add the JPA implementation in your classpath. Place in your classpath the jar of datanucleus (or toplink, or whatever you're using), which take care of entity manager creation.

Kartoch
  • 7,610
  • 9
  • 40
  • 68
  • It IS in the classpath, note that the error was the same with NO persistence.xml file, so even without knowing WHICH provider to look for the error was the same; hence, the error is not when finding the JPA implementation (DataNucleus BTW). – WhyNotHugo Mar 06 '10 at 23:44
0

Reference: http://code.google.com/webtoolkit/articles/using_gwt_with_hibernate.html

Why Hibernate objects can't be understood when they reach the browser world?

So what went wrong? Looking at the hosted mode console, you'll notice the warning message "Exception while dispatching incoming RPC call" was logged to the console. Selecting the warning message, the lower pane will display a rather long stack trace.

This is the part to pay attention to:

Caused by: com.google.gwt.user.client.rpc.SerializationException: Type 'org.hibernate.collection.PersistentSet' 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. at com.google.gwt.user.server.rpc.impl.StandardSerializationPolicy.validateSerialize(StandardSerializationPolicy.java:83) at com.google.gwt.user.server.rpc.impl.ServerSerializationStreamWriter.serialize(ServerSerializationStreamWriter.java:591)

The key here is the SerializationException that was thrown when we tried to load up and retrieve accounts.

So what exactly went wrong? Well, as you may have read in the GWT RPC docs, a SerializationException is thrown whenever a type transferred over RPC is not "serializable". The definition of serializable here means that the GWT RPC mechanism knows how to serialize and deserialize the type from bytecode to JSON and vice-versa. To declare a type as serializable to the GWT compiler, you can either make the type to be transferred over RPC implement the IsSerializable interface, especially created for this purpose, or implement the standard java.io.Serializable interface, provided that its members and methods consist of types that are also serializable.

In the case of the Account and Record Hibernate objects, we are implementing the Serializable interface, so these should work, shouldn't they?. As it turns out, the devil is in the details.

When you take an object and turn it into a Hibernate object, the object is now enhanced to be persistent. That persistence does not come without some type of instrumentation of the object. In the case of Hibernate, the Javassist library actually replaces and rewrites the bytecode for these objects by persistent entities to make the Hibernate magic work. What this means for GWT RPC is that by the time the object is ready to be transferred over the wire, it actually isn't the same object that the compiler thought was going to be transferred, so when trying to deserialize, the GWT RPC mechanism no longer knows what the type is and refuses to deserialize it.

In fact, if you were to look deeper to the earlier call to loadAccounts(), and step into the RPC.invokeAndEncodeResponse() method, you would see that the object we're trying to deserialize has now become an ArrayList of Account types with their java.util.Set of records replaced by the org.hibernate.collection.PersistentSet type.

Similar problems arise with other persistence frameworks, such as JDO or JPA, used on Google App Engine.

A potential solution would be to replace the types once more in the opposite direction before returning through the server-side RPC call. This is doable, and would solve the problem we encountered here, but we wouldn't be out of harm's way just yet. Another great benefit of using Hibernate is the fact that we can lazily load associated objects when needed. For example, on the server-side, I could load an account, change it around, and only load its associated records when a call to account.getRecords() and some action on those records was taken. The special Hibernate instrumentation will take care of actually fetching the records when I make the call, making them available only when really needed.

As you may imagine, this will translate to strange behaviour in the GWT RPC world where these Hibernate objects traveled from the Java server-side to browser land. If a GWT RPC service tries to access associations lazily, you might see something like a LazyInitializationException being thrown.

kostas trichas
  • 2,923
  • 7
  • 28
  • 37
-1

Since this is like the nth time I'm going to suggest switching to an external server for GWT, let me quote my previous answer (please read the full answer for a more in-depth explanation of GWT's embedded Jetty issues):

I'd recommend just switching to an external Java server (like Tomcat, which you seem to have installed and which works with your configuration) - much less problems, easier than trying to work with the crippled Jetty that comes with GWT.

The instructions can be found in the docs. If you stick with GWT's Jetty, you will only run into more issues in the future.

It's still true, though - the Jetty that comes with GWT is known to be problematic. Read through the docs for instructions on how to use an external server with GWT (easy procedure, IMHO) - no drawbacks and no problems with strange errors/exceptions.

Community
  • 1
  • 1
Igor Klimer
  • 15,321
  • 3
  • 47
  • 57
  • I've solved the problem; though I'll see what I find about these issues you mention. As a drawback, during early stages, deploying to tomcat takes much more time. – WhyNotHugo Mar 07 '10 at 02:24
  • I'll make the same comment as for your previous answer: if you have something to say or to show about "known" problems with Jetty, do it. If not, then I consider this as FUD. – Pascal Thivent Mar 07 '10 at 02:39
  • You are right, I've edited my previous answer (link in the answer above) to reflect this, hopefully it's less FUD and more up to the usual (high) standard on SO :) – Igor Klimer Mar 07 '10 at 03:42