From e0b925540dff5403edafb38a2564fed74937e35d Mon Sep 17 00:00:00 2001 From: Mateusz Krawiec Date: Tue, 21 Jul 2026 12:53:58 -0700 Subject: [PATCH] fix: migrate web server serialization from Gson to kotlinx-serialization The dev web server serializes /run and /run_sse responses with kotlinx-serialization, omitting null and default-valued fields so the output matches the rest of ADK. PiperOrigin-RevId: 951648603 --- gradle/libs.versions.toml | 1 + webserver/build.gradle.kts | 4 +- .../google/adk/kt/webserver/AdkWebServer.kt | 34 ++---------- .../adk/kt/webserver/models/ApiModels.kt | 18 ++++-- .../adk/kt/webserver/routes/RunRoutes.kt | 7 ++- .../adk/kt/webserver/AdkWebServerTest.kt | 16 ++++-- .../adk/kt/webserver/routes/AppRoutesTest.kt | 9 ++- .../kt/webserver/routes/ArtifactRoutesTest.kt | 32 ++++++----- .../kt/webserver/routes/DebugRoutesTest.kt | 13 +++-- .../kt/webserver/routes/SessionRoutesTest.kt | 55 +++---------------- 10 files changed, 79 insertions(+), 110 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7ca4903b..bd720f0e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -93,6 +93,7 @@ kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-t kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinx-datetime" } kotlinx-serialization = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization" } ktor-serialization-gson = { module = "io.ktor:ktor-serialization-gson", version.ref = "ktor" } +ktor-serialization-kotlinx-json = { module = "io.ktor:ktor-serialization-kotlinx-json", version.ref = "ktor" } ktor-server-call-logging = { module = "io.ktor:ktor-server-call-logging", version.ref = "ktor" } ktor-server-content-negotiation = { module = "io.ktor:ktor-server-content-negotiation", version.ref = "ktor" } ktor-server-core = { module = "io.ktor:ktor-server-core", version.ref = "ktor" } diff --git a/webserver/build.gradle.kts b/webserver/build.gradle.kts index c2e7f808..a9078382 100644 --- a/webserver/build.gradle.kts +++ b/webserver/build.gradle.kts @@ -16,6 +16,7 @@ plugins { kotlin("jvm") + kotlin("plugin.serialization") id("application") id("java-library") id("maven-publish") @@ -44,13 +45,14 @@ sourceSets { dependencies { implementation(project(":google-adk-kotlin-core")) implementation(libs.kotlinx.datetime) + implementation(libs.kotlinx.serialization) implementation(libs.graphviz.java) implementation(libs.opentelemetry.api) implementation(libs.opentelemetry.sdk) - implementation(libs.ktor.serialization.gson) + implementation(libs.ktor.serialization.kotlinx.json) implementation(libs.ktor.server.call.logging) implementation(libs.ktor.server.content.negotiation) implementation(libs.ktor.server.core) diff --git a/webserver/src/jvmMain/kotlin/com/google/adk/kt/webserver/AdkWebServer.kt b/webserver/src/jvmMain/kotlin/com/google/adk/kt/webserver/AdkWebServer.kt index ebbe69e5..568a1851 100644 --- a/webserver/src/jvmMain/kotlin/com/google/adk/kt/webserver/AdkWebServer.kt +++ b/webserver/src/jvmMain/kotlin/com/google/adk/kt/webserver/AdkWebServer.kt @@ -16,8 +16,10 @@ package com.google.adk.kt.webserver +import com.google.adk.kt.annotations.FrameworkInternalApi import com.google.adk.kt.artifacts.ArtifactService import com.google.adk.kt.runners.Runner +import com.google.adk.kt.serialization.adkJson import com.google.adk.kt.sessions.SessionService import com.google.adk.kt.telemetry.TelemetryConfig import com.google.adk.kt.webserver.AdkWebServer.StatusAwareLogger @@ -32,10 +34,7 @@ import com.google.adk.kt.webserver.routes.sessionRoutes import com.google.adk.kt.webserver.routes.staticRoutes import com.google.adk.kt.webserver.telemetry.ApiServerSpanExporter import com.google.adk.kt.webserver.telemetry.OpenTelemetryConfig -import com.google.gson.TypeAdapter -import com.google.gson.stream.JsonReader -import com.google.gson.stream.JsonWriter -import io.ktor.serialization.gson.gson +import io.ktor.serialization.kotlinx.json.json import io.ktor.server.application.Application import io.ktor.server.application.call import io.ktor.server.application.install @@ -49,7 +48,6 @@ import io.ktor.server.request.uri import io.ktor.server.response.respondText import io.ktor.server.routing.get import io.ktor.server.routing.routing -import kotlinx.datetime.Instant import org.slf4j.Logger import org.slf4j.LoggerFactory import org.slf4j.event.Level @@ -123,24 +121,6 @@ class AdkWebServer( logger.info("Ktor server stopped") } - class InstantTypeAdapter : TypeAdapter() { - override fun write(out: JsonWriter, value: Instant?) { - if (value == null) { - out.nullValue() - } else { - out.value(value.toEpochMilliseconds()) - } - } - - override fun read(reader: JsonReader): Instant? { - if (reader.peek() == com.google.gson.stream.JsonToken.NULL) { - reader.nextNull() - return null - } - return Instant.fromEpochMilliseconds(reader.nextLong()) - } - } - public class StatusAwareLogger(private val delegate: Logger) : Logger by delegate { override fun info(msg: String?) { if (msg != null && msg.contains("Status: 5")) { @@ -152,6 +132,7 @@ class AdkWebServer( } } +@OptIn(FrameworkInternalApi::class) fun Application.adkModule( sessionService: SessionService, artifactService: ArtifactService, @@ -169,12 +150,7 @@ fun Application.adkModule( "Status: $status, HTTP method: $httpMethod, URI: $uri" } } - install(ContentNegotiation) { - gson { - setPrettyPrinting() - registerTypeAdapter(Instant::class.java, AdkWebServer.InstantTypeAdapter()) - } - } + install(ContentNegotiation) { json(adkJson) } val otelConfig = OpenTelemetryConfig(apiServerSpanExporter) val sdkTracerProvider = otelConfig.sdkTracerProvider() diff --git a/webserver/src/jvmMain/kotlin/com/google/adk/kt/webserver/models/ApiModels.kt b/webserver/src/jvmMain/kotlin/com/google/adk/kt/webserver/models/ApiModels.kt index 17b8a5c4..cfc58cfa 100644 --- a/webserver/src/jvmMain/kotlin/com/google/adk/kt/webserver/models/ApiModels.kt +++ b/webserver/src/jvmMain/kotlin/com/google/adk/kt/webserver/models/ApiModels.kt @@ -17,25 +17,30 @@ package com.google.adk.kt.webserver.models import com.google.adk.kt.types.Content +import kotlinx.serialization.Contextual +import kotlinx.serialization.Serializable +@Serializable data class AgentRunRequest( val appName: String, val userId: String, val sessionId: String? = null, val newMessage: Content? = null, val streaming: Boolean = false, - val stateDelta: Map? = null, + val stateDelta: Map? = null, val invocationId: String? = null, ) +@Serializable data class RunRequest(val agentId: String, val input: String, val sessionId: String? = null) -data class RunResponse(val output: String, val sessionId: String) +@Serializable data class RunResponse(val output: String, val sessionId: String) -data class TurnModel(val role: String, val content: String) +@Serializable data class TurnModel(val role: String, val content: String) -data class SessionModel(val sessionId: String, val turnHistory: List) +@Serializable data class SessionModel(val sessionId: String, val turnHistory: List) +@Serializable data class ErrorResponse(val error: String, val message: String, val details: String? = null) /** @@ -45,13 +50,14 @@ data class ErrorResponse(val error: String, val message: String, val details: St * @property content The JSON string or text content of the event. * @property timestamp The ISO-8601 timestamp of the event. */ -data class SseModel(val type: String, val content: String, val timestamp: String) +@Serializable data class SseModel(val type: String, val content: String, val timestamp: String) +@Serializable data class SessionDto( val id: String?, val appName: String, val userId: String, - val state: Map?, + val state: Map?, val events: List?, val lastUpdateTime: Long?, ) diff --git a/webserver/src/jvmMain/kotlin/com/google/adk/kt/webserver/routes/RunRoutes.kt b/webserver/src/jvmMain/kotlin/com/google/adk/kt/webserver/routes/RunRoutes.kt index 46e90019..7ef2a493 100644 --- a/webserver/src/jvmMain/kotlin/com/google/adk/kt/webserver/routes/RunRoutes.kt +++ b/webserver/src/jvmMain/kotlin/com/google/adk/kt/webserver/routes/RunRoutes.kt @@ -18,12 +18,13 @@ package com.google.adk.kt.webserver.routes import com.google.adk.kt.agents.RunConfig import com.google.adk.kt.agents.StreamingMode +import com.google.adk.kt.annotations.FrameworkInternalApi import com.google.adk.kt.artifacts.ArtifactService import com.google.adk.kt.runners.InMemoryRunner +import com.google.adk.kt.serialization.adkJson import com.google.adk.kt.sessions.SessionService import com.google.adk.kt.webserver.loaders.AgentLoader import com.google.adk.kt.webserver.models.AgentRunRequest -import com.google.gson.Gson import io.ktor.http.ContentType import io.ktor.http.HttpStatusCode import io.ktor.server.application.call @@ -37,7 +38,9 @@ import io.ktor.utils.io.writeStringUtf8 import java.util.UUID import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.toList +import kotlinx.serialization.encodeToString +@OptIn(FrameworkInternalApi::class) fun Route.runRoutes( agentLoader: AgentLoader, sessionService: SessionService, @@ -111,7 +114,7 @@ fun Route.runRoutes( runConfig, ) .collect { event -> - val data = Gson().toJson(event) + val data = adkJson.encodeToString(event) writeStringUtf8("data: $data\n\n") flush() } diff --git a/webserver/src/jvmTest/kotlin/com/google/adk/kt/webserver/AdkWebServerTest.kt b/webserver/src/jvmTest/kotlin/com/google/adk/kt/webserver/AdkWebServerTest.kt index a84bc0ac..758de91e 100644 --- a/webserver/src/jvmTest/kotlin/com/google/adk/kt/webserver/AdkWebServerTest.kt +++ b/webserver/src/jvmTest/kotlin/com/google/adk/kt/webserver/AdkWebServerTest.kt @@ -179,8 +179,8 @@ class AdkWebServerTest { val response = client.get("/api/test-serialize") assertThat(response.status).isEqualTo(HttpStatusCode.OK) val body = response.bodyAsText() - assertThat(body).contains("\"output\": \"Ok output\"") - assertThat(body).contains("\"sessionId\": \"test-session\"") + assertThat(body).contains("\"output\":\"Ok output\"") + assertThat(body).contains("\"sessionId\":\"test-session\"") } @Test @@ -196,8 +196,10 @@ class AdkWebServerTest { } assertThat(response.status).isEqualTo(HttpStatusCode.OK) val body = response.bodyAsText() - println("RESPONSE BODY: $body") - assertThat(body).isNotEmpty() + // adkJson has encodeDefaults=false, so default-false partial/interrupted are omitted. + assertThat(body).contains("\"turnComplete\":true") + assertThat(body).doesNotContain("\"partial\"") + assertThat(body).doesNotContain("\"interrupted\"") } @Test @@ -213,5 +215,11 @@ class AdkWebServerTest { } assertThat(response.status).isEqualTo(HttpStatusCode.OK) assertThat(response.headers["Content-Type"]).contains("text/event-stream") + // The SSE stream serializes events with adkJson too, so the shape matches /run. + val body = response.bodyAsText() + assertThat(body).contains("data: ") + assertThat(body).contains("\"turnComplete\":true") + assertThat(body).doesNotContain("\"partial\"") + assertThat(body).doesNotContain("\"interrupted\"") } } diff --git a/webserver/src/jvmTest/kotlin/com/google/adk/kt/webserver/routes/AppRoutesTest.kt b/webserver/src/jvmTest/kotlin/com/google/adk/kt/webserver/routes/AppRoutesTest.kt index 492bde2e..75c9f1ca 100644 --- a/webserver/src/jvmTest/kotlin/com/google/adk/kt/webserver/routes/AppRoutesTest.kt +++ b/webserver/src/jvmTest/kotlin/com/google/adk/kt/webserver/routes/AppRoutesTest.kt @@ -17,12 +17,14 @@ package com.google.adk.kt.webserver.routes import com.google.adk.kt.agents.BaseAgent +import com.google.adk.kt.annotations.FrameworkInternalApi +import com.google.adk.kt.serialization.adkJson import com.google.adk.kt.webserver.loaders.AgentLoader import com.google.common.truth.Truth.assertThat import io.ktor.client.request.get import io.ktor.client.statement.bodyAsText import io.ktor.http.HttpStatusCode -import io.ktor.serialization.gson.gson +import io.ktor.serialization.kotlinx.json.json import io.ktor.server.application.install import io.ktor.server.plugins.contentnegotiation.ContentNegotiation import io.ktor.server.routing.routing @@ -31,6 +33,7 @@ import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 +@OptIn(FrameworkInternalApi::class) @RunWith(JUnit4::class) class AppRoutesTest { @@ -44,7 +47,7 @@ class AppRoutesTest { fun listApps_returnsAppList() = testApplication { val fakeLoader = FakeAgentLoader(agentList = listOf("app1", "app2")) application { - install(ContentNegotiation) { gson { setPrettyPrinting() } } + install(ContentNegotiation) { json(adkJson) } routing { appRoutes(fakeLoader) } } @@ -60,7 +63,7 @@ class AppRoutesTest { fun listApps_empty_returnsEmptyList() = testApplication { val fakeLoader = FakeAgentLoader(agentList = emptyList()) application { - install(ContentNegotiation) { gson { setPrettyPrinting() } } + install(ContentNegotiation) { json(adkJson) } routing { appRoutes(fakeLoader) } } diff --git a/webserver/src/jvmTest/kotlin/com/google/adk/kt/webserver/routes/ArtifactRoutesTest.kt b/webserver/src/jvmTest/kotlin/com/google/adk/kt/webserver/routes/ArtifactRoutesTest.kt index 3d0edd37..9ee066fd 100644 --- a/webserver/src/jvmTest/kotlin/com/google/adk/kt/webserver/routes/ArtifactRoutesTest.kt +++ b/webserver/src/jvmTest/kotlin/com/google/adk/kt/webserver/routes/ArtifactRoutesTest.kt @@ -16,13 +16,14 @@ package com.google.adk.kt.webserver.routes +import com.google.adk.kt.annotations.FrameworkInternalApi import com.google.adk.kt.artifacts.ArtifactService +import com.google.adk.kt.serialization.adkJson import com.google.adk.kt.sessions.SessionKey import com.google.adk.kt.types.Blob import com.google.adk.kt.types.FileData import com.google.adk.kt.types.Part import com.google.common.truth.Truth.assertThat -import com.google.gson.Gson import io.ktor.client.request.delete import io.ktor.client.request.get import io.ktor.client.request.header @@ -32,15 +33,18 @@ import io.ktor.client.statement.bodyAsText import io.ktor.http.ContentType import io.ktor.http.HttpHeaders import io.ktor.http.HttpStatusCode -import io.ktor.serialization.gson.gson +import io.ktor.serialization.kotlinx.json.json import io.ktor.server.application.install import io.ktor.server.plugins.contentnegotiation.ContentNegotiation import io.ktor.server.routing.routing import io.ktor.server.testing.testApplication +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.encodeToString import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 +@OptIn(FrameworkInternalApi::class) @RunWith(JUnit4::class) class ArtifactRoutesTest { @@ -79,7 +83,7 @@ class ArtifactRoutesTest { fun listArtifacts_empty_returnsEmptyList() = testApplication { val dummyService = FakeArtifactService(onListArtifactKeys = { emptyList() }) application { - install(ContentNegotiation) { gson { setPrettyPrinting() } } + install(ContentNegotiation) { json(adkJson) } routing { artifactRoutes(dummyService) } } @@ -94,7 +98,7 @@ class ArtifactRoutesTest { val dummyService = FakeArtifactService(onListArtifactKeys = { listOf("file1.txt", "file2.txt") }) application { - install(ContentNegotiation) { gson { setPrettyPrinting() } } + install(ContentNegotiation) { json(adkJson) } routing { artifactRoutes(dummyService) } } @@ -114,7 +118,7 @@ class ArtifactRoutesTest { onLoadArtifact = { _, filename, _ -> if (filename == "test.txt") testPart else null } ) application { - install(ContentNegotiation) { gson { setPrettyPrinting() } } + install(ContentNegotiation) { json(adkJson) } routing { artifactRoutes(dummyService) } } @@ -129,7 +133,7 @@ class ArtifactRoutesTest { fun loadArtifact_notFound_returnsNotFound() = testApplication { val dummyService = FakeArtifactService(onLoadArtifact = { _, _, _ -> null }) application { - install(ContentNegotiation) { gson { setPrettyPrinting() } } + install(ContentNegotiation) { json(adkJson) } routing { artifactRoutes(dummyService) } } @@ -151,7 +155,7 @@ class ArtifactRoutesTest { } } application { - install(ContentNegotiation) { gson { setPrettyPrinting() } } + install(ContentNegotiation) { json(adkJson) } routing { artifactRoutes(dummyService) } } @@ -225,19 +229,19 @@ class ArtifactRoutesTest { } } application { - install(ContentNegotiation) { gson { setPrettyPrinting() } } + install(ContentNegotiation) { json(adkJson) } routing { artifactRoutes(dummyService) } } val response = client.post("/apps/testApp/users/testUser/sessions/testSession/artifacts") { header(HttpHeaders.ContentType, ContentType.Application.Json.toString()) - setBody(Gson().toJson(testPart)) + setBody(adkJson.encodeToString(testPart)) } assertThat(response.status).isEqualTo(HttpStatusCode.OK) assertThat(savedFilename).isEqualTo("test.txt") - val responsePart = Gson().fromJson(response.bodyAsText(), Part::class.java) + val responsePart = adkJson.decodeFromString(response.bodyAsText()) assertThat(responsePart.fileData?.displayName).isEqualTo("test.txt") } @@ -257,14 +261,14 @@ class ArtifactRoutesTest { } } application { - install(ContentNegotiation) { gson { setPrettyPrinting() } } + install(ContentNegotiation) { json(adkJson) } routing { artifactRoutes(dummyService) } } val response = client.post("/apps/testApp/users/testUser/sessions/testSession/artifacts") { header(HttpHeaders.ContentType, ContentType.Application.Json.toString()) - setBody(Gson().toJson(testPart)) + setBody(adkJson.encodeToString(testPart)) } assertThat(response.status).isEqualTo(HttpStatusCode.OK) @@ -276,14 +280,14 @@ class ArtifactRoutesTest { val testPart = Part(text = "no filename") val dummyService = FakeArtifactService() application { - install(ContentNegotiation) { gson { setPrettyPrinting() } } + install(ContentNegotiation) { json(adkJson) } routing { artifactRoutes(dummyService) } } val response = client.post("/apps/testApp/users/testUser/sessions/testSession/artifacts") { header(HttpHeaders.ContentType, ContentType.Application.Json.toString()) - setBody(Gson().toJson(testPart)) + setBody(adkJson.encodeToString(testPart)) } assertThat(response.status).isEqualTo(HttpStatusCode.BadRequest) diff --git a/webserver/src/jvmTest/kotlin/com/google/adk/kt/webserver/routes/DebugRoutesTest.kt b/webserver/src/jvmTest/kotlin/com/google/adk/kt/webserver/routes/DebugRoutesTest.kt index 20a90ff3..ae1cd6a6 100644 --- a/webserver/src/jvmTest/kotlin/com/google/adk/kt/webserver/routes/DebugRoutesTest.kt +++ b/webserver/src/jvmTest/kotlin/com/google/adk/kt/webserver/routes/DebugRoutesTest.kt @@ -16,12 +16,14 @@ package com.google.adk.kt.webserver.routes +import com.google.adk.kt.annotations.FrameworkInternalApi +import com.google.adk.kt.serialization.adkJson import com.google.adk.kt.webserver.telemetry.ApiServerSpanExporter import com.google.common.truth.Truth.assertThat import io.ktor.client.request.get import io.ktor.client.statement.bodyAsText import io.ktor.http.HttpStatusCode -import io.ktor.serialization.gson.gson +import io.ktor.serialization.kotlinx.json.json import io.ktor.server.application.install import io.ktor.server.plugins.contentnegotiation.ContentNegotiation import io.ktor.server.routing.routing @@ -30,6 +32,7 @@ import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 +@OptIn(FrameworkInternalApi::class) @RunWith(JUnit4::class) class DebugRoutesTest { @@ -39,14 +42,14 @@ class DebugRoutesTest { exporter.eventIdTraceStorage["test-event"] = mapOf("key" to "value") application { - install(ContentNegotiation) { gson { setPrettyPrinting() } } + install(ContentNegotiation) { json(adkJson) } routing { debugRoutes(exporter) } } val response = client.get("/debug/trace/test-event") assertThat(response.status).isEqualTo(HttpStatusCode.OK) - assertThat(response.bodyAsText()).contains("\"key\": \"value\"") + assertThat(response.bodyAsText()).contains("\"key\":\"value\"") } @Test @@ -54,7 +57,7 @@ class DebugRoutesTest { val exporter = ApiServerSpanExporter() application { - install(ContentNegotiation) { gson { setPrettyPrinting() } } + install(ContentNegotiation) { json(adkJson) } routing { debugRoutes(exporter) } } @@ -68,7 +71,7 @@ class DebugRoutesTest { val exporter = ApiServerSpanExporter() application { - install(ContentNegotiation) { gson { setPrettyPrinting() } } + install(ContentNegotiation) { json(adkJson) } routing { debugRoutes(exporter) } } diff --git a/webserver/src/jvmTest/kotlin/com/google/adk/kt/webserver/routes/SessionRoutesTest.kt b/webserver/src/jvmTest/kotlin/com/google/adk/kt/webserver/routes/SessionRoutesTest.kt index fcdc00a8..ec25f3c2 100644 --- a/webserver/src/jvmTest/kotlin/com/google/adk/kt/webserver/routes/SessionRoutesTest.kt +++ b/webserver/src/jvmTest/kotlin/com/google/adk/kt/webserver/routes/SessionRoutesTest.kt @@ -16,6 +16,8 @@ package com.google.adk.kt.webserver.routes +import com.google.adk.kt.annotations.FrameworkInternalApi +import com.google.adk.kt.serialization.adkJson import com.google.adk.kt.sessions.ListSessionsResponse import com.google.adk.kt.sessions.Session import com.google.adk.kt.sessions.SessionKey @@ -27,16 +29,16 @@ import io.ktor.client.request.get import io.ktor.client.request.post import io.ktor.client.statement.bodyAsText import io.ktor.http.HttpStatusCode -import io.ktor.serialization.gson.gson +import io.ktor.serialization.kotlinx.json.json import io.ktor.server.application.install import io.ktor.server.plugins.contentnegotiation.ContentNegotiation import io.ktor.server.routing.routing import io.ktor.server.testing.testApplication -import kotlinx.datetime.Instant import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 +@OptIn(FrameworkInternalApi::class) @RunWith(JUnit4::class) class SessionRoutesTest { @@ -83,12 +85,7 @@ class SessionRoutesTest { fun listSessions_empty_returnsEmptyList() = testApplication { val fakeService = FakeSessionService() application { - install(ContentNegotiation) { - gson { - setPrettyPrinting() - registerTypeAdapter(Instant::class.java, InstantTypeAdapter()) - } - } + install(ContentNegotiation) { json(adkJson) } routing { sessionRoutes(fakeService) } } @@ -102,12 +99,7 @@ class SessionRoutesTest { fun createSession_validInput_createsSession() = testApplication { val fakeService = FakeSessionService() application { - install(ContentNegotiation) { - gson { - setPrettyPrinting() - registerTypeAdapter(Instant::class.java, InstantTypeAdapter()) - } - } + install(ContentNegotiation) { json(adkJson) } routing { sessionRoutes(fakeService) } } @@ -127,19 +119,14 @@ class SessionRoutesTest { Session(key = SessionKey(appName = "testApp", userId = "testUser", id = "test-session")) ) application { - install(ContentNegotiation) { - gson { - setPrettyPrinting() - registerTypeAdapter(Instant::class.java, InstantTypeAdapter()) - } - } + install(ContentNegotiation) { json(adkJson) } routing { sessionRoutes(fakeService) } } val response = client.get("/apps/testApp/users/testUser/sessions/test-session") assertThat(response.status).isEqualTo(HttpStatusCode.OK) - assertThat(response.bodyAsText()).contains("\"id\": \"test-session\"") + assertThat(response.bodyAsText()).contains("\"id\":\"test-session\"") } @Test @@ -149,12 +136,7 @@ class SessionRoutesTest { Session(key = SessionKey(appName = "testApp", userId = "testUser", id = "test-session")) ) application { - install(ContentNegotiation) { - gson { - setPrettyPrinting() - registerTypeAdapter(Instant::class.java, InstantTypeAdapter()) - } - } + install(ContentNegotiation) { json(adkJson) } routing { sessionRoutes(fakeService) } } @@ -200,22 +182,3 @@ class SessionRoutesTest { assertThat(error.error).isEqualTo(SessionRoutesErrors.ERR_MISSING_SESSION_ID) } } - -class InstantTypeAdapter : - com.google.gson.JsonSerializer, com.google.gson.JsonDeserializer { - override fun serialize( - src: Instant, - typeOfSrc: java.lang.reflect.Type, - context: com.google.gson.JsonSerializationContext, - ): com.google.gson.JsonElement { - return com.google.gson.JsonPrimitive(src.toEpochMilliseconds()) - } - - override fun deserialize( - json: com.google.gson.JsonElement, - typeOfT: java.lang.reflect.Type, - context: com.google.gson.JsonDeserializationContext, - ): Instant { - return Instant.fromEpochMilliseconds(json.asLong) - } -}