Skip to content

Commit 3b142b1

Browse files
authored
[kotlin-spring, java-spring] - gate @JsonSetter on openApiNullable for optional non-nullable fields (OpenAPITools#23993)
* fix(kotlin-spring, java-spring): gate @JsonSetter on openApiNullable for optional non-nullable fields For optional + non-nullable properties (required: false, nullable: false): - openApiNullable=false → @JsonSetter(nulls = Nulls.SKIP): silently ignores explicit JSON null, protecting any defined default from being overridden - openApiNullable=true → @JsonSetter(nulls = Nulls.FAIL): rejects explicit JSON null, enforcing the non-nullable contract (useful for PATCH semantics) Previously, Nulls.FAIL was unconditionally generated for all optional non-nullable fields regardless of openApiNullable, causing a breaking change for users on openApiNullable=false. Java Spring now also emits @JsonSetter(nulls = Nulls.SKIP) for the same case (previously it emitted nothing). Fixes OpenAPITools#23976 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix documentation * fix(kotlin-spring, java-spring): add @JsonInclude(NON_NULL) for optional non-nullable fields to prevent serializing them as explicit null in JSON * simplify implementation * gate by jackson config * update samples
1 parent 7b535a9 commit 3b142b1

1,664 files changed

Lines changed: 8305 additions & 703 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/generators/kotlin-spring.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
4343
|library|library template (sub-template)|<dl><dt>**spring-boot**</dt><dd>Spring-boot Server application.</dd><dt>**spring-cloud**</dt><dd>Spring-Cloud-Feign client with Spring-Boot auto-configured settings.</dd><dt>**spring-declarative-http-interface**</dt><dd>Spring Declarative Interface client</dd></dl>|spring-boot|
4444
|modelMutable|Create mutable models| |false|
4545
|modelPackage|model package for generated code| |org.openapitools.model|
46-
|openApiNullable|Enable OpenAPI Jackson Nullable library (jackson-databind-nullable) for optional + nullable properties (required: false, nullable: true). When enabled, such properties use JsonNullable&lt;T&gt; = JsonNullable.undefined() so callers can distinguish between a missing key and an explicitly provided null. Requires jackson-databind-nullable &gt;= 0.2.10 when used with useJackson3.| |false|
46+
|openApiNullable|Enable OpenAPI Jackson Nullable library (jackson-databind-nullable) for strict null handling. Controls how optional + non-nullable properties (required: false, nullable: false) handle explicit JSON null: when false (default), @JsonSetter(nulls = Nulls.SKIP) is used &mdash; explicit null is silently ignored (lenient, protects any default value from being overridden); when true, @JsonSetter(nulls = Nulls.FAIL) is used &mdash; explicit null causes deserialization to fail (strict, enforces the non-nullable contract, useful for PATCH semantics). Additionally, when true, optional + nullable properties (required: false, nullable: true) use JsonNullable&lt;T&gt; = JsonNullable.undefined() to distinguish between a missing key and an explicit null. Requires jackson-databind-nullable &gt;= 0.2.10 when used with useJackson3.| |false|
4747
|packageName|Generated artifact package name.| |org.openapitools|
4848
|parcelizeModels|toggle &quot;@Parcelize&quot; for generated models| |null|
4949
|reactive|use coroutines for reactive behavior| |false|

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -313,10 +313,15 @@ public KotlinSpringServerCodegen() {
313313
cliOptions.add(CliOption.newBoolean(CodegenConstants.USE_DEDUCTION_FOR_ONE_OF_INTERFACES, CodegenConstants.USE_DEDUCTION_FOR_ONE_OF_INTERFACES_DESC, useDeductionForOneOfInterfaces));
314314
addSwitch(CodegenConstants.USE_ENUM_VALUE_INTERFACE, CodegenConstants.USE_ENUM_VALUE_INTERFACE_DESC, useEnumValueInterface);
315315
addSwitch(CodegenConstants.OPENAPI_NULLABLE,
316-
"Enable OpenAPI Jackson Nullable library (jackson-databind-nullable) for optional + nullable "
317-
+ "properties (required: false, nullable: true). When enabled, such properties use "
318-
+ "JsonNullable<T> = JsonNullable.undefined() so callers can distinguish between a missing key "
319-
+ "and an explicitly provided null. Requires jackson-databind-nullable >= 0.2.10 when used with useJackson3.",
316+
"Enable OpenAPI Jackson Nullable library (jackson-databind-nullable) for strict null handling. "
317+
+ "Controls how optional + non-nullable properties (required: false, nullable: false) handle explicit JSON null: "
318+
+ "when false (default), @JsonSetter(nulls = Nulls.SKIP) is used — explicit null is silently ignored "
319+
+ "(lenient, protects any default value from being overridden); "
320+
+ "when true, @JsonSetter(nulls = Nulls.FAIL) is used — explicit null causes deserialization to fail "
321+
+ "(strict, enforces the non-nullable contract, useful for PATCH semantics). "
322+
+ "Additionally, when true, optional + nullable properties (required: false, nullable: true) use "
323+
+ "JsonNullable<T> = JsonNullable.undefined() to distinguish between a missing key and an explicit null. "
324+
+ "Requires jackson-databind-nullable >= 0.2.10 when used with useJackson3.",
320325
openApiNullable);
321326
supportedLibraries.put(SPRING_BOOT, "Spring-boot Server application.");
322327
supportedLibraries.put(SPRING_CLOUD_LIBRARY,
@@ -551,6 +556,7 @@ public void processOpts() {
551556
// Only jackson-databind moved to tools.jackson.databind in Jackson 3.x.
552557
importMapping.put("JsonSetter", "com.fasterxml.jackson.annotation.JsonSetter");
553558
importMapping.put("Nulls", "com.fasterxml.jackson.annotation.Nulls");
559+
importMapping.put("JsonInclude", "com.fasterxml.jackson.annotation.JsonInclude");
554560
// jackson-databind-nullable >= 0.2.10 supports both Jackson 2 and 3.
555561
importMapping.put("JsonNullable", "org.openapitools.jackson.nullable.JsonNullable");
556562
// JsonDeserialize lives in jackson-databind which moved packages in Jackson 3.x.
@@ -1266,12 +1272,20 @@ public void postProcessModelProperty(CodegenModel model, CodegenProperty propert
12661272
property.example = null;
12671273
}
12681274

1269-
// Scenario 3: optional + non-nullable → block explicit JSON nulls via @JsonSetter(nulls = Nulls.FAIL).
1270-
// Missing keys still succeed (default = null is used), but explicit {"field": null} fails deserialization.
1275+
// Scenario 3: optional + non-nullable → always emit @JsonSetter to handle explicit JSON nulls.
1276+
// When openApiNullable=true: Nulls.FAIL → reject explicit null (strict PATCH semantics).
1277+
// When openApiNullable=false: Nulls.SKIP → silently ignore explicit null (lenient, protects defaults).
1278+
// Always emit @JsonInclude(NON_NULL) so null fields are omitted from serialized output regardless
1279+
// of who is deserializing on the other end — closer to spec, avoids round-trip failures.
12711280
if (!property.required && !property.isNullable) {
1272-
property.vendorExtensions.put("x-has-json-setter-nulls-fail", true);
1281+
if (openApiNullable) {
1282+
property.vendorExtensions.put("x-has-json-setter-nulls-fail", true);
1283+
} else {
1284+
property.vendorExtensions.put("x-has-json-setter-nulls-skip", true);
1285+
}
12731286
model.imports.add("JsonSetter");
12741287
model.imports.add("Nulls");
1288+
model.imports.add("JsonInclude");
12751289
}
12761290

12771291
// Scenario 4: optional + nullable with openApiNullable → use JsonNullable<T> = JsonNullable.undefined()
@@ -1444,9 +1458,14 @@ public ModelsMap postProcessModelsEnum(ModelsMap objs) {
14441458
for (ModelMap mo : objs.getModels()) {
14451459
CodegenModel cm = mo.getModel();
14461460
for (CodegenProperty var : cm.optionalVars) {
1447-
// Scenario 3: optional + non-nullable → block explicit JSON nulls via @JsonSetter(nulls = Nulls.FAIL)
1461+
// Scenario 3: optional + non-nullable → always emit @JsonSetter and @JsonInclude(NON_NULL).
1462+
// openApiNullable=true: Nulls.FAIL (strict). openApiNullable=false: Nulls.SKIP (lenient).
14481463
if (!var.required && !var.isNullable) {
1449-
var.vendorExtensions.put("x-has-json-setter-nulls-fail", true);
1464+
if (openApiNullable) {
1465+
var.vendorExtensions.put("x-has-json-setter-nulls-fail", true);
1466+
} else {
1467+
var.vendorExtensions.put("x-has-json-setter-nulls-skip", true);
1468+
}
14501469
}
14511470
// Scenario 4: optional + nullable with openApiNullable → use JsonNullable<T>
14521471
if (openApiNullable && !var.required && var.isNullable) {

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,10 @@ public void processOpts() {
625625

626626
// override parent one
627627
importMapping.put("JsonDeserialize", (useJackson3 ? JACKSON3_PACKAGE : JACKSON2_PACKAGE) + ".databind.annotation.JsonDeserialize");
628+
// JsonSetter and Nulls always come from com.fasterxml.jackson.annotation regardless of Jackson 2 or 3
629+
// (Jackson 3.x intentionally keeps jackson-annotations at 2.x, same package)
630+
importMapping.put("JsonSetter", "com.fasterxml.jackson.annotation.JsonSetter");
631+
importMapping.put("Nulls", "com.fasterxml.jackson.annotation.Nulls");
628632

629633
typeMapping.put("file", "org.springframework.core.io.Resource");
630634
importMapping.put("Nullable", useJspecify? "org.jspecify.annotations.Nullable": "org.springframework.lang.Nullable");
@@ -1200,6 +1204,18 @@ public void postProcessModelProperty(CodegenModel model, CodegenProperty propert
12001204
if (model.getVendorExtensions().containsKey("x-jackson-optional-nullable-helpers")) {
12011205
model.imports.add("Arrays");
12021206
}
1207+
1208+
// Optional + non-nullable: always emit @JsonInclude(NON_NULL) so null fields are omitted from
1209+
// serialized output regardless of who deserializes on the other end — closer to spec.
1210+
// When openApiNullable=false, also add @JsonSetter(nulls = Nulls.SKIP) on the setter.
1211+
if (!property.required && !property.isNullable) {
1212+
model.imports.add("JsonInclude");
1213+
if (!openApiNullable) {
1214+
property.vendorExtensions.put("x-has-json-setter-nulls-skip", true);
1215+
model.imports.add("JsonSetter");
1216+
model.imports.add("Nulls");
1217+
}
1218+
}
12031219
}
12041220

12051221
@Override

modules/openapi-generator/src/main/resources/JavaSpring/pojo.mustache

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,13 @@ public {{>sealed}}class {{classname}}{{#parent}} extends {{{parent}}}{{/parent}}
6161
{{#vendorExtensions.x-field-extra-annotation}}
6262
{{{.}}}
6363
{{/vendorExtensions.x-field-extra-annotation}}
64+
{{#jackson}}
65+
{{^required}}
66+
{{^isNullable}}
67+
@JsonInclude(JsonInclude.Include.NON_NULL)
68+
{{/isNullable}}
69+
{{/required}}
70+
{{/jackson}}
6471
{{#deprecated}}
6572
@Deprecated
6673
{{/deprecated}}
@@ -242,6 +249,11 @@ public {{>sealed}}class {{classname}}{{#parent}} extends {{{parent}}}{{/parent}}
242249
{{#vendorExtensions.x-setter-extra-annotation}}
243250
{{{vendorExtensions.x-setter-extra-annotation}}}
244251
{{/vendorExtensions.x-setter-extra-annotation}}
252+
{{#jackson}}
253+
{{#vendorExtensions.x-has-json-setter-nulls-skip}}
254+
@JsonSetter(nulls = Nulls.SKIP)
255+
{{/vendorExtensions.x-has-json-setter-nulls-skip}}
256+
{{/jackson}}
245257
{{#deprecated}}
246258
@Deprecated
247259
{{/deprecated}}

modules/openapi-generator/src/main/resources/kotlin-spring/dataClassOptVar.mustache

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
@Schema({{#example}}example = "{{#lambdaRemoveLineBreak}}{{#lambdaEscapeInNormalString}}{{{.}}}{{/lambdaEscapeInNormalString}}{{/lambdaRemoveLineBreak}}", {{/example}}{{#isReadOnly}}readOnly = {{{isReadOnly}}}, {{/isReadOnly}}description = "{{{description}}}"){{/swagger2AnnotationLibrary}}{{#swagger1AnnotationLibrary}}
33
@ApiModelProperty({{#example}}example = "{{#lambdaRemoveLineBreak}}{{#lambdaEscapeInNormalString}}{{{.}}}{{/lambdaEscapeInNormalString}}{{/lambdaRemoveLineBreak}}", {{/example}}{{#isReadOnly}}readOnly = {{{isReadOnly}}}, {{/isReadOnly}}value = "{{{description}}}"){{/swagger1AnnotationLibrary}}{{#deprecated}}
44
@Deprecated(message = ""){{/deprecated}}{{#vendorExtensions.x-field-extra-annotation}}
5-
{{{.}}}{{/vendorExtensions.x-field-extra-annotation}}{{#vendorExtensions.x-has-json-setter-nulls-fail}}
5+
{{{.}}}{{/vendorExtensions.x-field-extra-annotation}}{{^isNullable}}
6+
@field:JsonInclude(JsonInclude.Include.NON_NULL){{/isNullable}}{{#vendorExtensions.x-has-json-setter-nulls-skip}}
7+
@field:JsonSetter(nulls = Nulls.SKIP){{/vendorExtensions.x-has-json-setter-nulls-skip}}{{#vendorExtensions.x-has-json-setter-nulls-fail}}
68
@field:JsonSetter(nulls = Nulls.FAIL){{/vendorExtensions.x-has-json-setter-nulls-fail}}
79
@get:JsonProperty("{{{baseName}}}"){{#isInherited}} override{{/isInherited}} {{>modelMutable}} {{{name}}}: {{#vendorExtensions.x-is-jackson-optional-nullable}}JsonNullable<{{#isEnum}}{{#isArray}}{{baseType}}<{{/isArray}}{{classname}}.{{{nameInPascalCase}}}{{#isArray}}>{{/isArray}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}>{{/vendorExtensions.x-is-jackson-optional-nullable}}{{^vendorExtensions.x-is-jackson-optional-nullable}}{{#isEnum}}{{#isArray}}{{baseType}}<{{/isArray}}{{classname}}.{{{nameInPascalCase}}}{{#isArray}}>{{/isArray}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}?{{/vendorExtensions.x-is-jackson-optional-nullable}} = {{#vendorExtensions.x-is-jackson-optional-nullable}}JsonNullable.undefined(){{/vendorExtensions.x-is-jackson-optional-nullable}}{{^vendorExtensions.x-is-jackson-optional-nullable}}{{^defaultValue}}null{{/defaultValue}}{{#defaultValue}}{{^isNumber}}{{{defaultValue}}}{{/isNumber}}{{#isNumber}}{{{dataType}}}("{{{defaultValue}}}"){{/isNumber}}{{/defaultValue}}{{/vendorExtensions.x-is-jackson-optional-nullable}}

modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java

Lines changed: 74 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6404,26 +6404,89 @@ public void requiredNullable_scenario2_requiredNullable() throws IOException {
64046404
}
64056405

64066406
/**
6407-
* Scenario 3: required=false, nullable=false
6408-
* Expected: nullable type with null default, AND @field:JsonSetter(nulls=Nulls.FAIL) to block explicit nulls.
6407+
* Scenario 3: required=false, nullable=false, no default, openApiNullable=false (default).
6408+
* Without openApiNullable, use lenient @JsonSetter(nulls = Nulls.SKIP) — silently ignores explicit null.
6409+
* Always emits @JsonInclude(NON_NULL) so null fields are omitted from serialized output.
64096410
*/
6410-
@Test(description = "Scenario 3 – optional+non-nullable: null default with JsonSetter FAIL to block explicit nulls")
6411+
@Test(description = "Scenario 3 – optional+non-nullable, no openApiNullable: @JsonSetter(SKIP) + @JsonInclude(NON_NULL)")
64116412
public void requiredNullable_scenario3_optionalNonNullable() throws IOException {
64126413
Map<String, File> files = generateFromContract(
64136414
"src/test/resources/3_0/kotlin/required-nullable-4-states.yaml",
64146415
new HashMap<>());
64156416

64166417
Path modelFile = files.get("TestModel.kt").toPath();
6417-
// Must have @field:JsonSetter(nulls = Nulls.FAIL) annotation
6418-
assertFileContains(modelFile, "@field:JsonSetter(nulls = Nulls.FAIL)");
6419-
// Must have JsonSetter and Nulls imports
6418+
String content = Files.readString(modelFile);
6419+
int idx = content.indexOf("val optionalNonNullable:");
6420+
Assert.assertTrue(idx >= 0, "optionalNonNullable property must exist");
6421+
String context = content.substring(Math.max(0, idx - 200), idx);
6422+
Assert.assertTrue(context.contains("@field:JsonInclude(JsonInclude.Include.NON_NULL)"),
6423+
"optionalNonNullable must have @JsonInclude(NON_NULL) to omit null from serialized output");
6424+
Assert.assertTrue(context.contains("@field:JsonSetter(nulls = Nulls.SKIP)"),
6425+
"optionalNonNullable (no openApiNullable) should have @field:JsonSetter(nulls = Nulls.SKIP)");
6426+
Assert.assertFalse(context.contains("@field:JsonSetter(nulls = Nulls.FAIL)"),
6427+
"optionalNonNullable (no openApiNullable) must not have FAIL mode");
6428+
// Must have JsonSetter, Nulls, and JsonInclude imports
6429+
assertFileContains(modelFile,
6430+
"import com.fasterxml.jackson.annotation.JsonInclude",
6431+
"import com.fasterxml.jackson.annotation.JsonSetter",
6432+
"import com.fasterxml.jackson.annotation.Nulls");
6433+
// Must still be nullable type with null default
6434+
assertFileContains(modelFile, "val optionalNonNullable: kotlin.String? = null");
6435+
}
6436+
6437+
/**
6438+
* Scenario 3 with openApiNullable=true: required=false, nullable=false, no default.
6439+
* Uses strict @JsonSetter(nulls = Nulls.FAIL) and always emits @JsonInclude(NON_NULL).
6440+
*/
6441+
@Test(description = "Scenario 3 – optional+non-nullable with openApiNullable=true: @JsonSetter(FAIL) + @JsonInclude(NON_NULL)")
6442+
public void requiredNullable_scenario3_optionalNonNullable_withOpenApiNullable() throws IOException {
6443+
Map<String, File> files = generateFromContract(
6444+
"src/test/resources/3_0/kotlin/required-nullable-4-states.yaml",
6445+
Map.of(CodegenConstants.OPENAPI_NULLABLE, "true"));
6446+
6447+
Path modelFile = files.get("TestModel.kt").toPath();
6448+
String content = Files.readString(modelFile);
6449+
int idx = content.indexOf("val optionalNonNullable:");
6450+
Assert.assertTrue(idx >= 0, "optionalNonNullable property must exist");
6451+
String context = content.substring(Math.max(0, idx - 200), idx);
6452+
Assert.assertTrue(context.contains("@field:JsonInclude(JsonInclude.Include.NON_NULL)"),
6453+
"optionalNonNullable must have @JsonInclude(NON_NULL) to omit null from serialized output");
6454+
Assert.assertTrue(context.contains("@field:JsonSetter(nulls = Nulls.FAIL)"),
6455+
"optionalNonNullable should have @field:JsonSetter(FAIL) when openApiNullable=true");
6456+
// Must have all three imports
64206457
assertFileContains(modelFile,
6458+
"import com.fasterxml.jackson.annotation.JsonInclude",
64216459
"import com.fasterxml.jackson.annotation.JsonSetter",
64226460
"import com.fasterxml.jackson.annotation.Nulls");
64236461
// Must be nullable type with null default
64246462
assertFileContains(modelFile, "val optionalNonNullable: kotlin.String? = null");
6425-
// Must NOT be JsonNullable
6426-
assertFileNotContains(modelFile, "JsonNullable<kotlin.String>");
6463+
}
6464+
6465+
/**
6466+
* Scenario 3 with a defined default value: required=false, nullable=false, default="defaultValue", openApiNullable=false.
6467+
* Uses SKIP mode and @JsonInclude(NON_NULL) — null fields are omitted, protecting the default.
6468+
*/
6469+
@Test(description = "Scenario 3 – optional+non-nullable with default value: @JsonSetter(SKIP) + @JsonInclude(NON_NULL)")
6470+
public void requiredNullable_scenario3_optionalNonNullable_withDefault() throws IOException {
6471+
Map<String, File> files = generateFromContract(
6472+
"src/test/resources/3_0/kotlin/required-nullable-4-states.yaml",
6473+
new HashMap<>());
6474+
6475+
Path modelFile = files.get("TestModel.kt").toPath();
6476+
String content = Files.readString(modelFile);
6477+
int idx = content.indexOf("val optionalNonNullableWithDefault:");
6478+
Assert.assertTrue(idx >= 0, "optionalNonNullableWithDefault property must exist");
6479+
String context = content.substring(Math.max(0, idx - 200), idx);
6480+
Assert.assertTrue(context.contains("@field:JsonInclude(JsonInclude.Include.NON_NULL)"),
6481+
"optionalNonNullableWithDefault must have @JsonInclude(NON_NULL)");
6482+
Assert.assertTrue(context.contains("@field:JsonSetter(nulls = Nulls.SKIP)"),
6483+
"optionalNonNullableWithDefault should have @field:JsonSetter(nulls = Nulls.SKIP) when openApiNullable=false");
6484+
Assert.assertFalse(context.contains("@field:JsonSetter(nulls = Nulls.FAIL)"),
6485+
"optionalNonNullableWithDefault must not have FAIL mode when openApiNullable=false");
6486+
assertFileContains(modelFile,
6487+
"import com.fasterxml.jackson.annotation.JsonInclude",
6488+
"import com.fasterxml.jackson.annotation.JsonSetter",
6489+
"import com.fasterxml.jackson.annotation.Nulls");
64276490
}
64286491

64296492
/**
@@ -6473,15 +6536,16 @@ public void requiredNullable_scenario4_optionalNullable_withOpenApiNullable() th
64736536
}
64746537

64756538
/**
6476-
* Scenario 3 with Jackson 3 (Spring Boot 4): optional + non-nullable.
6539+
* Scenario 3 with Jackson 3 (Spring Boot 4) + openApiNullable=true: optional + non-nullable.
64776540
*
64786541
* @JsonSetter / Nulls imports should come from com.fasterxml.jackson.annotation
64796542
* (Jackson 3.x intentionally kept jackson-annotations at 2.x, same package).
64806543
*/
6481-
@Test(description = "Scenario 3 with Jackson 3: com.fasterxml.jackson.annotation.JsonSetter + Nulls imports")
6544+
@Test(description = "Scenario 3 with Jackson 3 + openApiNullable: com.fasterxml.jackson.annotation.JsonSetter + Nulls imports")
64826545
public void requiredNullable_scenario3_optionalNonNullable_withJackson3() throws IOException {
64836546
Map<String, Object> props = new HashMap<>();
64846547
props.put(KotlinSpringServerCodegen.USE_SPRING_BOOT4, "true");
6548+
props.put(CodegenConstants.OPENAPI_NULLABLE, "true");
64856549

64866550
Map<String, File> files = generateFromContract(
64876551
"src/test/resources/3_0/kotlin/required-nullable-4-states.yaml", props);

0 commit comments

Comments
 (0)