diff --git a/purchases/src/main/kotlin/com/revenuecat/purchases/customercenter/CustomerCenterConfigData.kt b/purchases/src/main/kotlin/com/revenuecat/purchases/customercenter/CustomerCenterConfigData.kt index f9524b74c8..91a39b9fb6 100644 --- a/purchases/src/main/kotlin/com/revenuecat/purchases/customercenter/CustomerCenterConfigData.kt +++ b/purchases/src/main/kotlin/com/revenuecat/purchases/customercenter/CustomerCenterConfigData.kt @@ -258,7 +258,7 @@ data class CustomerCenterConfigData( val type: ScreenType, val title: String, @Serializable(with = EmptyStringToNullSerializer::class) val subtitle: String? = null, - val paths: List, + @Serializable(with = HelpPathsSerializer::class) val paths: List, ) { @Serializable enum class ScreenType { diff --git a/purchases/src/main/kotlin/com/revenuecat/purchases/customercenter/HelpPathsSerializer.kt b/purchases/src/main/kotlin/com/revenuecat/purchases/customercenter/HelpPathsSerializer.kt new file mode 100644 index 0000000000..8bcf810b54 --- /dev/null +++ b/purchases/src/main/kotlin/com/revenuecat/purchases/customercenter/HelpPathsSerializer.kt @@ -0,0 +1,40 @@ +package com.revenuecat.purchases.customercenter + +import com.revenuecat.purchases.ExperimentalPreviewRevenueCatPurchasesAPI +import com.revenuecat.purchases.common.debugLog +import kotlinx.serialization.KSerializer +import kotlinx.serialization.builtins.ListSerializer +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import kotlinx.serialization.json.JsonDecoder +import kotlinx.serialization.json.jsonArray + +@OptIn(ExperimentalPreviewRevenueCatPurchasesAPI::class) +internal object HelpPathsSerializer : KSerializer> { + override val descriptor: SerialDescriptor = ListSerializer( + CustomerCenterConfigData.HelpPath.serializer(), + ).descriptor + + override fun deserialize(decoder: Decoder): List { + val list = mutableListOf() + val jsonInput = decoder as? JsonDecoder ?: error("Can be deserialized only by JSON") + val jsonArray = jsonInput.decodeJsonElement().jsonArray + + jsonArray.forEach { jsonElement -> + try { + list.add( + jsonInput.json.decodeFromJsonElement(CustomerCenterConfigData.HelpPath.serializer(), jsonElement), + ) + } catch (e: IllegalArgumentException) { + debugLog("Issue deserializing CustomerCenter HelpPath. Ignoring. Error: $e") + } + } + + return list + } + + override fun serialize(encoder: Encoder, value: List) { + ListSerializer(CustomerCenterConfigData.HelpPath.serializer()).serialize(encoder, value) + } +} diff --git a/purchases/src/test/java/com/revenuecat/purchases/customercenter/CustomerCenterConfigDataTest.kt b/purchases/src/test/java/com/revenuecat/purchases/customercenter/CustomerCenterConfigDataTest.kt index e85014f4ec..dec3d8877c 100644 --- a/purchases/src/test/java/com/revenuecat/purchases/customercenter/CustomerCenterConfigDataTest.kt +++ b/purchases/src/test/java/com/revenuecat/purchases/customercenter/CustomerCenterConfigDataTest.kt @@ -4,6 +4,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import com.revenuecat.purchases.ExperimentalPreviewRevenueCatPurchasesAPI import com.revenuecat.purchases.common.Backend import org.assertj.core.api.Assertions.assertThat +import org.json.JSONObject import org.junit.Test import org.junit.runner.RunWith import org.robolectric.annotation.Config @@ -144,10 +145,33 @@ class CustomerCenterConfigDataTest { assertThat(support.email).isEqualTo("support@example.com") } - private fun createSampleConfigData(): CustomerCenterConfigData { + @Test + fun `can parse json with unknown screen types`() { + val json = JSONObject(loadTestJSON()) + val screens = json.getJSONObject("customer_center").getJSONObject("screens") + screens.put("random_screen_id", screens.getJSONObject("MANAGEMENT")) + val configData = createSampleConfigData(json.toString()) + assertThat(configData.screens).hasSize(2) + } + + @Test + fun `can parse json with unknown path types`() { + val json = JSONObject(loadTestJSON()) + val managementScreenPaths = json + .getJSONObject("customer_center") + .getJSONObject("screens") + .getJSONObject("MANAGEMENT") + .getJSONArray("paths") + val firstPathClone = JSONObject(managementScreenPaths.getJSONObject(0).toString()) + managementScreenPaths.put(firstPathClone.put("type", "UNKNOWN_PATH_TYPE")) + val configData = createSampleConfigData(json.toString()) + assertThat(configData.screens[CustomerCenterConfigData.Screen.ScreenType.MANAGEMENT]!!.paths).hasSize(4) + } + + private fun createSampleConfigData(json: String = loadTestJSON()): CustomerCenterConfigData { return Backend.json.decodeFromString( CustomerCenterRoot.serializer(), - loadTestJSON() + json, ).customerCenter }