Skip to content

fix(java): map OpenAPI 3.1 null type to Object to prevent ModelNull generation - #23961

Closed
anupamchaubey wants to merge 2 commits into
OpenAPITools:masterfrom
anupamchaubey:fix/java-webclient-model-null-23908
Closed

fix(java): map OpenAPI 3.1 null type to Object to prevent ModelNull generation#23961
anupamchaubey wants to merge 2 commits into
OpenAPITools:masterfrom
anupamchaubey:fix/java-webclient-model-null-23908

Conversation

@anupamchaubey

@anupamchaubey anupamchaubey commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

Problem / Context

When processing OpenAPI 3.1 specifications containing schema properties with an explicit type: 'null', the core code generator was failing to capture it as a primitive mapping. Instead, it was treating "null" as a custom model class name. This caused the engine to flag it as a language reserved word, fallback to appending "Null", and ultimately generate broken java compilation variables such as private ModelNull records = null; (#23908).

Solution Implemented

  • Modified AbstractJavaCodegen.java within the core engine translation layers (getSchemaType and getTypeDeclaration).
  • Added an intercept check so that when an explicit type: 'null' is resolved, it maps directly back to the standard native Java primitive wrapper type (Object).
  • Ensured this prevents the downstream factory engine from triggering internal reserved word class sanitization or spinning up unneeded phantom model code files.

Tests Added / Verification

  • Added programmatic coverage inside JavaClientCodegenTest.java (testNullTypeMapsToObject) to assert that structural schemas defined explicitly with a null type correctly declare variable instances as an Object.
  • Verified locally against target minimal test specs using the Spring webclient configuration library—confirming the invalid ModelNull import and variable syntax are successfully cleared out.
  • Ran the core automated regression suite (mvn test -pl modules/openapi-generator -Dtest=*CodegenTest) to ensure all concurrent Java-dependent framework engines build perfectly.

Fixes #23908


Summary by cubic

Maps OpenAPI 3.1 type: "null" to Java Object in the Java code generator to prevent phantom ModelNull classes and invalid fields. Fixes #23908.

  • Bug Fixes
    • Map "null" to Object in getSchemaType and getTypeDeclaration, intercepting both Schema.type and resolved openAPIType, while preserving fail-fast behavior when type is missing.
    • Added testNullTypeMapsToObject to ensure schemas with type: "null" generate Object.

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

Review in cubic

@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.

No issues found across 2 files

Re-trigger cubic

@anupamchaubey

Copy link
Copy Markdown
Contributor Author

@wing328 Hi! Gentle bump on this PR. It resolves the ModelNull compilation issue reported in #23908 by ensuring OpenAPI 3.1 type: 'null' maps to a Java Object. The AI review passed, but please let me know if there are any changes you need from me to get this merged!

@wing328

wing328 commented Jun 15, 2026

Copy link
Copy Markdown
Member

thanks for the PR

i'll take a look and try to get it merged before the next stable release.

@anupamchaubey

anupamchaubey commented Jun 15, 2026

Copy link
Copy Markdown
Contributor Author

Thank you! Sounds great.

@anupamchaubey

Copy link
Copy Markdown
Contributor Author

Thanks for the earlier feedback! Just noting that this PR also addresses the root cause behind #24519 and #24520 (OAS 3.1 null type handling / ModelNull regression). Since the AI review passed and no changes were requested, the fix is ready to merge whenever convenient. Happy to rebase against master if that helps move it forward.

typeMapping.put("date", "Date");
typeMapping.put("file", "File");
typeMapping.put("AnyType", "Object");
typeMapping.put("null", "Object");

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.

Does this serve any purpose? Isn't the idea that null should always be handled before any typeMapping?


@Override
public String getSchemaType(Schema p) {
if (p == null) {

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.

Is this fallback necessary for the fix? To me it seems like a rather large change in behavior, and I fail to see why we would want to have a fallback with an error rather than a complete ceasing of processing? Surely something is very wrong if we get here (and this isn't the proper way to handle that)?


// don't apply renaming on types from the typeMapping
if (null == openAPIType) {
LOGGER.error("No Type defined for Schema {}", p);

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.

Should we really log an error if this is an expected processing branch now?

}

// 2. Intercept the "null" type string immediately before it routes to typeMapping or toModelName
if ("null".equalsIgnoreCase(openAPIType) || "null".equalsIgnoreCase(p.getType())) {

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.

Are we sure that we should never check OAS 3.1 types here? Or is it expected that the openAPIType or normalization has handled that (but if so, why even check getType)?

@Mattias-Sehlstedt

Copy link
Copy Markdown
Contributor

I would strongly suggest that some sample test is modified to contain something that mirrors what the solved issue is, so that it is clear that this change in the Codegen is sent through correctly and handled as expected. Especially since it is the classical "spec is OAS 3.1, generally normalized and converted to 3.0 somewhere and then processed further", which comes with its unclarities.

Would it also be possible to highlight the actual regression so that one can deduce why this happened? With the intent to reason if the fix is placed in the right location or if it would be better to place it even further down (earlier) in the chain?

@anupamchaubey

Copy link
Copy Markdown
Contributor Author

Hi @Mattias-Sehlstedt, thank you for the detailed review! You raise some excellent points regarding where this should be handled in the pipeline and whether some of these fallbacks are masking larger issues. I agree with your feedback and will prepare a follow-up commit. Here are my thoughts:

On adding "null" to typeMapping:
You're absolutely right. If we intercept "null" properly earlier, this mapping is redundant. I will remove this line to keep the type mapping clean.

On the if (p == null) fallback:
Good catch. The intent was defensive programming, but I agree that halting processing completely is better than silently falling back and masking a deeper issue. I will revert this fallback so we maintain the original fail-fast behavior.

On the LOGGER.error for undefined types:
Spot on. Since a bare type: "null" means openAPIType might intentionally evaluate to "null", this error log creates unnecessary noise. I'll adjust the logic to skip logging the error if the schema represents an explicitly defined null type.

On intercepting OAS 3.1 types here:
The core issue is that the current OAS 3.1 -> 3.0 normalization process doesn't consistently resolve a standalone type: "null" into a nullable empty schema across all code paths. The literal string "null" slips through to the language-specific codegen layers, which then tries to format it as a model class (ModelNull).
I'm completely open to moving this intercept logic further upstream (e.g., in DefaultCodegen or the 3.1 normalization utility itself) so no language generator has to deal with it manually. Let me know if you'd prefer I move the fix there instead!

On adding a sample test and highlighting the regression:
Makes complete sense. The regression (reported in #24520) seems to stem from recent enhancements in the 7.17.0 OAS 3.1 normalization logic. I will add a dedicated test case that explicitly feeds an OAS 3.1 spec (with type: "null") through the normalization pipeline to ensure we track exactly how it resolves to a Java Object.

@anupamchaubey

Copy link
Copy Markdown
Contributor Author

Hi @Mattias-Sehlstedt, thanks again for the review guidance! I've pushed a refactored update addressing your points:

Removed the redundant typeMapping entry.

Preserved strict fail-fast behavior for p == null and openAPIType == null.

Cleaned up the null-type interception logic.

All tests pass successfully locally. Ready for your re-review whenever you have a moment!

@wing328

wing328 commented Aug 14, 2026

Copy link
Copy Markdown
Member

I couldn't repeat the issue and just merged a test to ensure it's covered moving forward:

#24701

(I also did a test with webclient in particular but no luck getting ModelNull in the output)

are you able to repeat the issue with the latest master or stable version? if yes, can you share the details please?

@anupamchaubey

Copy link
Copy Markdown
Contributor Author

Thanks for taking the time to review this PR and for adding the regression coverage in #24701.

After looking into the issue further, I’m not currently able to reliably reproduce the original ModelNull regression against the latest master/stable version, and I don’t want to continue making changes without a reliable reproduction.

I’m going to close this PR for now. I appreciate the review and feedback, especially around handling the issue at the appropriate stage of the code generation pipeline.

Thank you!

@anupamchaubey
anupamchaubey deleted the fix/java-webclient-model-null-23908 branch August 14, 2026 11:38
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.

[BUG] [webclient] Missing default null value for Object

3 participants