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

asf-gitbox-commits pushed a commit to branch asf-staging
in repository https://gitbox.apache.org/repos/asf/struts-site.git


The following commit(s) were added to refs/heads/asf-staging by this push:
     new b1ce68799 Updates stage by Jenkins
b1ce68799 is described below

commit b1ce687996070c5e775bf8b241882e4eb2db70c1
Author: jenkins <[email protected]>
AuthorDate: Wed Jul 29 07:04:00 2026 +0000

    Updates stage by Jenkins
---
 content/core-developers/chaining-interceptor.html  | 25 +++++++++
 content/core-developers/default-properties.html    |  9 +++
 .../struts-parameter-annotation.html               | 20 +++++++
 content/plugins/json/index.html                    | 65 ++++++++++++++++++++++
 4 files changed, 119 insertions(+)

diff --git a/content/core-developers/chaining-interceptor.html 
b/content/core-developers/chaining-interceptor.html
index 01682f93c..23a0ef8de 100644
--- a/content/core-developers/chaining-interceptor.html
+++ b/content/core-developers/chaining-interceptor.html
@@ -210,6 +210,31 @@ no properties are copied.</li>
   <li>This is a <strong>global</strong> constant only — there is no 
per-interceptor override.</li>
 </ul>
 
+<h2 id="security-considerations">Security Considerations</h2>
+
+<p>Action chaining makes the data path into the target action implicit: the 
target is populated
+from whatever happens to be on the value stack rather than from an explicit 
call. Keep that in
+mind when designing chained actions:</p>
+
+<ul>
+  <li><strong>Do not carry authorization, trust, identity, or approval state 
across a chain.</strong> Re-derive
+such state from the session or your security context inside the target action, 
so it never
+depends on what a previous action left on the stack.</li>
+  <li><strong>Prefer avoiding chaining where practical.</strong> It couples 
the two actions together and makes
+the target’s inputs harder to reason about; a shared service or an explicit 
redirect is
+usually clearer.</li>
+  <li><strong>If chaining is required, narrow what is copied.</strong> 
Implement
+<a 
href="/maven/struts2-core/apidocs/org/apache/struts2/Unchainable">Unchainable</a>
 on objects that must
+never be copied from, and use the interceptor’s <code 
class="language-plaintext highlighter-rouge">includes</code> or <code 
class="language-plaintext highlighter-rouge">excludes</code> parameters to limit
+the copied properties to the ones the target genuinely needs.</li>
+  <li><strong>Do not expose a public setter on the target action for state 
that must not be settable from
+outside that action.</strong> Anything with a public setter is, by design, 
part of the action’s
+input surface.</li>
+</ul>
+
+<p>See also <a 
href="struts-parameter-annotation.html#where-authorization-applies">Where 
authorization applies</a>
+for an overview of the channels that can populate an action.</p>
+
 <h2 id="parameters">Parameters</h2>
 
 <ul>
diff --git a/content/core-developers/default-properties.html 
b/content/core-developers/default-properties.html
index 148170a28..8b3f4d106 100644
--- a/content/core-developers/default-properties.html
+++ b/content/core-developers/default-properties.html
@@ -235,7 +235,10 @@ struts.multipart.parser=jakarta
 ### Uses jakarta.servlet.context.tempdir by default
 struts.multipart.saveDir=
 struts.multipart.maxSize=2097152
+# Maximum number of uploaded files (files only, not form fields)
 struts.multipart.maxFiles=256
+# Maximum number of non-file form fields (parameters)
+struts.multipart.maxParameterCount=256
 struts.multipart.maxStringLength=4096
 # struts.multipart.maxFileSize=
 
@@ -314,6 +317,12 @@ struts.mapper.action.prefix.crossNamespaces = false
 ###                them right away.
 struts.devMode = false
 
+### When set to true, a field's remaining validators are skipped once that 
field
+### has a type conversion error, avoiding a duplicate error (WW-2934).
+### The field's own conversion validator still runs, so its message is still 
shown.
+### valid values are: true, false (false is the default)
+struts.validators.skipValidatorsOnConversionError = false
+
 ### when set to true, resource bundles will be reloaded on _every_ request.
 ### this is good during development, but should never be used in production
 # struts.i18n.reload=false
