Skip to content

Bugfix/25160 - #25197

Draft
Picazsoo wants to merge 7 commits into
OpenAPITools:masterfrom
Picazsoo:bugfix/25160
Draft

Picazsoo wants to merge 7 commits into
OpenAPITools:masterfrom
Picazsoo:bugfix/25160

Conversation

@Picazsoo

@Picazsoo Picazsoo commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Why

Fixes #25160.

Spring's @PageableDefault.page is always zero-based, even when request parameters are configured as one-based. Copying an OpenAPI page.default: 1 directly into that annotation selects the second page when the request omits page. Generated page-validation bounds must also match Spring's internally zero-based Pageable.

What

  • Add generatePageableDefaults (default true) to Spring and Kotlin-Spring. Setting it to false suppresses both @PageableDefault and @SortDefault, without disabling validation.
  • Add oneIndexedPageParameters (default false). When enabled, convert page defaults and effective validation bounds to zero-based values; leave size and sort unchanged. Resolve fractional/exclusive bounds against the integer page domain before conversion.
  • Warn for an ambiguous page default of 1 unless indexing is explicitly configured as either true or false. Reuse TriStateBoolean to distinguish implicit defaults from explicit configuration through options or setters.
  • Fail generation clearly for invalid one-based defaults/bounds when their corresponding annotations are enabled, rather than silently clamping values or generating invalid annotations.
  • Regenerate option documentation and reuse the Java/Kotlin sort-validation samples with an isolated one-based spec. Handwritten controllers and integration tests verify the actual generated annotations, omitted/explicit page resolution, and upper bounds.
  • Run the Kotlin integration sample in a dedicated JDK 17 test group. Other samples retain compile-only checks. Keep JUnit Platform configuration local to the tested sample and preserve it during regeneration.
  • Remove duplicate client-starter dependencies from the Spring Boot 4 POM template and regenerate the four affected sample POMs. Cover both MVC (restclient) and reactive (webclient) output.

Runtime configuration and scope

oneIndexedPageParameters describes the spec; it does not configure Spring's resolver. Applications using one-based requests must separately set spring.data.web.pageable.one-indexed-parameters=true.

Both spring-boot and spring-cloud retain annotation support. Outgoing Feign page serialization is unchanged and remains a separate follow-up; matching controller/client generation options alone do not guarantee one-based round trips.

