Skip to content

Commit 7de446c

Browse files
authored
Merge pull request #4 from RivuChk/main
fix(jvm): resolve SerializationException for Map<String, Any?> on JVM platform
2 parents 9a8db26 + a09b109 commit 7de446c

1 file changed

Lines changed: 63 additions & 4 deletions

File tree

  • posthog-kmp/src/jvmMain/kotlin/io/github/samuolis/posthog

posthog-kmp/src/jvmMain/kotlin/io/github/samuolis/posthog/PostHog.jvm.kt

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ import io.ktor.http.*
99
import io.ktor.serialization.kotlinx.json.*
1010
import kotlinx.coroutines.*
1111
import kotlinx.serialization.json.*
12+
import kotlinx.serialization.*
13+
import kotlinx.serialization.descriptors.*
14+
import kotlinx.serialization.encoding.*
1215
import java.time.Instant
1316
import java.time.format.DateTimeFormatter
1417
import java.util.*
@@ -92,6 +95,7 @@ internal actual fun platformCapture(event: String, properties: Map<String, Any?>
9295
scope.launch { flushEvents() }
9396
}
9497
}
98+
println("PosthogAnalyticsManager platformCapture: Sent event $event $eventProperties")
9599
}
96100

97101
internal actual fun platformScreen(screenName: String, properties: Map<String, Any?>?) {
@@ -302,14 +306,16 @@ private suspend fun flushEvents() {
302306
"batch" to batch
303307
)
304308

309+
val requestBody = json.encodeToString(mapSerializer, body)
310+
305311
try {
306312
val response = client.post("${cfg.host}/batch") {
307313
contentType(ContentType.Application.Json)
308-
setBody(json.encodeToString(mapSerializer, body))
314+
setBody(requestBody)
309315
}
310316

311317
if (cfg.debug) {
312-
println("[PostHog] Flushed ${eventsToSend.size} events: ${response.status}")
318+
println("[PostHog] Flushed ${eventsToSend.size} events: ${response.status}\n${if (!response.status.isSuccess()) requestBody+"\n"+response else ""}")
313319
}
314320
} catch (e: Exception) {
315321
if (cfg.debug) {
@@ -376,5 +382,58 @@ private fun getCurrentISOTimestamp(): String {
376382
return DateTimeFormatter.ISO_INSTANT.format(Instant.now())
377383
}
378384

379-
// Simple map serializer for the body
380-
private val mapSerializer = kotlinx.serialization.serializer<Map<String, Any?>>()
385+
// Custom serializer for Map<String, Any?>
386+
@OptIn(ExperimentalSerializationApi::class)
387+
private object MapStringAnySerializer : KSerializer<Map<String, Any?>> {
388+
override val descriptor: SerialDescriptor = buildClassSerialDescriptor("MapStringAny")
389+
390+
private fun Any?.toJsonElement(): JsonElement = when (this) {
391+
null -> JsonNull
392+
is String -> JsonPrimitive(this)
393+
is Number -> JsonPrimitive(this)
394+
is Boolean -> JsonPrimitive(this)
395+
is List<*> -> buildJsonArray {
396+
this@toJsonElement.forEach { item ->
397+
add(item.toJsonElement())
398+
}
399+
}
400+
is Map<*, *> -> buildJsonObject {
401+
this@toJsonElement.forEach { (key, value) ->
402+
put(key.toString(), value.toJsonElement())
403+
}
404+
}
405+
else -> JsonPrimitive(this.toString())
406+
}
407+
408+
override fun serialize(encoder: Encoder, value: Map<String, Any?>) {
409+
val jsonObject = buildJsonObject {
410+
value.forEach { (key, v) ->
411+
put(key, v.toJsonElement())
412+
}
413+
}
414+
encoder.encodeSerializableValue(JsonObject.serializer(), jsonObject)
415+
}
416+
417+
override fun deserialize(decoder: Decoder): Map<String, Any?> {
418+
// For PostHog we mainly need serialization, but provide basic deserialization
419+
val jsonObject = decoder.decodeSerializableValue(JsonObject.serializer())
420+
return jsonObject.mapValues { (_, v) ->
421+
when (v) {
422+
is JsonPrimitive -> when {
423+
v.isString -> v.content
424+
v.booleanOrNull != null -> v.boolean
425+
v.intOrNull != null -> v.int
426+
v.longOrNull != null -> v.long
427+
v.floatOrNull != null -> v.float
428+
v.doubleOrNull != null -> v.double
429+
else -> v.content
430+
}
431+
is JsonNull -> null
432+
else -> v.toString()
433+
}
434+
}
435+
}
436+
}
437+
438+
// Custom map serializer for the body
439+
private val mapSerializer = MapStringAnySerializer

0 commit comments

Comments
 (0)