diff --git a/content/core-developers/struts-parameter-annotation.html 
b/content/core-developers/struts-parameter-annotation.html
index 7851c8912..8e744184e 100644
--- a/content/core-developers/struts-parameter-annotation.html
+++ b/content/core-developers/struts-parameter-annotation.html
@@ -308,6 +308,26 @@ collection or map needs <code class="language-plaintext 
highlighter-rouge">depth
 <span class="o">}</span>
 </code></pre></div></div>
 
+<p>This covers the case where the whole collection is assigned at once (name
+<code class="language-plaintext highlighter-rouge">mySelection</code>, <code 
class="language-plaintext highlighter-rouge">depth = 0</code>), as a checkbox 
list submits it.</p>
+
+<p>When the collection is instead populated <strong>element by 
element</strong> through indexed
+names — <code class="language-plaintext 
highlighter-rouge">mySelection[0]</code>, <code class="language-plaintext 
highlighter-rouge">mySelection[1]</code> — the annotation must be on the
+<strong>getter</strong> with <code class="language-plaintext 
highlighter-rouge">depth = 1</code>, because each element path contains one 
bracket. This
+is how JSON and REST payloads bind a collection of simple types: a body such as
+<code class="language-plaintext 
highlighter-rouge">{"mySelection":["A","B"]}</code> populates <code 
class="language-plaintext highlighter-rouge">mySelection[0]</code> and <code 
class="language-plaintext highlighter-rouge">mySelection[1]</code>, so
+the getter must be annotated for the elements to be accepted.</p>
+<div class="language-java highlighter-rouge"><div class="highlight"><pre 
class="highlight"><code><span class="kd">public</span> <span 
class="kd">class</span> <span class="nc">MyAction</span> <span 
class="o">{</span>
+    <span class="kd">private</span> <span class="nc">List</span><span 
class="o">&lt;</span><span class="nc">String</span><span class="o">&gt;</span> 
<span class="n">mySelection</span><span class="o">;</span>
+
+    <span class="nd">@StrutsParameter</span><span class="o">(</span><span 
class="n">depth</span> <span class="o">=</span> <span class="mi">1</span><span 
class="o">)</span>
+    <span class="kd">public</span> <span class="nc">List</span><span 
class="o">&lt;</span><span class="nc">String</span><span class="o">&gt;</span> 
<span class="nf">getMySelection</span><span class="o">()</span> <span 
class="o">{</span>
+        <span class="k">return</span> <span class="n">mySelection</span><span 
class="o">;</span>
+    <span class="o">}</span>
+    <span class="c1">// ... setter</span>
+<span class="o">}</span>
+</code></pre></div></div>
+
 <p>When populating properties of objects that are already in a collection, 
annotate the
 getter. Because reaching an element’s property requires indexing into the 
collection
 <em>and then</em> following the property, this needs <code 
