Request vs RequestContext
Only a Request will receive an invocation failure, not a RequestContext
GWT developers new to RequestFactory may get caught out by the fact that a RequestContext’s Receiver does not respond to server-side exceptions thrown while processing the request. A RequestContext will only receive constraint violations or general/transport failures.
It’s important to understand the difference between a Request and a RequestContext. A RequestContext allows you to bundle up multiple requests for more efficient data transportation – done by calling fire() from the RequestContext rather than from each individual Request. However as Thomas Broyer explains: “A RequestContext is not synonymous to a transaction … it’s more like a batching mechanism”. So when firing from a RequestContext you’ll still need to attach receivers to each individual request if you want to listen for server-side exceptions thrown during invocation processing.
Resending Request Data after a Server-Side Error
The procedure for resending data to the server differs according to the type of error:
- For constraint violations and general/transport errors (ie anything caught by RequestContext) – simply call fire() again
- For invocation failures – Create a new request context, copy the proxy’s values into a new mutable proxy and call fire() on the new request
GWT does not allow either a Request or RequestContext to be fired more than once, unless the RequestContext caught the error. Requests are locked and the proxies remain frozen and are only unlocked/defrosted in the case of a constraint violation/general failure to allow the application to resubmit its request.
Although it may seem like an oversight to not unlock a request after an invocation failure, Mr Broyer explains that this is by design. He explains that it is safe to unlock after a constraint violation, as bean validation is done before any invocations are processed, whereas an invocation exception may be thrown at any stage of the processing.
However, resending a request after an invocation exception may be necessary for common tasks such as checking that a value is unique. As bean validation does not handle this by default, this kind of validation check may be done during the invocation processing. So for any validation done during processing, the only choice is to follow option #2; create a new mutable proxy and fire another request.
Copying a GWT Proxy
There currently exists no official way to automatically copy a GWT proxy. There’s an accepted issue – #5794 that tracks this much needed feature by proposing to add a RequestContext.copy() method. Copying a proxy can’t be done by simply cloning it; requests manage proxies by tracking changes made to them so that only the diffs are sent across the wire – not the whole object. To copy the values from a source proxy into a destination proxy, the destination must be made mutable (and therefore tracked).
There are 3 workarounds that are possible:
- Manually copy all the proxy values across to a new proxy
- Use the user-supplied workaround from issue #5794 to clone a proxy’s autobean – although apparently this only works for a ValueProxy or a simple EntityProxy with no nesting.
- Try out the patch for #5794 that’s currently being reviewed by Mr Broyer
Issue with Spring Roo
Developers creating applications based on Spring Roo’s GWT front
end must update the generated code to catch server failures
The developers from Spring have certainly been caught out – the GWT module for Spring Roo generates code that listens for failures on the RequestContext. Applications based on Spring-Roo’s GWT front end may be failing on the server and never reporting an error to the user. The front end merely navigates away from the edit screen and all data entry is then lost – the user none the wiser.
The solution is to update each save request to listen for server failures, which is relatively straight forward. If you want the user to be able to resend the data then it gets a little more complicated as the MVP design needs to be altered to accommodate the ability to create multiple requests (for example the CreateAndEditProxy activity is tied to a single request/proxy pair).