With spring.data.web.pageable.serialization-mode=VIA_DTO, a Page<T> returned directly (or inside ResponseEntity) is documented as PagedModel<T>, but a Page<T> nested in another type is not:
The response is {"data": {"content": [...], "page": {...}}, ...}, while the spec documents data as the raw Page shape (pageable, sort, first, last, ...). The generated schema is also always named PageObject, so two wrappers with different element types share one schema and the second element type is missing from components.schemas.
PageOpenAPIConverter.resolve only swaps Page for PagedModel when the type is not a schema property. For a property it keeps Page and sets a name via getParentTypeName, which appends the parent's OpenAPI type ("object") rather than the parent class.
Change
In the schema-property branch, swap the AnnotatedType's type to the matching PagedModel<T> in place. The instance is kept, so ctxAnnotations, jsonViewAnnotation, parent and propertyName stay as they were (creating a new AnnotatedType here drops the @JsonView context from fix: propagate JsonView context when resolving Page<T> schema #3226).
Extract the PagedModel<T> type computation into pagedModelType(JavaType) so both branches share it.
Case
Before
After
Page<T> as response body, or inside ResponseEntity
PagedModelT
unchanged
DIRECT mode or property not set
raw Page
unchanged
Page<T> as a property of another type, VIA_DTO
PageObject (raw Page shape, shared name)
PagedModelT
Only the last row changes. PageObject, PageableObject and SortObject disappear from such specs and PagedModelXxx takes their place. A raw Page in that position becomes PagedModel, the same as a raw Page returned directly.
Test plan
Added Dummy<Page<String>> and Dummy<Page<Dummy<List<String>>>> endpoints to the app10 hateoas test (v30 and v31) and updated the four expected files. Without the fix the VIA_DTO variants fail with Unexpected: PageObject, PageableObject, SortObject; the DIRECT and not-specified variants pass before and after.
mvn test on springdoc-openapi-starter-common, -webmvc-api, -webflux-api, hateoas-tests, data-rest-tests, groovy-tests — all green.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #3319.
Summary
With spring.data.web.pageable.serialization-mode=VIA_DTO, a Page<T> returned directly (or inside ResponseEntity) is documented as PagedModel<T>, but a Page<T> nested in another type is not:
The response is {"data": {"content": [...], "page": {...}}, ...}, while the spec documents data as the raw Page shape (pageable, sort, first, last, ...). The generated schema is also always named PageObject, so two wrappers with different element types share one schema and the second element type is missing from components.schemas.
PageOpenAPIConverter.resolve only swaps Page for PagedModel when the type is not a schema property. For a property it keeps Page and sets a name via getParentTypeName, which appends the parent's OpenAPI type ("object") rather than the parent class.
Change
Only the last row changes. PageObject, PageableObject and SortObject disappear from such specs and PagedModelXxx takes their place. A raw Page in that position becomes PagedModel, the same as a raw Page returned directly.
Test plan