Покидаемся исключениями?

This commit is contained in:
DBotThePony 2022-12-31 13:20:03 +07:00
parent bfae6877c9
commit a27cba5e0f
Signed by: DBot
GPG Key ID: DCC23B5715498507

View File

@ -10,6 +10,7 @@ import com.google.gson.stream.JsonWriter
import it.unimi.dsi.fastutil.objects.ObjectArraySet import it.unimi.dsi.fastutil.objects.ObjectArraySet
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet
import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.LogManager
import ru.dbotthepony.kstarbound.util.NotNullVar
import kotlin.reflect.KClass import kotlin.reflect.KClass
import kotlin.reflect.KMutableProperty1 import kotlin.reflect.KMutableProperty1
import kotlin.reflect.full.isSubclassOf import kotlin.reflect.full.isSubclassOf
@ -37,7 +38,7 @@ class BuilderAdapter<T : Any> private constructor(
/** /**
* Свойства объекта [T], которые можно выставлять * Свойства объекта [T], которые можно выставлять
*/ */
val properties: ImmutableMap<String, WrappedProperty<T, Any?>>, val properties: ImmutableMap<String, WrappedProperty<T, *>>,
/** /**
* Ключи, которые необходимо игнорировать при чтении JSON * Ключи, которые необходимо игнорировать при чтении JSON
@ -51,7 +52,7 @@ class BuilderAdapter<T : Any> private constructor(
} }
override fun read(reader: JsonReader): T { override fun read(reader: JsonReader): T {
val missing = ObjectArraySet<WrappedProperty<T, Any?>>() val missing = ObjectArraySet<WrappedProperty<T, *>>()
missing.addAll(properties.values) missing.addAll(properties.values)
reader.beginObject() reader.beginObject()
@ -73,17 +74,17 @@ class BuilderAdapter<T : Any> private constructor(
val peek = reader.peek() val peek = reader.peek()
if (!property.returnType.isMarkedNullable && peek == JsonToken.NULL) { if (!property.returnType.isMarkedNullable && peek == JsonToken.NULL) {
throw NullPointerException("Property ${property.property.name} of ${instance::class.qualifiedName} does not accept nulls") throw NullPointerException("Property ${property.name} of ${instance::class.qualifiedName} does not accept nulls")
} else if (peek == JsonToken.NULL) { } else if (peek == JsonToken.NULL) {
property.property.set(instance, null) property.set(instance, null)
reader.nextNull() reader.nextNull()
} else { } else {
val readValue = property.adapter.read(reader) val readValue = property.adapter.read(reader)
property.property.set(instance, readValue) property.set(instance, readValue)
check(missing.remove(property)) check(missing.remove(property))
} }
} catch(err: Throwable) { } catch(err: Throwable) {
throw JsonSyntaxException("Reading property ${property.property.name} of ${instance::class.qualifiedName} near ${reader.path}", err) throw JsonSyntaxException("Reading property ${property.name} of ${instance::class.qualifiedName} near ${reader.path}", err)
} }
} else { } else {
if (!loggedMisses.contains(name)) { if (!loggedMisses.contains(name)) {
@ -98,8 +99,24 @@ class BuilderAdapter<T : Any> private constructor(
reader.endObject() reader.endObject()
for (property in missing) { for (property in missing) {
if (property.mustBePresent == null) { if (property.mustBePresent == true) {
// null - проверяем, есть ли делегат throw JsonSyntaxException("${instance::class.qualifiedName} demands for ${property.name} to be present, however, it is missing")
} else if (property.mustBePresent == null) {
if (property.returnType.isMarkedNullable) {
continue
}
val delegate = property.property.getDelegate(instance)
if (delegate is NotNullVar<*> && !delegate.isInitialized) {
throw JsonSyntaxException("${property.name} in ${instance::class.qualifiedName} can not be null, but it is missing from JSON structure")
} else {
try {
property.property.get(instance)
} catch (err: Throwable) {
throw JsonSyntaxException("${property.name} in ${instance::class.qualifiedName} does not like it being missing from JSON structure", err)
}
}
} }
} }
@ -109,10 +126,21 @@ class BuilderAdapter<T : Any> private constructor(
data class WrappedProperty<T, V : Any?>( data class WrappedProperty<T, V : Any?>(
val property: KMutableProperty1<T, V>, val property: KMutableProperty1<T, V>,
val adapter: TypeAdapter<V>, val adapter: TypeAdapter<V>,
/**
* @see PropertyConfigurator.mustBePresent
*/
val mustBePresent: Boolean?, val mustBePresent: Boolean?,
) { ) {
inline val name get() = property.name
// кеш // кеш
val returnType = property.returnType val returnType = property.returnType
// так как дженерики тут немного слабенькие
// Так что вот так...
@Suppress("unchecked_cast")
fun set(receiver: T, value: Any?) {
property.set(receiver, value as V)
}
} }
class PropertyConfigurator<T, V : Any?>( class PropertyConfigurator<T, V : Any?>(
@ -121,6 +149,10 @@ class BuilderAdapter<T : Any> private constructor(
) { ) {
/** /**
* Обязана ли присутствовать эта переменная внутри JSON структуры. * Обязана ли присутствовать эта переменная внутри JSON структуры.
*
* * `true` - всегда кидать исключения
* * `false` - никогда не кидать исключения
* * `null` - кидать исключения на усмотрение реализации (по умолчанию)
*/ */
var mustBePresent: Boolean? = null var mustBePresent: Boolean? = null
} }
@ -165,7 +197,7 @@ class BuilderAdapter<T : Any> private constructor(
throw IllegalArgumentException("${property.name} is a Map, please use autoMap() method instead") throw IllegalArgumentException("${property.name} is a Map, please use autoMap() method instead")
} }
@Suppress("unchecked_cast") @Suppress("unchecked_cast") // classifier.java не имеет обозначенного типа
return add(property, LazyTypeProvider(classifier.java) as TypeAdapter<V>, configurator) return add(property, LazyTypeProvider(classifier.java) as TypeAdapter<V>, configurator)
} }
@ -178,12 +210,11 @@ class BuilderAdapter<T : Any> private constructor(
return this return this
} }
@Suppress("unchecked_cast")
fun build(): BuilderAdapter<T> { fun build(): BuilderAdapter<T> {
val map = ImmutableMap.Builder<String, WrappedProperty<T, Any?>>() val map = ImmutableMap.Builder<String, WrappedProperty<T, *>>()
for (property in properties) for (property in properties)
map.put(property.property.name, property as WrappedProperty<T, Any?>) map.put(property.property.name, property)
return BuilderAdapter(factory, map.build(), ImmutableSet.copyOf(ignoreKeys)) return BuilderAdapter(factory, map.build(), ImmutableSet.copyOf(ignoreKeys))
} }