[PM-19793] Migrate ZonedDateTimeSerializer to core module (#4960)

This commit is contained in:
Patrick Honkonen
2025-04-02 13:42:51 -04:00
committed by GitHub
parent 8e7de92609
commit ce139623d6
20 changed files with 71 additions and 206 deletions

View File

@@ -4,7 +4,6 @@ import com.bitwarden.authenticator.data.platform.datasource.network.interceptor.
import com.bitwarden.authenticator.data.platform.datasource.network.interceptor.HeadersInterceptor
import com.bitwarden.authenticator.data.platform.datasource.network.retrofit.Retrofits
import com.bitwarden.authenticator.data.platform.datasource.network.retrofit.RetrofitsImpl
import com.bitwarden.authenticator.data.platform.datasource.network.serializer.ZonedDateTimeSerializer
import com.bitwarden.authenticator.data.platform.datasource.network.service.ConfigService
import com.bitwarden.authenticator.data.platform.datasource.network.service.ConfigServiceImpl
import dagger.Module
@@ -12,8 +11,6 @@ import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import kotlinx.serialization.json.Json
import kotlinx.serialization.modules.SerializersModule
import kotlinx.serialization.modules.contextual
import retrofit2.create
import javax.inject.Singleton
@@ -46,23 +43,4 @@ object PlatformNetworkModule {
headersInterceptor = headersInterceptor,
json = json,
)
@Provides
@Singleton
fun providesJson(): Json = Json {
// If there are keys returned by the server not modeled by a serializable class,
// ignore them.
// This makes additive server changes non-breaking.
ignoreUnknownKeys = true
// We allow for nullable values to have keys missing in the JSON response.
explicitNulls = false
serializersModule = SerializersModule {
contextual(ZonedDateTimeSerializer())
}
// Respect model default property values.
coerceInputValues = true
}
}

View File

@@ -1,33 +0,0 @@
package com.bitwarden.authenticator.data.platform.datasource.network.serializer
import kotlinx.serialization.KSerializer
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter
/**
* Used to serialize and deserialize [ZonedDateTime].
*/
class ZonedDateTimeSerializer : KSerializer<ZonedDateTime> {
private val dateTimeFormatterDeserialization = DateTimeFormatter
.ofPattern("yyyy-MM-dd'T'HH:mm:ss[.][:][SSSSSSS][SSSSSS][SSSSS][SSSS][SSS][SS][S]X")
private val dateTimeFormatterSerialization =
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSX")
override val descriptor: SerialDescriptor
get() = PrimitiveSerialDescriptor(serialName = "ZonedDateTime", kind = PrimitiveKind.STRING)
override fun deserialize(decoder: Decoder): ZonedDateTime =
decoder.decodeString().let { dateString ->
ZonedDateTime.parse(dateString, dateTimeFormatterDeserialization)
}
override fun serialize(encoder: Encoder, value: ZonedDateTime) {
encoder.encodeString(dateTimeFormatterSerialization.format(value))
}
}

View File

