diff --git a/src/main/kotlin/com/statsig/sdk/DynamicConfig.kt b/src/main/kotlin/com/statsig/sdk/DynamicConfig.kt index 4b44857..21698aa 100644 --- a/src/main/kotlin/com/statsig/sdk/DynamicConfig.kt +++ b/src/main/kotlin/com/statsig/sdk/DynamicConfig.kt @@ -1,7 +1,5 @@ package com.statsig.sdk -import com.google.gson.Gson - /** * A helper class for interfacing with Dynamic Configs defined in the Statsig console */ @@ -132,7 +130,7 @@ class DynamicConfig( } fun getExposureMetadata(): String { - return Gson().toJson( + return Utils.PLAIN_GSON.toJson( mapOf( "config" to this.name, "ruleID" to this.ruleID, diff --git a/src/main/kotlin/com/statsig/sdk/ErrorBoundary.kt b/src/main/kotlin/com/statsig/sdk/ErrorBoundary.kt index 7b51013..949b10c 100644 --- a/src/main/kotlin/com/statsig/sdk/ErrorBoundary.kt +++ b/src/main/kotlin/com/statsig/sdk/ErrorBoundary.kt @@ -1,6 +1,5 @@ package com.statsig.sdk -import com.google.gson.Gson import kotlinx.coroutines.* import okhttp3.Call import okhttp3.Callback @@ -93,7 +92,7 @@ internal class ErrorBoundary(private val apiKey: String, private val options: St if (safeInfo.length > maxInfoLength) { safeInfo = safeInfo.substring(0, maxInfoLength) } - val optionsCopy = Gson().toJson(options.getLoggingCopy()) + val optionsCopy = Utils.PLAIN_GSON.toJson(options.getLoggingCopy()) val body = """{ "tag": "$tag", "exception": "${ex.javaClass.name}", diff --git a/src/main/kotlin/com/statsig/sdk/Evaluator.kt b/src/main/kotlin/com/statsig/sdk/Evaluator.kt index c73cf7b..375c015 100644 --- a/src/main/kotlin/com/statsig/sdk/Evaluator.kt +++ b/src/main/kotlin/com/statsig/sdk/Evaluator.kt @@ -42,7 +42,6 @@ internal class Evaluator( private var configOverrides: MutableMap> = HashMap() private var layerOverrides: MutableMap> = HashMap() private var hashLookupTable: MutableMap = HashMap() - private val gson = Utils.getGson() private val logger = options.customLogger private val calendarOne = Calendar.getInstance() diff --git a/src/main/kotlin/com/statsig/sdk/Hashing.kt b/src/main/kotlin/com/statsig/sdk/Hashing.kt index 1128976..0b88e9d 100644 --- a/src/main/kotlin/com/statsig/sdk/Hashing.kt +++ b/src/main/kotlin/com/statsig/sdk/Hashing.kt @@ -1,6 +1,5 @@ package com.statsig.sdk -import com.google.gson.Gson import java.security.MessageDigest import java.util.Base64 @@ -22,8 +21,7 @@ class Hashing { } fun djb2ForMap(map: Map): String { - val gson = Gson() - return djb2(gson.toJson(Utils.sortMap(map))) + return djb2(Utils.PLAIN_GSON.toJson(Utils.sortMap(map))) } fun sha256(input: String): String { diff --git a/src/main/kotlin/com/statsig/sdk/Layer.kt b/src/main/kotlin/com/statsig/sdk/Layer.kt index 0f9bae5..88de326 100644 --- a/src/main/kotlin/com/statsig/sdk/Layer.kt +++ b/src/main/kotlin/com/statsig/sdk/Layer.kt @@ -1,7 +1,5 @@ package com.statsig.sdk -import com.google.gson.Gson - typealias OnLayerExposure = (layerExposureEventData: LayerExposureEventData) -> Unit internal typealias OnLayerExposureInternal = (layer: Layer, parameterName: String) -> Unit @@ -125,7 +123,7 @@ class Layer internal constructor( * Legacy exposure data at the layer level. Should NOT be used in new code as this will cause over exposure. */ fun getLegacyExposureMetadata(): String { - return Gson().toJson( + return Utils.PLAIN_GSON.toJson( mapOf( "config" to this.name, "ruleID" to this.ruleID, diff --git a/src/main/kotlin/com/statsig/sdk/SpecStore.kt b/src/main/kotlin/com/statsig/sdk/SpecStore.kt index 708e96b..f19ca26 100644 --- a/src/main/kotlin/com/statsig/sdk/SpecStore.kt +++ b/src/main/kotlin/com/statsig/sdk/SpecStore.kt @@ -1,8 +1,6 @@ package com.statsig.sdk -import com.google.gson.Gson import com.google.gson.GsonBuilder -import com.google.gson.reflect.TypeToken import com.statsig.sdk.datastore.IDataStore import com.statsig.sdk.network.StatsigTransport import kotlinx.coroutines.* @@ -20,6 +18,10 @@ internal class SpecStore( private val sdkConfigs: SDKConfigs, private val serverSecret: String, ) { + companion object { + val PRETTY_PRINTING_GSON = GsonBuilder().setPrettyPrinting().create() + } + private var initTime: Long = 0 private var evalReason: EvaluationReason = EvaluationReason.UNINITIALIZED private var downloadIDListCallCount: Long = 0 @@ -42,9 +44,6 @@ internal class SpecStore( specUpdater.registerConfigSpecListener(::processDownloadedConfigs) } - private val gson = Utils.getGson() - private inline fun Gson.fromJson(json: String) = fromJson(json, object : TypeToken() {}.type) - suspend fun initialize(): FailureDetails? { if (!options.localMode) { specUpdater.initialize() @@ -203,7 +202,7 @@ internal class SpecStore( var configString = "" try { - configString = gson.toJson(configSpecs) + configString = Utils.GSON.toJson(configSpecs) } catch (e: Exception) { errorBoundary.logException("fireRulesUpdatedCallback", e) options.customLogger.error("An exception was caught when fire callback: $e") @@ -419,8 +418,7 @@ internal class SpecStore( dataStore: IDataStore, response: APIDownloadedConfigs, ): APIDownloadedConfigs { - val gson = GsonBuilder().setPrettyPrinting().create() - val specs: String = gson.toJson(response) + val specs: String = PRETTY_PRINTING_GSON.toJson(response) val adapterKey = dataStore.dataStoreKey dataStore.set(adapterKey, specs) diff --git a/src/main/kotlin/com/statsig/sdk/SpecUpdater.kt b/src/main/kotlin/com/statsig/sdk/SpecUpdater.kt index 0214492..ec593d1 100644 --- a/src/main/kotlin/com/statsig/sdk/SpecUpdater.kt +++ b/src/main/kotlin/com/statsig/sdk/SpecUpdater.kt @@ -1,8 +1,6 @@ package com.statsig.sdk -import com.google.gson.Gson import com.google.gson.JsonSyntaxException -import com.google.gson.reflect.TypeToken import com.statsig.sdk.network.StatsigTransport import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job @@ -31,9 +29,6 @@ internal class SpecUpdater( private var backgroundDownloadIDLists: Job? = null private val logger = options.customLogger - private val gson = Utils.getGson() - private inline fun Gson.fromJson(json: String) = fromJson(json, object : TypeToken() {}.type) - fun initialize() { transport.setStreamingFallback(NetworkEndpoint.DOWNLOAD_CONFIG_SPECS) { this.transport.downloadConfigSpecsFromStatsig( @@ -133,7 +128,7 @@ internal class SpecUpdater( suspend fun updateIDLists(): Map? { return try { val response = transport.getIDLists() ?: return null - gson.fromJson>(response) + Utils.GSON.fromJson>(response) } catch (e: JsonSyntaxException) { null } @@ -147,7 +142,7 @@ internal class SpecUpdater( return Pair(null, FailureDetails(FailureReason.EMPTY_SPEC)) } try { - return Pair(gson.fromJson(specs, APIDownloadedConfigs::class.java), null) + return Pair(Utils.GSON.fromJson(specs, APIDownloadedConfigs::class.java), null) } catch (e: JsonSyntaxException) { errorBoundary.logException("parseConfigSpecs", e) logger.error("An exception was caught when parsing config specs: $e") @@ -160,7 +155,7 @@ internal class SpecUpdater( return Pair(null, response.second) } try { - val configs = gson.fromJson(response.first, APIDownloadedConfigs::class.java) + val configs = Utils.GSON.fromJson(response.first, APIDownloadedConfigs::class.java) if (configs.hashedSDKKeyUsed != null && configs.hashedSDKKeyUsed != Hashing.djb2(serverSecret)) { return Pair(null, FailureDetails(FailureReason.PARSE_RESPONSE_ERROR)) } @@ -177,7 +172,7 @@ internal class SpecUpdater( return null } try { - return gson.fromJson>(lists) + return Utils.GSON.fromJson>(lists) } catch (e: JsonSyntaxException) { errorBoundary.logException("parseIDLists", e) logger.warn("An exception was caught when parsing ID lists: $e") diff --git a/src/main/kotlin/com/statsig/sdk/StatsigLogger.kt b/src/main/kotlin/com/statsig/sdk/StatsigLogger.kt index 145197e..e0edd9c 100644 --- a/src/main/kotlin/com/statsig/sdk/StatsigLogger.kt +++ b/src/main/kotlin/com/statsig/sdk/StatsigLogger.kt @@ -54,7 +54,6 @@ internal class StatsigLogger( deduper.clear() } } - private val gson = Utils.getGson() internal var diagnostics: Diagnostics? = null private var eventQueueSize: Int? = null private val logger = statsigOptions.customLogger @@ -181,8 +180,8 @@ internal class StatsigLogger( val event = StatsigEvent(DIAGNOSTICS_EVENT) event.eventMetadata = mapOf( "context" to context.toString().lowercase(), - "markers" to gson.toJson(markers), - "statsigOptions" to gson.toJson(statsigOptions.getLoggingCopy()), + "markers" to Utils.GSON.toJson(markers), + "statsigOptions" to Utils.GSON.toJson(statsigOptions.getLoggingCopy()), ) log(event) } @@ -198,7 +197,7 @@ internal class StatsigLogger( val event = StatsigEvent(DIAGNOSTICS_EVENT) event.eventMetadata = mapOf( "context" to context.name.lowercase(), - "markers" to gson.toJson(markers), + "markers" to Utils.GSON.toJson(markers), ) if (statsigOptions.disableAllLogging) { return diff --git a/src/main/kotlin/com/statsig/sdk/StatsigMetadata.kt b/src/main/kotlin/com/statsig/sdk/StatsigMetadata.kt index 5a3e349..c4d2ccb 100644 --- a/src/main/kotlin/com/statsig/sdk/StatsigMetadata.kt +++ b/src/main/kotlin/com/statsig/sdk/StatsigMetadata.kt @@ -18,7 +18,6 @@ internal data class StatsigMetadata(@SerializedName("sdkType") var sdkType: Stri VERSION } fun asJson(): String { - val gson = Utils.getGson() - return gson.toJson(this) + return Utils.GSON.toJson(this) } } diff --git a/src/main/kotlin/com/statsig/sdk/StatsigServer.kt b/src/main/kotlin/com/statsig/sdk/StatsigServer.kt index 76ab213..42b5cb3 100644 --- a/src/main/kotlin/com/statsig/sdk/StatsigServer.kt +++ b/src/main/kotlin/com/statsig/sdk/StatsigServer.kt @@ -273,8 +273,6 @@ sealed class StatsigServer { private class StatsigServerImpl() : StatsigServer() { - private val gson = Utils.getGson() - override lateinit var errorBoundary: ErrorBoundary private lateinit var coroutineExceptionHandler: CoroutineExceptionHandler private lateinit var statsigJob: CompletableJob @@ -1228,7 +1226,7 @@ private class StatsigServerImpl() : normalizedUser, layer, paramName, - gson.toJson(metadata), + Utils.GSON.toJson(metadata), ), ) } else { diff --git a/src/main/kotlin/com/statsig/sdk/Utils.kt b/src/main/kotlin/com/statsig/sdk/Utils.kt index ad5c91f..5da333e 100644 --- a/src/main/kotlin/com/statsig/sdk/Utils.kt +++ b/src/main/kotlin/com/statsig/sdk/Utils.kt @@ -2,14 +2,18 @@ package com.statsig.sdk import com.google.gson.Gson import com.google.gson.GsonBuilder import com.google.gson.ToNumberPolicy +import com.google.gson.reflect.TypeToken import java.util.* +inline fun Gson.fromJson(json: String): T = fromJson(json, object : TypeToken() {}.type) + internal class Utils { companion object { fun getTimeInMillis(): Long { return System.currentTimeMillis() } - fun getGson(): Gson = GsonBuilder().setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE).create() + val GSON: Gson = GsonBuilder().setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE).create() + val PLAIN_GSON = Gson() fun toStringOrEmpty(value: Any?): String { return value?.toString() ?: "" } diff --git a/src/main/kotlin/com/statsig/sdk/network/HTTPHelper.kt b/src/main/kotlin/com/statsig/sdk/network/HTTPHelper.kt index 0efac32..2f72756 100644 --- a/src/main/kotlin/com/statsig/sdk/network/HTTPHelper.kt +++ b/src/main/kotlin/com/statsig/sdk/network/HTTPHelper.kt @@ -16,7 +16,6 @@ internal class HTTPHelper( private var diagnostics: Diagnostics? = null private val logger = options.customLogger - private val gson = Utils.getGson() private val json: MediaType = "application/json; charset=utf-8".toMediaType() fun setDiagnostics(diagnostics: Diagnostics) { @@ -34,7 +33,7 @@ internal class HTTPHelper( val request = Request.Builder() .url(url) if (body != null) { - val bodyJson = gson.toJson(body) + val bodyJson = Utils.GSON.toJson(body) request.post(bodyJson.toRequestBody(json)) } headers.forEach { (key, value) -> request.addHeader(key, value) } diff --git a/src/main/kotlin/com/statsig/sdk/network/HTTPWorker.kt b/src/main/kotlin/com/statsig/sdk/network/HTTPWorker.kt index 39f49c1..3bb4fe9 100644 --- a/src/main/kotlin/com/statsig/sdk/network/HTTPWorker.kt +++ b/src/main/kotlin/com/statsig/sdk/network/HTTPWorker.kt @@ -1,8 +1,6 @@ package com.statsig.sdk.network -import com.google.gson.Gson import com.google.gson.JsonParseException -import com.google.gson.reflect.TypeToken import com.statsig.sdk.* import kotlinx.coroutines.* import kotlinx.coroutines.flow.Flow @@ -55,7 +53,6 @@ internal class HTTPWorker( private val json: MediaType = "application/json; charset=utf-8".toMediaType() private val statsigHttpClient: OkHttpClient - private val gson = Utils.getGson() private var diagnostics: Diagnostics? = null private val logger = options.customLogger val apiForDownloadConfigSpecs = options.endpointProxyConfigs[NetworkEndpoint.DOWNLOAD_CONFIG_SPECS]?.proxyAddress ?: options.apiForDownloadConfigSpecs ?: options.api ?: STATSIG_CDN_URL_BASE @@ -63,8 +60,6 @@ internal class HTTPWorker( val apiForLogEvent = options.endpointProxyConfigs[NetworkEndpoint.LOG_EVENT]?.proxyAddress ?: options.api ?: STATSIG_API_URL_BASE private var eventsCount: String = "" - private inline fun Gson.fromJson(json: String) = fromJson(json, object : TypeToken() {}.type) - init { val clientBuilder = OkHttpClient.Builder() @@ -281,7 +276,7 @@ internal class HTTPWorker( return } - val bodyJson = gson.toJson(mapOf("events" to events, "statsigMetadata" to statsigMetadata)) + val bodyJson = Utils.GSON.toJson(mapOf("events" to events, "statsigMetadata" to statsigMetadata)) val requestBody: RequestBody = bodyJson.toRequestBody(json) eventsCount = events.size.toString()