PR checklist

  • Read the contribution guidelines.
  • Run the following to build the project and update samples:
    ./mvnw clean package || exit
    ./bin/generate-samples.sh ./bin/configs/*.yaml || exit
    ./bin/utils/export_docs_generators.sh || exit
    
    (For Windows users, please run the script in WSL)
    Commit all changed files.
    This is important, as CI jobs will verify all generator outputs of your HEAD commit as it would merge with master.
    These must match the expectations made by your contribution.
    You may regenerate an individual generator by passing the relevant config(s) as an argument to the script, for example ./bin/generate-samples.sh bin/configs/java*.
    IMPORTANT: Do NOT purge/delete any folders/files (e.g. tests) when regenerating the samples as manually written tests may be removed.
  • If your PR is targeting a particular programming language, @mention the technical committee members, so they are more likely to review the pull request.

Summary by cubic

Fixes #25160 by adding configurable one-based pagination support to the Java and Kotlin Spring generators. Specs using pages starting at 1 now produce zero-based Pageable defaults and validation bounds; existing behavior is unchanged unless oneIndexedPageParameters is enabled.

  • Adds generatePageableDefaults to control @PageableDefault and @SortDefault generation independently from validation.
  • Warns when a page default of 1 has no explicit indexing configuration and fails generation for invalid one-based defaults or bounds.
  • Converts page and size bounds through shared precise logic, skips bound resolution when constraint validation is disabled, and reports overflow with the operation context.
  • Removes the duplicate test-scoped client starter from the Spring Boot 4 POM template and regenerates affected samples.
  • Disables generated placeholder Kotlin API tests so unfinished samples no longer fail, and enables JUnit Platform in Kotlin Spring Boot templates; the Kotlin sample workflow runs its handwritten tests on JDK 17.
  • Aligns runtime indexing in the Java validation sample via spring.data.web.pageable.one-indexed-parameters=true.

Written for commit a9492ef. Summary will update on new commits.

View guided diff

Picazsoo and others added 4 commits October 8, 2026 16:46
Add configurable pageable default generation and normalize one-based page defaults and validation bounds for Java and Kotlin Spring. Warn for ambiguous page defaults unless indexing is explicitly configured, and document the separate Feign encoding limitation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Use an isolated one-based spec for Java and Kotlin validation samples and exercise generated defaults and bounds through handwritten integration tests. Run the Kotlin sample in a dedicated JDK17 test group while retaining compile-only checks for other samples. Keep JUnit Platform configuration scoped to that sample.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove redundant test-scoped client starters from the Boot 4 POM template, regenerate affected samples, and cover both MVC and reactive dependency uniqueness.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Picazsoo
Picazsoo marked this pull request as ready for review October 8, 2026 18:59
@Picazsoo
Picazsoo marked this pull request as draft October 8, 2026 18:59

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 30 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="samples/openapi3/server/petstore/springboot-3/src/test/java/org/openapitools/PageableDefaultsTest.java">

<violation number="1" location="samples/openapi3/server/petstore/springboot-3/src/test/java/org/openapitools/PageableDefaultsTest.java:13">
P2: This test only exercises Spring Data's resolver with annotations hand-written in `Endpoints`. The springboot-3 sample has no generated `@PageableDefault` to check, so the test would pass even if the generator emitted wrong defaults. Generate the one-indexed spec into this sample and assert on the generated `PetApi` parameter defaults, or resolve against the generated method.</violation>
</file>

<file name="samples/server/petstore/kotlin-springboot-sort-validation/src/main/kotlin/org/openapitools/api/PetApi.kt">

<violation number="1" location="samples/server/petstore/kotlin-springboot-sort-validation/src/main/kotlin/org/openapitools/api/PetApi.kt:179">
P2: The emitted `minPage = 0` bound is a no-op, so the spec's `minimum: 1` on the page parameter is never enforced. The spec (modules/openapi-generator/src/test/resources/3_0/spring/petstore-sort-validation-one-indexed.yaml, /pet/findWithPageSizeDefaultsOnly) declares page `default: 1, minimum: 1, maximum: 5`; the one-based conversion produces `@ValidPageable(minPage = 0, maxPage = 4)`. The validator (`ValidPageable.kt`/`ValidPageable.java` `isValid`) only fails when `pageable.pageNumber < minPage`, i.e. `pageNumber < 0` here. Spring never resolves a negative `Pageable` (PageRequest.of rejects negatives, and the one-indexed conversion leaves `page <= 0` at internal 0), so `?page=0` passes validation and the endpoint returns 200 with `X-Page-Number: 0` despite the spec minimum of 1. The same no-op lower bound appears in samples/server/petstore/springboot-sort-validation/src/main/java/org/openapitools/api/PetApi.java, and the manual guards (`pageable.pageNumber in 0..4` / `getPageNumber() < 0`) only mirror it. Enforce the lower bound on the raw request value (reject `page <= 0` before one-indexed conversion) or drop `minPage` when the translated internal minimum is 0; also add a test asserting `?page=0` is rejected so the gap is visible.</violation>
</file>

Reply with feedback, questions, or to request a fix.

View guided diff | Re-trigger cubic


import static org.assertj.core.api.Assertions.assertThat;

class PageableDefaultsTest {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: This test only exercises Spring Data's resolver with annotations hand-written in Endpoints. The springboot-3 sample has no generated @PageableDefault to check, so the test would pass even if the generator emitted wrong defaults. Generate the one-indexed spec into this sample and assert on the generated PetApi parameter defaults, or resolve against the generated method.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At samples/openapi3/server/petstore/springboot-3/src/test/java/org/openapitools/PageableDefaultsTest.java, line 13:

<comment>This test only exercises Spring Data's resolver with annotations hand-written in `Endpoints`. The springboot-3 sample has no generated `@PageableDefault` to check, so the test would pass even if the generator emitted wrong defaults. Generate the one-indexed spec into this sample and assert on the generated `PetApi` parameter defaults, or resolve against the generated method.</comment>

<file context>
@@ -0,0 +1,61 @@
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class PageableDefaultsTest {
+
+    static class Endpoints {
</file context>

produces = ["application/json"]
)
fun findPetsWithPageSizeDefaultsOnly(@PageableDefault(page = 0, size = 25) pageable: Pageable): ResponseEntity<List<Pet>> {
fun findPetsWithPageSizeDefaultsOnly(@ValidPageable(maxPage = 4, minPage = 0) @PageableDefault(page = 0, size = 25) pageable: Pageable): ResponseEntity<List<Pet>> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The emitted minPage = 0 bound is a no-op, so the spec's minimum: 1 on the page parameter is never enforced. The spec (modules/openapi-generator/src/test/resources/3_0/spring/petstore-sort-validation-one-indexed.yaml, /pet/findWithPageSizeDefaultsOnly) declares page default: 1, minimum: 1, maximum: 5; the one-based conversion produces @ValidPageable(minPage = 0, maxPage = 4). The validator (ValidPageable.kt/ValidPageable.java isValid) only fails when pageable.pageNumber < minPage, i.e. pageNumber < 0 here. Spring never resolves a negative Pageable (PageRequest.of rejects negatives, and the one-indexed conversion leaves page <= 0 at internal 0), so ?page=0 passes validation and the endpoint returns 200 with X-Page-Number: 0 despite the spec minimum of 1. The same no-op lower bound appears in samples/server/petstore/springboot-sort-validation/src/main/java/org/openapitools/api/PetApi.java, and the manual guards (pageable.pageNumber in 0..4 / getPageNumber() < 0) only mirror it. Enforce the lower bound on the raw request value (reject page <= 0 before one-indexed conversion) or drop minPage when the translated internal minimum is 0; also add a test asserting ?page=0 is rejected so the gap is visible.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At samples/server/petstore/kotlin-springboot-sort-validation/src/main/kotlin/org/openapitools/api/PetApi.kt, line 179:

<comment>The emitted `minPage = 0` bound is a no-op, so the spec's `minimum: 1` on the page parameter is never enforced. The spec (modules/openapi-generator/src/test/resources/3_0/spring/petstore-sort-validation-one-indexed.yaml, /pet/findWithPageSizeDefaultsOnly) declares page `default: 1, minimum: 1, maximum: 5`; the one-based conversion produces `@ValidPageable(minPage = 0, maxPage = 4)`. The validator (`ValidPageable.kt`/`ValidPageable.java` `isValid`) only fails when `pageable.pageNumber < minPage`, i.e. `pageNumber < 0` here. Spring never resolves a negative `Pageable` (PageRequest.of rejects negatives, and the one-indexed conversion leaves `page <= 0` at internal 0), so `?page=0` passes validation and the endpoint returns 200 with `X-Page-Number: 0` despite the spec minimum of 1. The same no-op lower bound appears in samples/server/petstore/springboot-sort-validation/src/main/java/org/openapitools/api/PetApi.java, and the manual guards (`pageable.pageNumber in 0..4` / `getPageNumber() < 0`) only mirror it. Enforce the lower bound on the raw request value (reject `page <= 0` before one-indexed conversion) or drop `minPage` when the translated internal minimum is 0; also add a test asserting `?page=0` is rejected so the gap is visible.</comment>

<file context>
@@ -176,7 +176,7 @@ interface PetApi {
         produces = ["application/json"]
     )
-    fun findPetsWithPageSizeDefaultsOnly(@PageableDefault(page = 0, size = 25) pageable: Pageable): ResponseEntity<List<Pet>> {
+    fun findPetsWithPageSizeDefaultsOnly(@ValidPageable(maxPage = 4, minPage = 0) @PageableDefault(page = 0, size = 25) pageable: Pageable): ResponseEntity<List<Pet>> {
         return ResponseEntity(HttpStatus.NOT_IMPLEMENTED)
     }
</file context>

Comment thread .github/workflows/samples-kotlin-server-jdk17.yaml Outdated
…form

Normalize page bounds consistently and report overflow with operation context. Exercise auto-detected pagination in both integration samples and remove redundant controller guards.

Configure JUnit Platform in Kotlin Spring Boot templates, regenerate sample builds, and use the maintained Gradle setup action.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Picazsoo
Picazsoo marked this pull request as ready for review October 8, 2026 20:08
@Picazsoo
Picazsoo marked this pull request as draft October 8, 2026 20:08

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 61 files

Reply with feedback, questions, or to request a fix.

View guided diff | Re-trigger cubic

Comment thread samples/server/petstore/kotlin-spring-default/build.gradle.kts
Comment thread .github/workflows/samples-kotlin-server-jdk17.yaml
Picazsoo and others added 2 commits October 9, 2026 00:48
Share precise page and size bound conversion, reject invalid emitted numeric defaults, and skip bound resolution when constraint validation is disabled.

Disable unfinished generated Kotlin API tests explicitly, align the Java sample runtime indexing configuration, and avoid duplicate Gradle caches.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Spring generator uses one-based API page default as zero-based Pageable default

1 participant