SerializationException when application is modified

87 views
Skip to first unread message

Óscar Frías Barranco

unread,
Jul 18, 2017, 12:15:23 PM7/18/17
to GWT Users
Hi.

When we modify the code of our GWT application, in particular the classes that travel through GWT calls, these exceptions are generated for many users for a few hours:

com.google.gwt.user.client.rpc.SerializationException: Type '.....' was not assignable to 'com.google.gwt.user.client.rpc.IsSerializable' and did not have a custom field serializer.For security purposes, this type will not be serialized.: instance = .....

We think that this is due to browsers caching the previous (old) code which is no longer aligned with the server code.  We have reviewed all HTTP headers related to caching and all of the are, we think, correctly configured.

So our plan is to force a reload of the browser page with a location.reload(true) when we detect that the SerializationException is being thrown at the server.  Any ideas about how to implement this easily?  Our code if full of AsyncCallback calls and we would like to avoid editing each one of them.  Is there a place where we could insert a client code that would be executed for every RPC call and that will call location.reload(true) if a SerializationException is thrown ?

Thanks!

Michael Joyner

unread,
Jul 18, 2017, 1:35:13 PM7/18/17
to google-we...@googlegroups.com

We use https://github.com/realityforge/gwt-cache-filter to help deal with caching issues.

--
You received this message because you are subscribed to the Google Groups "GWT Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-web-tool...@googlegroups.com.
To post to this group, send email to google-we...@googlegroups.com.
Visit this group at https://groups.google.com/group/google-web-toolkit.
For more options, visit https://groups.google.com/d/optout.

Óscar Frías Barranco

unread,
Jul 18, 2017, 2:15:49 PM7/18/17
to google-we...@googlegroups.com
We are following the recommendations on http://www.gwtproject.org/doc/latest/DevGuideCompilingAndDebugging.html#perfect_caching

But I am afraid that whatever the headers some browsers will cache some files anyway so we really need a way to force a reload of the web application when RPC calls return an exception.

Any ideas on how to implement this?


On Tue, Jul 18, 2017 at 7:34 PM, Michael Joyner <mic...@newsrx.com> wrote:

We use https://github.com/realityforge/gwt-cache-filter to help deal with caching issues.


On 07/18/2017 12:15 PM, Óscar Frías Barranco wrote:
Hi.

When we modify the code of our GWT application, in particular the classes that travel through GWT calls, these exceptions are generated for many users for a few hours:

com.google.gwt.user.client.rpc.SerializationException: Type '.....' was not assignable to 'com.google.gwt.user.client.rpc.IsSerializable' and did not have a custom field serializer.For security purposes, this type will not be serialized.: instance = .....

We think that this is due to browsers caching the previous (old) code which is no longer aligned with the server code.  We have reviewed all HTTP headers related to caching and all of the are, we think, correctly configured.

So our plan is to force a reload of the browser page with a location.reload(true) when we detect that the SerializationException is being thrown at the server.  Any ideas about how to implement this easily?  Our code if full of AsyncCallback calls and we would like to avoid editing each one of them.  Is there a place where we could insert a client code that would be executed for every RPC call and that will call location.reload(true) if a SerializationException is thrown ?

Thanks!

--
You received this message because you are subscribed to the Google Groups "GWT Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit+unsub...@googlegroups.com.
To post to this group, send email to google-web-toolkit@googlegroups.com.

--
You received this message because you are subscribed to a topic in the Google Groups "GWT Users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/google-web-toolkit/Kt9DygTyQ-U/unsubscribe.
To unsubscribe from this group and all its topics, send an email to google-web-toolkit+unsub...@googlegroups.com.
To post to this group, send email to google-web-toolkit@googlegroups.com.

Michael Joyner

unread,
Jul 18, 2017, 3:31:31 PM7/18/17
to google-we...@googlegroups.com

As far as trying to catch the rpc exception, you might try setting a global uncaught exception handler then seeing if you can trap them via that method. We have switched to using resty-gwt/json here and longer use the built in GWT-RPC serializer.

