Skip to content

Commit 1df3651

Browse files
committed
Add MessageAdapter for Kotlin Serialization (#92)
1 parent cbae5d1 commit 1df3651

File tree

9 files changed

+137
-3
lines changed

9 files changed

+137
-3
lines changed

build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ buildscript {
2121
classpath("org.jetbrains.dokka:dokka-gradle-plugin:${versions.dokkaGradlePlugin}")
2222
classpath("io.gitlab.arturbosch.detekt" +
2323
":detekt-gradle-plugin:${versions.detekt}")
24+
classpath(kotlin("serialization", version = versions.kotlin))
2425
}
2526
}
2627

buildSrc/src/main/kotlin/deps.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ object versions {
1010
const val jfrogBuildInfoExtractor = "4.23.4"
1111
const val navigation = "2.1.0-rc01"
1212
const val coroutines = "1.3.2"
13+
const val serialization = "1.3.3"
1314
const val broadcast = "1.0.0"
1415
const val lifecycle = "2.4.1"
1516
const val room = "2.2.5"
@@ -104,6 +105,8 @@ object deps {
104105
"org.jetbrains.kotlinx:kotlinx-coroutines-android:${versions.coroutines}"
105106
const val test = "org.jetbrains.kotlinx:kotlinx-coroutines-test:${versions.coroutines}"
106107
}
108+
109+
const val serializationJson = "org.jetbrains.kotlinx:kotlinx-serialization-json:${versions.serialization}"
107110
}
108111

109112
object logger {
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/build
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
public final class com/gojek/courier/messageadapter/kotlinserialization/KotlinSerializationMessageAdapterFactory : com/gojek/courier/MessageAdapter$Factory {
2+
public fun <init> ()V
3+
public fun <init> (Lkotlinx/serialization/json/Json;)V
4+
public synthetic fun <init> (Lkotlinx/serialization/json/Json;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
5+
public fun create (Ljava/lang/reflect/Type;[Ljava/lang/annotation/Annotation;)Lcom/gojek/courier/MessageAdapter;
6+
}
7+
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import plugin.KotlinLibraryConfigurationPlugin
2+
3+
apply<KotlinLibraryConfigurationPlugin>()
4+
apply("$rootDir/gradle/script-ext.gradle")
5+
6+
val version = ext.get("gitVersionName")
7+
8+
ext {
9+
set("PUBLISH_GROUP_ID", "com.gojek.courier")
10+
set("PUBLISH_ARTIFACT_ID", "courier-message-adapter-kotlin-serialization")
11+
set("PUBLISH_VERSION", ext.get("gitVersionName"))
12+
set("minimumCoverage", "0.0")
13+
}
14+
15+
plugins {
16+
id("java-library")
17+
kotlin("jvm")
18+
kotlin("plugin.serialization")
19+
id(ScriptPlugins.apiValidator) version versions.apiValidator
20+
}
21+
22+
dependencies {
23+
api(project(":courier-core"))
24+
api(deps.kotlin.serializationJson)
25+
implementation(deps.kotlin.stdlib.core)
26+
27+
testImplementation(deps.android.test.kotlinTestJunit)
28+
}
29+
30+
apply(from = "${rootProject.projectDir}/gradle/publish-module.gradle")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package com.gojek.courier.messageadapter.kotlinserialization
2+
3+
import com.gojek.courier.Message
4+
import com.gojek.courier.MessageAdapter
5+
import java.lang.reflect.Type
6+
import kotlinx.serialization.ExperimentalSerializationApi
7+
import kotlinx.serialization.KSerializer
8+
import kotlinx.serialization.json.Json
9+
import kotlinx.serialization.serializer
10+
11+
/**
12+
* A [message adapter][MessageAdapter] that uses Kotlin Serialization.
13+
*/
14+
private class KotlinSerializationMessageAdapter<T>(
15+
private val json: Json,
16+
private val serializer: KSerializer<T>
17+
) : MessageAdapter<T> {
18+
19+
override fun fromMessage(topic: String, message: Message): T {
20+
val stringValue = when (message) {
21+
is Message.Bytes -> String(message.value, Charsets.UTF_8)
22+
}
23+
return json.decodeFromString(serializer, stringValue)
24+
}
25+
26+
override fun toMessage(topic: String, data: T): Message =
27+
json.encodeToString(serializer, data)
28+
.toByteArray(Charsets.UTF_8)
29+
.let(Message::Bytes)
30+
31+
override fun contentType() = "application/json"
32+
}
33+
34+
@OptIn(ExperimentalSerializationApi::class)
35+
class KotlinSerializationMessageAdapterFactory(
36+
private val json: Json = Json.Default
37+
) : MessageAdapter.Factory {
38+
39+
override fun create(type: Type, annotations: Array<Annotation>): MessageAdapter<*> {
40+
val serializer = json.serializersModule.serializer(type)
41+
return KotlinSerializationMessageAdapter(json, serializer)
42+
}
43+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package com.gojek.courier.messageadapter.kotlinserialization
2+
3+
import com.gojek.courier.Message
4+
import com.gojek.courier.MessageAdapter
5+
import kotlinx.serialization.Serializable
6+
import org.junit.Assert.assertEquals
7+
import org.junit.Test
8+
9+
class KotlinSerializationMessageAdapterTest {
10+
private val messageAdapter = KotlinSerializationMessageAdapterFactory().create(
11+
type = TestClass::class.java,
12+
annotations = emptyArray()
13+
) as MessageAdapter<TestClass>
14+
15+
@Test
16+
fun `test toMessage`() {
17+
val testClass = TestClass(100, "test100")
18+
val testString = """{"id":100,"name":"test100"}"""
19+
20+
val message = messageAdapter.toMessage(
21+
topic = "any",
22+
data = testClass
23+
)
24+
25+
assertEquals(testString, String((message as Message.Bytes).value))
26+
}
27+
28+
@Test
29+
fun `test fromMessage`() {
30+
val testClass = TestClass(100, "test100")
31+
val testString = """{"id":100,"name":"test100"}"""
32+
33+
val message = messageAdapter.fromMessage(
34+
topic = "any",
35+
message = Message.Bytes(testString.toByteArray())
36+
)
37+
38+
assertEquals(testClass, message)
39+
}
40+
}
41+
42+
@Serializable
43+
data class TestClass(
44+
val id: Int,
45+
val name: String
46+
)

docs/docs/MessageStreamAdapters.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@ To serialize and deserialize received and published messages, Courier uses Messa
88

99
Courier library provides the following message adapters:
1010

11-
- courier-message-adapter-gson
11+
- [Gson](https://github.com/google/gson): courier-message-adapter-gson
1212

13-
- courier-message-adapter-moshi
13+
- [Kotlin Serialization](https://github.com/Kotlin/kotlinx.serialization): courier-message-adapter-kotlin-serialization
1414

15-
- courier-message-adapter-protobuf
15+
- [Moshi](https://github.com/square/moshi/): courier-message-adapter-moshi
16+
17+
- [Protobuf](https://developers.google.com/protocol-buffers/): courier-message-adapter-protobuf
1618

1719
You can also create your own custom message adapter by implementing the MessageAdapter.Factory interface.
1820

settings.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ include ':courier-core'
77
include ':courier-core-android'
88
include ':courier-message-adapter-text'
99
include ':courier-message-adapter-gson'
10+
include ':courier-message-adapter-kotlin-serialization'
1011
include ':courier-message-adapter-moshi'
1112
include ':courier-message-adapter-protobuf'
1213
include ':courier-stream-adapter-rxjava'

0 commit comments

Comments
 (0)