XDR
XDR

Reputation: 4470

Grails 2.5.0 controller command object binding after accessing request.JSON in a filter

In a Grails 2.5.0 controller action method, it seems like the properties in the HTTP JSON body will not be used for command object binding if request.JSON has been accessed in a filter.

Why is that? It doesn't make any sense to me.

Is there any way to allow request.JSON to be used in a filter, and also for command object binding?

Upvotes: 4

Views: 1266

Answers (1)

Shashank Agrawal
Shashank Agrawal

Reputation: 25797

Yes, this is the default behavior of Grails while it comes to data binding with request body. When you read the request body via request.JSON in your filter then the corresponding input stream will be closed or gets empty. So, now Grails can't further access that request body to bind to the command object.

So, you can either access the request body on your own in the filter or can use it with the command object but can't both.

From Binding The Request Body To Command Objects heading http://grails.github.io/grails-doc/2.5.0/guide/theWebLayer.html#dataBinding:

Note that the body of the request is being parsed to make that work. Any attempt to read the body of the request after that will fail since the corresponding input stream will be empty. The controller action can either use a command object or it can parse the body of the request on its own (either directly, or by referring to something like request.JSON), but cannot do both.

So, what are you trying to achieve is not possible directly. But, you can do something different. In your filter, read the incoming request body and store into the params or session (if filter passes the request to controller) and then manually bind the parameter in action:

MyFilters.groovy

class MyFilters {

    def filters = {
        foo(/* your filter */) {
            before = {
                // Your checks
                Map requestData = request.JSON as Map
                session.requestData = requestData
                return true
            }
        }
    }
}

Now, in your controller action, instead of doing:

class MyController {

    def fooAction(MyCommandObject object) {
    }
}

Do something like this:

class MyController {

    def fooAction() {
        MyCommandObject object = new MyCommandObject(session.requestData)
        // Clear from session to clear up the memory
        session.requestData = null
    }
}

Update: The above solution, I've provided will work well but is not clean. @JoshuaMoore provided a link with a cleaner solution Http Servlet request lose params from POST body after read it once.

Upvotes: 3

Related Questions