diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/OpenAPINormalizer.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/OpenAPINormalizer.java index a684bf326683..0faa2911461e 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/OpenAPINormalizer.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/OpenAPINormalizer.java @@ -1141,9 +1141,39 @@ protected void markSchemaAsVisited(Schema schema, Set visitedSchemas) { protected Schema normalizeArraySchema(Schema schema) { Schema result = processNormalize31Spec(schema, new HashSet<>()); + + processExtensionsInRefItems(result); return processSetArraytoNullable(result); } + /** + * Move the extensions starting with x-items to the items.extensions. + * + * @param schema the array schema to process + */ + protected void processExtensionsInRefItems(Schema schema) { + if (schema == null || schema.getItems() == null) { + return; + } + + Map extensions = schema.getExtensions(); + if (extensions != null) { + Map itemsExtensions = schema.getItems().getExtensions(); + for (Iterator it = extensions.keySet().iterator(); it.hasNext(); ) { + String key = it.next(); + if (key.startsWith("x-items-")) { + if (itemsExtensions == null) { + itemsExtensions = new LinkedHashMap<>(); + schema.getItems().setExtensions(itemsExtensions); + } + String newKey = key.substring("x-items-".length()); + itemsExtensions.put(newKey, extensions.get(key)); + it.remove(); + } + } + } + } + protected Schema normalizeMapSchema(Schema schema) { Schema result = processNormalize31Spec(schema, new HashSet<>()); return processSetMapToNullable(result); diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractJavaCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractJavaCodegen.java index 00a667571213..e48d7347c82c 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractJavaCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractJavaCodegen.java @@ -1248,9 +1248,15 @@ protected String getBeanValidation(Schema items) { return ""; } - if (items.get$ref() != null) { + String itemsRef = items.get$ref(); + if (itemsRef == null && items.getAllOf() != null && items.getAllOf().size() == 1) { + // $ref with siblings is wrapped by the normalizer into allOf: [$ref] + // -> ensure that @Valid is used below + itemsRef = items.getAllOf().get(0).get$ref(); + } + if (itemsRef != null) { Map schemas = this.openAPI.getComponents().getSchemas(); - String ref = ModelUtils.getSimpleRef(items.get$ref()); + String ref = ModelUtils.getSimpleRef(itemsRef); if (ref != null) { Schema schema = schemas.get(ref); // objects and oneOf/anyOf/allOf models cascade validation into their elements; diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java index 1185da2824c7..dcf27ccd9c2e 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java @@ -10185,7 +10185,9 @@ void listItems_annotated_with_x_field_extra_annotation() throws IOException { .fileContains( "private List<@NotNull @Size(max=50) String> listString", "private List<@Min(0)Integer> listInteger", - "private List<@Size(max=10) String> listCode" + "private List<@Size(max=10) String> listCode", + "private List<@NotEmpty @Valid Stubb> listRef", + "private List<@NotEmpty @Valid SampleModelListInlineInner>" ); } @@ -10201,6 +10203,8 @@ void listItems_with_additionalItemsAnnotations() throws IOException { "private List<@Size(max=50) String> listStringNullable", "private List<@NotNull @Valid Stubb> listSample", "private List<@NotNull @Min(0)Integer> listInteger", - "private List<@NotNull @Size(max=10) String> listCode"); + "private List<@NotNull @Size(max=10) String> listCode", + "private List<@NotNull @NotEmpty @Valid Stubb> listRef", + "private List<@NotNull @NotEmpty @Valid SampleModelListInlineInner>"); } } diff --git a/modules/openapi-generator/src/test/resources/3_0/issue_23705.yaml b/modules/openapi-generator/src/test/resources/3_0/issue_23705.yaml index 35c81d51c067..b86a0bdd3b99 100644 --- a/modules/openapi-generator/src/test/resources/3_0/issue_23705.yaml +++ b/modules/openapi-generator/src/test/resources/3_0/issue_23705.yaml @@ -43,4 +43,17 @@ components: allOf: - $ref: '#/components/schemas/Code' x-field-extra-annotation: '@Size(max=10)' + listRef: + type: array + x-items-x-field-extra-annotation: '@NotEmpty' + items: + $ref: '#/components/schemas/Stubb' + listInline: + type: array + x-items-x-field-extra-annotation: '@NotEmpty' + items: + type: object + properties: + name: + type: string