KStarbound/src/main/kotlin/ru/dbotthepony/kstarbound/json/builder/Properties.kt

64 lines
2.1 KiB
Kotlin

package ru.dbotthepony.kstarbound.json.builder
import com.google.gson.Gson
import com.google.gson.TypeAdapter
import com.google.gson.reflect.TypeToken
import ru.dbotthepony.kstarbound.util.KOptional
import kotlin.properties.Delegates
import kotlin.reflect.KMutableProperty1
import kotlin.reflect.KProperty1
import kotlin.reflect.KType
import kotlin.reflect.javaType
open class ReferencedProperty<T : Any, V>(
property: KProperty1<T, V>,
val isFlat: Boolean,
val mustBePresent: Boolean? = null,
val isIgnored: Boolean = false,
isMarkedNullable: Boolean? = null,
) {
@Suppress("CanBePrimaryConstructorProperty")
open val property: KProperty1<T, V> = property
val name: String get() = property.name
var adapter: TypeAdapter<V> by Delegates.notNull()
private set
val type: KType = property.returnType
val isMarkedNullable: Boolean = isMarkedNullable?.also {
if (it && !type.isMarkedNullable) throw IllegalArgumentException("Can't declare non-null property as nullable")
} ?: type.isMarkedNullable
operator fun component1() = property
operator fun component2() = adapter
private var isResolved = false
@OptIn(ExperimentalStdlibApi::class)
@Suppress("DEPRECATION")
fun resolve(gson: Gson) {
if (!isResolved) {
isResolved = true
val token = TypeToken.get(type.javaType)
if (token.rawType === KOptional::class.java && type.arguments.size == 1) {
val subtype = type.arguments[0]
if (subtype.type!!.isMarkedNullable) {
adapter = gson.getAdapter(TypeToken.getParameterized(KOptional.Nullable::class.java, subtype.type!!.javaType)) as TypeAdapter<V>
} else {
adapter = gson.getAdapter(TypeToken.getParameterized(KOptional.NotNull::class.java, subtype.type!!.javaType)) as TypeAdapter<V>
}
} else {
adapter = gson.getAdapter(token) as TypeAdapter<V>
}
}
}
}
class ReferencedMutableProperty<T : Any, V>(override val property: KMutableProperty1<T, V>, isFlat: Boolean, mustBePresent: Boolean?) : ReferencedProperty<T, V>(property, isFlat, mustBePresent) {
fun set(instance: T, value: Any?) {
(this.property as KMutableProperty1<T, Any?>).set(instance, value)
}
}