Skip to content

Instantly share code, notes, and snippets.

@jishindev
Last active September 18, 2021 12:26
Show Gist options
  • Save jishindev/9fd8f0191225dc8f0d1f7a6f6f0511a1 to your computer and use it in GitHub Desktop.
Save jishindev/9fd8f0191225dc8f0d1f7a6f6f0511a1 to your computer and use it in GitHub Desktop.
Kotlin | Moshi Type converters and adapters for common use cases. Will be updated with new ones.
@Suppress("UNCHECKED_CAST")
class ArrayListAdapter<T>(private val adapter: JsonAdapter<T>) : JsonAdapter<ArrayList<T>>() {
@Throws(IOException::class)
override fun fromJson(reader: JsonReader): ArrayList<T>? {
val arrayList = arrayListOf<T>()
reader.beginArray()
while (reader.hasNext()) {
(adapter.fromJson(reader))?.let { arrayList.add(it) }
}
reader.endArray()
return arrayList
}
@Throws(IOException::class)
override fun toJson(writer: JsonWriter, value: ArrayList<T>?) {
value ?: return
writer.beginArray()
for (element in value) {
adapter.toJson(writer, element)
}
writer.endArray()
}
class Factory<T : Any> : JsonAdapter.Factory {
override fun create(type: Type, annotations: Set<Annotation>, moshi: Moshi): JsonAdapter<*>? {
val rawType = Types.getRawType(type)
if (annotations.isNotEmpty()) return null
return if (rawType == ArrayList::class.java) {
newListAdapter<T>(type, moshi).nullSafe()
} else null
}
private fun <T : Any> newListAdapter(type: Type, moshi: Moshi): JsonAdapter<ArrayList<T>> {
val elementType = collectionElementType(type, ArrayList::class.java)
val elementAdapter = moshi.adapter<T>(elementType)
return ArrayListAdapter(elementAdapter)
}
}
}
/**
formats: yyyy-MM-dd, yyyy-MM-dd HH:mm:ss, HH:mm:ss etc
*/
@Retention(AnnotationRetention.RUNTIME)
@JsonQualifier
internal annotation class JsonDateTimeFormat(val format: String)
class DateTimeAdapter(private val format: String) : JsonAdapter<Date?>() {
override fun fromJson(reader: JsonReader): Date? {
val string = reader.nextString()
return SimpleDateFormat(format, Locale.getDefault()).parse(string)
}
override fun toJson(writer: JsonWriter, value: Date?) {
writer.value(SimpleDateFormat(format, Locale.getDefault()).format(value))
}
class Factory : JsonAdapter.Factory {
override fun create(type: Type, annotations: MutableSet<out Annotation>, moshi: Moshi): JsonAdapter<Date?>? {
if (annotations.size <= 1 && type != Date::class.java) return null
val annotation = annotations.iterator().next() as? JsonDateTimeFormat ?: return null
val format = annotation.format
return DateTimeAdapter(format).nullSafe()
}
}
}
class SafeEnumListAdapter<T : Enum<T>>(enumType: Class<T>) : JsonAdapter<List<T>>() {
private val nameStrings: Array<String>
private val constants: Array<T>
private val options: JsonReader.Options
init {
try {
constants = enumType.enumConstants
nameStrings = Array(constants.size) {
val constant = constants[it]
val annotation = enumType.getField(constant.name).getAnnotation(Json::class.java)
annotation?.name ?: constant.name
}
options = JsonReader.Options.of(*nameStrings)
} catch (e: NoSuchFieldException) {
throw AssertionError("Missing field in " + enumType.name, e)
}
}
@Throws(IOException::class)
override fun fromJson(reader: JsonReader): List<T> {
reader.beginArray()
val list = mutableListOf<T>()
while (reader.hasNext()) {
val index = reader.selectString(options)
if (index != -1) {
list += constants[index]
} else {
reader.skipValue()
}
}
reader.endArray()
return list
}
@Throws(IOException::class)
override fun toJson(writer: JsonWriter, value: List<T>?) {
if (value == null) {
throw IllegalArgumentException("Wrap in .nullSafe()")
}
writer.beginArray()
for (i in value.indices) {
writer.value(nameStrings[value[i].ordinal])
}
writer.endArray()
}
}
class UriAdapter : JsonAdapter<Uri>() {
companion object {
val FACTORY = Factory { type, _, _ ->
return@Factory if (type === Uri::class.java) {
UriAdapter()
} else {
null
}
}
}
@Throws(IOException::class)
override fun fromJson(reader: JsonReader): Uri {
return Uri.parse(reader.nextString())
}
@Throws(IOException::class)
override fun toJson(
writer: JsonWriter,
value: Uri?
) {
writer.value(value?.toString())
}
override fun toString(): String {
return "JsonAdapter(Uri)"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment