Skip to content

Commit 065b6c5

Browse files
authored
[core] Normalizer: x-items extension for List customization (#25105)
* simplify test * Feature: possibility to annotate type arguments in java List<> * Regenerate doc * Use standard x-field-extra-annotation instead of a new annotation * Test annotation with items allOf * regenerate doc * regenerate doc * Rollback invalid commit * Fix jakarta.validation.constraint.NotNull * Do not remove the @NotNull annotation if it was explicity provided * Rename tests * Normalizer: x-items-xxx * Ensure @Valid generated for items: allOf: [$ref] * Test for inline ref * Test for inline ref * merge remote
1 parent c229791 commit 065b6c5

4 files changed

Lines changed: 57 additions & 4 deletions

File tree

‎modules/openapi-generator/src/main/java/org/openapitools/codegen/OpenAPINormalizer.java‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1141,9 +1141,39 @@ protected void markSchemaAsVisited(Schema schema, Set<Schema> visitedSchemas) {
11411141

11421142
protected Schema normalizeArraySchema(Schema schema) {
11431143
Schema result = processNormalize31Spec(schema, new HashSet<>());
1144+
1145+
processExtensionsInRefItems(result);
11441146
return processSetArraytoNullable(result);
11451147
}
11461148

1149+
/**
1150+
* Move the extensions starting with x-items to the items.extensions.
1151+
*
1152+
* @param schema the array schema to process
1153+
*/
1154+
protected void processExtensionsInRefItems(Schema schema) {
1155+
if (schema == null || schema.getItems() == null) {
1156+
return;
1157+
}
1158+
1159+
Map<String, Object> extensions = schema.getExtensions();
1160+
if (extensions != null) {
1161+
Map<String, Object> itemsExtensions = schema.getItems().getExtensions();
1162+
for (Iterator<String> it = extensions.keySet().iterator(); it.hasNext(); ) {
1163+
String key = it.next();
1164+
if (key.startsWith("x-items-")) {
1165+
if (itemsExtensions == null) {
1166+
itemsExtensions = new LinkedHashMap<>();
1167+
schema.getItems().setExtensions(itemsExtensions);
1168+
}
1169+
String newKey = key.substring("x-items-".length());
1170+
itemsExtensions.put(newKey, extensions.get(key));
1171+
it.remove();
1172+
}
1173+
}
1174+
}
1175+
}
1176+
11471177
protected Schema normalizeMapSchema(Schema schema) {
11481178
Schema result = processNormalize31Spec(schema, new HashSet<>());
11491179
return processSetMapToNullable(result);

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1248,9 +1248,15 @@ protected String getBeanValidation(Schema<?> items) {
12481248
return "";
12491249
}
12501250

1251-
if (items.get$ref() != null) {
1251+
String itemsRef = items.get$ref();
1252+
if (itemsRef == null && items.getAllOf() != null && items.getAllOf().size() == 1) {
1253+
// $ref with siblings is wrapped by the normalizer into allOf: [$ref]
1254+
// -> ensure that @Valid is used below
1255+
itemsRef = items.getAllOf().get(0).get$ref();
1256+
}
1257+
if (itemsRef != null) {
12521258
Map<String, Schema> schemas = this.openAPI.getComponents().getSchemas();
1253-
String ref = ModelUtils.getSimpleRef(items.get$ref());
1259+
String ref = ModelUtils.getSimpleRef(itemsRef);
12541260
if (ref != null) {
12551261
Schema<?> schema = schemas.get(ref);
12561262
// objects and oneOf/anyOf/allOf models cascade validation into their elements;

‎modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10227,7 +10227,9 @@ void listItems_annotated_with_x_field_extra_annotation() throws IOException {
1022710227
.fileContains(
1022810228
"private List<@NotNull @Size(max=50) String> listString",
1022910229
"private List<@Min(0)Integer> listInteger",
10230-
"private List<@Size(max=10) String> listCode"
10230+
"private List<@Size(max=10) String> listCode",
10231+
"private List<@NotEmpty @Valid Stubb> listRef",
10232+
"private List<@NotEmpty @Valid SampleModelListInlineInner>"
1023110233
);
1023210234
}
1023310235

@@ -10243,6 +10245,8 @@ void listItems_with_additionalItemsAnnotations() throws IOException {
1024310245
"private List<@Size(max=50) String> listStringNullable",
1024410246
"private List<@NotNull @Valid Stubb> listSample",
1024510247
"private List<@NotNull @Min(0)Integer> listInteger",
10246-
"private List<@NotNull @Size(max=10) String> listCode");
10248+
"private List<@NotNull @Size(max=10) String> listCode",
10249+
"private List<@NotNull @NotEmpty @Valid Stubb> listRef",
10250+
"private List<@NotNull @NotEmpty @Valid SampleModelListInlineInner>");
1024710251
}
1024810252
}

‎modules/openapi-generator/src/test/resources/3_0/issue_23705.yaml‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,17 @@ components:
4343
allOf:
4444
- $ref: '#/components/schemas/Code'
4545
x-field-extra-annotation: '@Size(max=10)'
46+
listRef:
47+
type: array
48+
x-items-x-field-extra-annotation: '@NotEmpty'
49+
items:
50+
$ref: '#/components/schemas/Stubb'
51+
listInline:
52+
type: array
53+
x-items-x-field-extra-annotation: '@NotEmpty'
54+
items:
55+
type: object
56+
properties:
57+
name:
58+
type: string
4659

0 commit comments

Comments
 (0)