diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/validations/oas/OpenApiSchemaValidations.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/validations/oas/OpenApiSchemaValidations.java index c80f0c52494d..52069d9bbc97 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/validations/oas/OpenApiSchemaValidations.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/validations/oas/OpenApiSchemaValidations.java @@ -120,7 +120,14 @@ private static ValidationRule.Result checkNullableAttribute(SchemaWrapper schema if (schemaWrapper.getOpenAPI() != null) { SemVer version = new SemVer(schemaWrapper.getOpenAPI().getOpenapi()); if (version.atLeast("3.1")) { - if (ModelUtils.isNullable(schema)) { + // ModelUtils.isNullable checks schema.getNullable(), but swagger-parser does not populate + // that field when parsing OAS 3.1 documents — 'nullable' is not a valid 3.1 keyword, so + // the parser stores it as a raw extension under the key "nullable" instead. + // We must check both paths to catch the deprecated usage in either case, + // regardless of whether the value is true or false. + boolean hasNullableExtension = schema.getExtensions() != null + && schema.getExtensions().containsKey("nullable"); + if (ModelUtils.isNullable(schema) || schema.getNullable() != null || hasNullableExtension) { result = new ValidationRule.Fail(); result.setDetails(String.format(Locale.ROOT, "OAS document is version '%s'. Schema '%s' uses 'nullable' attribute, which has been deprecated in OAS 3.1.", diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/validations/oas/OpenApiSchemaValidationsTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/validations/oas/OpenApiSchemaValidationsTest.java index ebff8ea7e4b8..a48d714d88a5 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/validations/oas/OpenApiSchemaValidationsTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/validations/oas/OpenApiSchemaValidationsTest.java @@ -1,6 +1,8 @@ package org.openapitools.codegen.validations.oas; +import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.media.*; +import org.openapitools.codegen.TestUtils; import org.openapitools.codegen.validation.Invalid; import org.openapitools.codegen.validation.ValidationResult; import org.testng.Assert; @@ -67,6 +69,51 @@ public void testOneOfWithSiblingPropertiesDisabledRule(Schema schema, boolean ma Assert.assertEquals(warnings.size(), 0, "Expected rule to be disabled."); } + /** + * The validation warning for 'nullable: true' in an OAS 3.1 spec must fire. + * The existing checkNullableAttribute only checked ModelUtils.isNullable(schema) which relies on + * schema.getNullable() — but swagger-parser does not populate that field for 3.1 specs (it stores + * the value in extensions["nullable"] instead). The fix must also check extensions["nullable"]. + */ + @Test(description = "nullable: true in OAS 3.1 spec must trigger the nullable-deprecated warning") + public void testNullableAttributeInOas31_triggerWarning() { + OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_1/nullable-deprecated-in-oas31.yaml"); + Schema proxyUrl = (Schema) openAPI.getComponents().getSchemas().get("TestModel").getProperties().get("proxyUrl"); + + RuleConfiguration config = new RuleConfiguration(); + config.setEnableRecommendations(true); + OpenApiSchemaValidations validator = new OpenApiSchemaValidations(config); + + ValidationResult result = validator.validate(new SchemaWrapper(openAPI, proxyUrl)); + List nullableWarnings = result.getWarnings().stream() + .filter(invalid -> "Schema uses the 'nullable' attribute.".equals(invalid.getRule().getDescription())) + .collect(Collectors.toList()); + + Assert.assertEquals(nullableWarnings.size(), 1, + "Expected exactly one 'nullable attribute deprecated' warning for a 3.1 spec using nullable: true"); + } + + /** + * The nullable-deprecated warning must NOT fire for an OAS 3.1 spec using the correct 3.1 null type syntax. + */ + @Test(description = "correct OAS 3.1 null type syntax (type: [string, null]) must NOT trigger the nullable-deprecated warning") + public void testNullTypeInOas31_noWarning() { + OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_1/null-types-simple.yaml"); + Schema stringDataOrNull = (Schema) openAPI.getComponents().getSchemas().get("WithNullableType").getProperties().get("stringDataOrNull"); + + RuleConfiguration config = new RuleConfiguration(); + config.setEnableRecommendations(true); + OpenApiSchemaValidations validator = new OpenApiSchemaValidations(config); + + ValidationResult result = validator.validate(new SchemaWrapper(openAPI, stringDataOrNull)); + List nullableWarnings = result.getWarnings().stream() + .filter(invalid -> "Schema uses the 'nullable' attribute.".equals(invalid.getRule().getDescription())) + .collect(Collectors.toList()); + + Assert.assertEquals(nullableWarnings.size(), 0, + "OAS 3.1 with type:[string,null] must not trigger the nullable-deprecated warning"); + } + @DataProvider(name = "apacheNginxRecommendationExpectations") public Object[][] apacheNginxRecommendationExpectations() { return new Object[][]{ diff --git a/modules/openapi-generator/src/test/resources/3_1/nullable-deprecated-in-oas31.yaml b/modules/openapi-generator/src/test/resources/3_1/nullable-deprecated-in-oas31.yaml new file mode 100644 index 000000000000..5e3c2ddbec92 --- /dev/null +++ b/modules/openapi-generator/src/test/resources/3_1/nullable-deprecated-in-oas31.yaml @@ -0,0 +1,14 @@ +openapi: 3.1.0 +info: + title: Nullable deprecated in OAS 3.1 test + version: 1.0.0 +paths: {} +components: + schemas: + TestModel: + type: object + properties: + # OAS 3.0 'nullable: true' used in a 3.1 spec — deprecated and should trigger a warning + proxyUrl: + type: string + nullable: true