Skip to content

Repository files navigation

kotlinx.serialization ❤️ DynamoDB

DynamoDB format for kotlinx.serialization. Serialize and deserialize documents from DynamoDB using kotlinx.serialization. This library allows you to map DynamoDB documents to / from domain object.

Introduction

According with Wikipedia, Amazon DynamoDB is a fully managed proprietary NoSQL database offered by Amazon.com.

When using DynamoDB - Kotlin SDK, the SDK returns documents using AttributeValue. This library allows you to easily convert AttributeValue to Kotlin objects using the power of kotlinx.serialization.

Setup

To use the DynaMap library, you have to perform serialization and deserialization similar to how you would with kotlinx.serialization.

  1. Install kotlinx.serialization plugin.
  2. Add DynaMap serialization dependency.

Kotlin DSL:

plugins {
kotlin("jvm")
// ADD SERIALIZATION PLUGIN
kotlin("plugin.serialization")
}
dependencies {
// ADD SERIALIZATION DEPENDENCY
implementation("com.codanbaru.kotlin:dynamap:0.9.0")
}
Groovy DSL
plugins {
// ADD SERIALIZATION PLUGIN
id 'org.jetbrains.kotlin.plugin.serialization'
} dependencies {
// ADD SERIALIZATION DEPENDENCY
implementation 'com.codanbaru.kotlin:dynamap:0.9.0'
}

Simple Example

@Serializable
data classBook(valname:String, valauthor:String?)
val dynamap =Dynamap {
evaluateUndefinedAttributesAsNullAttribute =false
}
funencodeBook(book:Book): Map<String, AttributeValue> {
val item:Map<String, AttributeValue> = dynamap.encodeToItem(book)
return item
}
fundecodeBook(item:Map<String, AttributeValue>): Book {{
val obj:Book= dynamap.decodeFromItem(item)
return obj
}

By default, the DynaMap library evaluates undefined attributes as null attributes. This means that if the document in the database does not contain an attribute for a nullable property, DynaMap will create that attribute automatically.

@Serializable
data classBook(valname:String, valauthor:String?, valprice:Int)
val itemOnDatabase =mapOf(
"name" to AttributeValue.S("Harry Potter"),
"price" to AttributeValue.N("10")
)
// Will deserialize object successfully.val obj1 =Dynamap { evaluateUndefinedAttributesAsNullAttribute =true }.decodeFromItem<Book>(itemOnDatabase)
// Will raise DynamapSerializationException.UnexpectedUndefined exception.val obj2 =Dynamap { evaluateUndefinedAttributesAsNullAttribute =false }.decodeFromItem<Book>(itemOnDatabase)

Property Mapping

DynaMap can override the name used in encoded document using @SerialName annotation.

@Serializable
data classBook(
@SerialName("BookName")
valname:String,
valauthor:String?,
valprice:Int
)
val book =Book("Harry Potter", "JKRowling", 10)
val item =Dynamap.encodeToItem(book)
println(item) // {BookName=S(value=Harry Potter), author=S(value=JKRowling), price=N(value=10)}

Binary Serialization / Deserialization

kotlinx.serialization manages ByteArray internally as a list of bytes. So, if we try to serialize / deserialize it with default serializer, it will convert the ByteArray to a list of numbers in DynamoDB.

@Serializable
data classUser(valusername:String, valpasswordHash:ByteArray)
val user =User(username ="Codanbaru", passwordHash ="AQIDBA==".decodeBase64Bytes())
val item:Map<String, AttributeValue> =Dynamap.encodeToItem(user)
println(item) // {username=S(value=Codanbaru), passwordHash=L(value=[N(value=1), N(value=2), N(value=3), N(value=4)])}

To convert ByteArray to Binary type on DynamoDB, you can use DynamoBinarySerializer.

@Serializable
data classUser(
valusername:String,
@Serializable(with =DynamoBinarySerializer::class)
valpasswordHash:ByteArray
)
val user =User(username ="Codanbaru", passwordHash ="AQIDBA==".decodeBase64Bytes())
val item:Map<String, AttributeValue> =Dynamap.encodeToItem(user)
println(item) // {username=S(value=Codanbaru), passwordHash=B(value=[1, 2, 3, 4])}

Polymorphism

DynaMap also supports serialization / deserialization of polyphormic structures1.

At the moment, Dynamap currently support Closed polymorphism only.

  • ✅ Closed polymorphism
  • ❌ Open polymorphism

1 You can get more information about polymorphism on kotlinx.serialization documentation.

val dynamap =Dynamap { }
@Serializable
sealedclassSocial {
@Serializable
data classEmail(
varemail:String
) : Social()
@Serializable
data classPhone(
valcountry:String,
valnumber:String
) : Social()
@Serializable
data classInstagram(
valusername:String
) : Social()
}
@Serializable
data classUser(valname:String, valsocial:Social)
val user0 =User(name ="Codanbaru 0", social =Social.Email("demo@codanbaru.com"))
val user1 =User(name ="Codanbaru 0", social =Social.Instagram("@codanbaru"))
val item0:Map<String, AttributeValue> = dynamap.encodeToItem(user0)
val item1:Map<String, AttributeValue> = dynamap.encodeToItem(user1)
println(item0) // {name=S(value=Codanbaru 0), social=M(value={email=S(value=demo@codanbaru.com), __dynamap_serialization_type=S(value=com.codanbaru.app.Social.Email)})}println(item1) // {name=S(value=Codanbaru 0), social=M(value={username=S(value=@codanbaru), __dynamap_serialization_type=S(value=com.codanbaru.app.Social.Instagram)})}

You can specify, at Dynamap creation, which key kotlinx.serialization should use to discriminate classes.

val dynamap =Dynamap {
classDiscriminator ="type"
}
// ...println(item0) // {name=S(value=Codanbaru 0), social=M(value={email=S(value=demo@codanbaru.com), type=S(value=com.codanbaru.app.Social.Email)})}println(item1) // {name=S(value=Codanbaru 0), social=M(value={username=S(value=@codanbaru), type=S(value=com.codanbaru.app.Social.Instagram)})}

Also, with @SerialName annotation, you can override the class name used by kotlinx.serialization and Dynamap.

@Serializable
sealedclassSocial {
@Serializable
@SerialName("email")
data classEmail(
varemail:String
) : Social()
@Serializable
@SerialName("phone")
data classPhone(
valcountry:String,
valnumber:String
) : Social()
@Serializable
@SerialName("instagram")
data classInstagram(
valusername:String
) : Social()
}
// ...println(item0) // {name=S(value=Codanbaru 0), social=M(value={email=S(value=demo@codanbaru.com), type=S(value=com.codanbaru.app.Social.Email)})}println(item1) // {name=S(value=Codanbaru 0), social=M(value={username=S(value=@codanbaru), type=S(value=com.codanbaru.app.Social.Instagram)})}

About

Kotlin - DynamoDB Mapper Serialization

Resources

Stars

5 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages