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

robertlazarski pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/axis-axis2-java-core.git

commit 2940ab7d2cd4206205f1a34e32b83677d2415a32
Author: Robert Lazarski <[email protected]>
AuthorDate: Mon May 11 16:46:05 2026 -1000

    Add HbmBatchSchemaGenerator CLI tool for bulk HBM→OpenAPI conversion
    
    Standalone command-line tool that scans a directory of *.hbm.xml files
    and produces a single OpenAPI 3.0 JSON document with read and write
    schemas for every entity found.
    
    Features:
    - Deterministic output (sorted file processing)
    - Per-entity console reporting (field count, relationship count)
    - Read schema: all fields, generated IDs marked readOnly
    - Write schema: excludes @GeneratedValue, @Version, custom audit
    - Exit codes for build tool integration (0=success, 1=args, 2=no input, 
3=IO)
    - No database, SessionFactory, or compiled classes required
    
    Usage:
      java -cp ... HbmBatchSchemaGenerator <hbm-dir> <output.json> [annotations]
    
    Updated openapi-jpa-schema.xml documentation with batch generation
    section covering CLI usage, Ant integration, output format, and
    build pipeline positioning.
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
---
 .../axis2/jpa/schema/HbmBatchSchemaGenerator.java  | 219 +++++++++++++++++++++
 src/site/markdown/docs/mcp-examples.md             |   2 +-
 src/site/xdoc/docs/openapi-jpa-schema.xml          | 109 +++++++++-
 src/site/xdoc/docs/toc.xml                         |   2 +-
 4 files changed, 329 insertions(+), 3 deletions(-)

diff --git 
a/modules/jpa-schema/src/main/java/org/apache/axis2/jpa/schema/HbmBatchSchemaGenerator.java
 
