Spring Web Flow and jQuery Caching

A while ago as I was helping a client re-write a computationally heavy backend system that had a Spring Web Flow wizard interface. The system would retrieve all orders of gas shipments for that day and then run calculations on what orders would be able to ship that day based on a number of various factors. Because the retrieval and calculations could potentially take several minutes, the system used Ajax calls to kick off asynchronous processes for retrieval and calculations, along with polling to deliver progress messages to the user in a modal window. During testing we noticed that our calls to kick off the processes were not always picking up changes as jQuery defaults cache to true for Ajax.

Once we set cache: false in the AJAX call.

$.ajax({  
    url : ...,
    cache: false,
    success : function(data) {
        ...
    }
});

We saw the following helpful stack trace:

Caused by: org.springframework.webflow.execution.FlowExecutionException: Exception thrown in state ‘wizard’ of flow ‘wizardFlow'
at org.springframework.webflow.engine.impl.FlowExecutionImpl.wrap(FlowExecutionImpl.java:571)
at org.springframework.webflow.engine.impl.FlowExecutionImpl.resume(FlowExecutionImpl.java:265)
at org.springframework.webflow.executor.FlowExecutorImpl.resumeExecution(FlowExecutorImpl.java:169)
at org.springframework.webflow.mvc.servlet.FlowHandlerAdapter.handle(FlowHandlerAdapter.java:183)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:900)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:827)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
... 52 more
<strong>Caused by: java.lang.IllegalArgumentException: The expression string to parse is required and must not be empty
at org.springframework.util.Assert.hasText(Assert.java:162)</strong>
at org.springframework.binding.expression.spel.SpringELExpressionParser.parseExpression(SpringELExpressionParser.java:72)
at org.springframework.webflow.mvc.view.AbstractMvcView.addEmptyValueMapping(AbstractMvcView.java:472)
at org.springframework.webflow.mvc.view.AbstractMvcView.addDefaultMappings(AbstractMvcView.java:454)
at org.springframework.webflow.mvc.view.AbstractMvcView.bind(AbstractMvcView.java:373)
at org.springframework.webflow.mvc.view.AbstractMvcView.processUserEvent(AbstractMvcView.java:216)
at org.springframework.webflow.engine.ViewState.handleEvent(ViewState.java:226)
at org.springframework.webflow.engine.ViewState.resume(ViewState.java:196)
at org.springframework.webflow.engine.Flow.resume(Flow.java:545)
at org.springframework.webflow.engine.impl.FlowExecutionImpl.resume(FlowExecutionImpl.java:261)

This was caused by jQuery’s default solution to preventing browsers from caching AJAX requests which is enabled by setting cache: false in the settings of the ajax request, which adds the request param “_” with the request timestamp to the request url.

...app…/wizardFlow.html?execution=e1s1&amp;_eventId=retrieve&amp;gasDay=11/25/2012&amp;_=1365712827950

Spring Web Flow didn’t know what to do with the “_” request parameter when was parsing the request parameters to call the method in our action that handled that sequence in the flow:

public void retrieve(RequestContext requestContext, WizardStateHolder stateHolder, ProcessingStateHolder processingStateHolder, MessageContext messageContext, String gasDay)

In order to resolve this, we registered our own beforeSend method that would replace the “_” request parameter name that jQuery defaulted to with “jqueryCache” as the parameter name.

$.ajaxSetup({
    beforeSend : function(xhr, setting) {
        var url = setting.url;
        url = url.replace(&quot;&amp;_=&quot;, &quot;&amp;jqueryCache=&quot;);
        setting.url = url;
    }
});

This solution allowed jQuery to bypass the browser caching of requests and Web Flow to ignore the request parameter. By registering it as part of ajaxSetup, we were also able to avoid repeating the code wherever we needed to set cache: false, so that developers only had to set cache: false if the use case required it while not worrying about Web Flow.

About the Author

Rob Boler profile.

Rob Boler

Sr. Consultant

Rob has always been interested in computers, and remembers first attempting programming a hangman game on an Apple IIE in grade school. He has over 15 years of software development experience using Java / Spring, primarily in the transportation and defense industries. He prides himself as being able to solve complex software problems, while also being able to lead small teams of developers. Rob has a wide range of project experience ranging from dynamic web applications to high volume message processing, to applying Big Data technologies for data pattern analysis.

One thought on “Spring Web Flow and jQuery Caching

  1. Ben says:

    Another solution is to create a REST endpoint that accepts a timestamp + random number value and then every AJAX request is guaranteed unique. You could also use a UUID. You don’t have to do anything with that REST argument (not query string param) on the server side, it just has to exist to make the request unique looking. This prevents any caching from ruining your day.

    I have run into situations where the caching was not taking place on my server but rather infrastructure in between (that no one would own up to or explain the how/why of–there was also potentially a bug in IE8’s AJAX engine causing the same problem, for example).

Leave a Reply

Your email address will not be published. Required fields are marked *

Related Blog Posts
Android Development for iOS Developers
Android development has greatly improved since the early days. Maybe you tried it out when Android development was done in Eclipse, emulators were slow and buggy, and Java was the required language. Things have changed […]
Add a custom object to your Liquibase diff
Adding a custom object to your liquibase diff is a pretty simple two step process. Create an implementation of DatabaseObject Create an implementation of SnapshotGenerator In my case I wanted to add tracking of Stored […]
Keeping Secrets Out of Terraform State
There are many instances where you will want to create resources via Terraform with secrets that you just don’t want anyone to see. These could be IAM credentials, certificates, RDS DB credentials, etc. One problem […]
Validating Terraform Plans using Open Policy Agent
When developing infrastructure as code using terraform, it can be difficult to test and validate changes without executing the code against a real environment. The feedback loop between writing a line of code and understanding […]