[jaxrs-spec] Bring useRecords records to pojo feature parity - #7
Closed
Ignacio-Vidal wants to merge 3 commits into
Closed
[jaxrs-spec] Bring useRecords records to pojo feature parity#7Ignacio-Vidal wants to merge 3 commits into
Ignacio-Vidal wants to merge 3 commits into
Conversation
Adds a useRecords option to the jaxrs-spec generator. When useRecords=true, the concrete subtypes that implement a generated oneOf interface render as Java records instead of mutable classes. - JavaJAXRSSpecServerCodegen: useRecords option, and postProcessAllModels marks record-eligible implementors with x-jaxrs-record (no parent, no additional properties, implements a generated oneOf interface). - record.mustache renders the record; model.mustache routes x-jaxrs-record to it. - oneof_interface.mustache declares the discriminator accessor in record style (petType()) under useRecords so records satisfy the interface via their canonical accessors; sealed.mustache no longer marks a record final. - pom.mustache bumps java.version to 17 when useRecords (records need JDK 16+). - Adds testOneOfRecordImplementationGeneration and a jaxrs-spec-records sample (registered in the JDK17 samples workflow). useRecords is independent of useSealed. The feature stays opt-in; default jaxrs-spec output is unchanged.
Ignacio-Vidal
force-pushed
the
pr3-jaxrs-userecords
branch
from
July 30, 2026 21:40
d0960ba to
be5de89
Compare
Records stay scoped to the implementations of a generated oneOf interface (useOneOfInterfaces=true) and now additionally require useSealed=true. Models outside that hierarchy - ordinary pojos, inheritance participants and models with additionalProperties - are left untouched and keep rendering as classes. Brings record.mustache to feature parity with pojo.mustache for the records that are emitted: - defaults (scalar, enum, container) applied in a compact canonical constructor - x-is-jackson-optional-nullable properties render as JsonNullable components defaulting to undefined - byte[] properties get content-based equals/hashCode overrides (the implicit record equals compares arrays by reference) - password properties are masked in an explicit toString override - property doc annotations (@ApiModelProperty/@Schema/MicroProfile @Schema) emitted on the record components - generateBuilders produces a flat builder inside the record carrying the pojo field defaults, as a fluent replacement for setters - useRecords + withXml is rejected (JAXB requires mutable JavaBeans) The oneOf interface only drops the get-prefix from its accessor when records are actually emitted (useRecords and useSealed), so with useRecords alone the interface keeps getX() and still matches the classes implementing it.
Ignacio-Vidal
force-pushed
the
records-full-parity
branch
from
July 30, 2026 21:44
fdfeb9e to
e621e73
Compare
useRecords is implemented in the shared model/record templates, so it applies to all five jaxrs-spec libraries, but only the default one had a sample. Add a records sample per library - helidon, kumuluzee, openliberty, quarkus and thorntail - and register all five in the JDK17 samples workflow so they are compiled on every push and pull request. Two things had to be fixed to make those samples compile: * Each library overrides pom.mustache and hardcoded Java 1.8 (helidon: 11), so a records or sealed sample could not build. Gate the compiler source/target on useSealed/useRecords exactly as the base pom.mustache already does. * record.mustache imported JsonNullable unconditionally. The import is already contributed through the imports block for the models that use it, so records with a nullable component carried a duplicate import, and records without one carried an unused import that fails to compile on the libraries whose pom does not ship jackson-databind-nullable. kumuluzee, openliberty and thorntail additionally set openApiNullable=false in their sample config: their poms omit jackson-databind-nullable while the pojo template imports JsonNullable whenever openApiNullable is on, which is a pre-existing issue unrelated to records (it reproduces with no records flags set at all). All six records samples plus jaxrs-spec-sealed build under JDK 17.
Owner
Author
|
Superseded by a new PR that adds records samples for every jaxrs-spec library and builds them in CI. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fork-internal review PR. Base is
pr3-jaxrs-userecords(upstream PR OpenAPITools#24188), so the diff below is only the follow-on change.Summary
useRecordscurrently emits records with an essentially empty body. This brings those records to feature parity withpojo.mustache, without widening where records are emitted.Records stay scoped to the implementations of a generated oneOf interface (
useOneOfInterfaces=true) and now additionally requireuseSealed=true. Everything outside that hierarchy — ordinary pojos, inheritance participants, models withadditionalProperties— is left untouched and keeps rendering as a class.What is emitted where
CatRequest,DogRequest— implement the oneOf interfacePetRequest— the oneOf containerPetBase— standalone pojoadditionalPropertiesmodelsParity features added to
record.mustacheEach is gated by a vendor extension computed in
postProcessAllModels, so a record only carries what it needs:byte[]properties get content-basedequals/hashCode— the implicit recordequalscompares arrays by reference, which is a correctness bugtoStringx-is-jackson-optional-nullableproperties render asJsonNullable<T>components defaulting toundefined()@ApiModelProperty/@Schema/ MicroProfile@Schema) on the record componentsgenerateBuildersproduces a flat builder nested in the record (records can't use the pojo's abstract builder hierarchy), carrying the pojo field defaults as a replacement for settersuseRecords+withXmlis rejected — JAXB requires mutable JavaBeansAccessor-style bug fixed
oneof_interface.mustachedropped thegetprefix based onuseRecordsalone. Once records also requireuseSealed, the combinationuseRecords=true, useSealed=falsewould generate an interface declaringitemType()while the implementing classes havegetItemType()— code that does not compile. The conditional now tracks the same gate, pinned bytestUseRecordsWithoutUseSealedKeepsClasses.Verification
JavaJAXRSSpecServerCodegenTest), including 4 new tests.useRecords+useSealed, anduseRecordsalone).jaxrs-spec-recordssample regenerated and compiles;PetBasecorrectly reverts record → class. FILES manifest unchanged.jaxrs-spec.mdandjaxrs-cxf-cdi.md(cxf-cdi extends the same codegen).Review notes
records_parity.yaml:Itemcarries the full feature matrix and implements a oneOf interface;Standalone/Animal+Cat/FreeFormare the negative cases.public final class Standaloneandpublic sealed class Animal— those modifiers come fromuseSealed(pre-existing behaviour), not from this change.