class="language-plaintext highlighter-rouge">depth = 2</code> (see
diff --git a/content/plugins/json/index.html b/content/plugins/json/index.html
index 43f07cc62..efe51fe41 100644
--- a/content/plugins/json/index.html
+++ b/content/plugins/json/index.html
@@ -183,6 +183,7 @@
       <li><a href="#accepting-json" id="markdown-toc-accepting-json">Accepting 
JSON</a></li>
       <li><a href="#deserialization-limits" 
id="markdown-toc-deserialization-limits">Deserialization limits</a></li>
       <li><a href="#parameter-authorization" 
id="markdown-toc-parameter-authorization">Parameter authorization</a></li>
+      <li><a href="#input-parameter-filtering" 
id="markdown-toc-input-parameter-filtering">Input parameter filtering</a></li>
     </ul>
   </li>
   <li><a href="#json-rpc" id="markdown-toc-json-rpc">JSON RPC</a></li>
@@ -816,6 +817,70 @@ annotation <strong>per property, during 
deserialization</strong> — unauthorize
 never set on the target object. Annotate the action properties that may be
 populated from the JSON request body.</p>
 
+<h3 id="input-parameter-filtering">Input parameter filtering</h3>
+
+<p>Since Struts 7.3.0, populating an action from a JSON request body applies 
the
+same name/value acceptability controls that the
+<a href="../../core-developers/parameters-interceptor.html">Parameters 
Interceptor</a>
+applies to ordinary HTTP request parameters. Filtering uses the same
+dotted/indexed key paths as form parameters (<code class="language-plaintext 
highlighter-rouge">address.city</code>, <code class="language-plaintext 
highlighter-rouge">items[0].name</code>),
+so the shared pattern checkers behave identically on JSON and form input.
+Population itself stays pure reflection over bean setters — no OGNL name
+evaluation is introduced on the JSON path.</p>
+
+<p>The following controls are <strong>always on</strong>:</p>
+
+<ul>
+  <li><strong>Excluded and accepted name patterns</strong> — the same 
framework-wide
+accepted/excluded parameter-name patterns the Parameters Interceptor uses. A
+JSON key whose full dotted/indexed path matches an excluded pattern, or fails
+to match any accepted pattern, is not populated.</li>
+  <li><strong>Maximum key-path length</strong> — set with the <code 
class="language-plaintext highlighter-rouge">paramNameMaxLength</code> 
interceptor
+param (default <code class="language-plaintext highlighter-rouge">100</code>). 
JSON keys whose full dotted path is longer are rejected.</li>
+  <li><strong><code class="language-plaintext 
highlighter-rouge">ParameterNameAware</code> / <code class="language-plaintext 
highlighter-rouge">ParameterValueAware</code></strong> action callbacks — 
honored for
+JSON input exactly as for form parameters.</li>
+  <li><strong><code class="language-plaintext 
highlighter-rouge">@StrutsParameter</code> authorization</strong> — see
+<a href="#parameter-authorization">Parameter authorization</a> above.</li>
+</ul>
+
+<p>The following controls are <strong>opt-in</strong> — disabled by default to 
preserve existing
+behavior for permissive JSON apps:</p>
+
+<table>
+  <thead>
+    <tr>
+      <th>Interceptor param</th>
+      <th>Default</th>
+      <th>Effect</th>
+    </tr>
+  </thead>
+  <tbody>
+    <tr>
+      <td><code class="language-plaintext 
highlighter-rouge">acceptedValuePatterns</code></td>
+      <td><em>(none)</em></td>
+      <td>Comma-delimited regular expressions; when set, only JSON leaf 
<strong>values</strong> matching one of them are accepted (matching is 
case-insensitive).</td>
+    </tr>
+    <tr>
+      <td><code class="language-plaintext 
highlighter-rouge">excludedValuePatterns</code></td>
+      <td><em>(none)</em></td>
+      <td>Comma-delimited regular expressions; JSON leaf 
<strong>values</strong> matching any of them are removed (matching is 
case-insensitive).</td>
+    </tr>
+    <tr>
+      <td><code class="language-plaintext 
highlighter-rouge">applyPropertyFiltersToInput</code></td>
+      <td><code class="language-plaintext highlighter-rouge">false</code></td>
+      <td>When <code class="language-plaintext highlighter-rouge">true</code>, 
the interceptor’s own <code class="language-plaintext 
highlighter-rouge">excludeProperties</code> / <code class="language-plaintext 
highlighter-rouge">includeProperties</code> patterns — otherwise used only for 
serialization output — also gate which JSON keys are populated on 
<strong>input</strong>.</td>
+    </tr>
+  </tbody>
+</table>
+
+<div class="language-xml highlighter-rouge"><div class="highlight"><pre 
class="highlight"><code><span class="nt">&lt;interceptor-ref</span> <span 
class="na">name=</span><span class="s">"json"</span><span class="nt">&gt;</span>
+  <span class="nt">&lt;param</span> <span class="na">name=</span><span 
class="s">"paramNameMaxLength"</span><span class="nt">&gt;</span>120<span 
class="nt">&lt;/param&gt;</span>
+  <span class="nt">&lt;param</span> <span class="na">name=</span><span 
class="s">"acceptedValuePatterns"</span><span 
class="nt">&gt;</span>[\w\s.@-]+<span class="nt">&lt;/param&gt;</span>
+  <span class="nt">&lt;param</span> <span class="na">name=</span><span 
class="s">"applyPropertyFiltersToInput"</span><span 
class="nt">&gt;</span>true<span class="nt">&lt;/param&gt;</span>
+  <span class="nt">&lt;param</span> <span class="na">name=</span><span 
class="s">"excludeProperties"</span><span 
class="nt">&gt;</span>login.password<span class="nt">&lt;/param&gt;</span>
+<span class="nt">&lt;/interceptor-ref&gt;</span>
+</code></pre></div></div>
+
 <h2 id="json-rpc">JSON RPC</h2>
 
 <p>The json plugin can be used to execute action methods from javascript and 
return the output. This feature was developed 

Reply via email to