Покидаемся исключениями?
This commit is contained in:
parent
bfae6877c9
commit
a27cba5e0f
@ -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))
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user