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 59e8f447e DOCS: Refine @StrutsParameter annotation documentation (#282)
59e8f447e is described below

commit 59e8f447eaf4a99b0dce012a9afa7bcdac353000
Author: Lukasz Lenart <[email protected]>
AuthorDate: Sat Oct 18 14:29:17 2025 +0200

    DOCS: Refine @StrutsParameter annotation documentation (#282)
    
    The documentation for the `@StrutsParameter` annotation has been updated to 
provide clearer and more accurate guidance on its usage, especially in 
combination with checkboxes and collections.
    
    - Clarified the placement of the annotation based on the field type 
(simple, checkbox, complex object/collection) and the intended population 
behavior.
    - Corrected the examples to reflect the proper usage.
    - Added a section to the `checkbox-interceptor.md` documentation to explain 
how to use `@StrutsParameter` with checkbox lists.
---
 GEMINI.md                                          |  45 ++++++++
 source/core-developers/checkbox-interceptor.md     |  47 +++++++--
 .../core-developers/struts-parameter-annotation.md | 117 +++++++++++++++++----
 3 files changed, 181 insertions(+), 28 deletions(-)

diff --git a/GEMINI.md b/GEMINI.md
new file mode 100644
index 000000000..632a1c899
--- /dev/null
+++ b/GEMINI.md
@@ -0,0 +1,45 @@
+# Apache Struts Website
+
+## Project Overview
+
+This project contains the source code for the official Apache Struts website 
(https://struts.apache.org/). It is a static website generated by Jekyll. The 
site's content is written in Markdown and HTML. The project uses Maven to 
manage the build process, including fetching and converting documentation from 
Confluence.
+
+**Key Technologies:**
+
+*   **Jekyll:** A static site generator written in Ruby.
+*   **Maven:** A build automation tool used to manage the project's build 
lifecycle.
+*   **Java:** Used for the custom tools that fetch and convert documentation 
from Confluence.
+*   **HTML/CSS/JavaScript:** The core technologies used for the website's 
frontend.
+*   **Markdown (kramdown):** Used for writing the content of the website.
+
+**Architecture:**
+
+The website is structured as a typical Jekyll project. The main configuration 
is in `_config.yml`. The source files are in the `source` directory. The 
website's layout and includes are in the `_layouts` and `_includes` 
directories, respectively. The documentation is partially sourced from 
Confluence and converted to Markdown using custom Java tools managed by Maven.
+
+## Building and Running
+
+To build and run the website locally, you can use either Bundler and Jekyll 
directly or Docker.
+
+**Using Bundler and Jekyll:**
+
+1.  Install Bundler: `gem install bundler`
+2.  Install dependencies: `bundle install`
+3.  Run the Jekyll server: `bundle exec jekyll serve -w --trace --host 0.0.0.0`
+
+The website will be available at http://localhost:4000.
+
+**Using Docker:**
+
+There are shell scripts available to run the website in a Docker container:
+
+*   `./docker-run.sh` (for Bash/Sh)
+*   `./docker-run.fish` (for Fish shell)
+
+These scripts will build the Docker image and run the Jekyll server. The 
website will be available at http://localhost:4000.
+
+## Development Conventions
+
+*   **Content:** Content is written in Markdown (`.md`) or HTML (`.html`) 
files in the `source` directory.
+*   **Styling:** The website uses Bootstrap for styling. Custom styles are in 
the `source/css` directory.
+*   **Documentation:** The documentation is a mix of Markdown files and 
content imported from the Struts Confluence wiki. The import process is managed 
by Maven profiles.
+*   **Updating the Website:** The `README.md` file contains instructions on 
how to update the live website.
diff --git a/source/core-developers/checkbox-interceptor.md 
b/source/core-developers/checkbox-interceptor.md
index a3e1857ea..38aa2fc72 100644
--- a/source/core-developers/checkbox-interceptor.md
+++ b/source/core-developers/checkbox-interceptor.md
@@ -8,19 +8,50 @@ parent:
 
 # Checkbox Interceptor
 
-This interceptor is  defined in the `defaultStack`. It checks each form 
parameter submitted  to the action and if it 
-finds one with a prefix of `_checkbox` it inserts a value for a parameter 
whose name is derived from the suffix 
-to `_checkbox` if it does not exist. The default value inserted is `false` but 
this can be changed by setting 
-the `uncheckedValue` parameter on the interceptor.
+This interceptor is defined in the `defaultStack`. It is essential for 
handling HTML checkboxes, as unchecked checkboxes are not submitted as part of 
a form. This interceptor ensures that a value is always present for a checkbox, 
so that in the Action class, the property is not `null`.
 
-This means that a checkbox can be accompanied by a hidden input with the same 
name but a prefix of `_checkbox` so that 
-if the checkbox is not checked on the form the action will still receive a 
value rather than the default HTML action 
-of not providing a value for unchecked checkboxes.
+## How it works
+
+The interceptor looks for a special hidden field in the form that is 
associated with the checkbox. This hidden field must have a name that starts 
with `__checkbox_` followed by the name of the checkbox. For example, if your 
checkbox is named `myCheckbox`, the hidden field should be named 
`__checkbox_myCheckbox`.
+
+When the form is submitted, the `CheckboxInterceptor` does the following:
+1. It iterates through the request parameters.
+2. If it finds a parameter that starts with `__checkbox_`, it extracts the 
name of the checkbox from it (e.g., `myCheckbox`).
+3. It then checks if a parameter with the checkbox's name (`myCheckbox`) 
exists in the request.
+4. If the checkbox parameter does not exist (which means the checkbox was 
unchecked), the interceptor adds a new parameter to the request with the 
checkbox's name and a value of `false`.
+5. Finally, it removes the `__checkbox_` prefixed parameters from the request, 
so they are not processed further.
+
+This ensures that the Action property for the checkbox will be set to `false` 
instead of being `null`.
+
+The `<s:checkbox>` tag from the Struts UI Tags library automatically generates 
this hidden field for you.
 
 ## Parameters
 
- - `uncheckedValue` - the default value of an unchecked box can be overridden 
by setting the `uncheckedValue` property.
+ - `uncheckedValue` - The default value for an unchecked box is `false`. You 
can override this by setting the `uncheckedValue` property on the interceptor.
 
 ## Extending the Interceptor
 
 This interceptor does not have any known extension points.
+
+## Checkbox lists usage with @StrutsParameter
+
+The `<s:checkboxlist>` tag is used to render a list of checkboxes. When using 
this tag, the submitted values are populated into a `Collection` or an array in 
your Action.
+When using `@StrutsParameter` with a checkbox list, you must place the 
annotation on the setter method of the collection property.
+
+### Example
+
+```java
+public class MyAction extends ActionSupport {
+    private Collection<String> mySelection;
+
+    @StrutsParameter
+    public void setMySelection(Collection<String> mySelection) {
+        this.mySelection = mySelection;
+    }
+
+    @StrutsParameter
+    public Collection<String> getMySelection() {
+        return mySelection;
+    }
+}
+```
diff --git a/source/core-developers/struts-parameter-annotation.md 
b/source/core-developers/struts-parameter-annotation.md
index 75bf508f3..1e043dcd6 100644
--- a/source/core-developers/struts-parameter-annotation.md
+++ b/source/core-developers/struts-parameter-annotation.md
@@ -14,38 +14,115 @@ Why it matters: by default (when annotations are 
required), Struts will only inj
 
 ## Usage
 
-Used to annotate public _getter/setter_ methods or _fields_ on Action classes 
that are intended for parameter injection
+The placement of the `@StrutsParameter` annotation is crucial and depends on 
how you want to populate your action properties.
 
-## Parameters
+- **On a public setter method:** Place the annotation on a setter method when 
you want to populate the property with a value from the request. This applies 
to:
+    - Simple types (String, int, boolean, etc.).
+    - Checkboxes (single or multiple values).
+    - Collections and Maps, when you are populating the whole collection/map 
from the request.
 
-- `depth` controls how deep into nested objects parameters can be set:
+- **On a public getter method:** Place the annotation on a getter method when 
you want to allow populating the properties of the object returned by the 
getter. The `depth` parameter is used to control how deep the object graph can 
be populated. This is typically used for complex objects or collections of 
complex objects.
+
+- **On a public field:** For simple types, you can place the annotation 
directly on the public field as a shorthand for a setter annotation.
 
 ## Examples
 
+### Simple field
+
+Annotating the field:
 ```java
 public class MyAction {
     @StrutsParameter
     public String username;  // ✅ Can receive request parameter
+}
+```
+Annotating the setter:
+```java
+public class MyAction {
+    private String username;
+    @StrutsParameter
+    public void setUsername(String username) {
+        this.username = username;
+    }
+}
+```
 
-    public String password;  // ❌ Cannot receive request parameter (not 
annotated)
+### Checkbox
+
+For a single checkbox, the annotation must be on the setter.
+```java
+public class MyAction {
+    private boolean myCheckbox;
+
+    @StrutsParameter
+    public void setMyCheckbox(boolean myCheckbox) {
+        this.myCheckbox = myCheckbox;
+    }
+    // ... getter
 }
 ```
 
-The `depth` controls how deep into nested objects parameters can be set:
-- `depth = 0` (default): Only sets values directly on your action
-  ```
+### Collections
+
+#### Populating a collection of simple types
+
+When populating a collection of simple types (e.g., from a checkbox list), 
annotate the setter.
+```java
+public class MyAction {
+    private List<String> mySelection;
+
     @StrutsParameter
-    public String name;  // Accepts: ?name=value
-  ```
-- `depth = 1`: Allows one level of nesting
-  ```
+    public void setMySelection(List<String> mySelection) {
+        this.mySelection = mySelection;
+    }
+    // ... getter
+}
+```
+
+#### Populating properties of objects within a collection
+
+When populating properties of objects that are already in a collection, 
annotate the getter.
+```java
+public class MyAction {
+    private List<User> users; // assume this is initialized in the constructor 
or elsewhere
+
+    @StrutsParameter(depth = 1)
+    public List<User> getUsers() {
+        return users;
+    }
+    // ...
+}
+```
+This allows requests like `users[0].name=John`.
+
+### Complex object
+
+#### Populating the object itself
+
+To populate the whole object from the request (e.g., using a custom type 
converter), annotate the setter.
+```java
+public class MyAction {
+    private User user;
+
+    @StrutsParameter
+    public void setUser(User user) {
+        this.user = user;
+    }
+    // ... getter
+}
+```
+
+#### Populating properties of a complex object
+
+To populate the properties of a complex object, annotate the getter.
+```java
+public class MyAction {
+    private User user = new User();
+
     @StrutsParameter(depth = 1)
-    public User user;  // Accepts: ?user.name=value
-  ```
-- `depth = 2`: Allows two levels of nesting
-  ```
-    @StrutsParameter(depth = 2)
-    public User user;  // Accepts: ?user.address.city=value
-  ```
-
-Rule of thumb: The depth equals the number of dots (or brackets) allowed in 
the parameter name.
+    public User getUser() {
+        return user;
+    }
+}
+```
+This allows requests like `user.name=John`.

Reply via email to