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> +<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> + <!-- Input: directory containing *.hbm.xml --> + <arg value="src/main/resources"/> + <!-- Output: OpenAPI 3.0 JSON with all schemas --> + <arg value="build/openapi-schemas.json"/> + </java> +</target> +</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>