b/modules/jpa-schema/src/main/java/org/apache/axis2/jpa/schema/HbmBatchSchemaGenerator.java
new file mode 100644
index 0000000000..b6206e9f97
--- /dev/null
+++ 
b/modules/jpa-schema/src/main/java/org/apache/axis2/jpa/schema/HbmBatchSchemaGenerator.java
@@ -0,0 +1,219 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.axis2.jpa.schema;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Batch generator that scans a directory of Hibernate XML mapping files
+ * ({@code *.hbm.xml}) and produces a single JSON file containing OpenAPI
+ * 3.0 component schemas for every entity found.
+ *
+ * <p>Designed to run as a standalone build tool — invoked from Ant, Maven,
+ * Gradle, or the command line. The output file is a self-contained OpenAPI
+ * {@code components/schemas} fragment that can be merged into an OpenAPI
+ * specification or served directly by an Axis2 service.
+ *
+ * <h3>Command-line usage</h3>
+ * <pre>{@code
+ * java -cp axis2-jpa-schema.jar:jackson-*.jar \
+ *   org.apache.axis2.jpa.schema.HbmBatchSchemaGenerator \
+ *   src/main/resources \
+ *   build/openapi-schemas.json
+ * }</pre>
+ *
+ * <h3>Ant integration</h3>
+ * <pre>{@code
+ * <target name="openapi-schema"
+ *         description="Generate OpenAPI schemas from HBM XML mappings">
+ *     <java classname="org.apache.axis2.jpa.schema.HbmBatchSchemaGenerator"
+ *           fork="true" failonerror="true">
+ *         <classpath>
+ *             <fileset dir="lib" 
includes="axis2-jpa-schema*.jar,jackson-*.jar,commons-logging*.jar"/>
+ *         </classpath>
+ *         <arg value="src/main/resources"/>
+ *         <arg value="build/openapi-schemas.json"/>
+ *     </java>
+ * </target>
+ * }</pre>
+ *
+ * <h3>Output format</h3>
+ * <pre>{@code
+ * {
+ *   "openapi": "3.0.1",
+ *   "info": {
+ *     "title": "Generated from 146 HBM XML mappings",
+ *     "version": "1.0.0"
+ *   },
+ *   "components": {
+ *     "schemas": {
+ *       "CompanyBO": { "type": "object", "properties": { ... } },
+ *       "CompanyBOWrite": { "type": "object", "properties": { ... } },
+ *       "DepartmentBO": { ... },
+ *       "DepartmentBOWrite": { ... },
+ *       ...
+ *     }
+ *   }
+ * }
+ * }</pre>
+ *
+ * <p>Each entity produces two schemas: a read schema (all fields, IDs
+ * marked {@code readOnly}) and a write schema (excludes
+ * {@code @GeneratedValue} IDs, {@code @Version} fields, and any fields
+ * annotated with custom write-exclude annotations).
+ *
+ * <h3>Exit codes</h3>
+ * <ul>
+ *   <li>0 — success</li>
+ *   <li>1 — invalid arguments</li>
+ *   <li>2 — input directory does not exist or contains no HBM files</li>
+ *   <li>3 — I/O error writing output</li>
+ * </ul>
+ */
+public class HbmBatchSchemaGenerator {
+
+    public static void main(String[] args) {
+        if (args.length != 2) {
+            System.err.println("Usage: HbmBatchSchemaGenerator <hbm-dir> 
<output-json>");
+            System.err.println();
+            System.err.println("  hbm-dir       Directory containing *.hbm.xml 
files");
+            System.err.println("  output-json   Output file path (e.g., 
openapi-schemas.json)");
+            System.err.println();
+            System.err.println("Example:");
+            System.err.println("  java -cp ... 
org.apache.axis2.jpa.schema.HbmBatchSchemaGenerator \\");
+            System.err.println("    src/main/resources 
build/openapi-schemas.json");
+            System.exit(1);
+        }
+
+        File inputDir = new File(args[0]);
+        File outputFile = new File(args[1]);
+
+        if (!inputDir.isDirectory()) {
+            System.err.println("ERROR: Not a directory: " + 
inputDir.getAbsolutePath());
+            System.exit(2);
+        }
+
+        File[] hbmFiles = inputDir.listFiles((dir, name) ->
+                name.endsWith(".hbm.xml"));
+        if (hbmFiles == null || hbmFiles.length == 0) {
+            System.err.println("ERROR: No *.hbm.xml files found in: " + 
inputDir.getAbsolutePath());
+            System.exit(2);
+        }
+
+        // Sort for deterministic output ordering
+        Arrays.sort(hbmFiles);
+
+        HbmXmlIntrospector introspector = new HbmXmlIntrospector();
+        Map<String, ObjectNode> allSchemas = new LinkedHashMap<>();
+
+        int successCount = 0;
+        int errorCount = 0;
+
+        for (File hbmFile : hbmFiles) {
+            try (InputStream is = new FileInputStream(hbmFile)) {
+                EntitySchemaModel model = introspector.introspect(is, 
hbmFile.getName());
+                if (model == null) {
+                    System.err.println("  SKIP " + hbmFile.getName() + " (no 
entity found)");
+                    continue;
+                }
+
+                Map<String, ObjectNode> schemas = 
JpaSchemaGenerator.generateBothSchemas(model);
+                allSchemas.putAll(schemas);
+                successCount++;
+
+                int fieldCount = model.getFields().size();
+                int relCount = (int) model.getFields().values().stream()
+                        .filter(f -> f.getRefEntityName() != null).count();
+                System.out.println("  OK   " + hbmFile.getName()
+                        + " → " + model.getEntityName()
+                        + " (" + fieldCount + " fields, " + relCount + " 
relationships)");
+
+            } catch (IOException e) {
+                System.err.println("  FAIL " + hbmFile.getName() + " (I/O): " 
+ e.getMessage());
+                errorCount++;
+            } catch (RuntimeException e) {
+                System.err.println("  FAIL " + hbmFile.getName() + " 
(unexpected):");
+                e.printStackTrace(System.err);
+                errorCount++;
+            }
+        }
+
+        if (allSchemas.isEmpty()) {
+            System.err.println("ERROR: No schemas generated from " + 
hbmFiles.length + " files");
+            System.exit(2);
+        }
+
+        // Build the OpenAPI 3.0 document structure
+        ObjectMapper mapper = new ObjectMapper();
+        mapper.enable(SerializationFeature.INDENT_OUTPUT);
+
+        ObjectNode root = mapper.createObjectNode();
+        root.put("openapi", "3.0.1");
+
+        ObjectNode info = root.putObject("info");
+        info.put("title", "Generated from " + successCount + " HBM XML 
mappings");
+        info.put("version", "1.0.0");
+        info.put("description",
+                "Auto-generated OpenAPI component schemas from Hibernate XML 
mappings. "
+                + "Each entity has a read schema (all fields) and a write 
schema "
+                + "(excludes server-managed fields like generated IDs, 
version, "
+                + "and audit timestamps).");
+
+        ObjectNode components = root.putObject("components");
+        ObjectNode schemas = components.putObject("schemas");
+        for (Map.Entry<String, ObjectNode> entry : allSchemas.entrySet()) {
+            schemas.set(entry.getKey(), entry.getValue());
+        }
+
+        // Write output
+        try {
+            File parentDir = outputFile.getParentFile();
+            if (parentDir != null && !parentDir.exists()) {
+                parentDir.mkdirs();
+            }
+            try (FileWriter writer = new FileWriter(outputFile)) {
+                writer.write(mapper.writeValueAsString(root));
+            }
+        } catch (IOException e) {
+            System.err.println("ERROR: Failed to write output: " + 
e.getMessage());
+            System.exit(3);
+        }
+
+        System.out.println();
+        System.out.println("Generated " + allSchemas.size() + " schemas"
+                + " (" + successCount + " entities × 2 [read + write])"
+                + " from " + hbmFiles.length + " HBM files");
+        if (errorCount > 0) {
+            System.out.println("WARNING: " + errorCount + " files had errors");
+        }
+        System.out.println("Output: " + outputFile.getAbsolutePath());
+    }
+}
diff --git a/src/site/markdown/docs/mcp-examples.md 
b/src/site/markdown/docs/mcp-examples.md
index 1b3bef0fef..afcfcdf040 100644
--- a/src/site/markdown/docs/mcp-examples.md
+++ b/src/site/markdown/docs/mcp-examples.md
@@ -93,7 +93,7 @@ All curl examples below include paired MCP stdio equivalents.
 
 ---
 
-## Live Examples (Tested on WildFly 32.0.1.Final, 2026-04-08)
+## Live Examples (Tested on WildFly 32)
 
 ### Portfolio Variance — 5 assets
 
diff --git a/src/site/xdoc/docs/openapi-jpa-schema.xml 
b/src/site/xdoc/docs/openapi-jpa-schema.xml
index badb7c6c04..54a773c5a6 100644
--- a/src/site/xdoc/docs/openapi-jpa-schema.xml
+++ b/src/site/xdoc/docs/openapi-jpa-schema.xml
@@ -205,7 +205,114 @@ components convention:</p>
 </pre>
 
 <p>The caller is responsible for ensuring that referenced entity schemas
-are also generated and added to the OpenAPI components section.</p>
+are also generated and added to the OpenAPI components section.  The
+batch generator (below) handles this automatically by processing all
+HBM files in a directory at once.</p>
+
+<h2 id="batch_generation">Batch Generation from HBM XML Directory</h2>
+
+<p><code>HbmBatchSchemaGenerator</code> is a standalone command-line tool
+that scans a directory of <code>*.hbm.xml</code> files and produces a single
+OpenAPI 3.0 JSON document containing read and write schemas for every
+entity found.  This is the recommended approach for projects with many
+HBM-mapped entities.</p>
+
+<h3>Command Line</h3>
+<pre>
+java -cp 
axis2-jpa-schema.jar:jackson-databind.jar:jackson-core.jar:jackson-annotations.jar:commons-logging.jar
 \
+  org.apache.axis2.jpa.schema.HbmBatchSchemaGenerator \
+  src/main/resources \
+  resources-axis2/openapi-schemas.json
+</pre>
+
+<h3>Ant Integration</h3>
+
+<p>The batch generator follows the same pattern as Hibernate Tools'
+<code>hbm2java</code> and <code>hbm2ddl</code> tasks — same HBM input
+directory, different output artifact:</p>
+
+<pre>
+&lt;target name="openapi-schema"
+        description="Generate OpenAPI schemas from HBM XML mappings"&gt;
+    &lt;java classname="org.apache.axis2.jpa.schema.HbmBatchSchemaGenerator"
+          fork="true" failonerror="true"&gt;
+        &lt;classpath&gt;
+            &lt;fileset dir="lib" 
includes="axis2-jpa-schema*.jar,jackson-*.jar,commons-logging*.jar"/&gt;
+        &lt;/classpath&gt;
+        &lt;!-- Input: directory containing *.hbm.xml --&gt;
+        &lt;arg value="src/main/resources"/&gt;
+        &lt;!-- Output: OpenAPI 3.0 JSON with all schemas --&gt;
+        &lt;arg value="build/openapi-schemas.json"/&gt;
+    &lt;/java&gt;
+&lt;/target&gt;
+</pre>
+
+<h3>Output</h3>
+
+<p>The tool produces a valid OpenAPI 3.0 document:</p>
+
+<pre>
+{
+  "openapi": "3.0.1",
+  "info": {
+    "title": "Generated from 146 HBM XML mappings",
+    "version": "1.0.0"
+  },
+  "components": {
+    "schemas": {
+      "CompanyBO": { "type": "object", "properties": { ... } },
+      "CompanyBOWrite": { "type": "object", "properties": { ... } },
+      "DepartmentBO": { ... },
+      "DepartmentBOWrite": { ... },
+      "ProductBO": { ... },
+      "ProductBOWrite": { ... }
+    }
+  }
+}
+</pre>
+
+<p>Each entity produces two schemas:</p>
+<ul>
+  <li><strong>EntityBO</strong> — read schema (GET responses): all fields,
+    generated IDs marked <code>readOnly</code></li>
+  <li><strong>EntityBOWrite</strong> — write schema (POST/PUT requests):
+    excludes generated IDs, version fields, and custom audit annotations</li>
+</ul>
+
+<p>Console output reports each entity processed:</p>
+<pre>
+  OK   CompanyBO.hbm.xml → CompanyBO (12 fields, 2 relationships)
+  OK   DepartmentBO.hbm.xml → DepartmentBO (58 fields, 8 relationships)
+  OK   ProductBO.hbm.xml → ProductBO (8 fields, 1 relationships)
+  OK   OrderBO.hbm.xml → OrderBO (15 fields, 3 relationships)
+  SKIP HistoryData.hbm.xml (no entity found)
+
+Generated 8 schemas (4 entities × 2 [read + write]) from 5 HBM files
+Output: /path/to/resources-axis2/openapi-schemas.json
+</pre>
+
+<h3>Build Pipeline Position</h3>
+
+<p>The schema generator reads HBM XML files directly — it does not
+depend on compiled Java classes, a running database, or a Hibernate
+<code>SessionFactory</code>.  This means it can run:</p>
+
+<ul>
+  <li><strong>Before <code>codegen</code></strong> — HBM files are the
+    source of truth; the generator reads them before Java classes are
+    generated</li>
+  <li><strong>In CI</strong> — no database connection required, so it
+    runs in any CI environment</li>
+  <li><strong>On schema change</strong> — regenerate whenever an HBM
+    file changes; diff the output JSON to see exactly which fields or
+    relationships changed</li>
+</ul>
+
+<p>For projects that use Ant with Hibernate Tools, add
+<code>openapi-schema</code> to your existing build pipeline after
+code generation and before packaging.  The schemas will reflect the
+same entity definitions that the generated Java code and DDL use.</p>
 
 </body>
 </html>
+
diff --git a/src/site/xdoc/docs/toc.xml b/src/site/xdoc/docs/toc.xml
index 14c8f5e94d..37158a1063 100644
--- a/src/site/xdoc/docs/toc.xml
+++ b/src/site/xdoc/docs/toc.xml
@@ -194,7 +194,7 @@ Support</a></li>
     </li>
     <li><strong>23.7 <a href="mcp-examples.html">MCP Examples — Financial 
Services Benchmarks</a></strong>
     <ul>
-        <li><a 
href="mcp-examples.html#Live_Examples_.28Tested_on_WildFly_32.0.1.Final.2C_2026-04-08.29">Live
 Examples (WildFly 32)</a></li>
+        <li><a 
href="mcp-examples.html#Live_Examples_.28Tested_on_WildFly_32.29">Live Examples 
(WildFly 32)</a></li>
         <li><a 
href="mcp-examples.html#Demo_1.3A_Stress-test_.E2.80.94_.E2.80.9CWhat_if_correlations_spike.3F.E2.80.9D">Demo
 1: Stress Test</a></li>
         <li><a 
href="mcp-examples.html#Demo_2.3A_Pre-trade_risk_.E2.80.94_.E2.80.9CShould_I_add_this_name.3F.E2.80.9D">Demo
 2: Pre-Trade Risk</a></li>
         <li><a 
href="mcp-examples.html#Demo_3.3A_Convergence_.E2.80.94_.E2.80.9CHow_much_compute_do_I_actually_need.3F.E2.80.9D">Demo
 3: Convergence</a></li>

Reply via email to