fields icon indicating copy to clipboard operation
fields copied to clipboard

Using g:render with model attribute set inside f:with tags throws java.util.EmptyStackException

Open denis111 opened this issue 10 years ago • 3 comments

<f:with..>
<g:render template="my-template" model="${[bean:'user',property:'name']}"/>
</f:with>

throws excepstion at:
Around line 80 of grails-app/taglib/grails/plugin/formfields/FormFieldsTagLib.groovy

77:            beanStack.push(beanPrefix)
78:         out << body()
79:     } finally {
80:            beanStack.pop()
81:     }
82: }

denis111 avatar Jun 11 '15 09:06 denis111

Could you please provide a sample application or unit test that reproduces this issue? Please also include the stacktrace of the exception.

ghost avatar Jun 11 '15 09:06 ghost

Here's the sample project https://drive.google.com/file/d/0B1TIQMQPXvOZemtpQWFUVV9ZeGs/view?usp=sharing . Just navigate to http://localhost:8080/fwith/my/index

denis111 avatar Jun 12 '15 07:06 denis111

I can confirm that this issue is still present in version 2.1.3 of the fields plugin. In my case the model attribute doesn't even matter. A simple <g:render template="something"/> already causes the exception.

Edit: I believe I have found to source of this problem. This is not necessarily an error in the fields plugin itself, but an implementation error in Grails (not sure which versions are affected, I'm using 3.1.x).

In FormFieldsTagLib#getBeanStack() there is a call to pageScope.hasVariable(STACK_PAGE_SCOPE_VARIABLE). The pageScope variable is of type GroovyPageBinding, which is a hierarchical data structure: with each call to <g:render>, a child pageScope is created with a reference to the parent scope. The Problem: the method hasVariable was never overloaded to consider the hierarchical data structure, which means it will only find variables from child scope, but the bean stack variable was set in the parent scope! Because of this hasVariable always returns false, which results in FormFieldsTagLib#getBeanStack() creating a new empty stack. Setting the page scope variable with the new stack actually works in the hierarchy and overrides the existing one, which finally results in an EmptyStackException because the stack was replaced by an empty one.

I will open an issue in the grails project for this error, as it does seem to be an error in the framework and not fields plugin.

I managed to fix the error in my application with the following groovy metaprogramming hack:

class BootStrap {
    def init = {

        FormFieldsTagLib.metaClass.getBeanStack = { getBeansStackPatched(delegate) }

    }

    private FormFieldsTagLib.BeanAndPrefixStack getBeansStackPatched(FormFieldsTagLib tagLib) {
        Map variables = tagLib.pageScope.variables

        if (!variables.containsKey(FormFieldsTagLib.STACK_PAGE_SCOPE_VARIABLE)) {
            variables[FormFieldsTagLib.STACK_PAGE_SCOPE_VARIABLE] = new FormFieldsTagLib.BeanAndPrefixStack()
        }

        return variables[FormFieldsTagLib.STACK_PAGE_SCOPE_VARIABLE]
    }
}

davidkron avatar Jan 13 '17 07:01 davidkron