[Kotlin] Use mutable container types when 'modelMutable' is enabled#11154
Conversation
3f56d5f to
d569dfb
Compare
2570e60 to
1e3423f
Compare
There was a problem hiding this comment.
@rm3l could you please explain what this does and why it's needed? Thanks
There was a problem hiding this comment.
Similar reasons as in my other comment below.
For example, given the following input operation:
/store/inventory:
get:
tags:
- store
summary: Returns pet inventories by status
description: Returns a map of status codes to quantities
operationId: getInventory
produces:
- application/json
parameters: []
responses:
'200':
description: successful operation
schema:
type: object
additionalProperties:
type: integer
format: int32Without the changes here, this resulted in the following code generated by the kotlin-spring generator:
StoreApiController.kt: the Response field in theApiResponseannotation has changed toMutableMap, which, I guess, is not valid.
diff --git a/samples/server/petstore/kotlin-springboot-modelMutable/src/main/kotlin/org/openapitools/api/StoreApiController.kt b/samples/server/petstore/kotlin-springboot-modelMutable/src/main/kotlin/org/openapitools/api/StoreApiController.kt
index e2be73b4ec3..ad63efeae2d 100644
--- a/samples/server/petstore/kotlin-springboot-modelMutable/src/main/kotlin/org/openapitools/api/StoreApiController.kt
+++ b/samples/server/petstore/kotlin-springboot-modelMutable/src/main/kotlin/org/openapitools/api/StoreApiController.kt
@@ -58,7 +58,7 @@ class StoreApiController(@Autowired(required = true) val service: StoreApiServic
responseContainer = "Map",
authorizations = [Authorization(value = "api_key")])
@ApiResponses(
value = [ApiResponse(code = 200, message = "successful operation",
- response = kotlin.collections.Map::class,
responseContainer = "Map")])
value = [ApiResponse(code = 200, message = "successful operation",
+ response = kotlin.collections.MutableMap::class,
responseContainer = "Map")])
@RequestMapping(
method = [RequestMethod.GET],
value = ["/store/inventory"],Again, maybe this is not the right approach here or maybe I missed something, but I found no clear way to distinguish between the type mappings used for generating models (Kotlin data classes) and response types in the kotlin-spring generator. Also, since the original issue I reported was more related to model mutability, I thought it would be ok not to change the code generated for the Spring Controllers.
There was a problem hiding this comment.
Thanks for explaining, this way we have an explanation in case we need it 👍
There was a problem hiding this comment.
@rm3l could you please explain what this does and why it's needed? Thanks
There was a problem hiding this comment.
Sure. While testing, I noticed that changing the type mappings to their Mutable types resulted in all types being changed as well in the generated Spring Request handlers methods.
This included the types for all query parameters. On the other side, the generated tests would still use the non-mutable types, resulting in the generated test code not compiling at all.
For example, given the following operation in an OpenAPI definition:
/pet/findByStatus:
get:
operationId: findPetsByStatus
parameters:
- name: status
in: query
required: true
type: array
items:
type: string
enum:
- available
- pending
- soldWithout the changes here, this resulted in the following code generated by the kotlin-spring generator:
PetApiController.kt(notice thatstatusis generated as aMutableList):
@RequestMapping(
method = [RequestMethod.GET],
value = ["/pet/findByStatus"]
)
fun findPetsByStatus(...
@RequestParam(value = "status", required = true)
status: kotlin.collections.MutableList<kotlin.String>
): ResponseEntity<List<Pet>> {
return ResponseEntity(service.findPetsByStatus(status), HttpStatus.valueOf(200))
}PetApiTest.kt(which would not compile becauseapi.findPetsByStatusexpects aMutableList, butstatusis suprisingly generated as aList)
@Test
fun findPetsByStatusTest() {
val status:kotlin.collections.List<kotlin.String> = TODO()
val response: ResponseEntity<List<Pet>> = api.findPetsByStatus(status)
// TODO: test validations
}Maybe this is not the right approach here or maybe I missed something, but I found no clear way to distinguish between the type mappings used for generating models (Kotlin data classes) and request parameters in the kotlin-spring generator. Also, since the original issue I reported was more related to model mutability, I thought it would be ok not to change the code generated for the Spring Controllers.
Another possible approach I thought of that would fix the compilation issue was to make sure the test code generates request params as mutable containers instead.
Let me know your thoughts.
There was a problem hiding this comment.
Thanks for explaining, this way we have an explanation in case we need it 👍
There was a problem hiding this comment.
FYI, I added few comments in the code for reference.
There was a problem hiding this comment.
@rm3l As far as I can tell the mutable models are disabled by default, and since there is not sample project with it active, this change shouldn't happen, or am I wrong?
There was a problem hiding this comment.
This file got changed right after I launched the bin/generate-samples.sh script, as recommended in the PR checklist.
From what I understood after reading the script, it generates samples for all configs under the bin/configs folder. It therefore picks the kotlin-spring-boot-modelMutable.yaml file, which generates a sample project with mutable models.
So I guess mutable models are indeed disabled by default, except in this sample project.
|
@rm3l Could you please enable the mutable models in a sample project for this feature to be testes in every commit please? |
Sure. Indeed, since the existing |
1e3423f to
de65993
Compare
@4brunu I added additional configs to generate samples with model mutability enabled for all the other Kotlin generators impacted by this PR:
Could you please take a look when you get a chance? Thanks. |
4brunu
left a comment
There was a problem hiding this comment.
Thanks for making the changes.
Looks good to me 👍
…del_mutable_is_true
|
Great - thanks for your time and support, @4brunu! |
|
Hi, it works great for MutableLists with default values, but unfortunately not for MutableSets with default values. As example, this is what currently will be generated when modelMutable is set to true: My OAS: |
| dataTypeAssigner.setReturnType(returnType.substring("kotlin.collections.MutableMap<".length(), end).split(",")[1].trim()); | ||
| dataTypeAssigner.setReturnContainer("Map"); | ||
| } | ||
| } |
There was a problem hiding this comment.
I think there is a case missing for "MutableSet"
There was a problem hiding this comment.
Hi @martin-regis could you please open a PR with a fix please?
This should close #11088.
Basically, when the Kotlin generators are run with
modelMutableset totrue, the changes here allow to generate read-writeMutableKotlin container types (likeMutableListorMutableMap) for OpenAPI arrays and dictionaries, instead of read-only types (likeListorMap).This way, it makes it possible to mutate such containers right away, without performing potentially expensive copies.
See #11088 for more context and details.
Maybe I missed something, but I noticed that unlike the other Kotlin generators, the
kotlin-clientone uses the raw templates rather than the Java source files to determine the different data types.Please do let me know if things should be done differently.
PR checklist
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*.For Windows users, please run the script in Git BASH.
master(5.3.0),6.0.x@jimschubert @dr4ke616 @karismann @Zomzog @andrewemery @4brunu @yutaka0m Could anyone of you please take a look at this ? Thanks.