Serialization to openapi of org.springframework.data.domain.Sort is not done correctly
Hi, There is something wrong with the serialization (to openapi) of the org.springframework.data.domain.Sort
I've a method which returns a org.springframework.data.domain.Page<T> from a method in a RestController class. The implementation of org.springframework.data.domain.Page<T> is org.springframework.data.domain.PageImpl<T>
@RestController
public class MyRestController {
@PostMapping(path = "/", produces = APPLICATION_JSON_VALUE, consumes = APPLICATION_JSON_VALUE)
@Operation(operationId="myOperation")
public org.springframework.data.domain.Page<MyDto> queryMyDto(@RequestBody MyDtoQuery query, @ParameterObject org.springframework.data.domain.Pageable pageable) {
// This return a PageImpl with the data, the method parameter 'query' is a pojo containg filter properties
return myService.getResult(query, pageable);
}
}
The openapi defintion generated is:
"PageMyDto": {
"type": "object",
"properties": {
"totalPages": {
"type": "integer",
"format": "int32"
},
"totalElements": {
"type": "integer",
"format": "int64"
},
"first": {
"type": "boolean"
},
"last": {
"type": "boolean"
},
"size": {
"type": "integer",
"format": "int32"
},
"content": {
"type": "array",
"items": {
"$ref": "#/components/schemas/MyDto"
}
},
"number": {
"type": "integer",
"format": "int32"
},
"sort": {
"$ref": "#/components/schemas/SortObject"
},
"numberOfElements": {
"type": "integer",
"format": "int32"
},
"pageable": {
"$ref": "#/components/schemas/PageableObject"
},
"empty": {
"type": "boolean"
}
}
},
"SortObject": {
"type": "object",
"properties": {
"empty": {
"type": "boolean"
},
"sorted": {
"type": "boolean"
},
"unsorted": {
"type": "boolean"
}
}
}
When i call the method, the return object is (content is empty for this example):
http://localhost:8180/?page=0&size=20
{
"number": 0,
"numberOfElements": 0,
"totalElements": 0,
"totalPages": 0,
"size": 20,
"sort": [],
"content": []
}
As you can see, the "sort" property generated is not an array, and the SortObject does not contains the Sort properties like orders.
If i set the query parameter sort, the result is:
http://localhost:8180/?page=0&size=20&sort=id
{
"number": 0,
"numberOfElements": 0,
"totalElements": 0,
"totalPages": 0,
"size": 20,
"sort": [
{
"property": "id",
"direction": "ASC",
"ignoreCase": false,
"nullHandling": "NATIVE"
}
],
"content": []
}
I'm using spring boot 3.1.6 and springdoc-openapi-webmvc-ui 2.3.0.
Can you help me figure out if there is a bug or if i'm doing something wrong?
Thanks
@a-locatelli Did you manage to solve this? Any workarounds?
@a-locatelli,
I have added a fix for it. Let me know if the fix works for you with the latest snapshot.
I have the same problem, and your fix dosen't solved it.
Your excpected output is:
"sort": {
"$ref": "#/components/schemas/SortObject"
},
But have to be:
"sort": {
"type": "array",
"items": {
"$ref": "#/components/schemas/OrderObject"
}
},
I implemented a workaround like this, with this the desired openapi.json is generated and from that working DTOs to use with Pageable and Sort.
@Configuration
class CustomOpenApiConfiguration {
@Bean
fun CustomSortSchemaConverter(): SortSchemaConverter {
// Create and return the custom SortSchemaConverter
return SortSchemaConverter()
}
}
class SortSchemaConverter : ModelConverter {
override fun resolve(
type: AnnotatedType,
context: ModelConverterContext,
chain: MutableIterator<ModelConverter>
): Schema<*>? {
val javaType = type.type
return if (javaType is SimpleType && javaType.rawClass == Sort::class.java) {
val orderSchema = ObjectSchema()
.addProperty("direction", StringSchema())
.addProperty("property", StringSchema())
.addProperty("ignoreCase", BooleanSchema())
.addProperty("nullHandling", StringSchema())
.addProperty("ascending", BooleanSchema())
.addProperty("descending", BooleanSchema())
// needs to be called whenever a Model is defined which can be referenced from another
// Model or Property
context.defineModel("OrderObject", orderSchema)
ArraySchema().items(
Schema<Any>().`$ref`("#/components/schemas/OrderObject")
)
} else if (chain.hasNext()) {
chain.next().resolve(type, context, chain)
} else {
null
}
}
}
@SimoneFalzone,
Your proposed fix is too much lines of code, with too much assumptions that OrderObject schema exists.
There is much simpler way to do this.