From cee5223af6e6aca89a18f7d7d5df4c15586e485a Mon Sep 17 00:00:00 2001 From: yerunpeng014 Date: Mon, 17 Aug 2026 17:17:24 +0800 Subject: [PATCH 1/2] fix(spring): preserve original operation ID for pageable --- .../languages/SpringPageableScanUtils.java | 4 +- .../java/spring/SpringCodegenTest.java | 30 ++++++++++++++ .../resources/3_0/spring/issue_24721.yaml | 41 +++++++++++++++++++ 3 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 modules/openapi-generator/src/test/resources/3_0/spring/issue_24721.yaml diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringPageableScanUtils.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringPageableScanUtils.java index c4f44ee9832c..9e346169ab52 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringPageableScanUtils.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringPageableScanUtils.java @@ -350,7 +350,9 @@ public static void applyPageableAnnotations( Map pageableDefaultsRegistry, AnnotationSyntax syntax) { - String operationId = codegenOperation.operationId; + String operationId = codegenOperation.operationIdOriginal != null + ? codegenOperation.operationIdOriginal + : codegenOperation.operationId; List pageableAnnotations = new ArrayList<>(); if (generatePageableConstraintValidation && useBeanValidation 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 e5c1ad926aa6..815c5585ff0e 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 @@ -7888,6 +7888,36 @@ public void sortDefaultAndPageableDefaultBothApplied() throws IOException { .fileContains("@SortDefault.SortDefaults({@SortDefault(sort = {\"name\"}, direction = Sort.Direction.DESC), @SortDefault(sort = {\"id\"}, direction = Sort.Direction.ASC)})"); } + @Test + public void pageableAnnotationsUseOriginalOperationId_issue24721() throws IOException { + Map props = new HashMap<>(); + props.put(INTERFACE_ONLY, "true"); + props.put(SpringCodegen.SKIP_DEFAULT_INTERFACE, "true"); + props.put(SpringCodegen.USE_TAGS, "true"); + props.put(SpringCodegen.USE_SPRING_BOOT3, "true"); + props.put(SpringCodegen.AUTO_X_SPRING_PAGINATED, "true"); + props.put(SpringCodegen.GENERATE_PAGEABLE_CONSTRAINT_VALIDATION, "true"); + props.put(SpringCodegen.GENERATE_SORT_VALIDATION, "true"); + + Map files = generateFromContract( + "src/test/resources/3_0/spring/issue_24721.yaml", SPRING_BOOT, props); + + JavaFileAssert.assertThat(files.get("ItemsApi.java")) + .assertMethod("listItems") + .assertParameter("pageable") + .hasType("Pageable") + .assertParameterAnnotations() + .containsWithName("ValidPageable") + .containsWithName("ValidSort") + .containsWithName("PageableDefault"); + + JavaFileAssert.assertThat(files.get("ItemsApi.java")) + .fileContains("@ValidPageable(maxSize = 100, maxPage = 50)") + .fileContains("@ValidSort(allowedValues = {\"id,asc\", \"id,desc\", \"name,asc\", \"name,desc\"})") + .fileContains("@PageableDefault(page = 0, size = 25)") + .fileContains("@SortDefault.SortDefaults({@SortDefault(sort = {\"name\"}, direction = Sort.Direction.DESC)})"); + } + // ------------------------------------------------------------------------- // substituteGenericPagedModel tests // ------------------------------------------------------------------------- diff --git a/modules/openapi-generator/src/test/resources/3_0/spring/issue_24721.yaml b/modules/openapi-generator/src/test/resources/3_0/spring/issue_24721.yaml new file mode 100644 index 000000000000..d8f38b529b7d --- /dev/null +++ b/modules/openapi-generator/src/test/resources/3_0/spring/issue_24721.yaml @@ -0,0 +1,41 @@ +openapi: 3.0.1 +info: + title: Issue 24721 Pageable Operation ID Sanitization + version: 1.0.0 +paths: + /items: + get: + tags: + - items + operationId: list-items + parameters: + - name: page + in: query + schema: + type: integer + default: 0 + maximum: 50 + - name: size + in: query + schema: + type: integer + default: 25 + maximum: 100 + - name: sort + in: query + style: form + explode: true + schema: + type: array + items: + type: string + enum: + - id,asc + - id,desc + - name,asc + - name,desc + default: + - name,desc + responses: + '200': + description: Successful response From 1b1b14e592e99d701f699ddd5ed63f39a1fd3959 Mon Sep 17 00:00:00 2001 From: yerunpeng014 Date: Fri, 21 Aug 2026 17:38:58 +0800 Subject: [PATCH 2/2] test(spring): cover original pageable operation ID lookup --- .../SpringPageableScanUtilsTest.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/languages/SpringPageableScanUtilsTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/languages/SpringPageableScanUtilsTest.java index e42586035c83..c502c01598b6 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/languages/SpringPageableScanUtilsTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/languages/SpringPageableScanUtilsTest.java @@ -493,6 +493,31 @@ public void applyPageableAnnotations_sortDefault_kotlinSyntax() { .isEqualTo("@SortDefault.SortDefaults(SortDefault(sort = [\"name\"], direction = Sort.Direction.ASC))"); } + @Test + public void applyPageableAnnotations_usesOriginalOperationIdForRegistryLookup() { + CodegenOperation op = minimalOp("listItems"); + op.operationIdOriginal = "list-items"; + + Map constraintsRegistry = + Collections.singletonMap("list-items", new SpringPageableScanUtils.PageableConstraintsData(50, 100, -1, -1)); + Map> sortValidationRegistry = + Collections.singletonMap("list-items", List.of("id,asc", "name,desc")); + Map defaultsRegistry = + Collections.singletonMap("list-items", new SpringPageableScanUtils.PageableDefaultsData( + 0, 25, List.of(new SpringPageableScanUtils.SortFieldDefault("name", "DESC")))); + + SpringPageableScanUtils.applyPageableAnnotations(op, true, true, constraintsRegistry, + true, sortValidationRegistry, defaultsRegistry, + SpringPageableScanUtils.AnnotationSyntax.JAVA); + + List annotations = (List) op.vendorExtensions.get("x-pageable-extra-annotation"); + assertThat(annotations).containsExactly( + "@ValidPageable(maxSize = 100, maxPage = 50)", + "@ValidSort(allowedValues = {\"id,asc\", \"name,desc\"})", + "@PageableDefault(page = 0, size = 25)", + "@SortDefault.SortDefaults({@SortDefault(sort = {\"name\"}, direction = Sort.Direction.DESC)})"); + } + @Test public void applyPageableAnnotations_noMatchingRegistryEntries_noAnnotationsAdded() { CodegenOperation op = minimalOp("someOtherOp");