You could try putting a ?=versionNumber at the end of the nocache js include in the main html file. (of course bumping the version number each release or what not). This should force a reload of the main js when reloading the main html file. I do know at one time there was a bug in the compiled output in version 2.7 in regards to timestamps for the output js file which would cause this issue on consistent basis. The only thing I can think of is that the html file is being cached and not reloaded perhaps or that the timestamp on the nocache or main html file is screwy.

To unsubscribe from this group and stop receiving emails from it, send an email to google-web-tool...@googlegroups.com.
To post to this group, send email to google-we...@googlegroups.com.

Jens

unread,
Jul 18, 2017, 5:02:43 PM7/18/17
to GWT Users

We think that this is due to browsers caching the previous (old) code which is no longer aligned with the server code.  We have reviewed all HTTP headers related to caching and all of the are, we think, correctly configured.

The issue is that your users have downloaded your GWT app and are actively using it while you make an update of that app. Because the app is already downloaded it will make requests with different, outdated serialization information. No caching header can help here.

You are correct that you need to detect the server upgrade and then notify the user that a new version of your app is available and finally reload the browser. At work we do the same and it works pretty well. Basically two things can go wrong:

1.) Downloading a split points (GWT.runAsync)
2.) GWT-RPC requests

So in the first case if GWT.runAsync() fails we simply assume the app has been updated and act accordingly. IMHO downloading a split point should never ever fail unless you do not have internet access and get a StatusCodeException with status code 0. So I think the assumption is relatively safe to make.

For the second case (and any other server requests outside of GWT-RPC, e.g. manually requesting a different servlet) we use a HTTP header containing the app version the user has downloaded. That version will be send with every server request, in case of GWT-RPC we use a custom RpcRequestBuilder to add the header. To set a custom RpcRequestBuilder for your GWT-RPC service you need to hard cast the async service to ServiceDefTarget and then call a setter. The app version itself is embedded into the host page, e.g. index.html, which we generate dynamically on the server. We deploy index.template and app.nocache.js and inline app.nocache.js on the server into the template. The template also has some replacement strings for other information, like the app version. The app version itself can be as easy as the hash of the context root on your server, e.g. hash(/app_20170718). A servlet filter can then check the version and send back a HTTP status code to indicate that the app has been updated.

Sadly you can not really use a custom RpcRequestBuilder to catch GWT-RPC exceptions because the response hasn't been deserialized yet. So if you can not use the version approach described above, maybe you can search for "EX" and "com.google.gwt.user.client.rpc.SerializationException" in the response text but that seems like a poor workaround. Ideally you would do some clever refactoring and introduce a base class for all your AsyncCallback, so you have a central place to handle this exception.

-- J.

Vassilis Virvilis

unread,
Jul 19, 2017, 3:47:29 AM7/19/17
to google-we...@googlegroups.com
Hi,

Here is what we do.

1. We don't use gwt-rpc. We use resty-gwt instead.
2. resty-gwt has the option to register a global request callback handler in order to intercept all http requests. See resty-gwt Defaults.setDispatcher() for details
3. On every new build of the gwt script I autogenerate (via ant build file) a timestamp file named version.txt
4. On every service call/request the server side reads the version.txt that resides at gwt war directory and adds a http header e.g myapp-version: 20170719-123841
5. The gwt client side global request callback handler reads the header and if it differs from the previous one it forces a hard reload.

Actually in my case step 5 is more like:
5a) Inform the user that a newer version is available and the application will reload (only on ok button) but his current work/state is saved in localstorage
5b) on ok click reload(true)
5c) on reload check localstorage and if state exists load it from there

I don't know if in gwt-rpc it is possible to intercept all request calls as in rest-gwt. If it is possible a similar strategy could also be employed in that case.

With this scheme and with additional headers you can create custom notifiers for other events i.e. configuration changed, database changed etc.

Hope that helps.


