This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch WW-5256-textarea-whitespace-devmode
in repository https://gitbox.apache.org/repos/asf/struts.git

commit d9e0b975f5de464be2d932b276c45dc22c5b2e8d
Author: Lukasz Lenart <[email protected]>
AuthorDate: Mon Jun 15 10:40:35 2026 +0200

    WW-5256 docs: design to decouple FreeMarker whitespace stripping from 
devMode
    
    Fixes s:textarea rendering blank lines and HTML whitespace bloat in devMode
    by honoring struts.freemarker.whitespaceStripping unconditionally.
    
    Co-Authored-By: Claude Opus 4.8 <[email protected]>
---
 ...emarker-whitespace-devmode-decoupling-design.md | 125 +++++++++++++++++++++
 1 file changed, 125 insertions(+)

diff --git 
a/docs/superpowers/specs/2026-06-15-WW-5256-freemarker-whitespace-devmode-decoupling-design.md
 
b/docs/superpowers/specs/2026-06-15-WW-5256-freemarker-whitespace-devmode-decoupling-design.md
new file mode 100644
index 000000000..bd74accd5
--- /dev/null
+++ 
b/docs/superpowers/specs/2026-06-15-WW-5256-freemarker-whitespace-devmode-decoupling-design.md
@@ -0,0 +1,125 @@
+---
+date: 2026-06-15
+ticket: WW-5256
+url: https://issues.apache.org/jira/browse/WW-5256
+status: design
+---
+
+# WW-5256 — Decouple FreeMarker whitespace stripping from devMode
+
+## Problem
+
+In `release/7.2.0-RC1`, `s:textarea` renders blank lines inside an empty 
textarea, and
+the overall HTML output contains noticeably more whitespace than in 6.x. 
Reported symptom
+on CRUD entry/add pages: an empty `bean.data` (null default) textarea shows up 
as two blank
+lines on screen, and the raw HTML source has far more whitespace throughout 
than the 6.x
+equivalent.
+
+## Root cause
+
+The FreeMarker templates are **not** the cause. `textarea.ftl` and all of its 
included
+sub-templates (`css.ftl`, `scripting-events.ftl`, `common-attributes.ftl`,
+`dynamic-attributes.ftl`) are byte-for-byte identical between 
`support/struts-6-x-x` and
+`release/7.2.0-RC1` apart from the `parameters` → `attributes` rename. Their 
whitespace
+structure is unchanged.
+
+The regression is in `FreemarkerManager.java:355`, introduced by WW-5256
+(commit `9305a5812`, `@since 7.2.0`):
+
+```java
+// 6.x — whitespace stripping unconditionally on:
+configuration.setWhitespaceStripping(true);
+
+// 7.2.0-RC1 — stripping turned off whenever devMode is on:
+boolean enableWhitespaceStripping = whitespaceStripping && !devMode;
+configuration.setWhitespaceStripping(enableWhitespaceStripping);
+```
+
+When `struts.devMode=true` (the normal development setting), whitespace 
stripping is
+forced off. FreeMarker then stops collapsing directive-only lines (e.g. `<#if 
…>` /
+`</#if>`), which produces two distinct effects:
+
+1. **General whitespace bloat** — every directive-only line in every UI 
template now emits
+   its newline and indentation.
+2. **Visible `s:textarea` breakage** — the directive lines around `nameValue` 
sit *inside*
+   `<textarea>…</textarea>`, where whitespace is **significant content**. The 
collapsed
+   newlines that 6.x removed now render as blank lines in the browser.
+
+The `&& !devMode` term also **overrides** the 
`struts.freemarker.whitespaceStripping`
+config flag: a developer running in devMode has no way to turn stripping back 
on.
+
+### Why the coupling was introduced (and why it was wrong)
+
+Per the WW-5256 research note
+(`thoughts/shared/research/2025-09-24-WW-5256-freemarker-whitespace-compression.md`),
 the
+devMode auto-disable was copied by analogy from the new `<s:compress>` tag, 
which
+intentionally disables compression in devMode with a `force` override. The 
stated goal was
+"readable output while debugging." The note itself raised this as an *open 
question*
+("Should whitespace stripping be automatically disabled in DevMode … or 
require explicit
+configuration?") rather than a settled decision.
+
+The analogy does not hold: for most tags the extra dev whitespace is harmless 
cosmetic
+noise, but for `<textarea>` (and `<pre>`) the stripped newlines are 
semantically
+significant page content. "Make dev output readable" therefore silently broke 
`s:textarea`
+rendering, with no escape hatch. The configurable flag from WW-5256 is the 
useful part and
+is kept; the devMode auto-disable is the unvalidated part and is removed.
+
+## Design
+
+Decouple whitespace stripping from devMode. Honor 
`struts.freemarker.whitespaceStripping`
+(default `true`) unconditionally. This restores 6.x behavior by default while 
keeping an
+explicit opt-out for anyone who genuinely wants raw, un-collapsed template 
output.
+
+### Changes
+
+1. 
**`core/src/main/java/org/apache/struts2/views/freemarker/FreemarkerManager.java`**
+   - Replace the coupling with a direct call:
+     ```java
+     configuration.setWhitespaceStripping(whitespaceStripping);
+     ```
+   - Simplify the debug log to drop the devMode reference.
+   - Remove the now-unused `devMode` field, the `setDevMode(String)` setter, 
and its
+     `@Inject(value = StrutsConstants.STRUTS_DEVMODE, required = false)` 
annotation. The
+     field was added in 7.2.0 solely for this coupling and is referenced 
nowhere else in
+     the class, so removing it before final 7.2.0 release breaks no released 
API.
+
+2. **`core/src/main/java/org/apache/struts2/StrutsConstants.java`**
+   - Remove the line "*Automatically disabled when devMode is enabled.*" from 
the
+     `STRUTS_FREEMARKER_WHITESPACE_STRIPPING` Javadoc. Keep `@since 7.2.0`.
+
+3. **`core/src/main/resources/org/apache/struts2/default.properties`**
+   - No change. `struts.freemarker.whitespaceStripping=true` remains the 
default.
+
+4. 
**`core/src/test/java/org/apache/struts2/views/freemarker/FreemarkerManagerTest.java`**
+   - Remove `testWhitespaceStrippingDisabledInDevMode` and
+     `testWhitespaceStrippingEnabledWhenNotInDevMode` — they assert the 
removed coupling and
+     call the removed `setDevMode` setter.
+   - Remove the stray `manager.setDevMode("false")` call from
+     `testWhitespaceStrippingDisabledViaConfiguration`.
+   - Keep `testWhitespaceStrippingEnabledByDefault` and the explicit-disable 
test; together
+     they fully cover the remaining behavior (default on; honored when set 
false).
+
+### Behavior after the change
+
+| devMode | `struts.freemarker.whitespaceStripping` | Stripping enabled? |
+|---------|-----------------------------------------|--------------------|
+| any     | unset (default)                         | yes (matches 6.x)  |
+| any     | `true`                                  | yes                |
+| any     | `false`                                 | no                 |
+
+## Scope and risk
+
+- Contained, single-purpose fix landing in `release/7.2.0-RC1` before the 
final 7.2.0
+  release. No migration or backward-compatibility concern, since the removed 
`devMode`
+  wiring was never in a released version.
+- **Not** a security change — this is purely rendering/whitespace behavior. 
The normal
+  PR flow applies (no private security-triage path needed).
+- The `<s:compress>` tag's own devMode/`force` behavior is unrelated and 
unchanged.
+
+## Verification
+
+- `mvn test -DskipAssembly -pl core -Dtest=FreemarkerManagerTest` passes with 
the updated
+  test set.
+- Manual check (or an `AbstractUITagTest`-style assertion): an `s:textarea` 
bound to a null
+  value renders as `<textarea …></textarea>` with no internal blank lines when
+  `struts.devMode=true`.

Reply via email to