Struts 2
  1. Struts 2
  2. WW-1273

freemarker 'parameters' model attribute - incorrect TemplateModel

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Critical Critical
    • Resolution: Fixed
    • Affects Version/s: WW 2.2.1, WW 2.2.2
    • Fix Version/s: 2.0.0
    • Component/s: Plugin - Tags
    • Labels:
      None
    • Environment:

      FreeMarker 2.3.4, 2.3.6; using recommended FreeMarker 'result type'

    • Flags:
      Important

      Description

      There seems to be a very nasty bug with FreeMarker, which still hasn't been fixed. To access url parameter values one should use 'parameters' variable (btw, this is not documented anywhere, eg, it's not on the 'FreeMarker' integration page in the list of other variable accessible from FreeMarker view).

      The problem with 'parameters' variable is that it seems like incorrect TemplateModel is currently used, specifically 'ArrayModel', while it should be 'HashModel' or smth similar. I'm a novice with FreeMarker, so it might also be something else, but one thing I confirmed is that FreeMarker supplied freemarker.ext.servlet.FreemarkerServlet exposes url parameters through RequestParameters attribute correctly and it is using HttpRequestParametersHashModel).

      This bug makes it currently impossible to access parameter values by name, eg, by using $

      {parameters.param1} to access 'param1' value in the url http://smth.com/test.action?param1=xxx. The above attempt will result in the following exception:

      ======================================
      Expecting a string, date or number here, Expression parameters.message is instead a freemarker.ext.beans.ArrayModel
      The problematic instruction:
      ----------
      ==> ${parameters.param1}

      [on line 8, column 13 in test.ftl]
      ----------

      Java backtrace for programmers:
      ----------
      freemarker.core.NonStringException: Error on line 8, column 15 in test.ftl
      Expecting a string, date or number here, Expression parameters.message is instead a freemarker.ext.beans.ArrayModel
      at freemarker.core.Expression.getStringValue(Expression.java:126)
      at freemarker.core.Expression.getStringValue(Expression.java:93)
      at freemarker.core.DollarVariable.accept(DollarVariable.java:76)
      at freemarker.core.Environment.visit(Environment.java:196)
      at freemarker.core.MixedContent.accept(MixedContent.java:92)
      at freemarker.core.Environment.visit(Environment.java:196)
      at freemarker.core.Environment.process(Environment.java:176)
      at freemarker.template.Template.process(Template.java:232)
      at com.opensymphony.webwork.views.freemarker.FreemarkerResult.doExecute(FreemarkerResult.java:130)
      at com.opensymphony.webwork.dispatcher.WebWorkResultSupport.execute(WebWorkResultSupport.java:101)
      at com.opensymphony.xwork.DefaultActionInvocation.executeResult(DefaultActionInvocation.java:312)
      at com.opensymphony.xwork.DefaultActionInvocation.invoke(DefaultActionInvocation.java:207)
      at com.opensymphony.xwork.interceptor.DefaultWorkflowInterceptor.doIntercept(DefaultWorkflowInterceptor.java:137)
      at com.opensymphony.xwork.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:81)
      at com.opensymphony.xwork.DefaultActionInvocation.invoke(DefaultActionInvocation.java:189)
      at com.opensymphony.xwork.validator.ValidationInterceptor.doIntercept(ValidationInterceptor.java:115)
      at com.opensymphony.xwork.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:81)
      at com.opensymphony.xwork.DefaultActionInvocation.invoke(DefaultActionInvocation.java:189)
      at com.opensymphony.xwork.interceptor.AroundInterceptor.intercept(AroundInterceptor.java:31)
      at com.opensymphony.xwork.DefaultActionInvocation.invoke(DefaultActionInvocation.java:189)
      at com.opensymphony.xwork.interceptor.AroundInterceptor.intercept(AroundInterceptor.java:31)
      at com.opensymphony.xwork.DefaultActionInvocation.invoke(DefaultActionInvocation.java:189)
      at com.opensymphony.xwork.interceptor.AroundInterceptor.intercept(AroundInterceptor.java:31)
      at com.opensymphony.xwork.DefaultActionInvocation.invoke(DefaultActionInvocation.java:189)
      at com.opensymphony.webwork.interceptor.FileUploadInterceptor.intercept(FileUploadInterceptor.java:171)
      at com.opensymphony.xwork.DefaultActionInvocation.invoke(DefaultActionInvocation.java:189)
      at com.opensymphony.xwork.interceptor.AroundInterceptor.intercept(AroundInterceptor.java:31)
      at com.opensymphony.xwork.DefaultActionInvocation.invoke(DefaultActionInvocation.java:189)
      at com.opensymphony.xwork.interceptor.AroundInterceptor.intercept(AroundInterceptor.java:31)
      at com.opensymphony.xwork.DefaultActionInvocation.invoke(DefaultActionInvocation.java:189)
      at com.opensymphony.xwork.interceptor.I18nInterceptor.intercept(I18nInterceptor.java:151)
      at com.opensymphony.xwork.DefaultActionInvocation.invoke(DefaultActionInvocation.java:189)
      at com.opensymphony.xwork.interceptor.AroundInterceptor.intercept(AroundInterceptor.java:31)
      at com.opensymphony.xwork.DefaultActionInvocation.invoke(DefaultActionInvocation.java:189)
      at com.opensymphony.xwork.interceptor.AroundInterceptor.intercept(AroundInterceptor.java:31)
      at com.opensymphony.xwork.DefaultActionInvocation.invoke(DefaultActionInvocation.java:189)
      at com.opensymphony.xwork.interceptor.AroundInterceptor.intercept(AroundInterceptor.java:31)
      at com.opensymphony.xwork.DefaultActionInvocation.invoke(DefaultActionInvocation.java:189)
      at com.opensymphony.xwork.interceptor.ExceptionMappingInterceptor.intercept(ExceptionMappingInterceptor.java:100)
      at com.opensymphony.xwork.DefaultActionInvocation.invoke(DefaultActionInvocation.java:189)
      at com.opensymphony.xwork.DefaultActionProxy.execute(DefaultActionProxy.java:113)
      at com.opensymphony.webwork.dispatcher.DispatcherUtils.serviceAction(DispatcherUtils.java:233)
      at com.opensymphony.webwork.dispatcher.FilterDispatcher.doFilter(FilterDispatcher.java:198)
      at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:202)
      at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
      at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
      at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:178)
      at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:126)
      at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)
      at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:107)
      at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)
      at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:856)
      at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.processConnection(Http11Protocol.java:744)
      at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:527)
      at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:80)
      at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:684)
      at java.lang.Thread.run(Thread.java:595)
      ============================

      while following call: $

      {parameters}

      , will printout what seems to be 'toString' call of List:

      {param1=[Ljava.lang.String;@6210fb, param2=[Ljava.lang.String;@48edb5}

      As I mentioned, if original Freemarker's FreemarkerServlet is used to render the view, variable access like $

      {RequestParameters.param1}

      work just fine.

        Activity

        Lukasz Lenart made changes -
        Status Resolved [ 5 ] Closed [ 6 ]
        Jeff Turner made changes -
        Project Import Mon Feb 01 01:17:42 UTC 2010 [ 1264987062082 ]
        Antonio Petrelli made changes -
        Workflow Struts - editable closed status (temporary) [ 48259 ] Struts - editable closed status [ 51476 ]
        Antonio Petrelli made changes -
        Workflow Struts - editable closed status [ 43856 ] Struts - editable closed status (temporary) [ 48259 ]
        Jeff Turner made changes -
        Workflow Struts [ 40383 ] Struts - editable closed status [ 43856 ]
        Don Brown made changes -
        Workflow jira [ 35213 ] Struts [ 40383 ]
        Hide
        Marco Behler added a comment -

        What tm_jee said is not exactly true:

        The problem is, that you get arrays of strings and not strings in the param map. So if your action is Parameteraware, and the map "params" contains , say, a parameter view, you'll have to do a $

        {parameters.view[0]}

        , as view is an array, not a string.

        Show
        Marco Behler added a comment - What tm_jee said is not exactly true: The problem is, that you get arrays of strings and not strings in the param map. So if your action is Parameteraware, and the map "params" contains , say, a parameter view, you'll have to do a $ {parameters.view[0]} , as view is an array, not a string.
        tm_jee made changes -
        Resolution Fixed [ 1 ]
        Status Open [ 1 ] Resolved [ 5 ]
        Hide
        tm_jee added a comment -
        Show
        tm_jee added a comment - added information to confluence at http://confluence.twdata.org/display/WW/JSP and http://confluence.twdata.org/display/WW/FreeMarker
        Hide
        tm_jee added a comment -

        fixed.

        Followings are way to access attribute/parameters Application scope, Session scope, Request scope and specified in Servlet/Jsp Spec.

        Freemarker
        ========

        <#if Application.myApplicttionAttribute?exists>
        $

        {Application.myApplicationAttribute}

        </#if>

        <#if Session.mySessionAttribute?exists>
        $

        {Session.mySessionAttribute}

        </#if>

        <#if Request.myRequestAttribute?exists>
        $

        {Request.myRequestAttribute}

        </#if>

        <#if Parameters.myRequestParameter?exists>
        $

        {Parameters.myRequestParameter}

        </#if>

        Using SAF/WebWork Tag
        ==================
        <@saf.property value="%

        {application.myApplicationAttribute}" />
        <saf:property value="%{application.myApplicationAttribute}

        " />

        <@saf.property value="%

        {session.mySessionAttribute}" />
        <saf:property value="%{session.mySessionAttribute}

        " />

        <@saf.property value="%

        {request.myRequestAttribute}" />
        <saf:property value="%{request.myRequestAttribute}

        " />

        <@saf.property value="%

        {parameters.myRequestParameter}" />
        <saf:property value="%{parameters.myRequestParameter}

        " />

        Show
        tm_jee added a comment - fixed. Followings are way to access attribute/parameters Application scope, Session scope, Request scope and specified in Servlet/Jsp Spec. Freemarker ======== <#if Application.myApplicttionAttribute?exists> $ {Application.myApplicationAttribute} </#if> <#if Session.mySessionAttribute?exists> $ {Session.mySessionAttribute} </#if> <#if Request.myRequestAttribute?exists> $ {Request.myRequestAttribute} </#if> <#if Parameters.myRequestParameter?exists> $ {Parameters.myRequestParameter} </#if> Using SAF/WebWork Tag ================== <@saf.property value="% {application.myApplicationAttribute}" /> <saf:property value="%{application.myApplicationAttribute} " /> <@saf.property value="% {session.mySessionAttribute}" /> <saf:property value="%{session.mySessionAttribute} " /> <@saf.property value="% {request.myRequestAttribute}" /> <saf:property value="%{request.myRequestAttribute} " /> <@saf.property value="% {parameters.myRequestParameter}" /> <saf:property value="%{parameters.myRequestParameter} " />
        tm_jee made changes -
        Assignee tm_jee [ tm_jee ]
        Rainer Hermanns made changes -
        Field Original Value New Value
        Fix Version/s 2.3 [ 21510 ]
        Vladimir Olenin created issue -

          People

          • Assignee:
            tm_jee
            Reporter:
            Vladimir Olenin
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development