bengbengbalabalabeng opened a new issue, #741:
URL: https://github.com/apache/fesod/issues/741

   ### Search before asking
   
   - [x] I searched in the [issues](https://github.com/apache/fesod/issues) and 
found nothing similar.
   
   
   ### Motivation
   
   This enhancement aims to integrate the **Bean Validation API** into the 
Fesod reading lifecycle, allowing users to define validation rules 
declaratively using annotations on their POJOs. This will eliminate the need 
for redundant and complex validation logic—such as long chains of `if-else` 
statements—within `ReadListener` implementations, resulting in a more robust 
and maintainable data validation solution.
   
   ### Solution
   
   To provide comprehensive support for Bean Validation, we must address the 
namespace change from `javax.validation` to `jakarta.validation` that occurred 
after Java 8. Given that Fesod supports a wide range of JDKs (8 through 25), a 
flexible, multi-module approach is required.
   
   ### Content
   
   1. A `Validator` SPI (Service Provider Interface) will be defined within the 
main `fesod` module. This ensures the core library remains decoupled from any 
specific validation API.
   2. Create two separate adapter modules:
   - `fesod-bval` will adapt Fesod's SPI to the **`jakarta.validation`** API.
   - `fesod-bval-javax` will be created by duplicating `fesod-bval` and 
modifying the imports to support the legacy **`javax.validation`** API.
   3.  The adapter modules will only depend on the standard Bean Validation 
APIs. The user is free to choose and provide any compliant implementation 
(e.g., Hibernate Validator, Apache BVal).
   
   ```mermaid
   graph TD
       app["Application"]
   
       subgraph "SPI Definition"
           A["fesod"]
       end
   
       subgraph " "
           B["fesod-bval (for jakarta)"]
           C["fesod-bval-javax (for javax)"]
       end
       
       subgraph " "
           D["hibernate-validator"]
           E["apache bval-jsr"]
           F["others"]
       end
   
       A --> B
       A --> C
       app -.-> A
       app -.-> adapters{"Choose One SPI Implementation"}
       adapters -.-> B
       adapters -.-> C
       app -.-> beanvalidation{"Choose One Bean Validation Implementation"}
       beanvalidation -.-> D
       beanvalidation -.-> E
       beanvalidation -.-> F
   ```
   
   ### API Usage Example
   
   #### 1. Add Dependencies
   
   ```xml
   <dependency>
       <groupId>org.apache.fesod</groupId>
       <artifactId>fesod</artifactId>
       <version>${fesod.version}</version>
   </dependency>
   
   <dependency>
       <groupId>org.apache.fesod</groupId>
       <artifactId>fesod-bval</artifactId>
       <version>${fesod.version}</version>
   </dependency>
   
   <!-- Users provide their chosen Bean Validation implementation, e.g., 
Hibernate Validator, Apache BVal -->
   <dependency>
       <groupId>org.hibernate.validator</groupId>
       <artifactId>hibernate-validator</artifactId>
       <version>${hibernate-validator.version}</version>
   </dependency>
   <!-- EL Support -->
   <dependency>
       <groupId>org.glassfish.expressly</groupId>
       <artifactId>expressly</artifactId>
       <version>${expressly.version}</version>
   </dependency>
   ```
   
   #### 2. Define the POJO with Validation Annotations
   
   ```java
   public class ExcelModel {
        
        @NotBlank(message = "In sheet '{sheetName}', row {rownum}, column 
{column}: Name is required")
        @ExcelProperty("Name")
        private String name;
   
        @Min(value = 20, message = "Age must be greater than or equal to 
{value}")
        @ExcelProperty("Age")
        private Integer age;
   }
   ```
   
   #### 3. Read the Excel File
   
   ```java
   File file = new File("file.xlsx");
   
   Fesod.read(file, ExcelModel.class, new CustomAnalysisEventListener())
        .useValidation(true)
        .sheet()
        .doRead();
   ```
   
   The `ValidatingAnalysisEventListener` provides precise error information 
through its callback methods. After the entire analysis is complete, a 
comprehensive `Errors` object containing all validation failures can be 
retrieved via a new convenience method on the `AnalysisContext`. The `Errors` 
object contains a detailed list of `RowError` (for row-level validation) and 
`PropertyError` (for cell-level validation) objects.
   
   ```java
   public class CustomAnalysisEventListener extends 
ValidatingAnalysisEventListener<ExcelModel> {
        
        @Override
        public void onValidated(ExcelModel data, AnalysisContext context) {
                // Called for each row that successfully passes validation.
        }
   
        @Override
       public void onValidated(ExcelModel data, List<RowError> 
validationErrors, AnalysisContext context) {
        // Called for each row that fails validation.
        // Each error in validationErrors contains detailed context like 
sheetNo, sheetName, rownum...
       }
   
       @Override
       public void doAfterAllAnalysed(AnalysisContext context) {
         // Retrieve the full report of all errors
         Errors validatedErrors = context.getValidationErrors();
         if (validatedErrors.hasErrors) {
                // ...
         }
       }
   }
   ```
   
   #### 4. Support Fesod-Specific Parameters Expression (such as `{sheetNo}`, 
`{sheetName}`, `{rownum}`, and `{column}` ...)
   
   ```txt
   Before > "In sheet '{sheetName}', row {rownum}, column {column}: Name is 
required"
   
   After  > "In sheet 'Sheet1', row 1, column 1: Name is required"
   ```
   
   ### Alternatives
   
   Regarding compatibility support for the `javax.validation` namespace, an 
alternative approach was considered: maintaining only a single source module, 
`fesod-bval` (for Jakarta), and then leveraging a build plugin like 
`maven-shade-plugin`, `transformer-maven-plugin` to dynamically transform the 
`jakarta.*` namespace into `javax.*` during the packaging phase.
   
   The intended outcome of this strategy was to generate two distinct artifacts 
using a classifier, allowing users to choose the one that fits their 
environment:
   
   ```xml
   <!-- For Jakarta support -->
   <dependency>
       <groupId>org.apache.fesod</groupId>
       <artifactId>fesod-bval</artifactId>
       <version>${fesod.version}</version>
   </dependency>
   
   <!-- For Javax support -->
   <dependency>
       <groupId>org.apache.fesod</groupId>
       <artifactId>fesod-bval</artifactId>
       <version>${fesod.version}</version>
       <classifier>javax</classifier>
   </dependency>
   ```
   
   Problem:
   
   The build plugins are unable to modify the dependency declarations within 
the generated `pom.xml` file. This would require manual intervention after the 
build, which is incompatible with and unfriendly to our automated CI/CD 
processes, such as the GitHub workflows.
   
   ### Anything else?
   
   _No response_
   
   ### Are you willing to submit a PR?
   
   - [x] I'm willing to submit a PR!


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to