[kotlin-spring] use spring resource for file handling (#2455)

* [kotlin-spring] use org.springframework.core.io.Resource for file handling

* run ./bin/kotlin-springboot-petstore-server.sh

* run ./bin/kotlin-springboot-petstore-server.sh after building the CLI

* use MultipartFile for file in form and the specified type otherwise

* remplace tab with space

* [kotlin-springboot] replace all instance of MultipartFile by Resource

* run ./bin/kotlin-springboot-petstore-server.sh
This commit is contained in:
sylvainmoindron 2019-03-27 14:44:24 +01:00 committed by William Cheng
parent 46e8ccbd1e
commit 74fbd3454b
12 changed files with 50 additions and 25 deletions

View File

@ -44,7 +44,7 @@ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen
LoggerFactory.getLogger(KotlinSpringServerCodegen.class); LoggerFactory.getLogger(KotlinSpringServerCodegen.class);
private static final HashSet<String> VARIABLE_RESERVED_WORDS = private static final HashSet<String> VARIABLE_RESERVED_WORDS =
new HashSet<String>(Arrays.asList( new HashSet<>(Arrays.asList(
"ApiClient", "ApiClient",
"ApiException", "ApiException",
"ApiResponse" "ApiResponse"
@ -109,6 +109,10 @@ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen
importMapping.put("Date", "java.time.LocalDate"); importMapping.put("Date", "java.time.LocalDate");
importMapping.put("DateTime", "java.time.OffsetDateTime"); importMapping.put("DateTime", "java.time.OffsetDateTime");
// use resource for file handling
typeMapping.put("file", "org.springframework.core.io.Resource");
languageSpecificPrimitives.addAll(Arrays.asList( languageSpecificPrimitives.addAll(Arrays.asList(
"Any", "Any",
"Byte", "Byte",
@ -562,4 +566,33 @@ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen
return m; return m;
} }
/**
* Output the proper model name (capitalized).
* In case the name belongs to the TypeSystem it won't be renamed.
*
* @param name the name of the model
* @return capitalized model name
*/
@Override
public String toModelName(final String name) {
// Allow for explicitly configured spring.*
if (name.startsWith("org.springframework.") ) {
return name;
}
return super.toModelName(name);
}
/**
* Check the type to see if it needs import the library/module/package
*
* @param type name of the type
* @return true if the library/module/package of the corresponding type needs to be imported
*/
@Override
protected boolean needToImport(String type) {
// provides extra protection against improperly trying to import language primitives and java types
boolean imports = !type.startsWith("org.springframework.") && super.needToImport(type);
return imports;
}
} }

View File

@ -20,7 +20,6 @@ import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.validation.annotation.Validated import org.springframework.validation.annotation.Validated
{{/useBeanValidation}} {{/useBeanValidation}}
import org.springframework.web.context.request.NativeWebRequest import org.springframework.web.context.request.NativeWebRequest
import org.springframework.web.multipart.MultipartFile
import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Autowired
{{#useBeanValidation}} {{#useBeanValidation}}

View File

@ -1 +1 @@
{{#isFormParam}}{{^isFile}}{{#swaggerAnnotations}}@ApiParam(value = "{{{description}}}"{{#required}}, required=true{{/required}}{{#allowableValues}}, allowableValues="{{#values}}{{{.}}}{{^-last}}, {{/-last}}{{#-last}}{{/-last}}{{/values}}"{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}){{/swaggerAnnotations}} @RequestParam(value="{{baseName}}"{{#required}}, required=true{{/required}}{{^required}}, required=false{{/required}}) {{paramName}}: {{>optionalDataType}} {{/isFile}}{{#isFile}}{{#swaggerAnnotations}}@ApiParam(value = "file detail"){{/swaggerAnnotations}} {{#useBeanValidation}}@Valid{{/useBeanValidation}} @RequestPart("file") {{baseName}}: MultipartFile{{/isFile}}{{/isFormParam}} {{#isFormParam}}{{^isFile}}{{#swaggerAnnotations}}@ApiParam(value = "{{{description}}}"{{#required}}, required=true{{/required}}{{#allowableValues}}, allowableValues="{{#values}}{{{.}}}{{^-last}}, {{/-last}}{{#-last}}{{/-last}}{{/values}}"{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}){{/swaggerAnnotations}} @RequestParam(value="{{baseName}}"{{#required}}, required=true{{/required}}{{^required}}, required=false{{/required}}) {{paramName}}: {{>optionalDataType}} {{/isFile}}{{#isFile}}{{#swaggerAnnotations}}@ApiParam(value = "file detail"){{/swaggerAnnotations}} {{#useBeanValidation}}@Valid{{/useBeanValidation}} @RequestPart("file") {{baseName}}: {{>optionalDataType}}{{/isFile}}{{/isFormParam}}

View File

@ -7,7 +7,7 @@ package {{package}}
interface {{classname}}Service { interface {{classname}}Service {
{{#operation}} {{#operation}}
fun {{operationId}}({{#allParams}}{{paramName}}: {{^isFile}}{{>optionalDataType}}{{/isFile}}{{#isFile}}org.springframework.web.multipart.MultipartFile{{/isFile}}{{#hasMore}},{{/hasMore}}{{/allParams}}): {{>returnTypes}} fun {{operationId}}({{#allParams}}{{paramName}}: {{{dataType}}}{{#hasMore}},{{/hasMore}}{{/allParams}}): {{>returnTypes}}
{{/operation}} {{/operation}}
} }
{{/operations}} {{/operations}}

View File

@ -3,13 +3,12 @@ package {{package}}
{{#imports}}import {{import}} {{#imports}}import {{import}}
{{/imports}} {{/imports}}
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
@Service @Service
{{#operations}} {{#operations}}
class {{classname}}ServiceImpl : {{classname}}Service { class {{classname}}ServiceImpl : {{classname}}Service {
{{#operation}} {{#operation}}
override fun {{operationId}}({{#allParams}}{{paramName}}: {{^isFile}}{{>optionalDataType}}{{/isFile}}{{#isFile}}org.springframework.web.multipart.MultipartFile{{/isFile}}{{#hasMore}},{{/hasMore}}{{/allParams}}): {{>returnTypes}} { override fun {{operationId}}({{#allParams}}{{paramName}}: {{{dataType}}}{{#hasMore}},{{/hasMore}}{{/allParams}}): {{>returnTypes}} {
TODO("Implement me") TODO("Implement me")
} }
{{/operation}} {{/operation}}

View File

@ -16,7 +16,6 @@ import org.springframework.web.bind.annotation.RequestMethod
import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.validation.annotation.Validated import org.springframework.validation.annotation.Validated
import org.springframework.web.context.request.NativeWebRequest import org.springframework.web.context.request.NativeWebRequest
import org.springframework.web.multipart.MultipartFile
import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Autowired
import javax.validation.Valid import javax.validation.Valid
@ -71,7 +70,7 @@ class PetApiController(@Autowired(required = true) val service: PetApiService) {
value = [ApiResponse(code = 200, message = "successful operation", response = Pet::class, responseContainer = "List"),ApiResponse(code = 400, message = "Invalid status value")]) value = [ApiResponse(code = 200, message = "successful operation", response = Pet::class, responseContainer = "List"),ApiResponse(code = 400, message = "Invalid status value")])
@RequestMapping( @RequestMapping(
value = ["/pet/findByStatus"], value = ["/pet/findByStatus"],
produces = ["application/xml", "application/json"], produces = ["application/xml", "application/json"],
method = [RequestMethod.GET]) method = [RequestMethod.GET])
fun findPetsByStatus(@NotNull @ApiParam(value = "Status values that need to be considered for filter", required = true, allowableValues = "available, pending, sold") @Valid @RequestParam(value = "status", required = true) status: List<String>): ResponseEntity<List<Pet>> { fun findPetsByStatus(@NotNull @ApiParam(value = "Status values that need to be considered for filter", required = true, allowableValues = "available, pending, sold") @Valid @RequestParam(value = "status", required = true) status: List<String>): ResponseEntity<List<Pet>> {
return ResponseEntity(service.findPetsByStatus(status), HttpStatus.OK) return ResponseEntity(service.findPetsByStatus(status), HttpStatus.OK)
@ -88,7 +87,7 @@ class PetApiController(@Autowired(required = true) val service: PetApiService) {
value = [ApiResponse(code = 200, message = "successful operation", response = Pet::class, responseContainer = "List"),ApiResponse(code = 400, message = "Invalid tag value")]) value = [ApiResponse(code = 200, message = "successful operation", response = Pet::class, responseContainer = "List"),ApiResponse(code = 400, message = "Invalid tag value")])
@RequestMapping( @RequestMapping(
value = ["/pet/findByTags"], value = ["/pet/findByTags"],
produces = ["application/xml", "application/json"], produces = ["application/xml", "application/json"],
method = [RequestMethod.GET]) method = [RequestMethod.GET])
fun findPetsByTags(@NotNull @ApiParam(value = "Tags to filter by", required = true) @Valid @RequestParam(value = "tags", required = true) tags: List<String>): ResponseEntity<List<Pet>> { fun findPetsByTags(@NotNull @ApiParam(value = "Tags to filter by", required = true) @Valid @RequestParam(value = "tags", required = true) tags: List<String>): ResponseEntity<List<Pet>> {
return ResponseEntity(service.findPetsByTags(tags), HttpStatus.OK) return ResponseEntity(service.findPetsByTags(tags), HttpStatus.OK)
@ -104,7 +103,7 @@ class PetApiController(@Autowired(required = true) val service: PetApiService) {
value = [ApiResponse(code = 200, message = "successful operation", response = Pet::class),ApiResponse(code = 400, message = "Invalid ID supplied"),ApiResponse(code = 404, message = "Pet not found")]) value = [ApiResponse(code = 200, message = "successful operation", response = Pet::class),ApiResponse(code = 400, message = "Invalid ID supplied"),ApiResponse(code = 404, message = "Pet not found")])
@RequestMapping( @RequestMapping(
value = ["/pet/{petId}"], value = ["/pet/{petId}"],
produces = ["application/xml", "application/json"], produces = ["application/xml", "application/json"],
method = [RequestMethod.GET]) method = [RequestMethod.GET])
fun getPetById(@ApiParam(value = "ID of pet to return", required=true) @PathVariable("petId") petId: Long): ResponseEntity<Pet> { fun getPetById(@ApiParam(value = "ID of pet to return", required=true) @PathVariable("petId") petId: Long): ResponseEntity<Pet> {
return ResponseEntity(service.getPetById(petId), HttpStatus.OK) return ResponseEntity(service.getPetById(petId), HttpStatus.OK)
@ -136,7 +135,7 @@ class PetApiController(@Autowired(required = true) val service: PetApiService) {
value = ["/pet/{petId}"], value = ["/pet/{petId}"],
consumes = ["application/x-www-form-urlencoded"], consumes = ["application/x-www-form-urlencoded"],
method = [RequestMethod.POST]) method = [RequestMethod.POST])
fun updatePetWithForm(@ApiParam(value = "ID of pet that needs to be updated", required=true) @PathVariable("petId") petId: Long,@ApiParam(value = "Updated name of the pet") @RequestParam(value="name", required=false) name: String? ,@ApiParam(value = "Updated status of the pet") @RequestParam(value="status", required=false) status: String? ): ResponseEntity<Unit> { fun updatePetWithForm(@ApiParam(value = "ID of pet that needs to be updated", required=true, defaultValue="null") @PathVariable("petId") petId: Long,@ApiParam(value = "Updated name of the pet", defaultValue="null") @RequestParam(value="name", required=false) name: String,@ApiParam(value = "Updated status of the pet", defaultValue="null") @RequestParam(value="status", required=false) status: String): ResponseEntity<Unit> {
return ResponseEntity(service.updatePetWithForm(petId, name, status), HttpStatus.OK) return ResponseEntity(service.updatePetWithForm(petId, name, status), HttpStatus.OK)
} }
@ -150,10 +149,10 @@ class PetApiController(@Autowired(required = true) val service: PetApiService) {
value = [ApiResponse(code = 200, message = "successful operation", response = ModelApiResponse::class)]) value = [ApiResponse(code = 200, message = "successful operation", response = ModelApiResponse::class)])
@RequestMapping( @RequestMapping(
value = ["/pet/{petId}/uploadImage"], value = ["/pet/{petId}/uploadImage"],
produces = ["application/json"], produces = ["application/json"],
consumes = ["multipart/form-data"], consumes = ["multipart/form-data"],
method = [RequestMethod.POST]) method = [RequestMethod.POST])
fun uploadFile(@ApiParam(value = "ID of pet to update", required=true) @PathVariable("petId") petId: Long,@ApiParam(value = "Additional data to pass to server") @RequestParam(value="additionalMetadata", required=false) additionalMetadata: String? ,@ApiParam(value = "file detail") @Valid @RequestPart("file") file: MultipartFile): ResponseEntity<ModelApiResponse> { fun uploadFile(@ApiParam(value = "ID of pet to update", required=true, defaultValue="null") @PathVariable("petId") petId: Long,@ApiParam(value = "Additional data to pass to server", defaultValue="null") @RequestParam(value="additionalMetadata", required=false) additionalMetadata: String,@ApiParam(value = "file detail") @Valid @RequestPart("file") file: org.springframework.core.io.Resource): ResponseEntity<ModelApiResponse> {
return ResponseEntity(service.uploadFile(petId, additionalMetadata, file), HttpStatus.OK) return ResponseEntity(service.uploadFile(petId, additionalMetadata, file), HttpStatus.OK)
} }
} }

View File

@ -19,5 +19,5 @@ interface PetApiService {
fun updatePetWithForm(petId: Long,name: String?,status: String?): Unit fun updatePetWithForm(petId: Long,name: String?,status: String?): Unit
fun uploadFile(petId: Long,additionalMetadata: String?,file: org.springframework.web.multipart.MultipartFile): ModelApiResponse fun uploadFile(petId: Long,additionalMetadata: String,file: org.springframework.core.io.Resource): ModelApiResponse
} }

View File

@ -3,7 +3,6 @@ package org.openapitools.api
import org.openapitools.model.ModelApiResponse import org.openapitools.model.ModelApiResponse
import org.openapitools.model.Pet import org.openapitools.model.Pet
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
@Service @Service
class PetApiServiceImpl : PetApiService { class PetApiServiceImpl : PetApiService {
@ -35,7 +34,7 @@ class PetApiServiceImpl : PetApiService {
TODO("Implement me") TODO("Implement me")
} }
override fun uploadFile(petId: Long,additionalMetadata: String?,file: org.springframework.web.multipart.MultipartFile): ModelApiResponse { override fun uploadFile(petId: Long,additionalMetadata: String,file: org.springframework.core.io.Resource): ModelApiResponse {
TODO("Implement me") TODO("Implement me")
} }
} }

View File

@ -15,7 +15,6 @@ import org.springframework.web.bind.annotation.RequestMethod
import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.validation.annotation.Validated import org.springframework.validation.annotation.Validated
import org.springframework.web.context.request.NativeWebRequest import org.springframework.web.context.request.NativeWebRequest
import org.springframework.web.multipart.MultipartFile
import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Autowired
import javax.validation.Valid import javax.validation.Valid
@ -54,7 +53,7 @@ class StoreApiController(@Autowired(required = true) val service: StoreApiServic
value = [ApiResponse(code = 200, message = "successful operation", response = Map::class, responseContainer = "Map")]) value = [ApiResponse(code = 200, message = "successful operation", response = Map::class, responseContainer = "Map")])
@RequestMapping( @RequestMapping(
value = ["/store/inventory"], value = ["/store/inventory"],
produces = ["application/json"], produces = ["application/json"],
method = [RequestMethod.GET]) method = [RequestMethod.GET])
fun getInventory(): ResponseEntity<Map<String, Int>> { fun getInventory(): ResponseEntity<Map<String, Int>> {
return ResponseEntity(service.getInventory(), HttpStatus.OK) return ResponseEntity(service.getInventory(), HttpStatus.OK)
@ -69,7 +68,7 @@ class StoreApiController(@Autowired(required = true) val service: StoreApiServic
value = [ApiResponse(code = 200, message = "successful operation", response = Order::class),ApiResponse(code = 400, message = "Invalid ID supplied"),ApiResponse(code = 404, message = "Order not found")]) value = [ApiResponse(code = 200, message = "successful operation", response = Order::class),ApiResponse(code = 400, message = "Invalid ID supplied"),ApiResponse(code = 404, message = "Order not found")])
@RequestMapping( @RequestMapping(
value = ["/store/order/{orderId}"], value = ["/store/order/{orderId}"],
produces = ["application/xml", "application/json"], produces = ["application/xml", "application/json"],
method = [RequestMethod.GET]) method = [RequestMethod.GET])
fun getOrderById(@Min(1L) @Max(5L) @ApiParam(value = "ID of pet that needs to be fetched", required=true) @PathVariable("orderId") orderId: Long): ResponseEntity<Order> { fun getOrderById(@Min(1L) @Max(5L) @ApiParam(value = "ID of pet that needs to be fetched", required=true) @PathVariable("orderId") orderId: Long): ResponseEntity<Order> {
return ResponseEntity(service.getOrderById(orderId), HttpStatus.OK) return ResponseEntity(service.getOrderById(orderId), HttpStatus.OK)
@ -84,7 +83,7 @@ class StoreApiController(@Autowired(required = true) val service: StoreApiServic
value = [ApiResponse(code = 200, message = "successful operation", response = Order::class),ApiResponse(code = 400, message = "Invalid Order")]) value = [ApiResponse(code = 200, message = "successful operation", response = Order::class),ApiResponse(code = 400, message = "Invalid Order")])
@RequestMapping( @RequestMapping(
value = ["/store/order"], value = ["/store/order"],
produces = ["application/xml", "application/json"], produces = ["application/xml", "application/json"],
method = [RequestMethod.POST]) method = [RequestMethod.POST])
fun placeOrder(@ApiParam(value = "order placed for purchasing the pet" ,required=true ) @Valid @RequestBody body: Order): ResponseEntity<Order> { fun placeOrder(@ApiParam(value = "order placed for purchasing the pet" ,required=true ) @Valid @RequestBody body: Order): ResponseEntity<Order> {
return ResponseEntity(service.placeOrder(body), HttpStatus.OK) return ResponseEntity(service.placeOrder(body), HttpStatus.OK)

View File

@ -2,7 +2,6 @@ package org.openapitools.api
import org.openapitools.model.Order import org.openapitools.model.Order
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
@Service @Service
class StoreApiServiceImpl : StoreApiService { class StoreApiServiceImpl : StoreApiService {

View File

@ -15,7 +15,6 @@ import org.springframework.web.bind.annotation.RequestMethod
import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.validation.annotation.Validated import org.springframework.validation.annotation.Validated
import org.springframework.web.context.request.NativeWebRequest import org.springframework.web.context.request.NativeWebRequest
import org.springframework.web.multipart.MultipartFile
import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Autowired
import javax.validation.Valid import javax.validation.Valid
@ -91,7 +90,7 @@ class UserApiController(@Autowired(required = true) val service: UserApiService)
value = [ApiResponse(code = 200, message = "successful operation", response = User::class),ApiResponse(code = 400, message = "Invalid username supplied"),ApiResponse(code = 404, message = "User not found")]) value = [ApiResponse(code = 200, message = "successful operation", response = User::class),ApiResponse(code = 400, message = "Invalid username supplied"),ApiResponse(code = 404, message = "User not found")])
@RequestMapping( @RequestMapping(
value = ["/user/{username}"], value = ["/user/{username}"],
produces = ["application/xml", "application/json"], produces = ["application/xml", "application/json"],
method = [RequestMethod.GET]) method = [RequestMethod.GET])
fun getUserByName(@ApiParam(value = "The name that needs to be fetched. Use user1 for testing.", required=true) @PathVariable("username") username: String): ResponseEntity<User> { fun getUserByName(@ApiParam(value = "The name that needs to be fetched. Use user1 for testing.", required=true) @PathVariable("username") username: String): ResponseEntity<User> {
return ResponseEntity(service.getUserByName(username), HttpStatus.OK) return ResponseEntity(service.getUserByName(username), HttpStatus.OK)
@ -106,7 +105,7 @@ class UserApiController(@Autowired(required = true) val service: UserApiService)
value = [ApiResponse(code = 200, message = "successful operation", response = String::class),ApiResponse(code = 400, message = "Invalid username/password supplied")]) value = [ApiResponse(code = 200, message = "successful operation", response = String::class),ApiResponse(code = 400, message = "Invalid username/password supplied")])
@RequestMapping( @RequestMapping(
value = ["/user/login"], value = ["/user/login"],
produces = ["application/xml", "application/json"], produces = ["application/xml", "application/json"],
method = [RequestMethod.GET]) method = [RequestMethod.GET])
fun loginUser(@NotNull @ApiParam(value = "The user name for login", required = true) @Valid @RequestParam(value = "username", required = true) username: String,@NotNull @ApiParam(value = "The password for login in clear text", required = true) @Valid @RequestParam(value = "password", required = true) password: String): ResponseEntity<String> { fun loginUser(@NotNull @ApiParam(value = "The user name for login", required = true) @Valid @RequestParam(value = "username", required = true) username: String,@NotNull @ApiParam(value = "The password for login in clear text", required = true) @Valid @RequestParam(value = "password", required = true) password: String): ResponseEntity<String> {
return ResponseEntity(service.loginUser(username, password), HttpStatus.OK) return ResponseEntity(service.loginUser(username, password), HttpStatus.OK)

View File

@ -2,7 +2,6 @@ package org.openapitools.api
import org.openapitools.model.User import org.openapitools.model.User
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
@Service @Service
class UserApiServiceImpl : UserApiService { class UserApiServiceImpl : UserApiService {