Lukasz Lenart created WW-5823:
---------------------------------
Summary: Javatemplates plugin renders dynamic attributes
differently from the simple theme: values are not HTML-escaped and are
evaluated a second time
Key: WW-5823
URL: https://issues.apache.org/jira/browse/WW-5823
Project: Struts 2
Issue Type: Bug
Components: Plugin - Java Templates
Reporter: Lukasz Lenart
Fix For: 7.5.0, 6.13.0
The javatemplates plugin is documented as a drop-in replacement for the simple
theme. {{DynamicAttributesHandler.processDynamicAttributes}} differs from the
FreeMarker {{dynamic-attributes.ftl}} in two ways.
# Dynamic attribute values are stored with {{Attributes.put}}. Every other
handler in the plugin goes through {{Attributes.add}} or {{addIfExists}}, which
apply {{escapeHtml4}}, and the FreeMarker template renders {{${value}}} under
the configuration's HTML auto-escaping. {{XHTMLTagSerializer.start}} then
writes the stored value between double quotes as it is.
# {{UIBean.setDynamicAttributes}} already translates {{%{...}}} for every
component that is not lazily evaluated. The handler tests the resolved value
with {{ComponentUtils.isExpression}} again and calls {{findString}} on it, so a
value that resolves to text of the form {{%{...}}} is evaluated a second time.
The FreeMarker template evaluates only when {{evaluate_dynamic_attributes}} is
set, which {{radiomap.ftl}} and {{checkboxlist.ftl}} do because {{Radio}} and
{{CheckboxList}} return {{lazyEvaluation() == true}} and render their dynamic
attributes per list item.
h2. Observed
{{<s:textfield name="q" data-hint="%{hint}"/>}} with
{{struts.ui.templateSuffix=java}} and the {{hint}} property bound from the
request:
{code}hint = a "b" c java: data-hint="a "b" c" ftl: data-hint="a
"b" c"
hint = %{1+1} java: data-hint="2" ftl: data-hint="%{1+1}"
{code}
The standard attributes of the same tag ({{value}}, {{title}}) render
identically under both engines. Every tag wired through
{{DynamicAttributesHandler}} in {{SimpleTheme}} behaves the same way.
h2. Proposed change
* Store dynamic attribute values through {{Attributes.add}}, in line with the
other handlers and the FreeMarker templates.
* Evaluate a dynamic attribute in the handler only when the component is lazily
evaluated. {{UIBean}} already knows this through {{lazyEvaluation()}}; expose
it as a component parameter so the plugin can read it. {{Radio}} and
{{CheckboxList}} keep their per-item evaluation in the handler chain, where
{{RadioHandler}} and {{CheckboxListHandler}} push each item before calling
{{start}}.
h2. Compatibility
Under the java engine, a dynamic attribute value is now HTML-escaped once, as
it already is under the FreeMarker themes; a value that already contains
entities is escaped again, matching the FreeMarker output. A value that
resolves to text of the form {{%{...}}} is rendered literally instead of being
evaluated, matching the FreeMarker output. Lazily evaluated components are
unchanged.
h2. Tests
* A dynamic attribute whose resolved value contains a double quote renders
escaped under the java engine.
* A dynamic attribute whose resolved value has the form {{%{...}}} renders
literally on a non-lazy component.
* A dynamic attribute on {{Radio}} is still evaluated per item in the handler.
* The existing dynamic-attribute rendering tests keep passing for every tag in
{{SimpleTheme}}.
Reported by Claude and Ada Logics.
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)