[java][spring][kotlin-spring] Make @JsonInclude/@JsonSetter opt-in to stop overriding global ObjectMapper - #24428
[java][spring][kotlin-spring] Make @JsonInclude/@JsonSetter opt-in to stop overriding global ObjectMapper#24428Picazsoo wants to merge 29 commits into
Conversation
There was a problem hiding this comment.
2 issues found across 10 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/JavaSpring/pojo.mustache">
<violation number="1" location="modules/openapi-generator/src/main/resources/JavaSpring/pojo.mustache:66">
P1: A manual `x-jackson-json-include-policy: NONE` now generates an annotation even though `NONE` means no annotation; because `SpringCodegen` also skips the import for this value, generated Java fails to compile. Suppress the template section for `NONE` (or remove that extension before rendering).</violation>
<violation number="2" location="modules/openapi-generator/src/main/resources/JavaSpring/pojo.mustache:66">
P2: Invalid `x-jackson-json-include-policy` values now produce uncompilable Java/Kotlin output because the template inserts the extension directly as a `JsonInclude.Include` constant. Validating the override against the supported policies (or rejecting it during generator processing) would turn this into an actionable generation error instead of a downstream compile failure.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| @JsonInclude(JsonInclude.Include.NON_ABSENT) | ||
| {{/vendorExtensions.x-is-jackson-optional-nullable}} | ||
| {{#vendorExtensions.x-jackson-json-include-policy}} | ||
| @JsonInclude(JsonInclude.Include.{{{vendorExtensions.x-jackson-json-include-policy}}}) |
There was a problem hiding this comment.
P1: A manual x-jackson-json-include-policy: NONE now generates an annotation even though NONE means no annotation; because SpringCodegen also skips the import for this value, generated Java fails to compile. Suppress the template section for NONE (or remove that extension before rendering).
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/JavaSpring/pojo.mustache, line 66:
<comment>A manual `x-jackson-json-include-policy: NONE` now generates an annotation even though `NONE` means no annotation; because `SpringCodegen` also skips the import for this value, generated Java fails to compile. Suppress the template section for `NONE` (or remove that extension before rendering).</comment>
<file context>
@@ -62,14 +62,9 @@ public {{>sealed}}class {{classname}}{{#parent}} extends {{{parent}}}{{/parent}}
- @JsonInclude(JsonInclude.Include.NON_ABSENT)
- {{/vendorExtensions.x-is-jackson-optional-nullable}}
+ {{#vendorExtensions.x-jackson-json-include-policy}}
+ @JsonInclude(JsonInclude.Include.{{{vendorExtensions.x-jackson-json-include-policy}}})
+ {{/vendorExtensions.x-jackson-json-include-policy}}
{{/jackson}}
</file context>
There was a problem hiding this comment.
This was taken care of
| @JsonInclude(JsonInclude.Include.NON_ABSENT) | ||
| {{/vendorExtensions.x-is-jackson-optional-nullable}} | ||
| {{#vendorExtensions.x-jackson-json-include-policy}} | ||
| @JsonInclude(JsonInclude.Include.{{{vendorExtensions.x-jackson-json-include-policy}}}) |
There was a problem hiding this comment.
P2: Invalid x-jackson-json-include-policy values now produce uncompilable Java/Kotlin output because the template inserts the extension directly as a JsonInclude.Include constant. Validating the override against the supported policies (or rejecting it during generator processing) would turn this into an actionable generation error instead of a downstream compile failure.
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/JavaSpring/pojo.mustache, line 66:
<comment>Invalid `x-jackson-json-include-policy` values now produce uncompilable Java/Kotlin output because the template inserts the extension directly as a `JsonInclude.Include` constant. Validating the override against the supported policies (or rejecting it during generator processing) would turn this into an actionable generation error instead of a downstream compile failure.</comment>
<file context>
@@ -62,14 +62,9 @@ public {{>sealed}}class {{classname}}{{#parent}} extends {{{parent}}}{{/parent}}
- @JsonInclude(JsonInclude.Include.NON_ABSENT)
- {{/vendorExtensions.x-is-jackson-optional-nullable}}
+ {{#vendorExtensions.x-jackson-json-include-policy}}
+ @JsonInclude(JsonInclude.Include.{{{vendorExtensions.x-jackson-json-include-policy}}})
+ {{/vendorExtensions.x-jackson-json-include-policy}}
{{/jackson}}
</file context>
There was a problem hiding this comment.
This was taken care of
There was a problem hiding this comment.
1 issue found across 10 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/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java">
<violation number="1" location="modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java:6910">
P2: The new invalid-override regression test cannot run because its referenced fixture `issue_24401_json_include_invalid_override.yaml` is not present in the repository. Adding the fixture (with `NOT_A_REAL_POLICY`) or removing the test reference is needed; otherwise the Kotlin Spring test suite fails unconditionally.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| @Test(description = "Issue #24401 – invalid manual override fails fast (kotlin-spring)") | ||
| public void jsonInclude_manualOverride_invalid_failsWithActionableError() { | ||
| Throwable thrown = Assert.expectThrows(Throwable.class, () -> generateFromContract( | ||
| "src/test/resources/3_0/spring/issue_24401_json_include_invalid_override.yaml", |
There was a problem hiding this comment.
P2: The new invalid-override regression test cannot run because its referenced fixture issue_24401_json_include_invalid_override.yaml is not present in the repository. Adding the fixture (with NOT_A_REAL_POLICY) or removing the test reference is needed; otherwise the Kotlin Spring test suite fails unconditionally.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java, line 6910:
<comment>The new invalid-override regression test cannot run because its referenced fixture `issue_24401_json_include_invalid_override.yaml` is not present in the repository. Adding the fixture (with `NOT_A_REAL_POLICY`) or removing the test reference is needed; otherwise the Kotlin Spring test suite fails unconditionally.</comment>
<file context>
@@ -6690,28 +6695,226 @@ public void requiredNullable_scenario3_optionalNonNullable_withJackson3() throws
+ @Test(description = "Issue #24401 – invalid manual override fails fast (kotlin-spring)")
+ public void jsonInclude_manualOverride_invalid_failsWithActionableError() {
+ Throwable thrown = Assert.expectThrows(Throwable.class, () -> generateFromContract(
+ "src/test/resources/3_0/spring/issue_24401_json_include_invalid_override.yaml",
+ Map.of(KotlinSpringServerCodegen.GENERATE_JSON_INCLUDE_ANNOTATIONS, "true")));
+
</file context>
There was a problem hiding this comment.
This was taken care of
…rExtension and CodegenConstants
…ON include policy handling
There was a problem hiding this comment.
1 issue found across 14 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/java/org/openapitools/codegen/languages/SpringCodegen.java">
<violation number="1" location="modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java:1277">
P2: Models using Lombok-generated setters ignore `generateJsonSetterNullsAnnotations=true`, so explicit JSON nulls can still overwrite optional non-nullable defaults. Render the `@JsonSetter` annotation on the field or otherwise support the Lombok setter path.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| // setter so an explicit null in the payload does not overwrite the field's default. Only emitted when | ||
| // generateJsonSetterNullsAnnotations is explicitly enabled; otherwise deserialization defers to the mapper. | ||
| if (Boolean.TRUE.equals(generateJsonSetterNullsAnnotations) && !property.required && !property.isNullable && !openApiNullable) { | ||
| property.vendorExtensions.put("x-has-json-setter-nulls-skip", true); |
There was a problem hiding this comment.
P2: Models using Lombok-generated setters ignore generateJsonSetterNullsAnnotations=true, so explicit JSON nulls can still overwrite optional non-nullable defaults. Render the @JsonSetter annotation on the field or otherwise support the Lombok setter path.
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/java/org/openapitools/codegen/languages/SpringCodegen.java, line 1277:
<comment>Models using Lombok-generated setters ignore `generateJsonSetterNullsAnnotations=true`, so explicit JSON nulls can still overwrite optional non-nullable defaults. Render the `@JsonSetter` annotation on the field or otherwise support the Lombok setter path.</comment>
<file context>
@@ -1213,24 +1270,48 @@ public void postProcessModelProperty(CodegenModel model, CodegenProperty propert
+ // setter so an explicit null in the payload does not overwrite the field's default. Only emitted when
+ // generateJsonSetterNullsAnnotations is explicitly enabled; otherwise deserialization defers to the mapper.
+ if (Boolean.TRUE.equals(generateJsonSetterNullsAnnotations) && !property.required && !property.isNullable && !openApiNullable) {
+ property.vendorExtensions.put("x-has-json-setter-nulls-skip", true);
+ model.imports.add("JsonSetter");
+ model.imports.add("Nulls");
</file context>
There was a problem hiding this comment.
@cubic-dev-ai, I think I took care of this issue. Please re-review
There was a problem hiding this comment.
@Picazsoo I have started the AI code review. It will take a few minutes to complete.
…th Lombok setters
…Setter annotations
| @Setter private boolean suspendFunctions = false; | ||
| @Getter @Setter private String optionalNonNullPropertyJsonInclude = "NON_NULL"; | ||
| // Tri-state: null = unset (weak default + warning), Boolean.FALSE = weak (muted), Boolean.TRUE = strict emission. | ||
| @Getter @Setter private Boolean generateJsonIncludeAnnotations = null; |
There was a problem hiding this comment.
I would suggest creating a concrete enum here to represent the tri-state.
Having a boxed boolean where the null has a separate values is always very difficulty to interpret, and given that it is not unusual to have it where only true and false are actually expected means that it is not unusual for it to be hard to interpret for no reason at all.
So rather than having Boolean and a comment next to the variables I think you get enormous benefit from just creating a small explicit enum that can express everything itself and also prevent reoccurring unclarities.
There was a problem hiding this comment.
Thanks for the comment! I will do so. I started with a primitive boolean and a separate boolean "unset" flag. Then I changed over to the tri-state Boolean. I agree that the implicit tri-state is a bit hacky.
…or improved JSON annotation handling
There was a problem hiding this comment.
1 issue found across 1721 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="samples/client/petstore/spring-http-interface-reactive-noResponseEntity/src/main/java/org/openapitools/model/ContainerDefaultValue.java">
<violation number="1" location="samples/client/petstore/spring-http-interface-reactive-noResponseEntity/src/main/java/org/openapitools/model/ContainerDefaultValue.java:29">
P2: Removing @JsonInclude(JsonInclude.Include.NON_ABSENT) from JsonNullable fields changes serialization behavior: undefined nullableArray and nullableArrayWithDefault will now be included in JSON output instead of omitted. Consumers relying on these optional fields being absent when unset will receive unexpected values, breaking the API contract.</violation>
</file>
Note: This PR contains a large number of files. cubic only reviews up to 200 files per PR, so some files may not have been reviewed. cubic prioritizes the most important files to review.
Re-trigger cubic
| @Generated(value = "org.openapitools.codegen.languages.SpringCodegen", comments = "Generator version: 7.25.0-SNAPSHOT") | ||
| public class ContainerDefaultValue { | ||
|
|
||
| @JsonInclude(JsonInclude.Include.NON_ABSENT) |
There was a problem hiding this comment.
P2: Removing @JsonInclude(JsonInclude.Include.NON_ABSENT) from JsonNullable fields changes serialization behavior: undefined nullableArray and nullableArrayWithDefault will now be included in JSON output instead of omitted. Consumers relying on these optional fields being absent when unset will receive unexpected values, breaking the API contract.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/client/petstore/spring-http-interface-reactive-noResponseEntity/src/main/java/org/openapitools/model/ContainerDefaultValue.java, line 29:
<comment>Removing @JsonInclude(JsonInclude.Include.NON_ABSENT) from JsonNullable fields changes serialization behavior: undefined nullableArray and nullableArrayWithDefault will now be included in JSON output instead of omitted. Consumers relying on these optional fields being absent when unset will receive unexpected values, breaking the API contract.</comment>
<file context>
@@ -26,14 +25,12 @@
- @JsonInclude(JsonInclude.Include.NON_ABSENT)
private JsonNullable<List<String>> nullableArray = JsonNullable.<List<String>>undefined();
private JsonNullable<List<String>> nullableRequiredArray = JsonNullable.<List<String>>undefined();
</file context>
This reverts commit 3da24e0.
|
Marking as ready for review, but definitely do not merge yet |
|
Tagging @gs-covariance, @MelleD , @jorgerod in the pull request with proposed solution as promised. |
There was a problem hiding this comment.
1 issue found across 709 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="samples/client/petstore/spring-http-interface-springboot-4/src/main/java/org/openapitools/model/AdditionalPropertiesStringDto.java">
<violation number="1" location="samples/client/petstore/spring-http-interface-springboot-4/src/main/java/org/openapitools/model/AdditionalPropertiesStringDto.java:34">
P1: @JsonSetter(nulls = Nulls.SKIP) is emitted on `name` which is `@Nullable`, but per the PR's rules this annotation should only appear on optional non-nullable properties. Skip nullable properties to match the intended matrix.</violation>
</file>
Note: This PR contains a large number of files. cubic only reviews up to 200 files per PR, so some files may not have been reviewed. cubic prioritizes the most important files to review.
Re-trigger cubic
| public class AdditionalPropertiesStringDto { | ||
|
|
||
| @JsonInclude(JsonInclude.Include.NON_NULL) | ||
| @JsonSetter(nulls = Nulls.SKIP) |
There was a problem hiding this comment.
P1: @JsonSetter(nulls = Nulls.SKIP) is emitted on name which is @Nullable, but per the PR's rules this annotation should only appear on optional non-nullable properties. Skip nullable properties to match the intended matrix.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/client/petstore/spring-http-interface-springboot-4/src/main/java/org/openapitools/model/AdditionalPropertiesStringDto.java, line 34:
<comment>@JsonSetter(nulls = Nulls.SKIP) is emitted on `name` which is `@Nullable`, but per the PR's rules this annotation should only appear on optional non-nullable properties. Skip nullable properties to match the intended matrix.</comment>
<file context>
@@ -31,6 +31,7 @@
public class AdditionalPropertiesStringDto {
@JsonInclude(JsonInclude.Include.NON_NULL)
+ @JsonSetter(nulls = Nulls.SKIP)
private @Nullable String name;
</file context>
There was a problem hiding this comment.
false positive. name is actually optional non-nullable here:
AdditionalPropertiesString:
type: object
properties:
name:
type: string|
Hi @gs-covariance, @MelleD , @jorgerod. If possible, could you try to build this branch and try it in your project to make sure it really satisfies all requirements? I tried it in our project and it seems to work fine, but I am not really the target audience as the regression was not a problem for us. |
|
@Picazsoo Thank you for working on the fix. We have run into this problem and this week. Do you plan to merge and these changes and release it soon ? |
Hello @singlaHarish , I am not a maintainer of this project. Just a contributor. If all goes well, I expect this to be hopefully merged by the time of the next typical release. In the meantime it would be greatly appreciated if you could try to build this branch and try it in you project whether it resolves the issues for you. I am pretty sure I pasted a possible workaround for this issue - you just need to modify and sideload a single mustache template file and should be good until the version with a proper fix. Once again sorry for any inconvenience caused. |
Thank you @Picazsoo! I have tested after checking in your feature and works fine for me! The JsonInclude NonNull annotation is no longer in the generated code
`Generated(value = "org.openapitools.codegen.languages.SpringCodegen", comments = "Generator version: 7.25.0-SNAPSHOT") private @nullable String x; |
Works great on our side too, with or without generateJsonIncludeAnnotations / generateJsonSetterNullsAnnotations set to false Thanks ! |
…nullable fields Add optionalNonNullPropertyJsonSetterNulls option (SKIP/FAIL) and the per-property x-jackson-json-setter-nulls vendor extension (SKIP/FAIL/NONE) to the spring and kotlin-spring generators, mirroring the JsonInclude mechanism. When unset, behavior is byte-identical to today (openApiNullable-derived default), so this is fully backward compatible. Setting them enables previously-unreachable combinations such as openApiNullable=true with SKIP. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
# Conflicts: # samples/openapi3/server/petstore/springboot-4-jspecify/src/main/java/org/openapitools/model/Foo.java
There was a problem hiding this comment.
All reported issues were addressed across 24 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
…clarify migration note Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Just a heads up, I made one extra tweak beyond the main fix: I decoupled the |
Summary
Fixes #24401 and fixes #24365
Since
7.24.0(#23993), thespringandkotlin-springgenerators emit field-level Jackson annotations on model properties:@JsonInclude(NON_NULL)on optional non-nullable fields,@JsonSetter(nulls = ...)on those fields, and@JsonInclude(NON_ABSENT)onJsonNullable<T>fields.Field-level
@JsonIncludeoverrides the project-wideObjectMapperinclusion policy (e.g.spring.jackson.default-property-inclusion=non_empty). Projects upgrading to7.24.0saw a silent wire-contract change: previously-omitted empty values (empty strings, lists, maps) started serializing, because per-fieldNON_NULLis looser than a stricter global setting and wins.Separately, the
@JsonSetter(nulls = ...)mode for optional non-nullable fields was hard-wired toopenApiNullable:openApiNullable=trueforcedNulls.FAIL(kotlin) / no annotation (spring), so the reasonable combination "keepopenApiNullable=truefor genuinely nullable optionals, but tolerate an incoming explicitnullon non-nullable fields viaNulls.SKIP" was unreachable.This PR makes annotation emission opt-in and configurable, restores
7.23.0-equivalent output by default, returns inclusion policy to the globalObjectMapperunless the user opts in, and decouples the@JsonSetter(nulls = ...)mode fromopenApiNullable.Reasoning
ObjectMappershould stay the source of truth unless a user deliberately opts into generated annotations.7.24.0behavior.false) silences it.openApiNullable(a tri-state serialization concern) should not dictate null-tolerance on non-nullable fields. For a non-nullable field there is no absent-vs-null ambiguity, so tolerating a receivednull(Nulls.SKIP, preserving the Kotlin non-null default) is a legitimate, safe policy that should be reachable regardless ofopenApiNullable.What changed
New options (both java
springandkotlin-spring)generateJsonIncludeAnnotations(boolean, opt-in):trueemits policy@JsonInclude(required-field protection + optional non-nullable policy). Unset emits none + warning;falseemits none, warning silenced.generateJsonSetterNullsAnnotations(boolean, opt-in):trueemits@JsonSetter(nulls = ...)on optional non-nullable properties. Unset emits none + warning;falseemits none, warning silenced.optionalNonNullPropertyJsonInclude(enum, defaultNON_NULL): policy for optional non-nullable properties whengenerateJsonIncludeAnnotations=true. One ofNON_NULL/NON_EMPTY/NON_DEFAULT/NONE(NONEemits nothing).optionalNonNullPropertyJsonSetterNulls(enumSKIP/FAIL, unset by default): explicitly controls the@JsonSetter(nulls = ...)mode for optional non-nullable properties whengenerateJsonSetterNullsAnnotations=true, decoupling it fromopenApiNullable. When unset, the mode is derived fromopenApiNullableexactly as in7.24.x(true→FAILwhere supported,false→SKIP), so this is fully backward compatible. Setting it enables the previously-unreachable combinations, e.g.openApiNullable=truewithSKIP. On the javaspringgenerator this is also the only way to emitNulls.FAIL.Per-property overrides
x-jackson-json-include-policyvendor extension (FIELD level) that always wins over the automatic matrix and the config options, even whengenerateJsonIncludeAnnotations=false. Accepts any valid JacksonIncludevalue, orNONE(trimmed, case-insensitive) to emit nothing.x-jackson-json-setter-nullsvendor extension (FIELD level,SKIP/FAIL/NONE, trimmed/case-insensitive) that always wins over both theoptionalNonNullPropertyJsonSetterNullsoption and theopenApiNullable-derived default, and is honored even whengenerateJsonSetterNullsAnnotationsis unset.NONEemits nothing. It applies to required properties too (not just optional non-nullable ones).Invalid values on either extension fail fast with an actionable error. Imports are added only when an annotation is emitted.
Automatic
@JsonIncludematrix (whengenerateJsonIncludeAnnotations=true)NON_NULL(spring) /ALWAYS(kotlin-spring)ALWAYSoptionalNonNullPropertyJsonInclude(defaultNON_NULL,NONE= omit)JsonNullablemodule governs inclusion)Automatic
@JsonSetter(nulls = ...)default (whengenerateJsonSetterNullsAnnotations=true, option unset)Applies to optional non-nullable properties (backward-compatible with
7.24.x):kotlin-spring:openApiNullable=true→Nulls.FAIL,openApiNullable=false→Nulls.SKIP.spring:openApiNullable=true→ no annotation,openApiNullable=false→Nulls.SKIP.Setting
optionalNonNullPropertyJsonSetterNulls(or the per-property extension) overrides this default. A warning is logged when the resolved default is the risky "no annotation" case so the choice is visible.Notable fixes
@JsonInclude(NON_ABSENT)is no longer emitted onJsonNullable<T>fields (redundant;JsonNullablealready governs inclusion).@JsonSetter(nulls = ...)now sits on the field, not just the setter, so it is honored when Lombok (@Setter) generates the setter and no explicit setter method is emitted.Refactors
JsonIncludePolicyenum (mirrors JacksonIncludeplus aNONEsentinel) andJsonSetterNullsModeenum (NONE/SKIP/FAIL).TriStateBooleanto distinguish "unset" from explicittrue/false(drives default-with-warning behavior).JsonAnnotationPolicyUtilscentralizing parsing/validation/normalization and the layered resolution for both@JsonIncludeand@JsonSetter(nulls), shared by both generators.CodegenConstantsentries andVendorExtension.X_JACKSON_JSON_INCLUDE_POLICY/VendorExtension.X_JACKSON_JSON_SETTER_NULLS; templates (JavaSpring/pojo.mustache,kotlin-spring/dataClassOptVar.mustache,kotlin-spring/dataClassReqVar.mustache) render from the single resolved vendor extensions (including newNulls.FAILbranches inpojo.mustacheanddataClassReqVar.mustache).Docs, tests, samples
7.24.xto7.25.0) covering the change, all new options and vendor extensions, theSKIP-vs-Nulls.SETsafety distinction, and how to restore strictNulls.FAIL(PATCH) behavior.spring.md,kotlin-spring.md,java-camel.md) with the new option and vendor-extension rows.NONE,false, manual overrides (onJsonNullable, paddedNONE, invalid values), per-schema import isolation, the Lombok-setter regression, and@JsonSetter(nulls)coverage (openApiNullable=true+SKIP(the previously-impossible combination),openApiNullable=true+FAIL,openApiNullable=false+FAIL, unset backward-compat defaults, per-property extension overrides, and invalid-value fail-fast). New fixtures undersrc/test/resources/3_0/spring/andsrc/test/resources/3_0/kotlin/.@JsonInclude(NON_NULL)annotations and unused imports removed).Migration
7.23.0(no field-level@JsonInclude/@JsonSetter); a warning is logged.generateJsonIncludeAnnotations=false/generateJsonSetterNullsAnnotations=falseto keep this behavior and silence the warnings.generateJsonIncludeAnnotations=true(optionally withoptionalNonNullPropertyJsonInclude) for spec-honest serialization annotations.generateJsonSetterNullsAnnotations=trueto emit@JsonSetter(nulls = ...); by default this restores strictNulls.FAILdeserialization for optional non-nullable fields withopenApiNullable=true(kotlin).optionalNonNullPropertyJsonSetterNulls=SKIP(orFAIL) to control the mode independently ofopenApiNullable, e.g. keepopenApiNullable=truewhile tolerating incoming nulls on non-nullable fields viaSKIP.x-jackson-json-include-policyorx-jackson-json-setter-nullson a property for per-field control.PR checklist
Commit all changed files.
This is important, as CI jobs will verify all generator outputs of your HEAD commit as it would merge with master.
These must match the expectations made by your contribution.
You may regenerate an individual generator by passing the relevant config(s) as an argument to the script, for example
./bin/generate-samples.sh bin/configs/java*.IMPORTANT: Do NOT purge/delete any folders/files (e.g. tests) when regenerating the samples as manually written tests may be removed.
Summary by cubic
Make
@JsonIncludeand@JsonSetter(nulls=...)opt‑in and configurable forspringandkotlin-spring. Default output now matches 7.23.0, so generated models no longer override the globalObjectMapper.New Features
generateJsonIncludeAnnotationsandgenerateJsonSetterNullsAnnotations(opt‑in; unset logs a one‑time warning).optionalNonNullPropertyJsonInclude(NON_NULL/NON_EMPTY/NON_DEFAULT/NONE) and per‑propertyx-jackson-json-include-policy(NONEomits; extension wins). Do not emit@JsonInclude(NON_ABSENT)forJsonNullable<T>.optionalNonNullPropertyJsonSetterNulls(SKIP/FAIL) decoupled fromopenApiNullable, plus per‑propertyx-jackson-json-setter-nulls(SKIP/FAIL/NONE; extension wins). Place@JsonSetter(nulls = Nulls.SKIP)on fields so Lombok setters honor it.bin/configsacrossspring,spring-cloud, andkotlin-springto opt in; some setoptionalNonNullPropertyJsonIncludetoNONE,NON_EMPTY,NON_DEFAULT, orNON_NULL. Regenerated samples and docs.Refactors
JsonAnnotationPolicyUtils(replacesJsonIncludePolicyUtils); introduceJsonIncludePolicy,JsonSetterNullsMode, andTriStateBoolean. UseCodegenConstants/VendorExtensionkeys. Fix NPE whenoptionalNonNullPropertyJsonSetterNullsis null and add a test guard; clarify migration note.Written for commit 494f3d0. Summary will update on new commits.