diff --git a/src/main/kotlin/com/cjbooms/fabrikt/model/KotlinTypeInfo.kt b/src/main/kotlin/com/cjbooms/fabrikt/model/KotlinTypeInfo.kt index 72279514..965f6423 100644 --- a/src/main/kotlin/com/cjbooms/fabrikt/model/KotlinTypeInfo.kt +++ b/src/main/kotlin/com/cjbooms/fabrikt/model/KotlinTypeInfo.kt @@ -66,7 +66,8 @@ sealed class KotlinTypeInfo(val modelKClass: KClass<*>, val generatedModelClassN Enum(schema.getEnumValues(), schema.toModelClassName(enclosingName.toModelClassName())) OasType.Uuid -> Uuid OasType.Uri -> Uri - OasType.ByteArray -> ByteArray + OasType.Base64String -> ByteArray + OasType.Binary -> ByteArray OasType.Double -> Double OasType.Float -> Float OasType.Number -> Numeric diff --git a/src/main/kotlin/com/cjbooms/fabrikt/model/OasType.kt b/src/main/kotlin/com/cjbooms/fabrikt/model/OasType.kt index af27bb95..fdb35074 100644 --- a/src/main/kotlin/com/cjbooms/fabrikt/model/OasType.kt +++ b/src/main/kotlin/com/cjbooms/fabrikt/model/OasType.kt @@ -37,7 +37,8 @@ sealed class OasType( object Enum : OasType("string", specialization = Specialization.ENUM) object Uuid : OasType("string", specialization = Specialization.UUID) object Uri : OasType("string", specialization = Specialization.URI) - object ByteArray : OasType("string", specialization = Specialization.BYTE) + object Base64String : OasType("string", specialization = Specialization.BYTE) + object Binary : OasType("string", specialization = Specialization.BINARY) object Map : OasType("object", specialization = Specialization.MAP) object UnknownAdditionalProperties : OasType("object", specialization = Specialization.UNKNOWN_ADDITIONAL_PROPERTIES) @@ -77,6 +78,7 @@ sealed class OasType( isStringDefinitionWithFormat("uuid") -> Specialization.UUID isStringDefinitionWithFormat("uri") -> Specialization.URI isStringDefinitionWithFormat("byte") -> Specialization.BYTE + isStringDefinitionWithFormat("binary") -> Specialization.BINARY isEnumDefinition() -> Specialization.ENUM isMapTypeAdditionalProperties(oasKey) -> Specialization.TYPED_MAP_ADDITIONAL_PROPERTIES isSimpleMapDefinition() -> Specialization.MAP @@ -101,6 +103,7 @@ sealed class OasType( URI, NONE, ONE_OF_ANY, - BYTE + BYTE, + BINARY } } diff --git a/src/main/kotlin/com/cjbooms/fabrikt/util/KaizenParserExtensions.kt b/src/main/kotlin/com/cjbooms/fabrikt/util/KaizenParserExtensions.kt index 798ad2e6..ca97c3be 100644 --- a/src/main/kotlin/com/cjbooms/fabrikt/util/KaizenParserExtensions.kt +++ b/src/main/kotlin/com/cjbooms/fabrikt/util/KaizenParserExtensions.kt @@ -199,6 +199,7 @@ object KaizenParserExtensions { .filterNot { invalidNames.contains(it) } .filter { it.toIntOrNull() == null } // Ignore numeric-identifiers path-parts in: allOf / oneOf / anyOf .last() + .replace("~1", "-") // so application~1octet-stream becomes application-octet-stream } fun Schema.safeType(): String? = diff --git a/src/test/kotlin/com/cjbooms/fabrikt/generators/MicronautControllerGeneratorTest.kt b/src/test/kotlin/com/cjbooms/fabrikt/generators/MicronautControllerGeneratorTest.kt index 07d5581e..9e7b2908 100644 --- a/src/test/kotlin/com/cjbooms/fabrikt/generators/MicronautControllerGeneratorTest.kt +++ b/src/test/kotlin/com/cjbooms/fabrikt/generators/MicronautControllerGeneratorTest.kt @@ -212,4 +212,13 @@ class MicronautControllerGeneratorTest { } return Linter.lintString(singleFileBuilder.build().toString()) } + + @Test + fun `ensure generates ByteArray body parameter and response for string with format binary`() { + val api = SourceApi(readTextResource("/examples/binary/api.yaml")) + val controllers = MicronautControllerInterfaceGenerator(Packages(basePackage), api, JavaxValidationAnnotations).generate().toSingleFile() + val expectedControllers = readTextResource("/examples/binary/controllers/micronaut/Controllers.kt") + + assertThat(controllers.trim()).isEqualTo(expectedControllers.trim()) + } } diff --git a/src/test/kotlin/com/cjbooms/fabrikt/generators/SpringControllerGeneratorTest.kt b/src/test/kotlin/com/cjbooms/fabrikt/generators/SpringControllerGeneratorTest.kt index 6a4343d8..aa1b92ff 100644 --- a/src/test/kotlin/com/cjbooms/fabrikt/generators/SpringControllerGeneratorTest.kt +++ b/src/test/kotlin/com/cjbooms/fabrikt/generators/SpringControllerGeneratorTest.kt @@ -224,4 +224,13 @@ class SpringControllerGeneratorTest { assertThat(controllers.trim()).isEqualTo(expectedControllers.trim()) } + + @Test + fun `ensure generates ByteArray body parameter and response for string with format binary`() { + val api = SourceApi(readTextResource("/examples/binary/api.yaml")) + val controllers = SpringControllerInterfaceGenerator(Packages(basePackage), api, JavaxValidationAnnotations).generate().toSingleFile() + val expectedControllers = readTextResource("/examples/binary/controllers/spring/Controllers.kt") + + assertThat(controllers.trim()).isEqualTo(expectedControllers.trim()) + } } diff --git a/src/test/resources/examples/binary/api.yaml b/src/test/resources/examples/binary/api.yaml new file mode 100644 index 00000000..359d26bf --- /dev/null +++ b/src/test/resources/examples/binary/api.yaml @@ -0,0 +1,24 @@ +openapi: 3.0.1 +info: + description: Testing binary body and binary response + title: Test + version: '0.0' +paths: + /binary-data: + post: + operationId: postBinaryData + requestBody: + required: true + content: + application/octet-stream: + schema: + type: string + format: binary + responses: + 200: + description: Success + content: + application/octet-stream: + schema: + type: string + format: binary diff --git a/src/test/resources/examples/binary/controllers/micronaut/Controllers.kt b/src/test/resources/examples/binary/controllers/micronaut/Controllers.kt new file mode 100644 index 00000000..698f7e0c --- /dev/null +++ b/src/test/resources/examples/binary/controllers/micronaut/Controllers.kt @@ -0,0 +1,26 @@ +package ie.zalando.controllers + +import io.micronaut.http.HttpResponse +import io.micronaut.http.annotation.Body +import io.micronaut.http.annotation.Consumes +import io.micronaut.http.annotation.Controller +import io.micronaut.http.annotation.Post +import io.micronaut.http.annotation.Produces +import javax.validation.Valid +import kotlin.ByteArray + +@Controller +interface BinaryDataController { + /** + * + * + * @param applicationOctetStream + */ + @Post(uri = "/binary-data") + @Consumes(value = ["application/octet-stream"]) + @Produces(value = ["application/octet-stream"]) + fun postBinaryData( + @Body @Valid + applicationOctetStream: ByteArray + ): HttpResponse +} diff --git a/src/test/resources/examples/binary/controllers/spring/Controllers.kt b/src/test/resources/examples/binary/controllers/spring/Controllers.kt new file mode 100644 index 00000000..fa5d2580 --- /dev/null +++ b/src/test/resources/examples/binary/controllers/spring/Controllers.kt @@ -0,0 +1,32 @@ +package ie.zalando.controllers + +import org.springframework.http.ResponseEntity +import org.springframework.stereotype.Controller +import org.springframework.validation.annotation.Validated +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestMethod +import javax.validation.Valid +import kotlin.ByteArray + +@Controller +@Validated +@RequestMapping("") +interface BinaryDataController { + /** + * + * + * @param applicationOctetStream + */ + @RequestMapping( + value = ["/binary-data"], + produces = ["application/octet-stream"], + method = [RequestMethod.POST], + consumes = ["application/octet-stream"] + ) + fun postBinaryData( + @RequestBody @Valid + applicationOctetStream: ByteArray + ): + ResponseEntity +}