@@ -1,7 +1,7 @@
package com.bitwarden.authenticator.data.platform.base
import com.bitwarden.authenticator.data.platform.datasource.network.core.ResultCallAdapterFactory
import com.bitwarden.authenticator.data.platform.datasource.network.di.PlatformNetworkModule
import com.bitwarden.core.di.CoreModule
import okhttp3.HttpUrl
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.mockwebserver.MockWebServer
@@ -14,7 +14,7 @@ import retrofit2.converter.kotlinx.serialization.asConverterFactory
*/
abstract class BaseServiceTest {
protected val json = PlatformNetworkModule.providesJson()
protected val json = CoreModule.providesJson()
protected val server = MockWebServer().apply { start() }

View File

@@ -4,10 +4,10 @@ import androidx.core.content.edit
import app.cash.turbine.test
import com.bitwarden.authenticator.data.platform.base.FakeSharedPreferences
import com.bitwarden.authenticator.data.platform.datasource.disk.model.ServerConfig
import com.bitwarden.authenticator.data.platform.datasource.network.di.PlatformNetworkModule
import com.bitwarden.authenticator.data.platform.datasource.network.model.ConfigResponseJson
import com.bitwarden.authenticator.data.platform.datasource.network.model.ConfigResponseJson.EnvironmentJson
import com.bitwarden.authenticator.data.platform.datasource.network.model.ConfigResponseJson.ServerJson
import com.bitwarden.core.di.CoreModule
import kotlinx.coroutines.test.runTest
import kotlinx.serialization.json.JsonPrimitive
import org.junit.jupiter.api.Assertions.assertEquals
@@ -16,7 +16,7 @@ import org.junit.jupiter.api.Test
import java.time.Instant
class ConfigDiskSourceTest {
private val json = PlatformNetworkModule.providesJson()
private val json = CoreModule.providesJson()
private val fakeSharedPreferences = FakeSharedPreferences()

View File

@@ -4,8 +4,8 @@ import androidx.core.content.edit
import app.cash.turbine.test
import com.bitwarden.authenticator.data.platform.base.FakeSharedPreferences
import com.bitwarden.authenticator.data.platform.datasource.disk.model.FeatureFlagsConfiguration
import com.bitwarden.authenticator.data.platform.datasource.network.di.PlatformNetworkModule
import com.bitwarden.authenticator.data.platform.manager.model.FlagKey
import com.bitwarden.core.di.CoreModule
import kotlinx.coroutines.test.runTest
import kotlinx.serialization.json.JsonPrimitive
import org.junit.jupiter.api.Assertions.assertEquals
@@ -13,7 +13,7 @@ import org.junit.jupiter.api.Assertions.assertNull
import org.junit.jupiter.api.Test
class FeatureFlagDiskSourceTest {
private val json = PlatformNetworkModule.providesJson()
private val json = CoreModule.providesJson()
private val fakeSharedPreferences = FakeSharedPreferences()
@@ -58,7 +58,7 @@ class FeatureFlagDiskSourceTest {
private const val FEATURE_FLAGS_CONFIGURATION_JSON = """
{
"featureFlags" : {
"bitwarden-authentication-enabled" : true
"bitwarden-authentication-enabled" : true
}
}

View File

@@ -1,99 +0,0 @@
package com.bitwarden.authenticator.data.platform.datasource.network.serializer
import com.bitwarden.authenticator.data.platform.datasource.network.di.PlatformNetworkModule
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.encodeToJsonElement
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
import java.time.ZoneId
import java.time.ZoneOffset
import java.time.ZonedDateTime
class ZonedDateTimeSerializerTest {
private val json = PlatformNetworkModule.providesJson()
@Test
fun `properly deserializes raw JSON to ZonedDateTime`() {
assertEquals(
ZonedDateTimeData(
dataAsZonedDateTime = ZonedDateTime.of(
2023,
10,
6,
17,
22,
28,
440000000,
ZoneOffset.UTC,
),
),
json.decodeFromString<ZonedDateTimeData>(
"""
{
"dataAsZonedDateTime": "2023-10-06T17:22:28.44Z"
}
""",
),
)
}
@Test
fun `properly deserializes raw JSON with nano seconds to ZonedDateTime`() {
assertEquals(
ZonedDateTimeData(
dataAsZonedDateTime = ZonedDateTime.of(
2023,
8,
1,
16,
13,
3,
502391000,
ZoneOffset.UTC,
),
),
json.decodeFromString<ZonedDateTimeData>(
"""
{
"dataAsZonedDateTime": "2023-08-01T16:13:03.502391Z"
}
""",
),
)
}
@Test
fun `properly serializes external model back to raw JSON`() {
assertEquals(
json.parseToJsonElement(
"""
{
"dataAsZonedDateTime": "2023-10-06T17:22:28.440Z"
}
""",
),
json.encodeToJsonElement(
ZonedDateTimeData(
dataAsZonedDateTime = ZonedDateTime.of(
2023,
10,
6,
17,
22,
28,
440000000,
ZoneId.of("UTC"),
),
),
),
)
}
}
@Serializable
private data class ZonedDateTimeData(
@Serializable(ZonedDateTimeSerializer::class)
@SerialName("dataAsZonedDateTime")
val dataAsZonedDateTime: ZonedDateTime,
)