History | Log In     View a printable version of the current page.  
Issue Details (XML | Word | Printable)

Key: WW-1273
Type: Bug Bug
Status: Resolved Resolved
Resolution: Not A Problem
Priority: Critical Critical
Assignee: Philip Luppens
Reporter: Vladimir Olenin
Votes: 0
Watchers: 1
Operations

If you were logged in you would be able to see more operations.
WebWork

freemarker 'parameters' model attribute - incorrect TemplateModel

Created: 27/Mar/06 11:14 AM   Updated: 10/Feb/07 03:20 AM
Component/s: Views
Affects Version/s: 2.2.1, 2.2.2
Fix Version/s: 2.2.5

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

Flags: Important


 Description  « Hide
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.

 All   Comments   Change History      Sort Order:
Philip Luppens - [10/Feb/07 03:20 AM ]
There are a couple of issues here. First, the error message, although correct, is a bit misleading. WW does in fact expose a HashMap with the parameters (HttpRequestParametersHashModel) - which you see when you print out the ${parameters} variable.
Now, it is indeed possible that ${parameters.param1} works fine with the Freemarker servlet. In this case, it works as well, but with a twist. After all, all request parameters have String arrays as a value (be it 'hidden'), so the error message (wrong model, array), is because you're trying to print an array rather than a String.

The solution is to use ${parameters.param1[0]}.

Why I mark this as not a problem ? Because you shouldn't directly expose parameters from the request in your view. You should let XWork set the on your Action, and use Freemarker to query your action. So, if you have a String getParam1() in your action, you could do ${param1} in your result. If you have a String[] getParam1(), you would have to do ${param1[0]}. The parameters variable is there to be used when using components or tags (to pass parameters).