From a27cba5e0ff3a2b846609fe21b26c5483816fe7c Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 31 Dec 2022 13:20:03 +0700 Subject: [PATCH] =?UTF-8?q?=D0=9F=D0=BE=D0=BA=D0=B8=D0=B4=D0=B0=D0=B5?= =?UTF-8?q?=D0=BC=D1=81=D1=8F=20=D0=B8=D1=81=D0=BA=D0=BB=D1=8E=D1=87=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D1=8F=D0=BC=D0=B8=3F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kstarbound/io/json/BuilderAdapter.kt | 55 +++++++++++++++---- 1 file changed, 43 insertions(+), 12 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/io/json/BuilderAdapter.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/io/json/BuilderAdapter.kt index 105dc174..2604e120 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/io/json/BuilderAdapter.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/io/json/BuilderAdapter.kt @@ -10,6 +10,7 @@ import com.google.gson.stream.JsonWriter import it.unimi.dsi.fastutil.objects.ObjectArraySet import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet import org.apache.logging.log4j.LogManager +import ru.dbotthepony.kstarbound.util.NotNullVar import kotlin.reflect.KClass import kotlin.reflect.KMutableProperty1 import kotlin.reflect.full.isSubclassOf @@ -37,7 +38,7 @@ class BuilderAdapter private constructor( /** * Свойства объекта [T], которые можно выставлять */ - val properties: ImmutableMap>, + val properties: ImmutableMap>, /** * Ключи, которые необходимо игнорировать при чтении JSON @@ -51,7 +52,7 @@ class BuilderAdapter private constructor( } override fun read(reader: JsonReader): T { - val missing = ObjectArraySet>() + val missing = ObjectArraySet>() missing.addAll(properties.values) reader.beginObject() @@ -73,17 +74,17 @@ class BuilderAdapter private constructor( val peek = reader.peek() 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) { - property.property.set(instance, null) + property.set(instance, null) reader.nextNull() } else { val readValue = property.adapter.read(reader) - property.property.set(instance, readValue) + property.set(instance, readValue) check(missing.remove(property)) } } 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 { if (!loggedMisses.contains(name)) { @@ -98,8 +99,24 @@ class BuilderAdapter private constructor( reader.endObject() for (property in missing) { - if (property.mustBePresent == null) { - // null - проверяем, есть ли делегат + if (property.mustBePresent == true) { + 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 private constructor( data class WrappedProperty( val property: KMutableProperty1, val adapter: TypeAdapter, + /** + * @see PropertyConfigurator.mustBePresent + */ val mustBePresent: Boolean?, ) { + inline val name get() = property.name // кеш val returnType = property.returnType + + // так как дженерики тут немного слабенькие + // Так что вот так... + @Suppress("unchecked_cast") + fun set(receiver: T, value: Any?) { + property.set(receiver, value as V) + } } class PropertyConfigurator( @@ -121,6 +149,10 @@ class BuilderAdapter private constructor( ) { /** * Обязана ли присутствовать эта переменная внутри JSON структуры. + * + * * `true` - всегда кидать исключения + * * `false` - никогда не кидать исключения + * * `null` - кидать исключения на усмотрение реализации (по умолчанию) */ var mustBePresent: Boolean? = null } @@ -165,7 +197,7 @@ class BuilderAdapter private constructor( 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, configurator) } @@ -178,12 +210,11 @@ class BuilderAdapter private constructor( return this } - @Suppress("unchecked_cast") fun build(): BuilderAdapter { - val map = ImmutableMap.Builder>() + val map = ImmutableMap.Builder>() for (property in properties) - map.put(property.property.name, property as WrappedProperty) + map.put(property.property.name, property) return BuilderAdapter(factory, map.build(), ImmutableSet.copyOf(ignoreKeys)) }