Skip to content

Commit 123b428

Browse files
authored
[scala-sttp4] Model named Request shadows sttp.client4.Request (#24682)
A schema named `Request` produces `import <modelPackage>.Request` in every generated API. An explicit import outranks a wildcard import regardless of order, so it shadows `sttp.client4.Request` from `import sttp.client4._` and the operation's return type resolves to the model: error: org.openapitools.client.model.Request does not take type parameters Qualify the return type as `sttp.client4.Request[...]`, matching what the scala-sttp generator already emits.
1 parent 53264a2 commit 123b428

9 files changed

Lines changed: 108 additions & 41 deletions

File tree

modules/openapi-generator/src/main/resources/scala-sttp4/api.mustache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class {{classname}}(baseUrl: String) {
2020
{{>javadoc}}
2121

2222
{{/javadocRenderer}}
23-
def {{operationId}}({{>methodParameters}}): Request[{{#separateErrorChannel}}Either[ResponseException[String], {{>operationReturnType}}]{{/separateErrorChannel}}{{^separateErrorChannel}}{{>operationReturnType}}{{/separateErrorChannel}}] =
23+
def {{operationId}}({{>methodParameters}}): sttp.client4.Request[{{#separateErrorChannel}}Either[ResponseException[String], {{>operationReturnType}}]{{/separateErrorChannel}}{{^separateErrorChannel}}{{>operationReturnType}}{{/separateErrorChannel}}] =
2424
basicRequest
2525
.method(Method.{{httpMethod.toUpperCase}}, uri"$baseUrl{{{path}}}{{#queryParams.0}}?{{/queryParams.0}}{{#queryParams}}{{baseName}}=${ {{paramName}} }{{^-last}}&{{/-last}}{{/queryParams}}{{#authMethods}}{{#isApiKey}}{{#isKeyInQuery}}{{#queryParams.0}}&{{/queryParams.0}}{{^queryParams.0}}?{{/queryParams.0}}{{keyParamName}}=${apiKeyQuery}{{/isKeyInQuery}}{{/isApiKey}}{{/authMethods}}")
2626
.contentType({{#consumes.0}}"{{{mediaType}}}"{{/consumes.0}}{{^consumes}}"application/json"{{/consumes}}){{#headerParams}}

modules/openapi-generator/src/test/java/org/openapitools/codegen/scala/Sttp4CodegenTest.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,4 +410,37 @@ public void verifyOptionalFieldsOmittedWhenNone() throws IOException {
410410
Path petPath = Paths.get(outputPath + "/src/main/scala/org/openapitools/client/model/Pet.scala");
411411
assertFileContains(petPath, "implicit val encoder: Encoder[Pet] = deriveEncoder[Pet].mapJson(_.dropNullValues)");
412412
}
413+
414+
@Test
415+
public void verifyModelNamedRequestDoesNotShadowSttpRequest() throws IOException {
416+
File output = Files.createTempDirectory("test").toFile().getCanonicalFile();
417+
output.deleteOnExit();
418+
String outputPath = output.getAbsolutePath().replace('\\', '/');
419+
420+
OpenAPI openAPI = new OpenAPIParser()
421+
.readLocation("src/test/resources/3_0/scala/sttp4-request-model-name.yaml", null, new ParseOptions())
422+
.getOpenAPI();
423+
424+
ScalaSttp4ClientCodegen codegen = new ScalaSttp4ClientCodegen();
425+
codegen.setOutputDir(output.getAbsolutePath());
426+
427+
ClientOptInput input = new ClientOptInput();
428+
input.openAPI(openAPI);
429+
input.config(codegen);
430+
431+
DefaultGenerator generator = new DefaultGenerator();
432+
433+
generator.setGeneratorPropertyDefault(CodegenConstants.MODELS, "true");
434+
generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_TESTS, "false");
435+
generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_DOCS, "false");
436+
generator.setGeneratorPropertyDefault(CodegenConstants.APIS, "true");
437+
generator.setGeneratorPropertyDefault(CodegenConstants.SUPPORTING_FILES, "false");
438+
generator.opts(input).generate();
439+
440+
// A model named Request is imported explicitly, which outranks the
441+
// `import sttp.client4._` wildcard, so the return type must be qualified.
442+
Path apiPath = Paths.get(outputPath + "/src/main/scala/org/openapitools/client/api/DefaultApi.scala");
443+
assertFileContains(apiPath, "import org.openapitools.client.model.Request");
444+
assertFileContains(apiPath, "): sttp.client4.Request[Either[ResponseException[String], Response]] =");
445+
}
413446
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
openapi: 3.0.0
2+
info:
3+
title: sttp4 model named Request
4+
version: 1.0.0
5+
paths:
6+
/predict:
7+
post:
8+
operationId: predict
9+
requestBody:
10+
content:
11+
application/json:
12+
schema:
13+
$ref: '#/components/schemas/Request'
14+
responses:
15+
'200':
16+
description: OK
17+
content:
18+
application/json:
19+
schema:
20+
$ref: '#/components/schemas/Response'
21+
components:
22+
schemas:
23+
Request:
24+
type: object
25+
required:
26+
- userId
27+
properties:
28+
userId:
29+
type: string
30+
Response:
31+
type: object
32+
properties:
33+
score:
34+
type: number

samples/client/petstore/scala-sttp4-circe/src/main/scala/org/openapitools/client/api/PetApi.scala

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class PetApi(baseUrl: String) {
3333
*
3434
* @param pet Pet object that needs to be added to the store
3535
*/
36-
def addPet(pet: Pet): Request[Either[ResponseException[String], Pet]] =
36+
def addPet(pet: Pet): sttp.client4.Request[Either[ResponseException[String], Pet]] =
3737
basicRequest
3838
.method(Method.POST, uri"$baseUrl/pet")
3939
.contentType("application/json")
@@ -49,7 +49,7 @@ class PetApi(baseUrl: String) {
4949
* @param petId Pet id to delete
5050
* @param apiKey
5151
*/
52-
def deletePet(petId: Long, apiKey: Option[String] = None): Request[Either[ResponseException[String], Unit]] =
52+
def deletePet(petId: Long, apiKey: Option[String] = None): sttp.client4.Request[Either[ResponseException[String], Unit]] =
5353
basicRequest
5454
.method(Method.DELETE, uri"$baseUrl/pet/${petId}")
5555
.contentType("application/json")
@@ -65,7 +65,7 @@ class PetApi(baseUrl: String) {
6565
*
6666
* @param status Status values that need to be considered for filter
6767
*/
68-
def findPetsByStatus(status: Seq[String] = Seq.empty): Request[Either[ResponseException[String], Seq[Pet]]] =
68+
def findPetsByStatus(status: Seq[String] = Seq.empty): sttp.client4.Request[Either[ResponseException[String], Seq[Pet]]] =
6969
basicRequest
7070
.method(Method.GET, uri"$baseUrl/pet/findByStatus?status=${ status }")
7171
.contentType("application/json")
@@ -80,7 +80,7 @@ class PetApi(baseUrl: String) {
8080
*
8181
* @param tags Tags to filter by
8282
*/
83-
def findPetsByTags(tags: Seq[String] = Seq.empty): Request[Either[ResponseException[String], Seq[Pet]]] =
83+
def findPetsByTags(tags: Seq[String] = Seq.empty): sttp.client4.Request[Either[ResponseException[String], Seq[Pet]]] =
8484
basicRequest
8585
.method(Method.GET, uri"$baseUrl/pet/findByTags?tags=${ tags }")
8686
.contentType("application/json")
@@ -99,7 +99,7 @@ class PetApi(baseUrl: String) {
9999
*
100100
* @param petId ID of pet to return
101101
*/
102-
def getPetById(apiKeyHeader: String)(petId: Long): Request[Either[ResponseException[String], Pet]] =
102+
def getPetById(apiKeyHeader: String)(petId: Long): sttp.client4.Request[Either[ResponseException[String], Pet]] =
103103
basicRequest
104104
.method(Method.GET, uri"$baseUrl/pet/${petId}")
105105
.contentType("application/json")
@@ -117,7 +117,7 @@ class PetApi(baseUrl: String) {
117117
*
118118
* @param pet Pet object that needs to be added to the store
119119
*/
120-
def updatePet(pet: Pet): Request[Either[ResponseException[String], Pet]] =
120+
def updatePet(pet: Pet): sttp.client4.Request[Either[ResponseException[String], Pet]] =
121121
basicRequest
122122
.method(Method.PUT, uri"$baseUrl/pet")
123123
.contentType("application/json")
@@ -134,7 +134,7 @@ class PetApi(baseUrl: String) {
134134
* @param name Updated name of the pet
135135
* @param status Updated status of the pet
136136
*/
137-
def updatePetWithForm(petId: Long, name: Option[String] = None, status: Option[String] = None): Request[Either[ResponseException[String], Unit]] =
137+
def updatePetWithForm(petId: Long, name: Option[String] = None, status: Option[String] = None): sttp.client4.Request[Either[ResponseException[String], Unit]] =
138138
basicRequest
139139
.method(Method.POST, uri"$baseUrl/pet/${petId}")
140140
.contentType("application/x-www-form-urlencoded")
@@ -154,7 +154,7 @@ class PetApi(baseUrl: String) {
154154
* @param additionalMetadata Additional data to pass to server
155155
* @param file file to upload
156156
*/
157-
def uploadFile(petId: Long, additionalMetadata: Option[String] = None, file: Option[File] = None): Request[Either[ResponseException[String], ApiResponse]] =
157+
def uploadFile(petId: Long, additionalMetadata: Option[String] = None, file: Option[File] = None): sttp.client4.Request[Either[ResponseException[String], ApiResponse]] =
158158
basicRequest
159159
.method(Method.POST, uri"$baseUrl/pet/${petId}/uploadImage")
160160
.contentType("multipart/form-data")

samples/client/petstore/scala-sttp4-circe/src/main/scala/org/openapitools/client/api/StoreApi.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class StoreApi(baseUrl: String) {
3131
*
3232
* @param orderId ID of the order that needs to be deleted
3333
*/
34-
def deleteOrder(orderId: String): Request[Either[ResponseException[String], Unit]] =
34+
def deleteOrder(orderId: String): sttp.client4.Request[Either[ResponseException[String], Unit]] =
3535
basicRequest
3636
.method(Method.DELETE, uri"$baseUrl/store/order/${orderId}")
3737
.contentType("application/json")
@@ -46,7 +46,7 @@ class StoreApi(baseUrl: String) {
4646
* Available security schemes:
4747
* api_key (apiKey)
4848
*/
49-
def getInventory(apiKeyHeader: String)(): Request[Either[ResponseException[String], Map[String, Int]]] =
49+
def getInventory(apiKeyHeader: String)(): sttp.client4.Request[Either[ResponseException[String], Map[String, Int]]] =
5050
basicRequest
5151
.method(Method.GET, uri"$baseUrl/store/inventory")
5252
.contentType("application/json")
@@ -63,7 +63,7 @@ class StoreApi(baseUrl: String) {
6363
*
6464
* @param orderId ID of pet that needs to be fetched
6565
*/
66-
def getOrderById(orderId: Long): Request[Either[ResponseException[String], Order]] =
66+
def getOrderById(orderId: Long): sttp.client4.Request[Either[ResponseException[String], Order]] =
6767
basicRequest
6868
.method(Method.GET, uri"$baseUrl/store/order/${orderId}")
6969
.contentType("application/json")
@@ -78,7 +78,7 @@ class StoreApi(baseUrl: String) {
7878
*
7979
* @param order order placed for purchasing the pet
8080
*/
81-
def placeOrder(order: Order): Request[Either[ResponseException[String], Order]] =
81+
def placeOrder(order: Order): sttp.client4.Request[Either[ResponseException[String], Order]] =
8282
basicRequest
8383
.method(Method.POST, uri"$baseUrl/store/order")
8484
.contentType("application/json")

samples/client/petstore/scala-sttp4-circe/src/main/scala/org/openapitools/client/api/UserApi.scala

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class UserApi(baseUrl: String) {
3434
*
3535
* @param user Created user object
3636
*/
37-
def createUser(apiKeyHeader: String)(user: User): Request[Either[ResponseException[String], Unit]] =
37+
def createUser(apiKeyHeader: String)(user: User): sttp.client4.Request[Either[ResponseException[String], Unit]] =
3838
basicRequest
3939
.method(Method.POST, uri"$baseUrl/user")
4040
.contentType("application/json")
@@ -53,7 +53,7 @@ class UserApi(baseUrl: String) {
5353
*
5454
* @param user List of user object
5555
*/
56-
def createUsersWithArrayInput(apiKeyHeader: String)(user: Seq[User]): Request[Either[ResponseException[String], Unit]] =
56+
def createUsersWithArrayInput(apiKeyHeader: String)(user: Seq[User]): sttp.client4.Request[Either[ResponseException[String], Unit]] =
5757
basicRequest
5858
.method(Method.POST, uri"$baseUrl/user/createWithArray")
5959
.contentType("application/json")
@@ -72,7 +72,7 @@ class UserApi(baseUrl: String) {
7272
*
7373
* @param user List of user object
7474
*/
75-
def createUsersWithListInput(apiKeyHeader: String)(user: Seq[User]): Request[Either[ResponseException[String], Unit]] =
75+
def createUsersWithListInput(apiKeyHeader: String)(user: Seq[User]): sttp.client4.Request[Either[ResponseException[String], Unit]] =
7676
basicRequest
7777
.method(Method.POST, uri"$baseUrl/user/createWithList")
7878
.contentType("application/json")
@@ -92,7 +92,7 @@ class UserApi(baseUrl: String) {
9292
*
9393
* @param username The name that needs to be deleted
9494
*/
95-
def deleteUser(apiKeyHeader: String)(username: String): Request[Either[ResponseException[String], Unit]] =
95+
def deleteUser(apiKeyHeader: String)(username: String): sttp.client4.Request[Either[ResponseException[String], Unit]] =
9696
basicRequest
9797
.method(Method.DELETE, uri"$baseUrl/user/${username}")
9898
.contentType("application/json")
@@ -109,7 +109,7 @@ class UserApi(baseUrl: String) {
109109
*
110110
* @param username The name that needs to be fetched. Use user1 for testing.
111111
*/
112-
def getUserByName(username: String): Request[Either[ResponseException[String], User]] =
112+
def getUserByName(username: String): sttp.client4.Request[Either[ResponseException[String], User]] =
113113
basicRequest
114114
.method(Method.GET, uri"$baseUrl/user/${username}")
115115
.contentType("application/json")
@@ -129,7 +129,7 @@ class UserApi(baseUrl: String) {
129129
* @param username The user name for login
130130
* @param password The password for login in clear text
131131
*/
132-
def loginUser(username: String, password: String): Request[Either[ResponseException[String], String]] =
132+
def loginUser(username: String, password: String): sttp.client4.Request[Either[ResponseException[String], String]] =
133133
basicRequest
134134
.method(Method.GET, uri"$baseUrl/user/login?username=${ username }&password=${ password }")
135135
.contentType("application/json")
@@ -144,7 +144,7 @@ class UserApi(baseUrl: String) {
144144
* Available security schemes:
145145
* api_key (apiKey)
146146
*/
147-
def logoutUser(apiKeyHeader: String)(): Request[Either[ResponseException[String], Unit]] =
147+
def logoutUser(apiKeyHeader: String)(): sttp.client4.Request[Either[ResponseException[String], Unit]] =
148148
basicRequest
149149
.method(Method.GET, uri"$baseUrl/user/logout")
150150
.contentType("application/json")
@@ -164,7 +164,7 @@ class UserApi(baseUrl: String) {
164164
* @param username name that need to be deleted
165165
* @param user Updated user object
166166
*/
167-
def updateUser(apiKeyHeader: String)(username: String, user: User): Request[Either[ResponseException[String], Unit]] =
167+
def updateUser(apiKeyHeader: String)(username: String, user: User): sttp.client4.Request[Either[ResponseException[String], Unit]] =
168168
basicRequest
169169
.method(Method.PUT, uri"$baseUrl/user/${username}")
170170
.contentType("application/json")

samples/client/petstore/scala-sttp4/src/main/scala/org/openapitools/client/api/PetApi.scala

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class PetApi(baseUrl: String) {
3333
*
3434
* @param pet Pet object that needs to be added to the store
3535
*/
36-
def addPet(pet: Pet): Request[Either[ResponseException[String], Pet]] =
36+
def addPet(pet: Pet): sttp.client4.Request[Either[ResponseException[String], Pet]] =
3737
basicRequest
3838
.method(Method.POST, uri"$baseUrl/pet")
3939
.contentType("application/json")
@@ -49,7 +49,7 @@ class PetApi(baseUrl: String) {
4949
* @param petId Pet id to delete
5050
* @param apiKey
5151
*/
52-
def deletePet(petId: Long, apiKey: Option[String] = None): Request[Either[ResponseException[String], Unit]] =
52+
def deletePet(petId: Long, apiKey: Option[String] = None): sttp.client4.Request[Either[ResponseException[String], Unit]] =
5353
basicRequest
5454
.method(Method.DELETE, uri"$baseUrl/pet/${petId}")
5555
.contentType("application/json")
@@ -65,7 +65,7 @@ class PetApi(baseUrl: String) {
6565
*
6666
* @param status Status values that need to be considered for filter
6767
*/
68-
def findPetsByStatus(status: Seq[String] = Seq.empty): Request[Either[ResponseException[String], Seq[Pet]]] =
68+
def findPetsByStatus(status: Seq[String] = Seq.empty): sttp.client4.Request[Either[ResponseException[String], Seq[Pet]]] =
6969
basicRequest
7070
.method(Method.GET, uri"$baseUrl/pet/findByStatus?status=${ status }")
7171
.contentType("application/json")
@@ -80,7 +80,7 @@ class PetApi(baseUrl: String) {
8080
*
8181
* @param tags Tags to filter by
8282
*/
83-
def findPetsByTags(tags: Seq[String] = Seq.empty): Request[Either[ResponseException[String], Seq[Pet]]] =
83+
def findPetsByTags(tags: Seq[String] = Seq.empty): sttp.client4.Request[Either[ResponseException[String], Seq[Pet]]] =
8484
basicRequest
8585
.method(Method.GET, uri"$baseUrl/pet/findByTags?tags=${ tags }")
8686
.contentType("application/json")
@@ -99,7 +99,7 @@ class PetApi(baseUrl: String) {
9999
*
100100
* @param petId ID of pet to return
101101
*/
102-
def getPetById(apiKeyHeader: String)(petId: Long): Request[Either[ResponseException[String], Pet]] =
102+
def getPetById(apiKeyHeader: String)(petId: Long): sttp.client4.Request[Either[ResponseException[String], Pet]] =
103103
basicRequest
104104
.method(Method.GET, uri"$baseUrl/pet/${petId}")
105105
.contentType("application/json")
@@ -117,7 +117,7 @@ class PetApi(baseUrl: String) {
117117
*
118118
* @param pet Pet object that needs to be added to the store
119119
*/
120-
def updatePet(pet: Pet): Request[Either[ResponseException[String], Pet]] =
120+
def updatePet(pet: Pet): sttp.client4.Request[Either[ResponseException[String], Pet]] =
121121
basicRequest
122122
.method(Method.PUT, uri"$baseUrl/pet")
123123
.contentType("application/json")
@@ -134,7 +134,7 @@ class PetApi(baseUrl: String) {
134134
* @param name Updated name of the pet
135135
* @param status Updated status of the pet
136136
*/
137-
def updatePetWithForm(petId: Long, name: Option[String] = None, status: Option[String] = None): Request[Either[ResponseException[String], Unit]] =
137+
def updatePetWithForm(petId: Long, name: Option[String] = None, status: Option[String] = None): sttp.client4.Request[Either[ResponseException[String], Unit]] =
138138
basicRequest
139139
.method(Method.POST, uri"$baseUrl/pet/${petId}")
140140
.contentType("application/x-www-form-urlencoded")
@@ -154,7 +154,7 @@ class PetApi(baseUrl: String) {
154154
* @param additionalMetadata Additional data to pass to server
155155
* @param file file to upload
156156
*/
157-
def uploadFile(petId: Long, additionalMetadata: Option[String] = None, file: Option[File] = None): Request[Either[ResponseException[String], ApiResponse]] =
157+
def uploadFile(petId: Long, additionalMetadata: Option[String] = None, file: Option[File] = None): sttp.client4.Request[Either[ResponseException[String], ApiResponse]] =
158158
basicRequest
159159
.method(Method.POST, uri"$baseUrl/pet/${petId}/uploadImage")
160160
.contentType("multipart/form-data")

samples/client/petstore/scala-sttp4/src/main/scala/org/openapitools/client/api/StoreApi.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class StoreApi(baseUrl: String) {
3131
*
3232
* @param orderId ID of the order that needs to be deleted
3333
*/
34-
def deleteOrder(orderId: String): Request[Either[ResponseException[String], Unit]] =
34+
def deleteOrder(orderId: String): sttp.client4.Request[Either[ResponseException[String], Unit]] =
3535
basicRequest
3636
.method(Method.DELETE, uri"$baseUrl/store/order/${orderId}")
3737
.contentType("application/json")
@@ -46,7 +46,7 @@ class StoreApi(baseUrl: String) {
4646
* Available security schemes:
4747
* api_key (apiKey)
4848
*/
49-
def getInventory(apiKeyHeader: String)(): Request[Either[ResponseException[String], Map[String, Int]]] =
49+
def getInventory(apiKeyHeader: String)(): sttp.client4.Request[Either[ResponseException[String], Map[String, Int]]] =
5050
basicRequest
5151
.method(Method.GET, uri"$baseUrl/store/inventory")
5252
.contentType("application/json")
@@ -63,7 +63,7 @@ class StoreApi(baseUrl: String) {
6363
*
6464
* @param orderId ID of pet that needs to be fetched
6565
*/
66-
def getOrderById(orderId: Long): Request[Either[ResponseException[String], Order]] =
66+
def getOrderById(orderId: Long): sttp.client4.Request[Either[ResponseException[String], Order]] =
6767
basicRequest
6868
.method(Method.GET, uri"$baseUrl/store/order/${orderId}")
6969
.contentType("application/json")
@@ -78,7 +78,7 @@ class StoreApi(baseUrl: String) {
7878
*
7979
* @param order order placed for purchasing the pet
8080
*/
81-
def placeOrder(order: Order): Request[Either[ResponseException[String], Order]] =
81+
def placeOrder(order: Order): sttp.client4.Request[Either[ResponseException[String], Order]] =
8282
basicRequest
8383
.method(Method.POST, uri"$baseUrl/store/order")
8484
.contentType("application/json")

0 commit comments

Comments
 (0)