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( property: KProperty1, val isFlat: Boolean, val mustBePresent: Boolean? = null, val isIgnored: Boolean = false, isMarkedNullable: Boolean? = null, ) { @Suppress("CanBePrimaryConstructorProperty") open val property: KProperty1 = property val name: String get() = property.name var adapter: TypeAdapter 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 } else { adapter = gson.getAdapter(TypeToken.getParameterized(KOptional.NotNull::class.java, subtype.type!!.javaType)) as TypeAdapter } } else { adapter = gson.getAdapter(token) as TypeAdapter } } } } class ReferencedMutableProperty(override val property: KMutableProperty1, isFlat: Boolean, mustBePresent: Boolean?) : ReferencedProperty(property, isFlat, mustBePresent) { fun set(instance: T, value: Any?) { (this.property as KMutableProperty1).set(instance, value) } }