Skip to content

Instantly share code, notes, and snippets.

@beigirad
Last active September 19, 2023 12:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save beigirad/05802ca153dfa178686063d004a70e0c to your computer and use it in GitHub Desktop.
Save beigirad/05802ca153dfa178686063d004a70e0c to your computer and use it in GitHub Desktop.
Moshi Json Adapter for Koltinx Immutable List/Collection
package com.example
import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.JsonAdapter.Factory
import com.squareup.moshi.JsonReader
import com.squareup.moshi.JsonWriter
import com.squareup.moshi.Types
import com.squareup.moshi.rawType
import kotlinx.collections.immutable.ImmutableList
/**
* A wrapper class that delegates adaption of type [T] (like [ImmutableList]) into [Delegate] (like [List])
*
* inspired from https://github.com/square/moshi/issues/449
* source: https://gist.github.com/beigirad/05802ca153dfa178686063d004a70e0c
*/
class DelegatingAdapter<T, Delegate> private constructor(
private val delegateAdapter: JsonAdapter<Delegate>,
private val fromDelegate: (Delegate?) -> T?,
private val toDelegate: (T?) -> Delegate?,
) : JsonAdapter<T>() {
override fun fromJson(reader: JsonReader): T? {
val delegate: Delegate? = delegateAdapter.fromJson(reader)
return fromDelegate.invoke(delegate)
}
override fun toJson(writer: JsonWriter, value: T?) {
delegateAdapter.toJson(writer, toDelegate.invoke(value))
}
companion object {
/**
* Creates a factory for [T] using the already-existing factory for [Delegate],
* and converting between [T] and [Delegate] using the `fromDelegate` and
* `toDelegate` arguments.
*
* todo: this factory is currently only supports parametrized types
*/
fun <T, Delegate> factory(
delegatingType: Class<T>,
delegateType: Class<Delegate>,
fromDelegate: (Delegate?) -> T?,
toDelegate: (T?) -> Delegate?,
): Factory = Factory { incomingType, annotations, moshi ->
if (annotations.isNotEmpty()) return@Factory null
if (incomingType.rawType != delegatingType) return@Factory null
val delegateRawType = delegateType.rawType
val elementType = Types.collectionElementType(incomingType, delegateRawType)
val genericDelegateType = Types.newParameterizedType(delegateRawType, elementType)
val delegateAdapter = moshi.adapter<Delegate>(genericDelegateType)
DelegatingAdapter(delegateAdapter, fromDelegate, toDelegate)
}
}
}
Moshi.Builder()
.add(DelegatingAdapter.factory(ImmutableList::class.java, List::class.java, { it?.toImmutableList() }, { it }))
.add(DelegatingAdapter.factory(ImmutableSet::class.java, Set::class.java, { it?.toImmutableSet() }, { it }))
.add(DelegatingAdapter.factory(ImmutableMap::class.java, Map::class.java, { it?.toImmutableMap() }, { it }))
.build()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment