Skip to content

Commit 8aad0ee

Browse files
committed
feat: add enum validation for pageable sort parameters in API
1 parent 8cb9f14 commit 8aad0ee

4 files changed

Lines changed: 208 additions & 2 deletions

File tree

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

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,10 +151,21 @@ public static Map<String, List<String>> scanSortValidationEnums(
151151
if (schema.get$ref() != null) {
152152
schema = ModelUtils.getReferencedSchema(openAPI, schema);
153153
}
154-
if (schema == null || schema.getEnum() == null || schema.getEnum().isEmpty()) {
154+
if (schema == null) {
155+
continue;
156+
}
157+
// If the top-level schema is an array, the enum lives on its items
158+
Schema<?> enumSchema = schema;
159+
if (schema.getItems() != null) {
160+
enumSchema = schema.getItems();
161+
if (enumSchema.get$ref() != null) {
162+
enumSchema = ModelUtils.getReferencedSchema(openAPI, enumSchema);
163+
}
164+
}
165+
if (enumSchema == null || enumSchema.getEnum() == null || enumSchema.getEnum().isEmpty()) {
155166
continue;
156167
}
157-
List<String> enumValues = schema.getEnum().stream()
168+
List<String> enumValues = enumSchema.getEnum().stream()
158169
.map(Object::toString)
159170
.collect(Collectors.toList());
160171
result.put(operationId, enumValues);

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

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4413,6 +4413,76 @@ public void generateSortValidationDoesNotGenerateValidSortFileWhenBeanValidation
44134413
assertFileNotContains(petApi.toPath(), "@ValidSort");
44144414
}
44154415

4416+
@Test
4417+
public void generateSortValidationWorksForArraySortEnum() throws Exception {
4418+
Map<String, Object> additionalProperties = new HashMap<>();
4419+
additionalProperties.put(USE_TAGS, "true");
4420+
additionalProperties.put(INTERFACE_ONLY, "true");
4421+
additionalProperties.put(SKIP_DEFAULT_INTERFACE, "true");
4422+
additionalProperties.put(GENERATE_SORT_VALIDATION, "true");
4423+
4424+
Map<String, File> files = generateFromContract("src/test/resources/3_0/spring/petstore-sort-validation.yaml", additionalProperties);
4425+
4426+
File petApi = files.get("PetApi.kt");
4427+
String content = Files.readString(petApi.toPath());
4428+
4429+
// findPetsWithArraySortEnum: sort is type:array, items have inline enum → @ValidSort applied with Kotlin [] syntax
4430+
int methodStart = content.indexOf("fun findPetsWithArraySortEnum(");
4431+
Assert.assertTrue(methodStart >= 0, "findPetsWithArraySortEnum method should exist");
4432+
String paramBlock = content.substring(methodStart, Math.min(content.length(), methodStart + 500));
4433+
Assert.assertTrue(paramBlock.contains("@ValidSort(allowedValues = [\"id,asc\", \"id,desc\", \"name,asc\", \"name,desc\"])"),
4434+
"@ValidSort with all four enum values should appear on the pageable parameter");
4435+
Assert.assertTrue(paramBlock.contains("pageable: Pageable"),
4436+
"findPetsWithArraySortEnum should have a pageable: Pageable parameter");
4437+
}
4438+
4439+
@Test
4440+
public void generateSortValidationWorksForArraySortRefEnum() throws Exception {
4441+
Map<String, Object> additionalProperties = new HashMap<>();
4442+
additionalProperties.put(USE_TAGS, "true");
4443+
additionalProperties.put(INTERFACE_ONLY, "true");
4444+
additionalProperties.put(SKIP_DEFAULT_INTERFACE, "true");
4445+
additionalProperties.put(GENERATE_SORT_VALIDATION, "true");
4446+
4447+
Map<String, File> files = generateFromContract("src/test/resources/3_0/spring/petstore-sort-validation.yaml", additionalProperties);
4448+
4449+
File petApi = files.get("PetApi.kt");
4450+
String content = Files.readString(petApi.toPath());
4451+
4452+
// findPetsWithArraySortRefEnum: sort is type:array, items $ref to PetSort enum → @ValidSort with PetSort values
4453+
int methodStart = content.indexOf("fun findPetsWithArraySortRefEnum(");
4454+
Assert.assertTrue(methodStart >= 0, "findPetsWithArraySortRefEnum method should exist");
4455+
String paramBlock = content.substring(methodStart, Math.min(content.length(), methodStart + 500));
4456+
Assert.assertTrue(paramBlock.contains("@ValidSort(allowedValues = [\"id,asc\", \"id,desc\", \"createdAt,asc\", \"createdAt,desc\"])"),
4457+
"@ValidSort with PetSort enum values should appear on the pageable parameter");
4458+
}
4459+
4460+
@Test
4461+
public void generateSortValidationWorksForExternalParamRefArraySort() throws Exception {
4462+
Map<String, Object> additionalProperties = new HashMap<>();
4463+
additionalProperties.put(USE_TAGS, "true");
4464+
additionalProperties.put(INTERFACE_ONLY, "true");
4465+
additionalProperties.put(SKIP_DEFAULT_INTERFACE, "true");
4466+
additionalProperties.put(GENERATE_SORT_VALIDATION, "true");
4467+
4468+
Map<String, File> files = generateFromContract("src/test/resources/3_0/spring/petstore-sort-validation.yaml", additionalProperties);
4469+
4470+
File petApi = files.get("PetApi.kt");
4471+
String content = Files.readString(petApi.toPath());
4472+
4473+
// findPetsWithExternalParamRefArraySort: sort param $ref to external components file,
4474+
// which defines type:array with items $ref to PetSortEnum in the same external file
4475+
int methodStart = content.indexOf("fun findPetsWithExternalParamRefArraySort(");
4476+
Assert.assertTrue(methodStart >= 0, "findPetsWithExternalParamRefArraySort method should exist");
4477+
String paramBlock = content.substring(methodStart, Math.min(content.length(), methodStart + 500));
4478+
Assert.assertTrue(paramBlock.contains("@ValidSort(allowedValues = ["),
4479+
"@ValidSort should appear when sort param is resolved from an external $ref parameter");
4480+
Assert.assertTrue(paramBlock.contains("\"name,asc\"") || paramBlock.contains("\"id,asc\""),
4481+
"@ValidSort should contain the enum values from the external PetSortEnum schema");
4482+
Assert.assertTrue(paramBlock.contains("pageable: Pageable"),
4483+
"findPetsWithExternalParamRefArraySort should have a pageable: Pageable parameter");
4484+
}
4485+
44164486
// ========== PAGEABLE DEFAULTS TESTS ==========
44174487

44184488
@Test
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
components:
2+
parameters:
3+
PetSortParam:
4+
name: sort
5+
in: query
6+
required: false
7+
description: Sort order — multi-column, each value must be one of the allowed enum values
8+
schema:
9+
type: array
10+
default: []
11+
items:
12+
$ref: '#/components/schemas/PetSortEnum'
13+
schemas:
14+
PetSortEnum:
15+
type: string
16+
enum:
17+
- "name,asc"
18+
- "name,desc"
19+
- "id,asc"
20+
- "id,desc"

modules/openapi-generator/src/test/resources/3_0/spring/petstore-sort-validation.yaml

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,111 @@ paths:
407407
type: array
408408
items:
409409
$ref: '#/components/schemas/Pet'
410+
/pet/findWithArraySortEnum:
411+
get:
412+
tags:
413+
- pet
414+
summary: Find pets with x-spring-paginated and array sort param with inline enum on items
415+
operationId: findPetsWithArraySortEnum
416+
x-spring-paginated: true
417+
parameters:
418+
- name: page
419+
in: query
420+
schema:
421+
type: integer
422+
default: 0
423+
- name: size
424+
in: query
425+
schema:
426+
type: integer
427+
default: 20
428+
- name: sort
429+
in: query
430+
description: Sort order (multi-column, each element must be an allowed value)
431+
style: form
432+
explode: true
433+
schema:
434+
type: array
435+
items:
436+
type: string
437+
enum:
438+
- "id,asc"
439+
- "id,desc"
440+
- "name,asc"
441+
- "name,desc"
442+
responses:
443+
200:
444+
description: successful operation
445+
content:
446+
application/json:
447+
schema:
448+
type: array
449+
items:
450+
$ref: '#/components/schemas/Pet'
451+
/pet/findWithArraySortRefEnum:
452+
get:
453+
tags:
454+
- pet
455+
summary: Find pets with x-spring-paginated and array sort param whose items use a $ref enum
456+
operationId: findPetsWithArraySortRefEnum
457+
x-spring-paginated: true
458+
parameters:
459+
- name: page
460+
in: query
461+
schema:
462+
type: integer
463+
default: 0
464+
- name: size
465+
in: query
466+
schema:
467+
type: integer
468+
default: 20
469+
- name: sort
470+
in: query
471+
description: Sort order (multi-column, items $ref to PetSort enum)
472+
style: form
473+
explode: true
474+
schema:
475+
type: array
476+
items:
477+
$ref: '#/components/schemas/PetSort'
478+
responses:
479+
200:
480+
description: successful operation
481+
content:
482+
application/json:
483+
schema:
484+
type: array
485+
items:
486+
$ref: '#/components/schemas/Pet'
487+
/pet/findWithExternalParamRefArraySort:
488+
get:
489+
tags:
490+
- pet
491+
summary: Find pets with x-spring-paginated and sort param referenced from an external components file
492+
operationId: findPetsWithExternalParamRefArraySort
493+
x-spring-paginated: true
494+
parameters:
495+
- name: page
496+
in: query
497+
schema:
498+
type: integer
499+
default: 0
500+
- name: size
501+
in: query
502+
schema:
503+
type: integer
504+
default: 20
505+
- $ref: './petstore-sort-validation-components.yaml#/components/parameters/PetSortParam'
506+
responses:
507+
200:
508+
description: successful operation
509+
content:
510+
application/json:
511+
schema:
512+
type: array
513+
items:
514+
$ref: '#/components/schemas/Pet'
410515
components:
411516
schemas:
412517
PetSort:

0 commit comments

Comments
 (0)