Archive

Posts Tagged ‘frustration’

JSON conversion and request thread reuse

December 18th, 2009

Wrapping up (I hope) my experience with custom JSON conversions in Grails… The day before we were supposed to hit a major release milestone last week, I finally caught sight of a random bug that had been driving us nuts. For some AJAX requests, seemingly at random, the object that has the transient properties was not being rendered with them. Instead, it had only the regular, persistent properties and full representations of its associated objects rather than just the normal stubs of related objects with just the type and id. In other words, it was using deep JSON rendering, and this was overriding the custom JSON ObjectMarshaller that we had set for the class. But why was it doing it seemingly at random? This is where luck and experience combined to make the solution clear rather quickly and avoided some painful slogging through request handling on the server.

The luck part was that I remembered seeing a checkin from a teammate a couple of weeks ago where he got rid of direct use of a grails.converters.deep.JSON object (which is deprecated) and instead switched to a normal grails.converters.JSON object with a use('deep') statement:

def get = {
def o = OurClass.get(params.id);
JSON.use("deep")
render(contentType: "application/json", text: o as JSON)
}

This change was in a different controller for a different domain object though. Why was it affecting our other domain class? That’s where the experience part came in. A few years ago I had to track down why hibernate transactions would fail seemingly at random in another web app when running under JBoss. I could see why an initial transaction would fail (we’d get a timeout and not rollback properly), but there was no reason why later requests would cause failures. That’s when I discovered the downside of request thread pooling. Under most web contains, HTTP requests are handled by a pool of reusable threads. That means changes to thread local variables stick around between requests unless explicitly reset. In the case of the Hibernate bug, since the session was not getting closed properly, it wasn’t getting fully reset and cleared out, so subsequent requests that used that thread were getting the old session and failing because there was no way to get it back to a good state.

For the current JSON conversion bug, the JSON.use method was calling ConvertersConfigurationHolder.setTheadLocalConverterConfiguration(...), thus making the deep converter stick around for that thread. So when future requests came in to any controller on that thread, all JSON conversion calls were made with the deep configuration.

The solution is straightforward. Use the JSON.use(String, Closure) call instead when you want to make a deep call:

def get = {
def o = OurClass.get(params.id);
JSON.use("deep") {
render(contentType: "application/json", text: o as JSON)
}
}

This sets the configuration only for the closure, saving you from thread-based side effects later on.

Uncategorized , , ,

When dynamic programming backfires

November 20th, 2009

I love Groovy’s meta-programming capabilities.  Duck typing, DSLs, ExpandoMetaClass… it’s all great until you blow your arm off with them and spend two hours picking the pieces back up.  Such was my experience today as I was trying to set up my first unit test for a Grails controller.  I needed to pass in some parameters.  As I just wrote in my last post, the grails user guide has information on integration testing controllers, but nothing more than a brief mention of the ControllerUnitTestCase.  Unfortunately, searching for phrases like “grails unit test controller” on Google turn up posts from last Fall, before the ControllerUnitTestCase was released with Grails 1.1.  Don’t ask me why I didn’t just search for ControllerUnitTestCase from the start.  20/20 hindsight.

Working with what I could find, I came across a blog post from March 2008 that covered integration testing with controllers, much like the grails User Guide.  It at least had some explicit examples of how to pass in parameters, so I hoped the approach would work with my ControllerUnitTestCase implementation.  Using the code snippets in the post as a guide, I setup my test something like this:

controller.request.params = [layoutType:'filmstrip',compKey:'testKey']
controller.create()

This looks good, right?  The test scaffolding connects the injected params property of the controller with the params property of the request.  Should work like a charm.

And so started my descent into WTF Land.

The tests compiled and ran fine, except that no params were getting passed through to the controller.  I assumed that the old documentation for integration testing no longer exactly applied for the new unit test setups.  Eventually I dug through enough of ControllerUnitTestCase, MvcUnitTestCase, and MockUtils that I figured out there was a way to get direct access to the params property of the controller.  “Makes sense,” I thought, “sort of a mini-mock.  Who needs the request for a unit test?”  Great, so let’s try this:

controller.params = [layoutType:'filmstrip',compKey:'testKey']
controller.create()

Run again and…

groovy.lang.ReadOnlyPropertyException: Cannot set readonly property: params for class: YourController

Erk.  Closer inspection of grails.test.MockUtils.addCommonWebProperties() reveals how the params property is added to the controller class with only a get method.  Okay, so we can still manipulate the map once we get it.  One more try:

controller.params.putAll([layoutType:"filmstrip",compKey:'testKey'])
controller.create()

Success!  Finally, information is going where it needs to be.  I later realized that section 9.2 of the user guide does actually show an example similar to this, except that it sets each item on params individually:

def controller = new AuthenticationController()
controller.params.login = "marcpalmer"
controller.params.password = "secret"
controller.params.passwordConfirm = "secret"
controller.signup()

“Oh well,” I say to myself, “at least I got it working.  I’d better post a comment on that old blog post so that others know the new way to set parameters.”  I returned to the blog page, moved down to the comments section… and saw that someone else had posted a comment just last month thanking the author for the good information.  Wait a second… you normally don’t thank someone if their examples don’t work.  So I scrolled up and took a closer look at the examples again:

controller.request.parameters = [sender:'me',msg:'test']
controller.create()

Anyone with a better eye for detail than me see the difference that sent me down the rat hole? It’s request.parameters, not request.params as I had entered.  For the 100th time today, Doh!

But wait a second (or an hour, as the case may be)… If I was calling request.params and there is no params property, how did my test run at all?  Dig, dig, dig… It turns out that the request is a GrailsMockHttpServletRequest object.  Scanning through that class, I see the ever so powerful and ever so dangerous setProperty(String name, value) override.  If you try to set a property that doesn’t exist, it adds the value as an entry in the request’s attributes map.  So the test scaffolding was perfectly happy with my request.params call.  It nicely tucked my params map away in the attributes and continued on its way.

Sigh…it almost makes me miss compile-time method checking… but not quite.

Uncategorized , ,