diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/converters/PageOpenAPIConverter.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/converters/PageOpenAPIConverter.java index a761a1c93..310f5f302 100644 --- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/converters/PageOpenAPIConverter.java +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/converters/PageOpenAPIConverter.java @@ -123,7 +123,7 @@ public Schema resolve(AnnotatedType type, ModelConverterContext context, Iterato Schema schema = (chain.hasNext()) ? chain.next().resolve(type, context, chain) : null; if (isPageType && !replacePageWithPagedModel) - sortPageSchemaProperties(schema, context); + customizePageSchema(schema, context); return schema; } @@ -161,12 +161,12 @@ private Type pagedModelType(JavaType type) { } /** - * Sort page schema properties. + * Require and sort page schema properties. * * @param schema the schema * @param context the context */ - private void sortPageSchemaProperties(Schema schema, ModelConverterContext context) { + private void customizePageSchema(Schema schema, ModelConverterContext context) { Schema pageSchema = resolveReferencedSchema(schema, context); if (pageSchema == null || pageSchema.getProperties() == null) return; @@ -179,6 +179,7 @@ private void sortPageSchemaProperties(Schema schema, ModelConverterContext conte PAGE_PROPERTY_ORDER.forEach(property -> sortedProperties.put(property, properties.get(property))); properties.forEach(sortedProperties::putIfAbsent); pageSchema.setProperties(sortedProperties); + pageSchema.setRequired(PAGE_PROPERTY_ORDER); } /** diff --git a/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app246.json b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app246.json index b0e9991ad..eae4e0a22 100644 --- a/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app246.json +++ b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app246.json @@ -79,6 +79,19 @@ } }, "PageHelloWorld_Hello": { + "required": [ + "content", + "empty", + "first", + "last", + "number", + "numberOfElements", + "pageable", + "size", + "sort", + "totalElements", + "totalPages" + ], "type": "object", "properties": { "totalElements": { diff --git a/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app249.json b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app249.json index 42595c74b..ae27edcac 100644 --- a/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app249.json +++ b/springdoc-openapi-starter-webmvc-api/src/test/resources/results/3.0.1/app249.json @@ -105,6 +105,19 @@ } }, "PageHelloWorld_Hello": { + "required": [ + "content", + "empty", + "first", + "last", + "number", + "numberOfElements", + "pageable", + "size", + "sort", + "totalElements", + "totalPages" + ], "type": "object", "properties": { "totalPages": { @@ -166,4 +179,4 @@ } } } -} \ No newline at end of file +} diff --git a/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/src/test/resources/results/3.0.1/app24.json b/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/src/test/resources/results/3.0.1/app24.json index 5447028dd..1aa83d04c 100644 --- a/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/src/test/resources/results/3.0.1/app24.json +++ b/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/src/test/resources/results/3.0.1/app24.json @@ -123,7 +123,20 @@ "empty": { "type": "boolean" } - } + }, + "required": [ + "content", + "empty", + "first", + "last", + "number", + "numberOfElements", + "pageable", + "size", + "sort", + "totalElements", + "totalPages" + ] }, "PageableObject": { "type": "object", diff --git a/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/src/test/resources/results/3.1.0/app24.json b/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/src/test/resources/results/3.1.0/app24.json index a6e140662..caf092d9f 100644 --- a/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/src/test/resources/results/3.1.0/app24.json +++ b/springdoc-openapi-tests/springdoc-openapi-data-rest-tests/src/test/resources/results/3.1.0/app24.json @@ -123,7 +123,20 @@ "empty": { "type": "boolean" } - } + }, + "required": [ + "content", + "empty", + "first", + "last", + "number", + "numberOfElements", + "pageable", + "size", + "sort", + "totalElements", + "totalPages" + ] }, "PageableObject": { "type": "object", diff --git a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/v30/app10/SpringDocApp10DirectTest.java b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/v30/app10/SpringDocApp10DirectTest.java index 55bdcf45f..9a96f9ef0 100644 --- a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/v30/app10/SpringDocApp10DirectTest.java +++ b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/v30/app10/SpringDocApp10DirectTest.java @@ -33,6 +33,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.data.web.config.EnableSpringDataWebSupport; +import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.is; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; @@ -47,6 +48,9 @@ protected void testApp() throws Exception { mockMvc.perform(get(Constants.DEFAULT_API_DOCS_URL)) .andExpect(status().isOk()) .andExpect(jsonPath("$.openapi", is("3.0.1"))) + .andExpect(jsonPath("$.components.schemas.PageString.required", containsInAnyOrder( + "totalPages", "totalElements", "size", "content", "number", "sort", "pageable", + "numberOfElements", "first", "last", "empty"))) .andExpect(content().json(getContent("results/3.0.1/app10-direct.json"), true)); } diff --git a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/v31/app10/SpringDocApp10DirectTest.java b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/v31/app10/SpringDocApp10DirectTest.java index e5222ec38..be6e45d37 100644 --- a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/v31/app10/SpringDocApp10DirectTest.java +++ b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/java/test/org/springdoc/api/v31/app10/SpringDocApp10DirectTest.java @@ -33,6 +33,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.data.web.config.EnableSpringDataWebSupport; +import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.is; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; @@ -47,6 +48,9 @@ protected void testApp() throws Exception { mockMvc.perform(get(Constants.DEFAULT_API_DOCS_URL)) .andExpect(status().isOk()) .andExpect(jsonPath("$.openapi", is("3.1.0"))) + .andExpect(jsonPath("$.components.schemas.PageString.required", containsInAnyOrder( + "totalPages", "totalElements", "size", "content", "number", "sort", "pageable", + "numberOfElements", "first", "last", "empty"))) .andExpect(content().json(getContent("results/3.1.0/app10-direct.json"), true)); } diff --git a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/resources/results/3.0.1/app10-direct.json b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/resources/results/3.0.1/app10-direct.json index 12f41a67f..b1411f5af 100644 --- a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/resources/results/3.0.1/app10-direct.json +++ b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/resources/results/3.0.1/app10-direct.json @@ -312,7 +312,20 @@ "empty": { "type": "boolean" } - } + }, + "required": [ + "content", + "empty", + "first", + "last", + "number", + "numberOfElements", + "pageable", + "size", + "sort", + "totalElements", + "totalPages" + ] }, "PageableObject": { "type": "object", @@ -398,7 +411,20 @@ "empty": { "type": "boolean" } - } + }, + "required": [ + "content", + "empty", + "first", + "last", + "number", + "numberOfElements", + "pageable", + "size", + "sort", + "totalElements", + "totalPages" + ] }, "UserDto": { "type": "object", @@ -455,7 +481,20 @@ "empty": { "type": "boolean" } - } + }, + "required": [ + "content", + "empty", + "first", + "last", + "number", + "numberOfElements", + "pageable", + "size", + "sort", + "totalElements", + "totalPages" + ] }, "PageDummyListString": { "type": "object", @@ -501,7 +540,20 @@ "empty": { "type": "boolean" } - } + }, + "required": [ + "content", + "empty", + "first", + "last", + "number", + "numberOfElements", + "pageable", + "size", + "sort", + "totalElements", + "totalPages" + ] }, "DummyPageString": { "type": "object", diff --git a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/resources/results/3.1.0/app10-direct.json b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/resources/results/3.1.0/app10-direct.json index e3fa6c995..113baacac 100644 --- a/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/resources/results/3.1.0/app10-direct.json +++ b/springdoc-openapi-tests/springdoc-openapi-hateoas-tests/src/test/resources/results/3.1.0/app10-direct.json @@ -290,7 +290,20 @@ "empty": { "type": "boolean" } - } + }, + "required": [ + "content", + "empty", + "first", + "last", + "number", + "numberOfElements", + "pageable", + "size", + "sort", + "totalElements", + "totalPages" + ] }, "PageableObject": { "type": "object", @@ -374,7 +387,20 @@ "empty": { "type": "boolean" } - } + }, + "required": [ + "content", + "empty", + "first", + "last", + "number", + "numberOfElements", + "pageable", + "size", + "sort", + "totalElements", + "totalPages" + ] }, "PageDummyListString": { "type": "object", @@ -420,7 +446,20 @@ "empty": { "type": "boolean" } - } + }, + "required": [ + "content", + "empty", + "first", + "last", + "number", + "numberOfElements", + "pageable", + "size", + "sort", + "totalElements", + "totalPages" + ] }, "DummyPageString": { "type": "object",