Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changes/fc4060e3-a826-46dd-a1f7-8fb041c77fd2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"id": "fc4060e3-a826-46dd-a1f7-8fb041c77fd2",
"type": "feature",
"description": "Add support for smithy Document type.",
"issues": [
"awslabs/smithy-kotlin#123"
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,11 @@ interface PrimitiveSerializer {
* Serializes the given value.
*/
fun serializeNull()

/**
* Serializes the given value.
*/
fun serializeDocument(value: Document?)
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ private class FormUrlSerializer(
override fun serializeNull() {
throw SerializationException("null values not supported by form-url serializer")
}

override fun serializeDocument(value: Document?) {
throw SerializationException("document values not supported by form-url serializer")
}
}

private class FormUrlStructSerializer(
Expand Down Expand Up @@ -212,6 +216,9 @@ private class FormUrlListSerializer(
}

override fun serializeNull() {}
override fun serializeDocument(value: Document?) {
throw SerializationException("document values not supported by form-url serializer")
}
}

private class FormUrlMapSerializer(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ class JsonSerializer : Serializer, ListSerializer, MapSerializer, StructSerializ
}
}

fun serializeDocument(value: Document?) {
override fun serializeDocument(value: Document?) {
when (value) {
is Document.Number -> jsonWriter.writeValue(value.value)
is Document.String -> jsonWriter.writeValue(value.value)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,10 @@ class XmlSerializer(private val xmlWriter: XmlStreamWriter = xmlStreamWriter())
// NOP
}

override fun serializeDocument(value: Document?) {
throw SerializationException("document values not supported by xml serializer")
}

override fun serializeBoolean(value: Boolean) { xmlWriter.text(value.toString()) }

override fun serializeByte(value: Byte) = serializeNumber(value)
Expand Down Expand Up @@ -286,6 +290,10 @@ private class XmlMapSerializer(
xmlWriter.writeTag(tagName, ns)
}

override fun serializeDocument(value: Document?) {
throw SerializationException("document values not supported by xml serializer")
}

private fun serializePrimitive(value: Any) {
val tagName = descriptor.findTrait<XmlMapName>()?.value ?: XmlMapName.Default.value
val ns = descriptor.findTrait<XmlCollectionValueNamespace>()
Expand Down Expand Up @@ -344,6 +352,10 @@ private class XmlListSerializer(
xmlWriter.writeTag(memberTagName, ns)
}

override fun serializeDocument(value: Document?) {
throw SerializationException("document values not supported by xml serializer")
}

override fun serializeInstant(value: Instant, format: TimestampFormat) = serializeString(value.format(format))

private fun serializePrimitive(value: Any) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,21 @@ fun <T : CodeWriter> T.withBlock(
block: T.() -> Unit
): T = wrapBlockIf(true, textBeforeNewLine, textAfterNewLine, *args) { block(this) }

/**
* Like [withBlock], except the closing write of [textAfterNewLine] does NOT include a line break.
*/
fun <T : CodeWriter> T.withInlineBlock(
textBeforeNewLine: String,
textAfterNewLine: String,
vararg args: Any,
block: T.() -> Unit
): T {
openBlock(textBeforeNewLine, *args)
block(this)
closeInlineBlock(textAfterNewLine)
return this
}

/**
* Extension function that is more idiomatic Kotlin that is roughly the same purpose as an if block wrapped around
* the provided function `openBlock(String textBeforeNewline, String textAfterNewline, Runnable r)`
Expand Down Expand Up @@ -64,6 +79,16 @@ fun <T : CodeWriter> T.wrapBlockIf(
return this
}

/**
* Like [CodeWriter.closeBlock], except the closing write of [textAfterNewLine] does NOT include a line break.
*/
fun <T : CodeWriter> T.closeInlineBlock(textAfterNewLine: String): T {
writeInline("\n")
dedent()
writeInline(textAfterNewLine)
return this
}

/**
* Extension function that closes the previous block, dedents, opens a new block with [textBeforeNewLine], and indents.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,11 @@ object RuntimeTypes {
val SuccessAcceptor = runtimeSymbol("SuccessAcceptor", KotlinDependency.CORE, "retries.policy")
}
}

object Smithy {
val Document = runtimeSymbol("Document", KotlinDependency.CORE, "smithy")
val buildDocument = runtimeSymbol("buildDocument", KotlinDependency.CORE, "smithy")
}
}

object Hashing {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,12 @@ class ShapeValueGenerator(
) : NodeVisitor<Unit> {

override fun objectNode(node: ObjectNode) {
if (currShape.type == ShapeType.DOCUMENT) {
writer
.writeInline("#T {\n", RuntimeTypes.Core.Smithy.buildDocument)
.indent()
}

var i = 0
node.members.forEach { (keyNode, valueNode) ->
val memberShape: Shape
Expand Down Expand Up @@ -168,7 +174,9 @@ class ShapeValueGenerator(
}
}
is DocumentShape -> {
// TODO - deal with document shapes
writer.writeInline("#S to ", keyNode.value)
generator.writeShapeValueInline(writer, currShape, valueNode)
writer.writeInline("\n")
}
is UnionShape -> {
val member = currShape.getMember(keyNode.value).orElseThrow {
Expand All @@ -186,6 +194,12 @@ class ShapeValueGenerator(
}
i++
}

if (currShape.type === ShapeType.DOCUMENT) {
writer
.dedent()
.writeInline("}")
}
}

override fun stringNode(node: StringNode) {
Expand All @@ -202,6 +216,8 @@ class ShapeValueGenerator(
writer.writeInline("#L", "$symbolName.$symbolMember")
}

ShapeType.DOCUMENT -> writer.writeInline("#T(#S)", RuntimeTypes.Core.Smithy.Document, node.value)

else -> writer.writeInline("#S", node.value)
}
}
Expand All @@ -211,14 +227,29 @@ class ShapeValueGenerator(
}

override fun arrayNode(node: ArrayNode) {
val memberShape = generator.model.expectShape((currShape as CollectionShape).member.target)
var i = 0
node.elements.forEach { element ->
generator.writeShapeValueInline(writer, memberShape, element)
if (i < node.elements.size - 1) {
writer.writeInline(",\n")
when (currShape.type) {
ShapeType.DOCUMENT -> {
writer.withInlineBlock("#T(", ")", RuntimeTypes.Core.Smithy.Document) {
writer.withInlineBlock("listOf(", ")") {
node.elements.forEach {
generator.writeShapeValueInline(writer, currShape, it)
writer.writeInline(",\n")
}
}
}
}

else -> {
val memberShape = generator.model.expectShape((currShape as CollectionShape).member.target)
var i = 0
node.elements.forEach { element ->
generator.writeShapeValueInline(writer, memberShape, element)
if (i < node.elements.size - 1) {
writer.writeInline(",\n")
}
i++
}
}
i++
}
}

Expand All @@ -242,19 +273,20 @@ class ShapeValueGenerator(
// TODO - We need to decide non-JVM only symbols to generate for these before we know how to assign values to them
}

ShapeType.DOCUMENT -> {
// TODO - deal with document shapes
}
ShapeType.DOCUMENT -> writer.writeInline(
"#T(#L#L)",
RuntimeTypes.Core.Smithy.Document,
node.value,
if (node.isFloatingPointNumber) "F" else "L"
)

else -> throw CodegenException("unexpected shape type $currShape for numberNode")
}
}

override fun booleanNode(node: BooleanNode) {
when (currShape.type) {
ShapeType.DOCUMENT -> {
// TODO - deal with document shapes
}
ShapeType.DOCUMENT -> writer.writeInline("#T(#L)", RuntimeTypes.Core.Smithy.Document, node.value)
ShapeType.BOOLEAN -> writer.writeInline("#L", if (node.value) "true" else "false")
else -> throw CodegenException("unexpected shape type $currShape for boolean value")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -447,15 +447,12 @@ abstract class HttpBindingProtocolGenerator : ProtocolGenerator {
}
writer.write("builder.body = #T(input.#L.#T())", RuntimeTypes.Http.ByteArrayContent, contents, KotlinTypes.Text.encodeToByteArray)
}
ShapeType.STRUCTURE, ShapeType.UNION -> {
ShapeType.STRUCTURE, ShapeType.UNION, ShapeType.DOCUMENT -> {
val sdg = structuredDataSerializer(ctx)
val payloadSerializerFn = sdg.payloadSerializer(ctx, binding.member)
writer.write("val payload = #T(input.#L)", payloadSerializerFn, memberName)
writer.write("builder.body = #T(payload)", RuntimeTypes.Http.ByteArrayContent)
}
ShapeType.DOCUMENT -> {
// TODO - deal with document members
}
else -> throw CodegenException("member shape ${binding.member} serializer not implemented yet")
}
writer.closeBlock("}")
Expand Down Expand Up @@ -897,7 +894,7 @@ abstract class HttpBindingProtocolGenerator : ProtocolGenerator {
}
writer.write("builder.$memberName = response.body.$conversion")
}
ShapeType.STRUCTURE, ShapeType.UNION -> {
ShapeType.STRUCTURE, ShapeType.UNION, ShapeType.DOCUMENT -> {
// delegate to the payload deserializer
val sdg = structuredDataParser(ctx)
val payloadDeserializerFn = sdg.payloadDeserializer(ctx, binding.member)
Expand All @@ -907,9 +904,6 @@ abstract class HttpBindingProtocolGenerator : ProtocolGenerator {
write("builder.#L = #T(payload)", memberName, payloadDeserializerFn)
}
}
ShapeType.DOCUMENT -> {
// TODO - implement document support
}
else -> throw CodegenException("member shape ${binding.member} deserializer not implemented")
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ open class DeserializeStructGenerator(
ShapeType.MAP -> renderMapMemberDeserializer(memberShape, targetShape as MapShape)
ShapeType.STRUCTURE,
ShapeType.UNION -> renderShapeDeserializer(memberShape)
ShapeType.DOCUMENT -> renderDocumentShapeDeserializer(memberShape)
ShapeType.BLOB,
ShapeType.BOOLEAN,
ShapeType.STRING,
Expand All @@ -101,17 +100,13 @@ open class DeserializeStructGenerator(
ShapeType.LONG,
ShapeType.FLOAT,
ShapeType.DOUBLE,
ShapeType.DOCUMENT,
ShapeType.BIG_DECIMAL,
ShapeType.BIG_INTEGER -> renderShapeDeserializer(memberShape)
else -> error("Unexpected shape type: ${targetShape.type}")
}
}

// TODO ~ Not yet implemented
@Suppress("UNUSED_PARAMETER") // Until method is implemented
protected fun renderDocumentShapeDeserializer(memberShape: MemberShape) {
}

/**
* Codegen the deserialization of a primitive value into a response type. Example:
* ```
Expand Down Expand Up @@ -179,6 +174,7 @@ open class DeserializeStructGenerator(
ShapeType.BIG_DECIMAL,
ShapeType.BIG_INTEGER,
ShapeType.BLOB,
ShapeType.DOCUMENT,
ShapeType.TIMESTAMP -> renderEntry(elementShape, nestingLevel, isSparse, parentMemberName)
ShapeType.SET,
ShapeType.LIST -> renderListEntry(rootMemberShape, elementShape as CollectionShape, nestingLevel, isSparse, parentMemberName)
Expand Down Expand Up @@ -380,6 +376,7 @@ open class DeserializeStructGenerator(
ShapeType.BIG_DECIMAL,
ShapeType.BIG_INTEGER,
ShapeType.BLOB,
ShapeType.DOCUMENT,
ShapeType.TIMESTAMP -> renderElement(elementShape, nestingLevel, isSparse, parentMemberName)
ShapeType.LIST,
ShapeType.SET -> renderListElement(rootMemberShape, elementShape as CollectionShape, nestingLevel, parentMemberName)
Expand Down Expand Up @@ -513,6 +510,7 @@ open class DeserializeStructGenerator(
ShapeType.LONG -> "deserializeLong()"
ShapeType.FLOAT -> "deserializeFloat()"
ShapeType.DOUBLE -> "deserializeDouble()"
ShapeType.DOCUMENT -> "deserializeDocument()"
ShapeType.BLOB -> {
writer.addImport("decodeBase64Bytes", KotlinDependency.UTILS)
"deserializeString().decodeBase64Bytes()"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ class DeserializeUnionGenerator(
is MapShape -> renderMapMemberDeserializer(memberShape, targetShape)
is StructureShape,
is UnionShape -> renderShapeDeserializer(memberShape)
is DocumentShape -> renderDocumentShapeDeserializer(memberShape)
is BlobShape,
is BooleanShape,
is StringShape,
Expand All @@ -63,6 +62,7 @@ class DeserializeUnionGenerator(
is FloatShape,
is DoubleShape,
is BigDecimalShape,
is DocumentShape,
is BigIntegerShape -> renderShapeDeserializer(memberShape)
else -> error("Unexpected shape type: ${targetShape.type}")
}
Expand Down
Loading