money.rave.common.backend.gson.GsonKotlinAdapterFactory.kt Maven / Gradle / Ivy
package money.rave.common.backend.gson
import com.google.gson.Gson
import com.google.gson.JsonParseException
import com.google.gson.TypeAdapter
import com.google.gson.TypeAdapterFactory
import com.google.gson.reflect.TypeToken
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonWriter
import kotlin.reflect.KClass
import kotlin.reflect.full.declaredMemberProperties
import kotlin.reflect.jvm.isAccessible
class GsonKotlinAdapterFactory(
private val checkNulls: Boolean = true
) : TypeAdapterFactory {
private val Class<*>.isKotlinClass: Boolean
get() = declaredAnnotations.find { it.annotationClass.java.name == "kotlin.Metadata" } != null
override fun create(gson: Gson, type: TypeToken): TypeAdapter? {
if (!type.rawType.isKotlinClass)
return null
val kClass = (type.rawType as Class<*>).kotlin
@Suppress("UNCHECKED_CAST")
return Adapter(this, gson, type, kClass as KClass, checkNulls)
}
class Adapter(
factory: GsonKotlinAdapterFactory,
gson: Gson,
type: TypeToken,
private val kClass: KClass,
private val checkNulls: Boolean
) : TypeAdapter() {
val delegate: TypeAdapter = gson.getDelegateAdapter(factory, type)
override fun write(out: JsonWriter, value: T) {
delegate.write(out, value)
}
override fun read(input: JsonReader): T {
return delegate.read(input).apply {
if (checkNulls) doNullCheck(this)
}
}
private fun doNullCheck(value: T) {
kClass.declaredMemberProperties.forEach { prop ->
prop.isAccessible = true
if (!prop.returnType.isMarkedNullable && prop(value) == null)
throw JsonParseException(
"Field: '${prop.name}' in Class '${prop.returnType.javaClass.typeName}' is not marked nullable but found null value"
)
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy