Ещё больше рефакторинга десериализера
This commit is contained in:
parent
b939373298
commit
53c4c3fa11
@ -1,7 +1,12 @@
|
|||||||
package ru.dbotthepony.kstarbound
|
package ru.dbotthepony.kstarbound
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList
|
import com.google.common.collect.ImmutableList
|
||||||
|
import com.google.common.collect.Interner
|
||||||
|
import com.google.common.collect.Interners
|
||||||
import com.google.gson.*
|
import com.google.gson.*
|
||||||
|
import com.google.gson.internal.bind.TypeAdapters
|
||||||
|
import com.google.gson.stream.JsonReader
|
||||||
|
import com.google.gson.stream.JsonWriter
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
|
||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap
|
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap
|
||||||
import org.apache.logging.log4j.LogManager
|
import org.apache.logging.log4j.LogManager
|
||||||
@ -104,6 +109,18 @@ object Starbound {
|
|||||||
val functionsAccess: Map<String, JsonFunction> = Collections.unmodifiableMap(functions)
|
val functionsAccess: Map<String, JsonFunction> = Collections.unmodifiableMap(functions)
|
||||||
val itemAccess: Map<String, ItemDefinition> = Collections.unmodifiableMap(items)
|
val itemAccess: Map<String, ItemDefinition> = Collections.unmodifiableMap(items)
|
||||||
|
|
||||||
|
val assetStringInterner: Interner<String> = Interners.newStrongInterner()
|
||||||
|
|
||||||
|
val stringTypeAdapter: TypeAdapter<String?> = object : TypeAdapter<String>() {
|
||||||
|
override fun write(out: JsonWriter, value: String) {
|
||||||
|
out.value(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun read(`in`: JsonReader): String {
|
||||||
|
return assetStringInterner.intern(TypeAdapters.STRING.read(`in`))
|
||||||
|
}
|
||||||
|
}.nullSafe()
|
||||||
|
|
||||||
val gson: Gson = GsonBuilder()
|
val gson: Gson = GsonBuilder()
|
||||||
.enableComplexMapKeySerialization()
|
.enableComplexMapKeySerialization()
|
||||||
.serializeNulls()
|
.serializeNulls()
|
||||||
@ -112,6 +129,9 @@ object Starbound {
|
|||||||
.setPrettyPrinting()
|
.setPrettyPrinting()
|
||||||
.registerTypeAdapter(Color::class.java, ColorTypeAdapter.nullSafe())
|
.registerTypeAdapter(Color::class.java, ColorTypeAdapter.nullSafe())
|
||||||
|
|
||||||
|
// чтоб строки всегда intern'ились
|
||||||
|
.registerTypeAdapter(stringTypeAdapter)
|
||||||
|
|
||||||
// math
|
// math
|
||||||
.registerTypeAdapter(AABB::class.java, AABBTypeAdapter)
|
.registerTypeAdapter(AABB::class.java, AABBTypeAdapter)
|
||||||
.registerTypeAdapter(AABBi::class.java, AABBiTypeAdapter)
|
.registerTypeAdapter(AABBi::class.java, AABBiTypeAdapter)
|
||||||
@ -137,6 +157,19 @@ object Starbound {
|
|||||||
|
|
||||||
.create()
|
.create()
|
||||||
|
|
||||||
|
@Suppress("unchecked_cast")
|
||||||
|
fun <T> getTypeAdapter(type: Class<T>): TypeAdapter<T> {
|
||||||
|
return when (type) {
|
||||||
|
Float::class.java -> TypeAdapters.FLOAT as TypeAdapter<T>
|
||||||
|
Double::class.java -> TypeAdapters.DOUBLE as TypeAdapter<T>
|
||||||
|
String::class.java -> stringTypeAdapter as TypeAdapter<T>
|
||||||
|
Int::class.java -> TypeAdapters.INTEGER as TypeAdapter<T>
|
||||||
|
Long::class.java -> TypeAdapters.LONG as TypeAdapter<T>
|
||||||
|
Boolean::class.java -> TypeAdapters.BOOLEAN as TypeAdapter<T>
|
||||||
|
else -> gson.getAdapter(type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var initializing = false
|
var initializing = false
|
||||||
private set
|
private set
|
||||||
var initialized = false
|
var initialized = false
|
||||||
@ -442,7 +475,8 @@ object Starbound {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun loadItemDefinitions(callback: (String) -> Unit) {
|
private fun loadItemDefinitions(callback: (String) -> Unit) {
|
||||||
val files = listOf(".item", ".currency", ".head", ".chest", ".legs")
|
//val files = listOf(".item", ".currency", ".head", ".chest", ".legs")
|
||||||
|
val files = listOf(".item", ".currency")
|
||||||
|
|
||||||
for (fs in fileSystems) {
|
for (fs in fileSystems) {
|
||||||
for (listedFile in fs.explore().filter { it.isFile }.filter { f -> files.any { f.name.endsWith(it) } }) {
|
for (listedFile in fs.explore().filter { it.isFile }.filter { f -> files.any { f.name.endsWith(it) } }) {
|
||||||
|
@ -313,7 +313,6 @@ data class ItemDefinition(
|
|||||||
.auto(FossilSetDescription::price)
|
.auto(FossilSetDescription::price)
|
||||||
.auto(FossilSetDescription::shortdescription)
|
.auto(FossilSetDescription::shortdescription)
|
||||||
.auto(FossilSetDescription::description)
|
.auto(FossilSetDescription::description)
|
||||||
.specifyStringInterner(ADAPTER.stringInterner)
|
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
val ARMOR_FRAMES_ADAPTER = KConcreteTypeAdapter.Builder(ArmorFrames::class)
|
val ARMOR_FRAMES_ADAPTER = KConcreteTypeAdapter.Builder(ArmorFrames::class)
|
||||||
|
@ -2,8 +2,6 @@ package ru.dbotthepony.kstarbound.io.json
|
|||||||
|
|
||||||
import com.google.common.collect.ImmutableList
|
import com.google.common.collect.ImmutableList
|
||||||
import com.google.common.collect.ImmutableMap
|
import com.google.common.collect.ImmutableMap
|
||||||
import com.google.common.collect.Interner
|
|
||||||
import com.google.common.collect.Interners
|
|
||||||
import com.google.gson.JsonArray
|
import com.google.gson.JsonArray
|
||||||
import com.google.gson.JsonObject
|
import com.google.gson.JsonObject
|
||||||
import com.google.gson.JsonParseException
|
import com.google.gson.JsonParseException
|
||||||
@ -27,145 +25,8 @@ import java.lang.reflect.Constructor
|
|||||||
import kotlin.jvm.internal.DefaultConstructorMarker
|
import kotlin.jvm.internal.DefaultConstructorMarker
|
||||||
import kotlin.reflect.*
|
import kotlin.reflect.*
|
||||||
import kotlin.reflect.full.isSubclassOf
|
import kotlin.reflect.full.isSubclassOf
|
||||||
import kotlin.reflect.full.isSuperclassOf
|
|
||||||
import kotlin.reflect.full.isSupertypeOf
|
import kotlin.reflect.full.isSupertypeOf
|
||||||
|
|
||||||
@Suppress("unchecked_cast")
|
|
||||||
private fun <T> resolveBound(bound: Class<T>, stringAdapter: TypeAdapter<String>): TypeAdapter<T> {
|
|
||||||
return when (bound) {
|
|
||||||
Float::class.java -> TypeAdapters.FLOAT as TypeAdapter<T>
|
|
||||||
Double::class.java -> TypeAdapters.DOUBLE as TypeAdapter<T>
|
|
||||||
String::class.java -> stringAdapter as TypeAdapter<T>
|
|
||||||
Int::class.java -> TypeAdapters.INTEGER as TypeAdapter<T>
|
|
||||||
Long::class.java -> TypeAdapters.LONG as TypeAdapter<T>
|
|
||||||
Boolean::class.java -> TypeAdapters.BOOLEAN as TypeAdapter<T>
|
|
||||||
else -> Starbound.gson.getAdapter(bound)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class ListAdapter<T>(private val type: Class<T>, private val stringAdapter: TypeAdapter<String>) : TypeAdapter<List<T>?>() {
|
|
||||||
private val resolvedBound by lazy { resolveBound(type, stringAdapter) }
|
|
||||||
|
|
||||||
override fun write(out: JsonWriter, value: List<T>?) {
|
|
||||||
out.beginArray()
|
|
||||||
|
|
||||||
if (value != null) {
|
|
||||||
val resolvedBound = resolvedBound
|
|
||||||
|
|
||||||
for (v in value) {
|
|
||||||
resolvedBound.write(out, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
out.endArray()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun read(reader: JsonReader): List<T> {
|
|
||||||
reader.beginArray()
|
|
||||||
|
|
||||||
val builder = ImmutableList.builder<T>()
|
|
||||||
val resolvedBound = resolvedBound
|
|
||||||
|
|
||||||
while (reader.peek() != JsonToken.END_ARRAY) {
|
|
||||||
val readObject = resolvedBound.read(reader) ?: throw JsonSyntaxException("List does not accept nulls")
|
|
||||||
builder.add(readObject as T)
|
|
||||||
}
|
|
||||||
|
|
||||||
reader.endArray()
|
|
||||||
|
|
||||||
return builder.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class MapAdapter<K, V>(private val keyType: Class<K>, private val valueType: Class<V>, private val stringAdapter: TypeAdapter<String>) : TypeAdapter<Map<K, V>?>() {
|
|
||||||
private val resolvedKey by lazy { resolveBound(keyType, stringAdapter) }
|
|
||||||
private val resolvedValue by lazy { resolveBound(valueType, stringAdapter) }
|
|
||||||
|
|
||||||
override fun write(out: JsonWriter, value: Map<K, V>?) {
|
|
||||||
out.beginArray()
|
|
||||||
|
|
||||||
if (value != null) {
|
|
||||||
val resolvedKey = resolvedKey
|
|
||||||
val resolvedValue = resolvedValue
|
|
||||||
|
|
||||||
for ((k, v) in value) {
|
|
||||||
out.beginArray()
|
|
||||||
resolvedKey.write(out, k)
|
|
||||||
resolvedValue.write(out, v)
|
|
||||||
out.endArray()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
out.endArray()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun read(reader: JsonReader): Map<K, V> {
|
|
||||||
reader.beginArray()
|
|
||||||
|
|
||||||
val builder = ImmutableMap.builder<K, V>()
|
|
||||||
|
|
||||||
val resolvedKey = resolvedKey
|
|
||||||
val resolvedValue = resolvedValue
|
|
||||||
|
|
||||||
while (reader.peek() != JsonToken.END_ARRAY) {
|
|
||||||
reader.beginArray()
|
|
||||||
builder.put(resolvedKey.read(reader), resolvedValue.read(reader))
|
|
||||||
reader.endArray()
|
|
||||||
}
|
|
||||||
|
|
||||||
reader.endArray()
|
|
||||||
|
|
||||||
return builder.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class StringMapAdapter<V>(private val type: Class<V>, private val stringAdapter: TypeAdapter<String>, private val interner: Interner<String>) : TypeAdapter<Map<String, V>?>() {
|
|
||||||
private val resolvedBound by lazy { resolveBound(type, stringAdapter) }
|
|
||||||
|
|
||||||
override fun write(out: JsonWriter, value: Map<String, V>?) {
|
|
||||||
val resolvedBound = resolvedBound
|
|
||||||
|
|
||||||
out.beginObject()
|
|
||||||
|
|
||||||
if (value != null) {
|
|
||||||
for ((k, v) in value) {
|
|
||||||
out.name(k)
|
|
||||||
resolvedBound.write(out, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
out.endObject()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun read(reader: JsonReader): Map<String, V> {
|
|
||||||
val builder = ImmutableMap.builder<String, V>()
|
|
||||||
|
|
||||||
reader.beginObject()
|
|
||||||
|
|
||||||
val resolvedBound = resolvedBound
|
|
||||||
|
|
||||||
while (reader.peek() != JsonToken.END_OBJECT) {
|
|
||||||
builder.put(interner.intern(reader.nextName()), resolvedBound.read(reader))
|
|
||||||
}
|
|
||||||
|
|
||||||
reader.endObject()
|
|
||||||
|
|
||||||
return builder.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class LazyTypeProvider<T : Any?>(private val bound: Class<T>) : TypeAdapter<T>() {
|
|
||||||
private val resolved by lazy { resolveBound(bound, TypeAdapters.STRING) }
|
|
||||||
|
|
||||||
override fun write(out: JsonWriter, value: T) {
|
|
||||||
resolved.write(out, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun read(`in`: JsonReader): T {
|
|
||||||
return resolved.read(`in`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private data class PackedProperty<Clazz : Any, T>(
|
private data class PackedProperty<Clazz : Any, T>(
|
||||||
val property: KProperty1<Clazz, T>,
|
val property: KProperty1<Clazz, T>,
|
||||||
val adapter: TypeAdapter<T>,
|
val adapter: TypeAdapter<T>,
|
||||||
@ -181,19 +42,18 @@ class KConcreteTypeAdapter<T : Any> private constructor(
|
|||||||
val bound: KClass<T>,
|
val bound: KClass<T>,
|
||||||
private val types: ImmutableList<PackedProperty<T, *>>,
|
private val types: ImmutableList<PackedProperty<T, *>>,
|
||||||
val asJsonArray: Boolean,
|
val asJsonArray: Boolean,
|
||||||
val stringInterner: Interner<String>,
|
|
||||||
val storesJson: Boolean
|
val storesJson: Boolean
|
||||||
) : TypeAdapter<T>() {
|
) : TypeAdapter<T>() {
|
||||||
private val mapped = Object2IntArrayMap<String>()
|
private val name2index = Object2IntArrayMap<String>()
|
||||||
private val loggedMisses = ObjectArraySet<String>()
|
private val loggedMisses = ObjectArraySet<String>()
|
||||||
|
|
||||||
var currentSymbolicName by ThreadLocal<String>()
|
var currentSymbolicName by ThreadLocal<String>()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
mapped.defaultReturnValue(-1)
|
name2index.defaultReturnValue(-1)
|
||||||
|
|
||||||
for ((i, pair) in types.withIndex()) {
|
for ((i, pair) in types.withIndex()) {
|
||||||
mapped[pair.property.name] = i
|
name2index[pair.property.name] = i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -328,7 +188,7 @@ class KConcreteTypeAdapter<T : Any> private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
reader = JsonTreeReader(readArray)
|
reader = JsonTreeReader(readArray)
|
||||||
readValues[readValues.size - 1] = enrollList(flattenJsonElement(readArray) as List<Any>, stringInterner::intern)
|
readValues[readValues.size - 1] = enrollList(flattenJsonElement(readArray) as List<Any>, Starbound.assetStringInterner::intern)
|
||||||
}
|
}
|
||||||
|
|
||||||
reader.beginArray()
|
reader.beginArray()
|
||||||
@ -373,14 +233,14 @@ class KConcreteTypeAdapter<T : Any> private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
reader = JsonTreeReader(readMap)
|
reader = JsonTreeReader(readMap)
|
||||||
readValues[readValues.size - 1] = enrollMap(flattenJsonElement(readMap) as Map<String, Any>, stringInterner::intern)
|
readValues[readValues.size - 1] = enrollMap(flattenJsonElement(readMap) as Map<String, Any>, Starbound.assetStringInterner::intern)
|
||||||
}
|
}
|
||||||
|
|
||||||
reader.beginObject()
|
reader.beginObject()
|
||||||
|
|
||||||
while (reader.peek() != JsonToken.END_OBJECT) {
|
while (reader.peek() != JsonToken.END_OBJECT) {
|
||||||
val name = reader.nextName()
|
val name = reader.nextName()
|
||||||
val fieldId = mapped.getInt(name)
|
val fieldId = name2index.getInt(name)
|
||||||
|
|
||||||
if (fieldId == -1) {
|
if (fieldId == -1) {
|
||||||
if (!storesJson && loggedMisses.add(name)) {
|
if (!storesJson && loggedMisses.add(name)) {
|
||||||
@ -498,7 +358,6 @@ class KConcreteTypeAdapter<T : Any> private constructor(
|
|||||||
*/
|
*/
|
||||||
class Builder<T : Any>(val clazz: KClass<T>) {
|
class Builder<T : Any>(val clazz: KClass<T>) {
|
||||||
private val types = ArrayList<PackedProperty<T, *>>()
|
private val types = ArrayList<PackedProperty<T, *>>()
|
||||||
var stringInterner: Interner<String> = Interners.newWeakInterner()
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Принимает ли класс *последним* аргументом JSON объект
|
* Принимает ли класс *последним* аргументом JSON объект
|
||||||
@ -515,21 +374,6 @@ class KConcreteTypeAdapter<T : Any> private constructor(
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
fun specifyStringInterner(interner: Interner<String>): Builder<T> {
|
|
||||||
stringInterner = interner
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
private val internedStringAdapter: TypeAdapter<String> = object : TypeAdapter<String>() {
|
|
||||||
override fun write(out: JsonWriter, value: String) {
|
|
||||||
return TypeAdapters.STRING.write(out, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun read(`in`: JsonReader): String {
|
|
||||||
return stringInterner.intern(TypeAdapters.STRING.read(`in`))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Добавляет поле с определённым адаптером
|
* Добавляет поле с определённым адаптером
|
||||||
*/
|
*/
|
||||||
@ -556,23 +400,7 @@ class KConcreteTypeAdapter<T : Any> private constructor(
|
|||||||
fun <In> auto(field: KProperty1<T, In>, transformer: (In) -> In = { it }): Builder<T> {
|
fun <In> auto(field: KProperty1<T, In>, transformer: (In) -> In = { it }): Builder<T> {
|
||||||
val returnType = field.returnType
|
val returnType = field.returnType
|
||||||
val classifier = returnType.classifier as? KClass<*> ?: throw ClassCastException("Unable to cast ${returnType.classifier} to KClass of property ${field.name}!")
|
val classifier = returnType.classifier as? KClass<*> ?: throw ClassCastException("Unable to cast ${returnType.classifier} to KClass of property ${field.name}!")
|
||||||
|
types.add(PackedProperty(field, LazyTypeProvider(classifier.java) as TypeAdapter<Any?>, transformer = transformer as (Any?) -> Any?))
|
||||||
if (classifier.isSuperclassOf(Float::class)) {
|
|
||||||
types.add(PackedProperty(field as KProperty1<T, Float>, TypeAdapters.FLOAT, transformer = transformer as (Number) -> Number))
|
|
||||||
} else if (classifier.isSuperclassOf(Double::class)) {
|
|
||||||
types.add(PackedProperty(field as KProperty1<T, Double>, TypeAdapters.DOUBLE, transformer = transformer as (Number) -> Number))
|
|
||||||
} else if (classifier.isSuperclassOf(Int::class)) {
|
|
||||||
types.add(PackedProperty(field as KProperty1<T, Int>, TypeAdapters.INTEGER, transformer = transformer as (Number) -> Number))
|
|
||||||
} else if (classifier.isSuperclassOf(Long::class)) {
|
|
||||||
types.add(PackedProperty(field as KProperty1<T, Long>, TypeAdapters.LONG, transformer = transformer as (Number) -> Number))
|
|
||||||
} else if (classifier.isSuperclassOf(String::class)) {
|
|
||||||
types.add(PackedProperty(field as KProperty1<T, String>, internedStringAdapter, transformer = transformer as (String) -> String))
|
|
||||||
} else if (classifier.isSuperclassOf(Boolean::class)) {
|
|
||||||
types.add(PackedProperty(field as KProperty1<T, Boolean>, TypeAdapters.BOOLEAN, transformer = transformer as (Boolean) -> Boolean))
|
|
||||||
} else {
|
|
||||||
types.add(PackedProperty(field, LazyTypeProvider(classifier.java) as TypeAdapter<Any?>, transformer = transformer as (Any?) -> Any?))
|
|
||||||
}
|
|
||||||
|
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -582,7 +410,7 @@ class KConcreteTypeAdapter<T : Any> private constructor(
|
|||||||
* Список неизменяем (создаётся объект [ImmutableList])
|
* Список неизменяем (создаётся объект [ImmutableList])
|
||||||
*/
|
*/
|
||||||
fun <V : Any> list(field: KProperty1<T, List<V>?>, type: Class<V>, transformer: (List<V>?) -> List<V>? = { it }): Builder<T> {
|
fun <V : Any> list(field: KProperty1<T, List<V>?>, type: Class<V>, transformer: (List<V>?) -> List<V>? = { it }): Builder<T> {
|
||||||
types.add(PackedProperty(field, ListAdapter(type, internedStringAdapter), transformer = transformer))
|
types.add(PackedProperty(field, ListAdapter(type), transformer = transformer))
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -601,7 +429,7 @@ class KConcreteTypeAdapter<T : Any> private constructor(
|
|||||||
* Таблица неизменяема (создаётся объект [ImmutableMap])
|
* Таблица неизменяема (создаётся объект [ImmutableMap])
|
||||||
*/
|
*/
|
||||||
fun <K, V> map(field: KProperty1<T, Map<K, V>>, keyType: Class<K>, valueType: Class<V>): Builder<T> {
|
fun <K, V> map(field: KProperty1<T, Map<K, V>>, keyType: Class<K>, valueType: Class<V>): Builder<T> {
|
||||||
types.add(PackedProperty(field, MapAdapter(keyType, valueType, internedStringAdapter)))
|
types.add(PackedProperty(field, MapAdapter(keyType, valueType)))
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -625,7 +453,7 @@ class KConcreteTypeAdapter<T : Any> private constructor(
|
|||||||
* Таблица неизменяема (создаётся объект [ImmutableMap])
|
* Таблица неизменяема (создаётся объект [ImmutableMap])
|
||||||
*/
|
*/
|
||||||
fun <K : Any, V : Any> map(field: KProperty1<T, Map<K, V>?>, keyType: KClass<K>, valueType: KClass<V>): Builder<T> {
|
fun <K : Any, V : Any> map(field: KProperty1<T, Map<K, V>?>, keyType: KClass<K>, valueType: KClass<V>): Builder<T> {
|
||||||
types.add(PackedProperty(field, MapAdapter(keyType.java, valueType.java, internedStringAdapter)))
|
types.add(PackedProperty(field, MapAdapter(keyType.java, valueType.java)))
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -635,7 +463,7 @@ class KConcreteTypeAdapter<T : Any> private constructor(
|
|||||||
* Таблица неизменяема (создаётся объект [ImmutableMap])
|
* Таблица неизменяема (создаётся объект [ImmutableMap])
|
||||||
*/
|
*/
|
||||||
fun <V> map(field: KProperty1<T, Map<String, V>?>, valueType: Class<V>): Builder<T> {
|
fun <V> map(field: KProperty1<T, Map<String, V>?>, valueType: Class<V>): Builder<T> {
|
||||||
types.add(PackedProperty(field, StringMapAdapter(valueType, internedStringAdapter, stringInterner)))
|
types.add(PackedProperty(field, StringMapAdapter(valueType)))
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -645,7 +473,7 @@ class KConcreteTypeAdapter<T : Any> private constructor(
|
|||||||
* Таблица неизменяема (создаётся объект [ImmutableMap])
|
* Таблица неизменяема (создаётся объект [ImmutableMap])
|
||||||
*/
|
*/
|
||||||
fun <V : Any> map(field: KProperty1<T, Map<String, V>?>, valueType: KClass<V>): Builder<T> {
|
fun <V : Any> map(field: KProperty1<T, Map<String, V>?>, valueType: KClass<V>): Builder<T> {
|
||||||
types.add(PackedProperty(field, StringMapAdapter(valueType.java, internedStringAdapter, stringInterner)))
|
types.add(PackedProperty(field, StringMapAdapter(valueType.java)))
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -666,7 +494,6 @@ class KConcreteTypeAdapter<T : Any> private constructor(
|
|||||||
bound = clazz,
|
bound = clazz,
|
||||||
types = ImmutableList.copyOf(types),
|
types = ImmutableList.copyOf(types),
|
||||||
asJsonArray = asList,
|
asJsonArray = asList,
|
||||||
stringInterner = stringInterner,
|
|
||||||
storesJson = storesJson
|
storesJson = storesJson
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
package ru.dbotthepony.kstarbound.io.json
|
||||||
|
|
||||||
|
import com.google.gson.TypeAdapter
|
||||||
|
import com.google.gson.stream.JsonReader
|
||||||
|
import com.google.gson.stream.JsonWriter
|
||||||
|
import ru.dbotthepony.kstarbound.Starbound
|
||||||
|
|
||||||
|
class LazyTypeProvider<T : Any?>(private val bound: Class<T>) : TypeAdapter<T>() {
|
||||||
|
private val resolved by lazy { Starbound.getTypeAdapter(bound) }
|
||||||
|
|
||||||
|
override fun write(out: JsonWriter, value: T) {
|
||||||
|
resolved.write(out, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun read(`in`: JsonReader): T {
|
||||||
|
return resolved.read(`in`)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
package ru.dbotthepony.kstarbound.io.json
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList
|
||||||
|
import com.google.gson.JsonSyntaxException
|
||||||
|
import com.google.gson.TypeAdapter
|
||||||
|
import com.google.gson.stream.JsonReader
|
||||||
|
import com.google.gson.stream.JsonToken
|
||||||
|
import com.google.gson.stream.JsonWriter
|
||||||
|
import ru.dbotthepony.kstarbound.Starbound
|
||||||
|
|
||||||
|
class ListAdapter<T>(private val type: Class<T>) : TypeAdapter<List<T>?>() {
|
||||||
|
private val resolvedBound by lazy { Starbound.getTypeAdapter(type) }
|
||||||
|
|
||||||
|
override fun write(out: JsonWriter, value: List<T>?) {
|
||||||
|
out.beginArray()
|
||||||
|
|
||||||
|
if (value != null) {
|
||||||
|
val resolvedBound = resolvedBound
|
||||||
|
|
||||||
|
for (v in value) {
|
||||||
|
resolvedBound.write(out, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out.endArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun read(reader: JsonReader): List<T> {
|
||||||
|
reader.beginArray()
|
||||||
|
|
||||||
|
val builder = ImmutableList.builder<T>()
|
||||||
|
val resolvedBound = resolvedBound
|
||||||
|
|
||||||
|
while (reader.peek() != JsonToken.END_ARRAY) {
|
||||||
|
val readObject = resolvedBound.read(reader) ?: throw JsonSyntaxException("List does not accept nulls")
|
||||||
|
builder.add(readObject as T)
|
||||||
|
}
|
||||||
|
|
||||||
|
reader.endArray()
|
||||||
|
|
||||||
|
return builder.build()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
package ru.dbotthepony.kstarbound.io.json
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMap
|
||||||
|
import com.google.gson.TypeAdapter
|
||||||
|
import com.google.gson.stream.JsonReader
|
||||||
|
import com.google.gson.stream.JsonToken
|
||||||
|
import com.google.gson.stream.JsonWriter
|
||||||
|
import ru.dbotthepony.kstarbound.Starbound
|
||||||
|
|
||||||
|
class MapAdapter<K, V>(private val keyType: Class<K>, private val valueType: Class<V>) : TypeAdapter<Map<K, V>?>() {
|
||||||
|
private val resolvedKey by lazy { Starbound.getTypeAdapter(keyType) }
|
||||||
|
private val resolvedValue by lazy { Starbound.getTypeAdapter(valueType) }
|
||||||
|
|
||||||
|
override fun write(out: JsonWriter, value: Map<K, V>?) {
|
||||||
|
out.beginArray()
|
||||||
|
|
||||||
|
if (value != null) {
|
||||||
|
val resolvedKey = resolvedKey
|
||||||
|
val resolvedValue = resolvedValue
|
||||||
|
|
||||||
|
for ((k, v) in value) {
|
||||||
|
out.beginArray()
|
||||||
|
resolvedKey.write(out, k)
|
||||||
|
resolvedValue.write(out, v)
|
||||||
|
out.endArray()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out.endArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun read(reader: JsonReader): Map<K, V> {
|
||||||
|
reader.beginArray()
|
||||||
|
|
||||||
|
val builder = ImmutableMap.builder<K, V>()
|
||||||
|
|
||||||
|
val resolvedKey = resolvedKey
|
||||||
|
val resolvedValue = resolvedValue
|
||||||
|
|
||||||
|
while (reader.peek() != JsonToken.END_ARRAY) {
|
||||||
|
reader.beginArray()
|
||||||
|
builder.put(resolvedKey.read(reader), resolvedValue.read(reader))
|
||||||
|
reader.endArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
reader.endArray()
|
||||||
|
|
||||||
|
return builder.build()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
package ru.dbotthepony.kstarbound.io.json
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMap
|
||||||
|
import com.google.gson.TypeAdapter
|
||||||
|
import com.google.gson.stream.JsonReader
|
||||||
|
import com.google.gson.stream.JsonToken
|
||||||
|
import com.google.gson.stream.JsonWriter
|
||||||
|
import ru.dbotthepony.kstarbound.Starbound
|
||||||
|
|
||||||
|
class StringMapAdapter<V>(private val type: Class<V>) : TypeAdapter<Map<String, V>?>() {
|
||||||
|
private val resolvedBound by lazy { Starbound.getTypeAdapter(type) }
|
||||||
|
|
||||||
|
override fun write(out: JsonWriter, value: Map<String, V>?) {
|
||||||
|
val resolvedBound = resolvedBound
|
||||||
|
|
||||||
|
out.beginObject()
|
||||||
|
|
||||||
|
if (value != null) {
|
||||||
|
for ((k, v) in value) {
|
||||||
|
out.name(k)
|
||||||
|
resolvedBound.write(out, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out.endObject()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun read(reader: JsonReader): Map<String, V> {
|
||||||
|
val builder = ImmutableMap.builder<String, V>()
|
||||||
|
|
||||||
|
reader.beginObject()
|
||||||
|
|
||||||
|
val resolvedBound = resolvedBound
|
||||||
|
|
||||||
|
while (reader.peek() != JsonToken.END_OBJECT) {
|
||||||
|
builder.put(Starbound.assetStringInterner.intern(reader.nextName()), resolvedBound.read(reader))
|
||||||
|
}
|
||||||
|
|
||||||
|
reader.endObject()
|
||||||
|
|
||||||
|
return builder.build()
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user