--
You received this message because you are subscribed to the Google Groups "GWT Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit+unsub...@googlegroups.com.
To post to this group, send email to google-web-toolkit@googlegroups.com.
Visit this group at https://groups.google.com/group/google-web-toolkit.
For more options, visit https://groups.google.com/d/optout.



--
Vassilis Virvilis

Thomas Broyer

unread,
Jul 19, 2017, 6:22:10 AM7/19/17
to GWT Users


On Tuesday, July 18, 2017 at 6:15:23 PM UTC+2, Óscar Frías Barranco wrote:
Hi.

When we modify the code of our GWT application, in particular the classes that travel through GWT calls, these exceptions are generated for many users for a few hours:

com.google.gwt.user.client.rpc.SerializationException: Type '.....' was not assignable to 'com.google.gwt.user.client.rpc.IsSerializable' and did not have a custom field serializer.For security purposes, this type will not be serialized.: instance = .....

We think that this is due to browsers caching the previous (old) code which is no longer aligned with the server code.  We have reviewed all HTTP headers related to caching and all of the are, we think, correctly configured.

So our plan is to force a reload of the browser page with a location.reload(true) when we detect that the SerializationException is being thrown at the server.

From a UX point of view, it's probably better to show an error (possibly with a button to reload the app) than forcibly reload, as that could possibly lead to losing data the user has entered.
This is what Google Groups is doing, and it allows users to copy their message before reloading, pasting and re-sending it.
 
Any ideas about how to implement this easily?  Our code if full of AsyncCallback calls and we would like to avoid editing each one of them.  Is there a place where we could insert a client code that would be executed for every RPC call and that will call location.reload(true) if a SerializationException is thrown ?

If your GWT.create() for the services are relatively centralized, you could implement wrappers that wrap the AsyncCallback before delegating to the real service.

I.e. from 

FooServiceAsync fooService = GWT.create(FooService.class);

to

FooServiceAsync fooService = new FooServiceAsyncWrapper();

with

class FooServiceAsyncWrapper implements FooServiceAsync {
  private final FooServiceAsync delegate = GWT.create(FooService.class);

  @Override
  public void doFoo(int param1, String param2, AsyncCallback<Bar> callback) {
    delegate.doFoo(param1, param2, new AsyncCallbackWrapper<Bar>(callback));
  }
}

class AsyncCallbackWrapper<T> implements AsyncCallback<T> {
  private final AsyncCallback<T> delegate;

  public AsyncCallbackWrapper(AsyncCallback<T> delegate) {
    this.delegate = delegate;
  }

  @Override
  public void onSuccess(T result) {
    delegate.onSuccess(result);
  }

  @Override
  public void onFailure(Throwable caught) {
    if (caught instanceof Xxx) {
      // handle failure
    } else {
      delegate.onFailure(caught);
    }
  }
}

Óscar Frías Barranco

unread,
Jul 20, 2017, 5:19:26 AM7/20/17
to google-we...@googlegroups.com
Hi.

Thanks a lot for you all your replies.  We have just noticed that the behavior of the RPC calls is different depending on whether the beans travelling through the wire implement Serializable or IsSerializable.

When they implement IsSerializable the onFailure(Throwable) method of the AsyncCallback contains a IncompatibleRemoteServiceException.  According to its Javadoc "The correct response to receiving an instance of this exception in the AsyncCallback.onFailure(Throwable) method is to get the application into a state where a browser refresh can be done."

On the other side, when they implement the generic Serializable method, the exception is the more generic StatusCodeException with a message "500 The call failed on the server; see server log for details".  This is too generic, it could be caused by any problems on the server, not just code changes requiring a reload.

So it looks like its better to implement IsSerializable rather than Serializable.

What do you think?  Am I missing something?


--
You received this message because you are subscribed to a topic in the Google Groups "GWT Users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/google-web-toolkit/Kt9DygTyQ-U/unsubscribe.
To unsubscribe from this group and all its topics, send an email to google-web-toolkit+unsub...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages