This is an automated email from the ASF dual-hosted git repository.
lukaszlenart pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/struts-site.git
The following commit(s) were added to refs/heads/main by this push:
new 2142d1aac docs: add documentation for Struts 7.2.0 new features and
changes (#289)
2142d1aac is described below
commit 2142d1aac5372b5b227cabfe4d6519b076b042dd
Author: Lukasz Lenart <[email protected]>
AuthorDate: Tue Feb 17 08:49:53 2026 +0100
docs: add documentation for Struts 7.2.0 new features and changes (#289)
- Checkbox hidden field prefix constant (WW-3429)
- Spring autowire alwaysRespect default change to true (WW-3647)
- Spring bean names support in type converters (WW-4291)
- Preparable.prepare() default method (WW-5588)
- Dynamic file upload validation parameters (WW-5585)
- @Validations annotation fix for doubleRange/shortRange (WW-5579)
- JSP direct access security warning (WW-5294)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude <[email protected]>
---
.asf.yaml | 8 +-
.claude/settings.json | 5 +-
CLAUDE.md | 141 ++++++++-------------
.../action-file-upload-interceptor.md | 19 ++-
source/core-developers/prepare-interceptor.md | 6 +-
source/core-developers/type-conversion.md | 11 +-
source/plugins/spring/index.md | 15 ++-
source/security/index.md | 9 +-
source/tag-developers/checkbox-tag.md | 18 +++
9 files changed, 135 insertions(+), 97 deletions(-)
diff --git a/.asf.yaml b/.asf.yaml
index 506b842ad..d79376564 100644
--- a/.asf.yaml
+++ b/.asf.yaml
@@ -22,8 +22,14 @@ jekyll:
target: asf-site
github:
- del_branch_on_merge: true
protected_branches:
main: { }
+ pull_requests:
+ # allow auto-merge
+ allow_auto_merge: true
+ # auto-delete head branches after being merged
+ del_branch_on_merge: true
autolink_jira:
- WW
+ dependabot_alerts: true
+ dependabot_updates: true
diff --git a/.claude/settings.json b/.claude/settings.json
index a22e52465..d78853e27 100644
--- a/.claude/settings.json
+++ b/.claude/settings.json
@@ -7,12 +7,15 @@
"WebFetch(domain:github.com)",
"WebFetch(domain:struts.apache.org)",
"WebFetch(domain:raw.githubusercontent.com)",
+ "WebFetch(domain:cwiki.apache.org)",
"Bash(git checkout:*)",
"Bash(git add:*)",
"Bash(git commit:*)",
"Bash(git push:*)",
"Bash(gh pr create:*)",
- "Bash(gh pr view:*)"
+ "Bash(gh pr view:*)",
+ "Bash(gh pr diff:*)",
+ "Bash(ls:*)"
],
"deny": [],
"ask": []
diff --git a/CLAUDE.md b/CLAUDE.md
index de11465d0..16811823d 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -4,122 +4,89 @@ This file provides guidance to Claude Code (claude.ai/code)
when working with co
## Project Overview
-This is the Apache Struts website repository, which powers
https://struts.apache.org/. The site is built with Jekyll and uses a mix of
Markdown and HTML files.
+This is the Apache Struts website repository, which powers
https://struts.apache.org/. The site is built with Jekyll 4.2 and uses a mix of
Markdown and HTML files.
## Development Commands
### Running the Site Locally
-The site can be run locally using Jekyll or Docker:
-
-**Using Jekyll directly:**
-```bash
-bundle exec jekyll serve -w --trace --host 0.0.0.0
-```
-
-**Using Docker (recommended):**
```bash
-# Build the Docker image (only needed when Dockerfile changes)
-./docker-build.sh
+# Using Docker (recommended, Apple Silicon)
+./docker-build.sh # Build image (only when Dockerfile changes)
+./docker-arm64-serve.sh # Serve site at http://localhost:4000
-# Run the site in Docker
-./docker-arm64-serve.sh # For ARM64 architecture (Apple Silicon)
-```
-
-The site will be available at http://localhost:4000
-
-### Installing Dependencies
-
-```bash
-bundle install
+# Using Jekyll directly
+bundle install # Install dependencies
+bundle exec jekyll serve -w --trace --host 0.0.0.0
```
-## Directory Structure
-
-- `source/` - All source content files (Markdown and HTML)
- - `source/_layouts/` - Jekyll layout templates (main-page, default,
core-developers, maven-archetypes)
- - `source/_includes/` - Reusable HTML partials (header, footer)
- - `source/.htaccess` - Redirect rules
-- `content/` - Generated output (not committed to git)
-- `_config.yml` - Jekyll configuration and site variables
-
-## Site Configuration
+## Architecture
-The `_config.yml` file contains important site-wide variables:
+### Directory Structure
-- `current_version` / `prev_version` - Struts version tracking
-- `release_date` / `prev_release_date` - Release date tracking
-- `archetype_version` - Maven archetype version
-- `repository_url` - GitHub repository for edit links
-- `apidocs` - Path to API documentation
-- `wiki_url` - Confluence wiki URL
-- `archive_url` - Archive distribution URL
-- `jira_url` - JIRA issue tracking URL
+- `source/` - All source content (Markdown/HTML), Jekyll source directory
+ - `_layouts/` - Page templates: `default`, `main-page`, `core-developers`,
`maven-archetypes`
+ - `_includes/` - Shared partials: `header.html`, `footer.html`
+ - `_plugins/` - Custom Liquid tags (see below)
+ - `.htaccess` - Apache redirect rules (update when adding yearly
announcement pages)
+- `_config.yml` - Jekyll config and site-wide version/release variables
+- `.asf.yaml` - ASF infrastructure config (deployment, notifications, branch
protection)
-These variables are used throughout the site for dynamic content.
+### Content Sections
-## Content Guidelines
+The `source/` directory contains these main content areas:
+- `docs/` - Framework documentation
+- `getting-started/` - Getting started guides
+- `plugins/` - Plugin documentation
+- `core-developers/` - Core developer guide (uses `core-developers` layout)
+- `security/` - Security bulletins
+- `tag-developers/` - Tag developer documentation
+- `maven-archetypes/` - Maven archetype docs (uses `maven-archetypes` layout)
+- `announce-YYYY.md/html` - Yearly announcement pages
-### Page Front Matter
+### Site Variables in `_config.yml`
-All Markdown pages should start with YAML front matter:
-
-```yaml
----
-layout: default
-title: Page Title
----
-```
+Version and release date variables (`current_version`, `prev_version`,
`release_date`, etc.) are referenced throughout `source/index.html`,
`source/download.md`, and `source/releases.md` using `{{ site.variable_name
}}`. When preparing a new release, update these in `_config.yml` rather than
editing individual pages.
-Available layouts: `default`, `main-page`, `core-developers`,
`maven-archetypes`
+### Custom Jekyll Plugins
-### Styling Classes
+Two custom Liquid tags in `source/_plugins/`:
-Use these Kramdown-style classes for formatting:
+- **`{% snippet %}`** - Fetches and embeds code snippets from remote sources
(Apache Git repos). Supports parameters: `url=`, `id=` (for snippet markers),
`lang=` (syntax highlighting), `javadoc=` (strip Javadoc formatting). Caches
fetched content in `target/snippet_*.cache`.
+- **`{% remote_file_content %}`** - Fetches and inlines content from a remote
URL.
-**Text alignment:** `{:.text-left}`, `{:.text-center}`, `{:.text-right}`,
`{:.text-justify}`
+### Layouts
-**Text colors:** `{:.text-primary}`, `{:.text-info}`, `{:.text-success}`,
`{:.text-warning}`, `{:.text-danger}`
+- `default` - Standard content page with "Edit on GitHub" link and optional
parent breadcrumb
+- `main-page` - Homepage layout (no sidebar, no edit link)
+- `core-developers` - Like default but with hardcoded "back to Core Developers
Guide" link
+- `maven-archetypes` - Similar to core-developers
-**Backgrounds:** `{:.bg-primary}`, `{:.bg-info}`, `{:.bg-success}`,
`{:.bg-warning}`, `{:.bg-danger}`
+### Styling
-**Labels:** `{:.label .label-primary}`, etc.
+Kramdown attribute syntax for Bootstrap classes:
+- Alerts: `{:.alert .alert-warning}`, `{:.alert .alert-info}`, etc.
+- Text: `{:.text-primary}`, `{:.text-danger}`, etc.
+- See `source/updating-website.md` for complete examples.
-**Alert panels:** `{:.alert .alert-info}`, `{:.alert .alert-success}`,
`{:.alert .alert-warning}`, `{:.alert .alert-danger}`
+## Deployment
-See `source/updating-website.md` for complete styling examples.
+### Branching
-## Deployment Process
-
-### Branching Strategy
-
-- `main` - Source branch for all changes and PRs
-- `asf-site` - Production site (auto-deployed, DO NOT MODIFY MANUALLY)
-- `asf-staging` - Staging site (auto-deployed, DO NOT MODIFY MANUALLY)
+- `main` - Source branch for all changes/PRs
+- `asf-site` - Production (auto-deployed, DO NOT MODIFY)
+- `asf-staging` - Staging (auto-deployed, DO NOT MODIFY)
### Workflow
-1. Make changes to the `main` branch
-2. Small changes: Push directly to `main` (for contributors)
-3. Larger changes: Open a Pull Request against `main`
-4. PRs are automatically built and deployed to the staging site:
https://struts.staged.apache.org/
-5. After PR merge, changes are automatically built and deployed to production
via buildbot
-
-### Build Infrastructure
-
-- `.asf.yaml` - Controls ASF infrastructure integration (notifications, JIRA
linking, Jekyll deployment)
-- Buildbot job builds and deploys the main site
-- Jenkins job builds and deploys the staging site and JavaDocs
+1. Push changes to `main` or open a PR against `main`
+2. PRs auto-deploy to staging: https://struts.staged.apache.org/
+3. After merge, auto-deployed to production via buildbot
-### JavaDocs Deployment
+### Common Tasks
-JavaDocs are deployed via a dedicated Jenkins job. Provide the Git tag (e.g.,
`STRUTS_2_5_22`) to generate and deploy JavaDocs for a specific release.
+**New release**: Update version variables in `_config.yml`, add announcement
entry to the current year's `announce-YYYY.md`.
-## Jekyll Configuration
+**New announcement year**: Create `source/announce-YYYY.md`, update the
redirect in `source/.htaccess` (`RedirectMatch \/announce.html` line) to point
to the new year.
-- Uses Kramdown markdown processor with GFM (GitHub Flavored Markdown) input
-- Syntax highlighting via Rouge
-- Auto-generates IDs for headings
-- Table of contents levels: 1-3
-- Source directory: `source/`
-- Encoding: UTF-8
\ No newline at end of file
+**New security bulletin**: Add to `source/security/` directory.
\ No newline at end of file
diff --git a/source/core-developers/action-file-upload-interceptor.md
b/source/core-developers/action-file-upload-interceptor.md
index 06a67c55d..52e489e8b 100644
--- a/source/core-developers/action-file-upload-interceptor.md
+++ b/source/core-developers/action-file-upload-interceptor.md
@@ -37,13 +37,30 @@ You can override the text of these messages by providing
text for the following
## Parameters
- `maximumSize` (optional) - the maximum size (in bytes) that the interceptor
will allow a file reference to be set
- on the action. Note, this is <b>not</b> related to the various properties
found in struts.properties.
+ on the action. Note, this is <b>not</b> related to the various properties
found in struts.properties.
Default to approximately 2MB.
- `allowedTypes` (optional) - a comma separated list of content types (ie:
`text/html`) that the interceptor will allow
a file reference to be set on the action. If none is specified allow all
types to be uploaded.
- `allowedExtensions` (optional) - a comma separated list of file extensions
(ie: `.html`) that the interceptor will allow
a file reference to be set on the action. If none is specified allow all
extensions to be uploaded.
+### Dynamic Parameter Evaluation
+
+> Since Struts 7.2.0
+
+The `allowedTypes`, `allowedExtensions`, and `maximumSize` parameters support
`${...}` expression evaluation,
+enabling per-request dynamic validation. This is available when used with
`WithLazyParams`.
+
+```xml
+<interceptor-ref name="actionFileUpload">
+ <param name="allowedTypes">${allowedContentTypes}</param>
+ <param name="maximumSize">${maxFileSize}</param>
+</interceptor-ref>
+```
+
+The expressions are evaluated against the ValueStack at the time of the
upload, allowing your action to provide
+dynamic values based on the current request context.
+
## Extending the Interceptor
You can extend this interceptor and override the acceptFile method to provide
more control over which files are supported
diff --git a/source/core-developers/prepare-interceptor.md
b/source/core-developers/prepare-interceptor.md
index c2e97c94e..40fcde2fb 100644
--- a/source/core-developers/prepare-interceptor.md
+++ b/source/core-developers/prepare-interceptor.md
@@ -29,9 +29,13 @@ on the actual object loaded from the database. See the
example for more info.
In `PrepareInterceptor` applies only when action implements `Preparable`
1. if the action class have `prepare<MethodName>()`, it will be invoked
2. else if the action class have `prepareDo<MethodName>()`, it will be invoked
- 3. no matter if 1] or 2] is performed, if `alwaysInvokePrepare` property of
the interceptor is `true` (which is by
+ 3. no matter if 1) or 2) is performed, if `alwaysInvokePrepare` property of
the interceptor is `true` (which is by
default `true`), `prepare()` will be invoked.
+> Note: since Struts 7.2.0, the `Preparable.prepare()` method is now a
`default` method with an empty implementation.
+> Actions that only use per-method variants (e.g., `prepareEdit()`,
`prepareSave()`) no longer need to provide
+> an empty `prepare()` override.
+
## Parameters
- `alwaysInvokePrepare` - Default to true. If true, prepare will always be
invoked, otherwise it will not.
diff --git a/source/core-developers/type-conversion.md
b/source/core-developers/type-conversion.md
index 85b16bac2..f52d61ef6 100644
--- a/source/core-developers/type-conversion.md
+++ b/source/core-developers/type-conversion.md
@@ -114,14 +114,21 @@ amount=com.acme.converters.MyCustomBigDecimalConverter
## Applying a Type Converter for an application
-Application-wide converters can be specified in a file called
`struts-conversion.properties` or `xwork-conversion.properties` (deprecated)
+Application-wide converters can be specified in a file called
`struts-conversion.properties` or `xwork-conversion.properties` (deprecated)
located in the root of the classpath.
```
# syntax: <type> = <converterClassName>
-java.math.BigDecimal = com.acme.MyBigDecimalConverter
+java.math.BigDecimal = com.acme.MyBigDecimalConverter
```
+> NOTE: since Struts 7.2.0, when the Spring plugin is active, you can use
Spring bean names in addition to fully qualified
+> class names as converter values in `struts-conversion.properties`. For
example, if you have a Spring bean named
+> `myBigDecimalConverter`, you can reference it directly:
+> ```
+> java.math.BigDecimal = myBigDecimalConverter
+> ```
+
## A Simple Example
Type conversion is great for situations where you need to turn a String in to
a more complex object. Because the web
diff --git a/source/plugins/spring/index.md b/source/plugins/spring/index.md
index 3203a681d..e35f76934 100644
--- a/source/plugins/spring/index.md
+++ b/source/plugins/spring/index.md
@@ -228,6 +228,19 @@ so only actions are handled by it. This constant supports
a comma separated list
> This feature is experimental, and **should never** be used in production
> systems.
+## Migration Note: autowire alwaysRespect default change (7.2.0)
+
+Starting with Struts 7.2.0, the
`struts.objectFactory.spring.autoWire.alwaysRespect` constant defaults to `true`
+(previously `false`). This means the configured autowire strategy is now
always applied consistently, which fixes issues
+such as broken redirect URLs when Spring String beans are involved.
+{:.alert .alert-warning}
+
+If you experience unexpected behavior after upgrading to 7.2.0, you can
restore the previous behavior by setting:
+
+```xml
+<constant name="struts.objectFactory.spring.autoWire.alwaysRespect"
value="false" />
+```
+
## Settings
The following settings can be customized. See the [developer
guide](/core-developers/configuration-files).
@@ -235,7 +248,7 @@ The following settings can be customized. See the
[developer guide](/core-develo
|Setting|Description|Default|Possible Values|
|-------|-----------|-------|---------------|
|struts.objectFactory.spring.autoWire|The autowire
strategy|name|name,type,auto, or constructor|
-|struts.objectFactory.spring.autoWire.alwaysRespect|Whether the autowire
strategy should always be used, or if the framework should try to guess the
best strategy based on the situation|false for backwards-compatibility|true or
false|
+|struts.objectFactory.spring.autoWire.alwaysRespect|Whether the autowire
strategy should always be used, or if the framework should try to guess the
best strategy based on the situation|true (changed from false in 7.2.0)|true or
false|
|struts.objectFactory.spring.useClassCache|Whether to have Spring use its
class cache or not|true|true or false|
|struts.class.reloading.watchList|List of jar files or directories to watch
for changes|null|Comma separated list of absolute or relative paths to jars or
directories|
|struts.class.reloading.acceptClasses|List of regular expressions of accepted
class names|null|Comma separated list of regular expressions of classes that
will be loaded by the reloading class loader(we suggest to add regular
expressions so only action classes are handled by the reloading class loader)|
diff --git a/source/security/index.md b/source/security/index.md
index 19eff51bd..79ddd46e7 100644
--- a/source/security/index.md
+++ b/source/security/index.md
@@ -40,11 +40,14 @@ by security level.
### Never expose JSP files directly
-You must always hide JSP file behind an action, you cannot allow for direct
access to the JSP files as this can leads
-to unpredictable security vulnerabilities. You can achieve this by putting all
your JSP files under the `WEB-INF` folder
-- most of the JEE containers restrict access to files placed under the
`WEB-INF` folder. Second option is to add security
+You must always hide JSP file behind an action, you cannot allow for direct
access to the JSP files as this can leads
+to unpredictable security vulnerabilities. You can achieve this by putting all
your JSP files under the `WEB-INF` folder
+- most of the JEE containers restrict access to files placed under the
`WEB-INF` folder. Second option is to add security
constraint to the `web.xml` file:
+> Note: since Struts 7.2.0, the framework now logs a security warning when JSP
tags are accessed directly outside of
+> an action scope. This helps identify JSP files that are inadvertently
exposed without action protection.
+
```xml
<!-- Restricts access to pure JSP files - access available only via Struts
action -->
<security-constraint>
diff --git a/source/tag-developers/checkbox-tag.md
b/source/tag-developers/checkbox-tag.md
index 38426f42d..58f0b6ffa 100644
--- a/source/tag-developers/checkbox-tag.md
+++ b/source/tag-developers/checkbox-tag.md
@@ -39,3 +39,21 @@ Renders an HTML input element of type checkbox, populated by
the specified prope
```html
<input type="checkbox" name="checkboxField1" value="true" checked="checked" />
```
+
+## Hidden Field Prefix
+
+> Since Struts 7.2.0
+
+The checkbox tag generates a companion hidden field to ensure that unchecked
values are still submitted with the form.
+By default, this hidden field uses the prefix `__checkbox_` (e.g.,
`__checkbox_checkboxField1`).
+
+For HTML5 compliance, you can change the prefix to `struts_checkbox_` using
the `struts.ui.checkbox.hiddenPrefix` constant:
+
+```xml
+<constant name="struts.ui.checkbox.hiddenPrefix" value="struts_checkbox_" />
+```
+
+| Prefix | Example Hidden Field Name | Notes |
+|--------|--------------------------|-------|
+| `__checkbox_` | `__checkbox_checkboxField1` | Default, backward-compatible |
+| `struts_checkbox_` | `struts_checkbox_checkboxField1` | HTML5-compliant
alternative |