Skip to content

[JAVA, JAVA-SPRING, KOTLIN-CLIENT, KOTLIN-SPRING] - feature - add x-jackson-default-impl / typeInfoDefaultImpls support to allow specifying of fallback schema when deserializing#23955

Open
Picazsoo wants to merge 13 commits into
OpenAPITools:masterfrom
Picazsoo:feature/use-deduction-default
Open

[JAVA, JAVA-SPRING, KOTLIN-CLIENT, KOTLIN-SPRING] - feature - add x-jackson-default-impl / typeInfoDefaultImpls support to allow specifying of fallback schema when deserializing#23955
Picazsoo wants to merge 13 commits into
OpenAPITools:masterfrom
Picazsoo:feature/use-deduction-default

Conversation

@Picazsoo

@Picazsoo Picazsoo commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Purpose of this PR is to complement the current oneOf jackson polymorphism - to make it possible to supply default fallback value. this is useful e.g. when one wants to specify a default for deduction based polymorphism (FasterXML/jackson-databind#3055) or when one wants to fallback to some no-op class.

PR checklist


Summary by cubic

Adds Jackson default deserialization fallback for polymorphic oneOf models across all Java generators, kotlin-spring, and the kotlin client. Configure @JsonTypeInfo(defaultImpl = ...) via x-jackson-default-impl or the typeInfoDefaultImpls option.

  • New Features
    • Added typeInfoDefaultImpls: {SchemaName: ClassName}; overrides x-jackson-default-impl per schema.
    • Centralized in AbstractJavaCodegen; Java and Spring emit defaultImpl for both Id.NAME and Id.DEDUCTION. kotlin-spring does both; kotlin client supports discriminator-based (Id.NAME) with Jackson.
    • Names resolve via toModelName, honoring mappings and DTO prefix/suffix; warns on overrides and unknown targets.
    • New vendor extension x-jackson-default-impl; docs updated for java, spring, kotlin-spring, kotlin, and java-camel. java-microprofile disables this (its models don’t use oneOf interfaces).
    • Tests added for Java client, Spring, kotlin-spring, and kotlin client covering deduction/discriminator paths, overrides, suffix handling, and absence cases.

Written for commit e005ea4. Summary will update on new commits.

Review in cubic

…foDefaultImpls support

   Emit `@JsonTypeInfo(defaultImpl = ...)` for both deduction-based and
   discriminator-based oneOf interfaces.

   Two configuration sources (config option takes precedence):
   - Schema extension: `x-jackson-default-impl: ClassName`
   - Config option: `typeInfoDefaultImpls: {SchemaName: ClassName}`

   The resolved class name passes through `toModelName()` so schemaMapping,
   importMapping, and DTO prefix/suffix are all honoured. A LOGGER.warn is
   emitted when the config option shadows a schema-level annotation.
@Picazsoo Picazsoo marked this pull request as ready for review June 5, 2026 13:29
@Picazsoo Picazsoo marked this pull request as draft June 5, 2026 13:29

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 9 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

public static final String USE_SEALED_RESPONSE_INTERFACES = "useSealedResponseInterfaces";
public static final String COMPANION_OBJECT = "companionObject";
public static final String SUSPEND_FUNCTIONS = "suspendFunctions";
public static final String TYPE_INFO_DEFAULT_IMPLS = "typeInfoDefaultImpls";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move to CodegenConstants ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Picazsoo Could you also add the feature to the java generators?
See src/main/resources/Java/deductionAnnotation.mustache and the different typeInfoAnnotation.mustache under java/libraries

@Picazsoo Picazsoo Jun 5, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will take a look at it. And this is early implementation without any polish. I marked temporarily as "ready for review" just to gather early feedback from Cubic

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But thanks for the review! I will properly tag you once I think it is ready for wasting human review time (-:

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @jpfinne, I added it to the java generators as well.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is now ready for review

Picazsoo and others added 4 commits June 17, 2026 23:18
# Conflicts:
#	modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java
…Java generators

- Add TYPE_INFO_DEFAULT_IMPLS/DESC constants to CodegenConstants (addresses
  reviewer request to avoid duplication across SpringCodegen and
  KotlinSpringServerCodegen)
- Move typeInfoDefaultImpls field, option registration, processOpts parsing,
  and x-jackson-resolved-default-impl resolution loop from SpringCodegen into
  AbstractJavaCodegen so all Java generators inherit the feature
- Remove duplicated code from SpringCodegen; update KotlinSpringServerCodegen
  to reference CodegenConstants.TYPE_INFO_DEFAULT_IMPLS and apply the same
  safe instanceof cast fix already present in SpringCodegen
- Update Java/deductionAnnotation.mustache: emit defaultImpl = X.class on
  @JsonTypeInfo(use = DEDUCTION) when x-jackson-resolved-default-impl is set
- Update Java/typeInfoAnnotation.mustache: emit defaultImpl = X.class on both
  @JsonTypeInfo(use = NAME) variants (discriminator present/absent) via
  discriminator.vendorExtensions.x-jackson-resolved-default-impl
- Add JavaClientCodegenTest tests covering deduction, discriminator,
  typeInfoDefaultImpls config option, and absence cases for Java client

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Picazsoo Picazsoo changed the title feat(kotlin-spring, java-spring): add x-jackson-default-impl / typeInfoDefaultImpls support [kotlin-spring, java(-spring)] -feature - add x-jackson-default-impl / typeInfoDefaultImpls support to allow specifying of fallback schema when deserializing Jun 17, 2026
@Picazsoo Picazsoo changed the title [kotlin-spring, java(-spring)] -feature - add x-jackson-default-impl / typeInfoDefaultImpls support to allow specifying of fallback schema when deserializing [KOTLIN-SPRING, JAVA(-SPRING)] - feature - add x-jackson-default-impl / typeInfoDefaultImpls support to allow specifying of fallback schema when deserializing Jun 17, 2026
@Picazsoo Picazsoo marked this pull request as ready for review June 17, 2026 22:07

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 17 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="modules/openapi-generator/src/main/resources/kotlin-spring/typeInfoAnnotation.mustache">

<violation number="1" location="modules/openapi-generator/src/main/resources/kotlin-spring/typeInfoAnnotation.mustache:6">
P1: Missing validation that the resolved defaultImpl is a subtype of the polymorphic base; misconfigured `x-jackson-default-impl` or `typeInfoDefaultImpls` values will compile but fail at runtime during deserialization.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

allowSetters = true // allows the {{{discriminator.propertyBaseName}}} to be set during deserialization
)
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "{{{discriminator.propertyBaseName}}}", visible = true)
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "{{{discriminator.propertyBaseName}}}", visible = true{{#vendorExtensions.x-jackson-resolved-default-impl}}, defaultImpl = {{vendorExtensions.x-jackson-resolved-default-impl}}::class{{/vendorExtensions.x-jackson-resolved-default-impl}})

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Missing validation that the resolved defaultImpl is a subtype of the polymorphic base; misconfigured x-jackson-default-impl or typeInfoDefaultImpls values will compile but fail at runtime during deserialization.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At modules/openapi-generator/src/main/resources/kotlin-spring/typeInfoAnnotation.mustache, line 6:

<comment>Missing validation that the resolved defaultImpl is a subtype of the polymorphic base; misconfigured `x-jackson-default-impl` or `typeInfoDefaultImpls` values will compile but fail at runtime during deserialization.</comment>

<file context>
@@ -3,7 +3,7 @@
   allowSetters = true // allows the {{{discriminator.propertyBaseName}}} to be set during deserialization
 )
-@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "{{{discriminator.propertyBaseName}}}", visible = true)
+@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "{{{discriminator.propertyBaseName}}}", visible = true{{#vendorExtensions.x-jackson-resolved-default-impl}}, defaultImpl = {{vendorExtensions.x-jackson-resolved-default-impl}}::class{{/vendorExtensions.x-jackson-resolved-default-impl}})
 @JsonSubTypes(
   {{#discriminator.mappedModels}}
</file context>

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is not a valid issue - defaultImpl does not need to be a @JsonSubTypes subtype.

Jackson's @JsonTypeInfo(defaultImpl = ...) intentionally accepts any class assignable to the field's declared type at the injection site, not just registered subtypes. So one can use e.g. a no-op catch-all class (e.g. class UnknownAnimal : Animal) to absorb unrecognized payloads.

The PR already handles the "unknown model" case correctly by emitting a LOGGER.warn(...) rather than failing.

I want to warn on potential typos, but to not block intentional use of external/no-op fallback classes.

@Picazsoo Picazsoo changed the title [KOTLIN-SPRING, JAVA(-SPRING)] - feature - add x-jackson-default-impl / typeInfoDefaultImpls support to allow specifying of fallback schema when deserializing [JAVA, JAVA-SPRING, KOTLIN-SPRING] - feature - add x-jackson-default-impl / typeInfoDefaultImpls support to allow specifying of fallback schema when deserializing Jun 18, 2026

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

9 issues found across 27 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="modules/openapi-generator/src/main/resources/kotlin-spring/typeInfoAnnotation.mustache">

<violation number="1" location="modules/openapi-generator/src/main/resources/kotlin-spring/typeInfoAnnotation.mustache:6">
P1: Missing validation that the resolved defaultImpl is a subtype of the polymorphic base; misconfigured `x-jackson-default-impl` or `typeInfoDefaultImpls` values will compile but fail at runtime during deserialization.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread docs/generators/java-play-framework.md Outdated
Comment thread docs/generators/java-micronaut-server.md Outdated
Comment thread docs/generators/jaxrs-spec.md Outdated
Comment thread docs/generators/java-undertow-server.md Outdated
Comment thread docs/generators/java-dubbo.md Outdated
Comment thread docs/generators/java-inflector.md
Comment thread docs/generators/java-wiremock.md Outdated
Comment thread docs/generators/java-microprofile.md Outdated
Comment thread docs/generators/java-play-framework.md Outdated
@Picazsoo Picazsoo changed the title [JAVA, JAVA-SPRING, KOTLIN-SPRING] - feature - add x-jackson-default-impl / typeInfoDefaultImpls support to allow specifying of fallback schema when deserializing [JAVA, JAVA-SPRING, KOTLIN-CLIENT, KOTLIN-SPRING] - feature - add x-jackson-default-impl / typeInfoDefaultImpls support to allow specifying of fallback schema when deserializing Jun 18, 2026
# Conflicts:
#	modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants