Using GWT
, I have deployed my server into Tomcat. This works fine, but when GWT
throws an exception, a Popup shows the client the
This works as expected, because the optimaziation will remove the method and class names.
You can compile as PRETTY or DETAILED, to get better readable Stacktraces.
There is also the posibility to emulate Stacktraces.
<set-property name="compiler.emulatedStack" value="true"/>
<set-configuration-property name="compiler.emulatedStack.recordLineNumbers" value="true"/>
<set-configuration-property name="compiler.emulatedStack.recordFileNames" value="true"/>
This is a bad idea for production use, because it will increase the size of your javascript.
update: I see a Exception_FieldSerializer Exception.
Do you try to serialize something, which is not serializable?
Classes, without a default constructor are not serializable, Classes which aren't within your client or shared package. If you try to serialize an Exception this can be the problem.
Why?
As Christian Kuetbach said, this is the difference between running in DevMode (where your code executes in Java) and prod mode (where your code has been compiled to JavaScript and optimized, which includes renaming classes and methods).
How do you fix this?
You don't. Generally speaking, showing stack traces to your users is not a good idea. Much better is to log the exception by sending it to the server (e.g. use java.util.logging
to log, along with the SimpleRemoteLogHandler
to send the log to the server, where it'll be logged using java.util.logging
).
There are ways to deobfuscate the stack trace though, and the RemoteLoggingServiceImpl
servlet can be configured to do it automatically.
See http://code.google.com/p/google-web-toolkit/wiki/WebModeExceptions for the gory details.
If you can't or don't want to use remote logging, then you can "manually" deobfuscate the stack trace: look at the file in WEB-INF/deploy
(default location, can be changed by passing -deploy
to the GWT compiler) corresponding with the permutation (same name as the *.cache.*
file loaded by the browser), it'll tell you which Java method the Le
method originates from.
But you already have the source file name and line number, so you don't really need it, right?
It's a bit difficult to find all the information in the GWT docs, which you need to setup de-obfuscated logging, so here's the short version:
In your module file (.gwt.xml), add:
<inherits name="com.google.gwt.logging.Logging"/>
<set-property name="gwt.logging.simpleRemoteHandler" value="ENABLED" />
<set-property name="compiler.stackMode" value="emulated" />
<set-configuration-property name="compiler.emulatedStack.recordLineNumbers"
value="true" />
On the client side, use something like
import java.util.logging.Logger;
private static Logger rootLogger = Logger.getLogger("");
...
rootLogger.log(Level.SEVERE, "My message", e);
You don't have to create a RemoteLoggingServiceAsync
instance on the client side - it's used automatically by the logger, because we specified <set-property name="gwt.logging.simpleRemoteHandler" value="ENABLED" />
.
On the server side, configure the RemoteLoggingServiceImpl. You will have to tell it, where it finds the symbolMaps, which will be generated when compiling with the GWT compiler argument -extra /path/to/myExtraDir
. I personally use the approach to override RemoteLoggingServiceImpl, to allow specifying the directory from web.xml's <init-param>
s [*]
package mypackage.server;
public class ConfigurableRemoteLoggingServiceImpl extends RemoteLoggingServiceImpl {
@Override
public void init(final ServletConfig config) throws ServletException {
super.init(config);
final String symbolMapsDirectory =
config.getInitParameter("symbolMapsDirectory");
setSymbolMapsDirectory(symbolMapsDirectory);
}
}
In web.xml
, register it like
<servlet>
<servlet-name>remoteLogging</servlet-name>
<servlet-class>mypackage.server.ConfigurableRemoteLoggingServiceImpl</servlet-class>
<init-param>
<param-name>symbolMapsDirectory</param-name>
<param-value>/path/to/myExtraDir/mymodulename/symbolMaps</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>remoteLogging</servlet-name>
<url-pattern>/mymodulename/remote_logging</url-pattern>
</servlet-mapping>
Replace /path/to/myExtraDir
, mymodulename
and mypackage
with your own values, and don't forget to call the GWT compiler with the -extra argument (Note that you you don't have to use -style PRETTY
or DETAILED, it also works with OBF). Keep all generated symbolMaps: Without them, deobfuscation will not work. As every new version gets a unique name automatically, you can collect them all in a safe central place when building.
[*] And I really, really wonder, why RemoteLoggingServiceImpl doesn't implement that itself!