🎯 Motivation & Background
Currently, PolyXML defaults to modern immutable data representations across all ecosystems—specifically Java 21+ record and C# 12 primary constructor record types.
While modern, immutable records provide excellent thread-safety and pattern-matching ergonomics, enterprise engineering teams often face severe friction in real-world production environments when integrating with existing enterprise stacks:
-
Legacy ORM & Framework Compatibility (The Spring/Hibernate Problem):
- Enterprise Java frameworks (Hibernate / JPA, MyBatis, Spring Data, ModelMapper, Dozer, MapStruct, Apache Commons BeanUtils) require a parameterless default constructor (
new EntityMt()) and standard JavaBean getters/setters (getId(), setId(...)).
- Java
record types only provide canonical constructors and component accessor methods named id() instead of getId(), which breaks older reflection-based bean introspection and dynamic proxying.
-
Constructor Parameter Explosion on Massive Schemas:
- Complex enterprise schemas—such as USAF UCI (
EntityMt), ISO 20022 (pacs.008), and CEN NeTEx—routinely feature 40 to 100+ fields, the majority of which are optional.
- With an immutable
record, instantiating an instance manually requires passing 80+ positional arguments:
// Unwieldy and error-prone with 50-80 parameters:
var entity = new EntityMt(id, null, null, null, null, timestamp, null, ...);
- With a traditional class or builder pattern, instantiation is clean and ergonomic:
var entity = new EntityMt();
entity.setId("UUID-1234");
entity.setTimestamp(Instant.now());
-
In-Place Pipeline Mutation:
- In telematics gateways, message routers, and financial settlement switches, an application often receives an XML message, updates 1 or 2 fields (e.g.
status, processedAt), and re-serializes it downstream. Immutability forces copying the entire object hierarchy on every step, causing unnecessary garbage collection churn.
-
Drop-in JAXB (xjc) & xsd.exe Migration:
- Enterprises with 10- to 20-year-old codebases written against
xjc-generated classes often have thousands of lines of code expecting order.getItems().add(...) or entity.setStatus(...). Providing traditional classes enables zero-refactoring, drop-in replacement of JAXB.
🚀 Modern POJOs vs. Legacy JAXB (xjc): Architectural Advantages
While --style pojo provides drop-in compatibility for enterprise codebases expecting JavaBeans, PolyXML does not simply replicate 2003-era JAXB (xjc) output. It modernizes the POJO paradigm with key architectural improvements:
| Feature |
Legacy JAXB (xjc) |
PolyXML Modern POJO (--style pojo) |
| Target Java Version |
Java 5 / 6 / 8 era |
Java 17 / 21+ |
| Dates & Times |
Archaic XMLGregorianCalendar |
Modern java.time.* (Instant, LocalDate, OffsetDateTime) |
| Wrapper Bloat |
JAXBElement<T> & massive ObjectFactory.java |
Clean idiomatic types, direct fields, or standard Optional<T> |
| JSON Support |
❌ None (Forces duplicate DTOs + manual mappers) |
✅ Native dual-serialization (Jackson @JsonProperty & @JacksonXmlProperty) |
| Facet Validation |
❌ Discarded in generated code |
✅ Jakarta Validation annotations (@NotNull, @Size, @Pattern, @Min, @Max) |
| Construction |
Empty constructor + 50 setters |
Fluent, type-safe .builder() pattern (--builder) |
| Performance Engine |
Heavy JVM reflection (JAXBContext.newInstance) |
Jackson, Direct Compile-Time Codecs, or Zero-Copy Panama FFI streaming |
| External Dependencies |
Heavy (jaxb-api / jaxb-impl classpath conflicts) |
Zero required runtime jars (or standard Jackson in Spring Boot) |
Detailed Advantages:
-
Modern Date/Time Types (java.time.*) vs. XMLGregorianCalendar:
- JAXB generates archaic
XMLGregorianCalendar and javax.xml.datatype.Duration (Java 5 era), which are notoriously cumbersome, thread-unsafe, and require manual conversion helpers.
- PolyXML generates standard Java 8+ JSR-310 types directly:
Instant, OffsetDateTime, LocalDate, and LocalTime.
-
Elimination of JAXBElement<T> & ObjectFactory Hell:
- For nillable, substitution, or optional choice elements, JAXB wraps fields in cumbersome
JAXBElement<T> wrappers (e.g. order.getDetails().getValue().getCustomerRef().getValue()) and generates multi-thousand-line ObjectFactory.java boilerplate files.
- PolyXML generates clean, idiomatic Java types with direct nullable fields or standard
Optional<T> accessors—zero JAXBElement<T> wrappers and zero ObjectFactory clutter.
-
Dual-Format Serialization (Single DTO for XML + JSON):
- JAXB is strictly XML-only. In modern microservice architectures, developers must maintain duplicate DTO classes or write complex MapStruct mappers to convert between JAXB XML DTOs and Jackson/REST JSON DTOs.
- PolyXML POJOs support native dual annotations (
@JsonProperty and @JacksonXmlProperty), allowing the exact same POJO to serialize and deserialize to both XML and JSON seamlessly.
-
XSD Facet Enforcement via Jakarta Validation:
- JAXB completely discards XSD facets (
pattern, minLength, maxLength, minInclusive, maxInclusive) in generated Java code, requiring an external Xerces XML validator.
- PolyXML converts XSD facets directly into standard Jakarta Validation annotations (
@NotNull, @Size(min=..., max=...), @Pattern(regexp=...), @Min, @Max), enabling automatic validation at Spring @Valid controller and service boundaries.
-
Type-Safe Fluent Builders (--builder):
- In massive 50–100+ field enterprise schemas (ISO 20022, UCI, FIXML), JAXB leaves developers with an empty constructor and 80 setters. PolyXML generates type-safe fluent builders (
EntityMt.builder().id(...).build()).
-
Escape from Reflection Bottlenecks via Project Panama:
- JAXB depends on heavy runtime reflection (
JAXBContext.newInstance(...)), which causes slow cold starts and high heap churn. PolyXML offers native Rust-powered streaming codecs accessible via Project Panama (Java 22+ FFI JEP 454), running 10x–20x faster with zero reflection.
-
Zero Jakarta/JAXB Dependency Clashes:
- JAXB was removed from the JDK in Java 11, creating constant classpath conflicts (
javax.xml.bind vs jakarta.xml.bind vs jaxb-runtime). PolyXML POJOs run cleanly with standard Java libraries or standard Jackson already present in modern Spring/Quarkus/Micronaut apps.
⚡ High-Performance Modern Java Enhancements (Serialization & Deserialization)
Beyond syntax ergonomics, we can exploit modern Java runtime features to achieve industry-leading serialization/deserialization throughput:
1. Compile-Time Companion Codecs (--codec direct)
- The Problem with Reflection: Traditional libraries (JAXB, standard Jackson, Hibernate) use runtime reflection (
Field.get(), Method.invoke()) to inspect annotations and read/write fields. This incurs dynamic method dispatch checks, boxing overhead, and prevents HotSpot C2 compiler inlining.
- The Solution: PolyXML can generate a companion compile-time serializer/deserializer (
EntityMtCodec.java):
public final class EntityMtCodec {
public static void writeXml(EntityMt entity, XMLStreamWriter writer) throws XMLStreamException {
writer.writeStartElement("EntityMt");
if (entity.getId() != null) {
writer.writeAttribute("id", entity.getId()); // Direct getter, zero reflection
}
if (entity.getTimestamp() != null) {
writer.writeAttribute("timestamp", entity.getTimestamp().toString());
}
writer.writeEndElement();
}
}
- Performance Impact: Direct method calls allow HotSpot C2 to completely inline serialization into the call site, operating at near-handwritten speed with zero reflection overhead.
2. GraalVM Native Image AOT Reachability (Zero Reflection Config)
- In cloud-native microservices (Spring Boot 3 / Quarkus) compiled via GraalVM Native Image (
native-image), JAXB requires manually registering hundreds of classes and private members in reflect-config.json.
- With PolyXML's static builders and optional companion compile-time codecs, the entire serialization graph is 100% statically reachable.
- Impact: Instant sub-15ms container cold-starts, minimal memory footprint (under 35MB RSS), and zero reflection configuration files.
3. Direct UTF-8 & Compact Strings (Zero Allocation Churn)
- Traditional Java XML parsing creates millions of short-lived
java.lang.String instances during parsing ("name", "id", "CONFIRMED"), putting severe pressure on the Garbage Collector.
- PolyXML can generate static UTF-8 byte constants (
byte[]) for all known tag names, attribute keys, and enumeration literals. Tag matching is performed directly against raw incoming byte streams before ever allocating a String on the JVM heap.
4. Project Panama Direct Memory Streaming (Java 22+ JEP 454)
- Using Java 22's Foreign Function & Memory API (
java.lang.foreign.MemorySegment and Arena), PolyXML can parse structured files directly out of native off-heap memory or memory-mapped files without intermediate ByteBuffer heap copies.
5. Project Loom Virtual Thread Friendliness (Java 21 JEP 444)
- Complex reactive async programming models (WebFlux, Mutiny, Netty) are notoriously difficult to debug.
- Because PolyXML streaming serializers and deserializers operate cleanly over standard blocking
InputStream and OutputStream, they run seamlessly on lightweight Java 21 Virtual Threads (Executors.newVirtualThreadPerTaskExecutor()). An application can scale to 100,000+ concurrent XML streaming pipelines with plain, straightforward synchronous code.
🔬 Benchmarking & Tradeoff Analysis
To determine the concrete trade-offs between immutable record, mutable pojo, reflection-based Jackson, and direct compile-time codecs, a comprehensive JMH benchmark must be established.
Benchmark Setup & Tooling
- Framework: Java Microbenchmark Harness (JMH) with
-prof gc (allocation profiler) and Java Flight Recorder (JFR).
- Workloads:
- Financial Batch: 10,000 ISO 20022
pacs.008 settlement messages (~25 MB).
- Telemetry Stream: 50,000 USAF UCI
EntityMt track reports (~35 MB).
- Competitors / Baselines:
- Legacy JAXB (
jakarta.xml.bind.JAXBContext + xjc generated classes).
- Jackson XML (
XmlMapper reading into PolyXML --style pojo).
- PolyXML Direct Companion Codec (
--codec direct + StAX XMLStreamReader).
- PolyXML Zero-Copy Panama FFI (
polyxml-c + Java 22 MemorySegment).
Metrics to Measure
- Throughput (ops/sec & MB/s): Ingestion rate across single-threaded and virtual thread executors.
- Allocation Rate (bytes/op): Heap allocations measured via JMH
-prof gc to evaluate GC pause pressure.
- Warmup Penalty (Cold Start vs Steady State): Number of iterations required to reach peak C2 JIT throughput (measuring the reflection penalty of JAXB/Jackson).
- GraalVM Native Image Compilation Time & Binary Size: Verifying 100% static reachability with zero
reflect-config.json.
Hypothesized Tradeoffs & Evaluation Criteria
-
Immutable Record vs Mutable POJO:
-
Tradeoff: Modern JVMs optimize records via scalar replacement (EA - Escape Analysis). However, when performing in-place pipeline mutations (modifying 1 field in an 80-field object), records require a full copy.
-
Hypothesis: For read-only ingestion,
record matches or edges out pojo. For mutating message broker pipelines, pojo mutability reduces GC churn by $> 40%$.
-
Jackson Reflection vs Direct Companion Codecs:
-
Hypothesis:
--codec direct will outperform Jackson by $\ge 3\times$ in steady-state and $\ge 8\times$ during the first 50 iterations due to zero reflection warmup.
🛠️ Proposed Solution
Introduce a unified --style (or --class-style) CLI flag and configuration option in polyxml.toml:
1. Style Selection: --style <record|pojo>
--style record (Default): Current Java 21+ record and C# 12 record output.
--style pojo (or --style class): Traditional mutable class generation.
2. Fluent Builder Support: --builder
- Generate an inner or standalone fluent Builder pattern for complex classes/records:
var entity = EntityMt.builder()
.id("UUID-1234")
.timestamp(Instant.now())
.build();
This completely solves the constructor parameter explosion problem even when using immutable records.
3. Codec Mode: --codec <annotation|direct>
--codec annotation (Default): Annotates POJOs with Jackson (@JsonProperty, @JacksonXmlProperty) or Jakarta Validation.
--codec direct: In addition to POJOs, generates a zero-reflection companion *Codec.java for maximum HotSpot C2 JIT inlining and GraalVM AOT native-image compatibility.
📋 Design Specifications
A. Java Traditional POJO Generation (use_records = false)
When --style pojo is selected:
-
Class Structure:
public class EntityMt implements Serializable {
private String id;
private Instant timestamp;
private List<SubItem> items = new ArrayList<>();
// 1. No-arg default constructor
public EntityMt() {}
// 2. Standard JavaBean Getters & Setters
public String getId() { return this.id; }
public void setId(String id) { this.id = id; }
public Instant getTimestamp() { return this.timestamp; }
public void setTimestamp(Instant timestamp) { this.timestamp = timestamp; }
// 3. JAXB-compatible collection accessors
public List<SubItem> getItems() {
if (this.items == null) {
this.items = new ArrayList<>();
}
return this.items;
}
public void setItems(List<SubItem> items) { this.items = items; }
// 4. Standard Object overrides
@Override public boolean equals(Object o) { ... }
@Override public int hashCode() { ... }
@Override public String toString() { ... }
}
-
Jackson Integration (--backend jackson):
Field-level and getter/setter annotations (@JsonProperty, @JacksonXmlProperty, @JacksonXmlElementWrapper) are emitted on properties or getters.
-
Class Inheritance:
When a complexType extends a base complexType, emit true Java inheritance:
public class Vehicle extends BaseAsset { ... }
B. C# Traditional Class Generation
When --style class is selected:
- Emits standard C# classes with parameterless constructors and mutable auto-properties:
public class EntityMt {
[JsonPropertyName("id")]
public string? Id { get; set; }
[JsonPropertyName("timestamp")]
public DateTimeOffset? Timestamp { get; set; }
}
💻 CLI & Configuration Usage
CLI Invocations:
# Java: Generate traditional JavaBean POJOs
polyxml generate schema.xsd --lang java --style pojo
# Java: Generate POJOs with Jackson annotations and Builders
polyxml generate schema.xsd --lang java --style pojo --backend jackson --builder
# Java: Generate POJOs with compile-time zero-reflection direct codecs (GraalVM AOT friendly)
polyxml generate schema.xsd --lang java --style pojo --builder --codec direct
# C#: Generate traditional mutable classes
polyxml generate schema.xsd --lang csharp --style class
polyxml.toml Workspace Configuration:
[[generate]]
target = "java"
package = "com.enterprise.uci"
style = "pojo" # "record" (default) or "pojo"
builder = true # generate fluent builder
backend = "jackson" # standard or jackson
codec = "direct" # "annotation" (default) or "direct"
✅ Acceptance Criteria
🎯 Motivation & Background
Currently, PolyXML defaults to modern immutable data representations across all ecosystems—specifically Java 21+
recordand C# 12 primary constructorrecordtypes.While modern, immutable records provide excellent thread-safety and pattern-matching ergonomics, enterprise engineering teams often face severe friction in real-world production environments when integrating with existing enterprise stacks:
Legacy ORM & Framework Compatibility (The Spring/Hibernate Problem):
new EntityMt()) and standard JavaBean getters/setters (getId(),setId(...)).recordtypes only provide canonical constructors and component accessor methods namedid()instead ofgetId(), which breaks older reflection-based bean introspection and dynamic proxying.Constructor Parameter Explosion on Massive Schemas:
EntityMt), ISO 20022 (pacs.008), and CEN NeTEx—routinely feature 40 to 100+ fields, the majority of which are optional.record, instantiating an instance manually requires passing 80+ positional arguments:In-Place Pipeline Mutation:
status,processedAt), and re-serializes it downstream. Immutability forces copying the entire object hierarchy on every step, causing unnecessary garbage collection churn.Drop-in JAXB (
xjc) &xsd.exeMigration:xjc-generated classes often have thousands of lines of code expectingorder.getItems().add(...)orentity.setStatus(...). Providing traditional classes enables zero-refactoring, drop-in replacement of JAXB.🚀 Modern POJOs vs. Legacy JAXB (
xjc): Architectural AdvantagesWhile
--style pojoprovides drop-in compatibility for enterprise codebases expecting JavaBeans, PolyXML does not simply replicate 2003-era JAXB (xjc) output. It modernizes the POJO paradigm with key architectural improvements:xjc)--style pojo)XMLGregorianCalendarjava.time.*(Instant,LocalDate,OffsetDateTime)JAXBElement<T>& massiveObjectFactory.javaOptional<T>@JsonProperty&@JacksonXmlProperty)@NotNull,@Size,@Pattern,@Min,@Max).builder()pattern (--builder)JAXBContext.newInstance)jaxb-api/jaxb-implclasspath conflicts)Detailed Advantages:
Modern Date/Time Types (
java.time.*) vs.XMLGregorianCalendar:XMLGregorianCalendarandjavax.xml.datatype.Duration(Java 5 era), which are notoriously cumbersome, thread-unsafe, and require manual conversion helpers.Instant,OffsetDateTime,LocalDate, andLocalTime.Elimination of
JAXBElement<T>&ObjectFactoryHell:JAXBElement<T>wrappers (e.g.order.getDetails().getValue().getCustomerRef().getValue()) and generates multi-thousand-lineObjectFactory.javaboilerplate files.Optional<T>accessors—zeroJAXBElement<T>wrappers and zeroObjectFactoryclutter.Dual-Format Serialization (Single DTO for XML + JSON):
@JsonPropertyand@JacksonXmlProperty), allowing the exact same POJO to serialize and deserialize to both XML and JSON seamlessly.XSD Facet Enforcement via Jakarta Validation:
pattern,minLength,maxLength,minInclusive,maxInclusive) in generated Java code, requiring an external Xerces XML validator.@NotNull,@Size(min=..., max=...),@Pattern(regexp=...),@Min,@Max), enabling automatic validation at Spring@Validcontroller and service boundaries.Type-Safe Fluent Builders (
--builder):EntityMt.builder().id(...).build()).Escape from Reflection Bottlenecks via Project Panama:
JAXBContext.newInstance(...)), which causes slow cold starts and high heap churn. PolyXML offers native Rust-powered streaming codecs accessible via Project Panama (Java 22+ FFI JEP 454), running 10x–20x faster with zero reflection.Zero Jakarta/JAXB Dependency Clashes:
javax.xml.bindvsjakarta.xml.bindvsjaxb-runtime). PolyXML POJOs run cleanly with standard Java libraries or standard Jackson already present in modern Spring/Quarkus/Micronaut apps.⚡ High-Performance Modern Java Enhancements (Serialization & Deserialization)
Beyond syntax ergonomics, we can exploit modern Java runtime features to achieve industry-leading serialization/deserialization throughput:
1. Compile-Time Companion Codecs (
--codec direct)Field.get(),Method.invoke()) to inspect annotations and read/write fields. This incurs dynamic method dispatch checks, boxing overhead, and prevents HotSpot C2 compiler inlining.EntityMtCodec.java):2. GraalVM Native Image AOT Reachability (Zero Reflection Config)
native-image), JAXB requires manually registering hundreds of classes and private members inreflect-config.json.3. Direct UTF-8 & Compact Strings (Zero Allocation Churn)
java.lang.Stringinstances during parsing ("name","id","CONFIRMED"), putting severe pressure on the Garbage Collector.byte[]) for all known tag names, attribute keys, and enumeration literals. Tag matching is performed directly against raw incoming byte streams before ever allocating aStringon the JVM heap.4. Project Panama Direct Memory Streaming (Java 22+ JEP 454)
java.lang.foreign.MemorySegmentandArena), PolyXML can parse structured files directly out of native off-heap memory or memory-mapped files without intermediateByteBufferheap copies.5. Project Loom Virtual Thread Friendliness (Java 21 JEP 444)
InputStreamandOutputStream, they run seamlessly on lightweight Java 21 Virtual Threads (Executors.newVirtualThreadPerTaskExecutor()). An application can scale to 100,000+ concurrent XML streaming pipelines with plain, straightforward synchronous code.🔬 Benchmarking & Tradeoff Analysis
To determine the concrete trade-offs between immutable
record, mutablepojo, reflection-based Jackson, and direct compile-time codecs, a comprehensive JMH benchmark must be established.Benchmark Setup & Tooling
-prof gc(allocation profiler) and Java Flight Recorder (JFR).pacs.008settlement messages (~25 MB).EntityMttrack reports (~35 MB).jakarta.xml.bind.JAXBContext+xjcgenerated classes).XmlMapperreading into PolyXML--style pojo).--codec direct+ StAXXMLStreamReader).polyxml-c+ Java 22MemorySegment).Metrics to Measure
-prof gcto evaluate GC pause pressure.reflect-config.json.Hypothesized Tradeoffs & Evaluation Criteria
recordmatches or edges outpojo. For mutating message broker pipelines,pojomutability reduces GC churn by--codec directwill outperform Jackson by🛠️ Proposed Solution
Introduce a unified
--style(or--class-style) CLI flag and configuration option inpolyxml.toml:1. Style Selection:
--style <record|pojo>--style record(Default): Current Java 21+recordand C# 12recordoutput.--style pojo(or--style class): Traditional mutable class generation.2. Fluent Builder Support:
--builder3. Codec Mode:
--codec <annotation|direct>--codec annotation(Default): Annotates POJOs with Jackson (@JsonProperty,@JacksonXmlProperty) or Jakarta Validation.--codec direct: In addition to POJOs, generates a zero-reflection companion*Codec.javafor maximum HotSpot C2 JIT inlining and GraalVM AOT native-image compatibility.📋 Design Specifications
A. Java Traditional POJO Generation (
use_records = false)When
--style pojois selected:Class Structure:
Jackson Integration (
--backend jackson):Field-level and getter/setter annotations (
@JsonProperty,@JacksonXmlProperty,@JacksonXmlElementWrapper) are emitted on properties or getters.Class Inheritance:
When a
complexTypeextends a basecomplexType, emit true Java inheritance:B. C# Traditional Class Generation
When
--style classis selected:💻 CLI & Configuration Usage
CLI Invocations:
polyxml.tomlWorkspace Configuration:✅ Acceptance Criteria
--style <record|pojo>,--builder, and--codec <annotation|direct>flags toGenerateArgsinpolyxml-cli.style = "record" | "pojo",builder = true | false, andcodec = "annotation" | "direct"inpolyxml.tomlmanifest parser.use_records: bool,emit_builder: bool, andemit_direct_codec: boolintoJavaOptionsinpolyxml-core.get*/set*/is*accessors.public class Derived extends Baseinheritance.equals,hashCode, andtoString.--backend jacksonis specified.--builderpattern generator for Java.--codec directcompanion serializer/deserializer generator for zero-reflection HotSpot inlining and GraalVM AOT native compilation.--style class).test_java_codegen.rsandtest_csharp_codegen.rsvalidating compile-ready output and Jackson serialization.docs/guides/java.mdanddocs/guides/csharp.md.