com.ancientlightstudios.quarkus.kotlin.openapi.emitter.TestClientRequestBuilderEmitter.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of quarkus-kotlin-openapi-maven-plugin Show documentation
Show all versions of quarkus-kotlin-openapi-maven-plugin Show documentation
A Maven plugin to use the OpenAPI generator.
package com.ancientlightstudios.quarkus.kotlin.openapi.emitter
import com.ancientlightstudios.quarkus.kotlin.openapi.emitter.serialization.SerializationStatementEmitter
import com.ancientlightstudios.quarkus.kotlin.openapi.emitter.serialization.UnsafeSerializationStatementEmitter
import com.ancientlightstudios.quarkus.kotlin.openapi.inspection.RequestInspection
import com.ancientlightstudios.quarkus.kotlin.openapi.inspection.inspect
import com.ancientlightstudios.quarkus.kotlin.openapi.models.hints.ParameterVariableNameHint.parameterVariableName
import com.ancientlightstudios.quarkus.kotlin.openapi.models.hints.RequestBuilderClassNameHint.requestBuilderClassName
import com.ancientlightstudios.quarkus.kotlin.openapi.models.hints.TypeUsageHint.typeUsage
import com.ancientlightstudios.quarkus.kotlin.openapi.models.kotlin.*
import com.ancientlightstudios.quarkus.kotlin.openapi.models.kotlin.InvocationExpression.Companion.invoke
import com.ancientlightstudios.quarkus.kotlin.openapi.models.kotlin.MethodName.Companion.methodName
import com.ancientlightstudios.quarkus.kotlin.openapi.models.kotlin.MethodName.Companion.rawMethodName
import com.ancientlightstudios.quarkus.kotlin.openapi.models.kotlin.NullCheckExpression.Companion.nullCheck
import com.ancientlightstudios.quarkus.kotlin.openapi.models.kotlin.PropertyExpression.Companion.property
import com.ancientlightstudios.quarkus.kotlin.openapi.models.kotlin.TypeName.GenericTypeName.Companion.of
import com.ancientlightstudios.quarkus.kotlin.openapi.models.kotlin.TypeName.SimpleTypeName.Companion.typeName
import com.ancientlightstudios.quarkus.kotlin.openapi.models.kotlin.VariableName.Companion.variableName
import com.ancientlightstudios.quarkus.kotlin.openapi.models.transformable.ContentType
import com.ancientlightstudios.quarkus.kotlin.openapi.models.transformable.ParameterKind
import com.ancientlightstudios.quarkus.kotlin.openapi.models.transformable.TransformableBody
import com.ancientlightstudios.quarkus.kotlin.openapi.models.types.ObjectTypeDefinition
import com.ancientlightstudios.quarkus.kotlin.openapi.models.types.OneOfTypeDefinition
import com.ancientlightstudios.quarkus.kotlin.openapi.refactoring.AssignContentTypesRefactoring.Companion.getContentTypeForFormPart
import com.ancientlightstudios.quarkus.kotlin.openapi.utils.ProbableBug
class TestClientRequestBuilderEmitter : CodeEmitter {
private lateinit var emitterContext: EmitterContext
override fun EmitterContext.emit() {
emitterContext = this
spec.inspect {
bundles {
requests {
emitRequestBuilderFile()
.writeFile()
}
}
}
}
private fun RequestInspection.emitRequestBuilderFile() = kotlinFile(request.requestBuilderClassName) {
val requestSpecificationVariable = "requestSpecification".variableName()
kotlinClass(fileName) {
registerImports(Library.AllClasses)
registerImports(emitterContext.getAdditionalImports())
kotlinMember(
requestSpecificationVariable,
type = RestAssured.RequestSpecificationClass.typeName(),
mutable = true,
accessModifier = null
)
kotlinMember(
"objectMapper".variableName(),
type = Misc.ObjectMapperClass.typeName()
)
parameters {
if (parameter.kind != ParameterKind.Path) {
kotlinMethod(parameter.name.methodName()) {
kotlinParameter("value".variableName(), parameter.content.typeUsage.buildValidType())
val methodName = when (parameter.kind) {
ParameterKind.Query -> "queryParams"
ParameterKind.Header -> "headers"
ParameterKind.Cookie -> "cookies"
ParameterKind.Path -> "lazyVogel" // filtered out above
}.methodName()
val parameterStatement = emitterContext.runEmitter(
SerializationStatementEmitter(
parameter.content.typeUsage,
"value".variableName(),
parameter.content.mappedContentType
)
).resultStatement
val builder: (StatementAware.() -> Unit) = {
val argument = invoke(
"mapOf".methodName(),
invoke(
Kotlin.PairClass.constructorName,
parameter.name.literal(),
parameterStatement
)
)
requestSpecificationVariable.invoke(methodName, argument)
.assignment(requestSpecificationVariable)
}
if (parameter.content.typeUsage.isNullable()) {
"value".variableName().nullCheck().invoke("let".methodName()) {
builder()
}.statement()
} else {
builder()
}
}
}
}
body {
body.emitBodyMethods(this@kotlinClass, requestSpecificationVariable)
}
}
}
private fun TransformableBody.emitBodyMethods(clazz: KotlinClass, requestSpecificationVariable: VariableName) {
when (content.mappedContentType) {
ContentType.ApplicationJson -> emitJsonBodyMethod(clazz, requestSpecificationVariable)
ContentType.TextPlain -> emitPlainBodyMethod(clazz, requestSpecificationVariable)
ContentType.ApplicationFormUrlencoded -> emitFormBodyMethod(clazz, requestSpecificationVariable)
ContentType.ApplicationOctetStream -> emitOctetStreamBodyMethod(clazz, requestSpecificationVariable)
ContentType.MultipartFormData -> ProbableBug("Multipart-Form not yet supported for test client")
}
}
private fun TransformableBody.emitJsonBodyMethod(clazz: KotlinClass, requestSpecificationVariable: VariableName) {
clazz.kotlinMethod("body".methodName()) {
kotlinParameter("value".variableName(), content.typeUsage.buildValidType())
val bodyStatement = emitterContext.runEmitter(
SerializationStatementEmitter(content.typeUsage, "value".variableName(), content.mappedContentType)
).resultStatement
requestSpecificationVariable
.invoke("contentType".methodName(), content.rawContentType.literal())
.invoke(
"body".methodName(),
bodyStatement.invoke("asString".methodName(), "objectMapper".variableName())
)
.assignment(requestSpecificationVariable)
}
if (content.typeUsage.type is ObjectTypeDefinition || content.typeUsage.type is OneOfTypeDefinition) {
clazz.kotlinMethod("body".methodName()) {
kotlinParameter("value".variableName(), content.typeUsage.buildUnsafeJsonType())
val bodyStatement = emitterContext.runEmitter(
UnsafeSerializationStatementEmitter(content.typeUsage, "value".variableName(), content.mappedContentType)
).resultStatement
requestSpecificationVariable
.invoke("contentType".methodName(), content.rawContentType.literal())
.invoke(
"body".methodName(),
bodyStatement.invoke("asString".methodName(), "objectMapper".variableName())
)
.assignment(requestSpecificationVariable)
}
}
}
private fun TransformableBody.emitPlainBodyMethod(clazz: KotlinClass, requestSpecificationVariable: VariableName) {
clazz.kotlinMethod("body".methodName()) {
kotlinParameter("value".variableName(), content.typeUsage.buildValidType())
val bodyStatement = emitterContext.runEmitter(
SerializationStatementEmitter(content.typeUsage, "value".variableName(), content.mappedContentType)
).resultStatement
requestSpecificationVariable
.invoke("contentType".methodName(), content.rawContentType.literal())
.invoke("body".methodName(), bodyStatement)
.assignment(requestSpecificationVariable)
}
}
private fun TransformableBody.emitFormBodyMethod(clazz: KotlinClass, requestSpecificationVariable: VariableName) {
clazz.kotlinMethod("body".methodName()) {
val typeUsage = content.typeUsage
kotlinParameter("value".variableName(), typeUsage.buildValidType())
var statement = requestSpecificationVariable
.invoke("contentType".methodName(), content.rawContentType.literal())
val safeType = typeUsage.type
if (safeType is ObjectTypeDefinition) {
val baseStatement = if (typeUsage.isNullable()) {
"value".variableName().nullCheck()
} else {
"value".variableName()
}
// TODO: in case of json we probably want the writeValueAsString method to convert the payload
// see jsonBody. same for restClient
safeType.properties.forEach {
val propertyType = it.typeUsage
val contentType = getContentTypeForFormPart(propertyType.type)
val propertyStatement =
emitterContext.runEmitter(
SerializationStatementEmitter(propertyType, baseStatement.property(it.name), contentType)
).resultStatement
statement =
statement.wrap().invoke("formParam".methodName(), it.sourceName.literal(), propertyStatement)
}
} else {
val serializeStatement = emitterContext.runEmitter(
SerializationStatementEmitter(typeUsage, "value".variableName(), content.mappedContentType)
).resultStatement
statement = statement.invoke("formParam".methodName(), parameterVariableName, serializeStatement)
}
statement.assignment(requestSpecificationVariable)
}
}
private fun TransformableBody.emitOctetStreamBodyMethod(clazz: KotlinClass, requestSpecificationVariable: VariableName) {
clazz.kotlinMethod("body".methodName()) {
val typeUsage = content.typeUsage
kotlinParameter("value".variableName(), Kotlin.ByteArrayClass.typeName(typeUsage.isNullable()))
var statement = requestSpecificationVariable
.invoke("contentType".methodName(), content.rawContentType.literal())
.invoke("body".methodName(), "value".variableName())
.assignment(requestSpecificationVariable)
}
}
}