Более функциональный подход к typeadapter

This commit is contained in:
DBotThePony 2022-12-30 17:24:13 +07:00
parent 53c4c3fa11
commit 366e59cf14
Signed by: DBot
GPG Key ID: DCC23B5715498507
8 changed files with 112 additions and 83 deletions

View File

@ -33,7 +33,7 @@ data class MaterialModifier(
.auto(MaterialModifier::grass) .auto(MaterialModifier::grass)
.list(MaterialModifier::miningSounds) .list(MaterialModifier::miningSounds)
.auto(MaterialModifier::miningParticle) .auto(MaterialModifier::miningParticle)
.plain(MaterialModifier::renderTemplate, RenderTemplate.CACHE) .add(MaterialModifier::renderTemplate, RenderTemplate.CACHE)
.auto(MaterialModifier::renderParameters) .auto(MaterialModifier::renderParameters)
.build() .build()

View File

@ -38,7 +38,7 @@ data class TileDefinition(
TileDefinition::health, TileDefinition::health,
TileDefinition::category TileDefinition::category
) )
.plain(TileDefinition::renderTemplate, RenderTemplate.CACHE) .add(TileDefinition::renderTemplate, RenderTemplate.CACHE)
.auto( .auto(
TileDefinition::renderParameters, TileDefinition::renderParameters,
) )

View File

@ -0,0 +1,41 @@
package ru.dbotthepony.kstarbound.io.json
import com.google.gson.TypeAdapter
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonWriter
fun <T> TypeAdapter<T>.transformRead(transformer: (T) -> T): TypeAdapter<T> {
return object : TypeAdapter<T>() {
override fun write(out: JsonWriter, value: T) {
return this@transformRead.write(out, value)
}
override fun read(`in`: JsonReader): T {
return transformer(this@transformRead.read(`in`))
}
}
}
fun <T> TypeAdapter<T>.transformWrite(transformer: (T) -> T): TypeAdapter<T> {
return object : TypeAdapter<T>() {
override fun write(out: JsonWriter, value: T) {
return this@transformWrite.write(out, transformer(value))
}
override fun read(`in`: JsonReader): T {
return this@transformWrite.read(`in`)
}
}
}
fun <T> TypeAdapter<T>.transform(transformRead: (T) -> T, transformWrite: (T) -> T): TypeAdapter<T> {
return object : TypeAdapter<T>() {
override fun write(out: JsonWriter, value: T) {
return this@transform.write(out, transformWrite(value))
}
override fun read(`in`: JsonReader): T {
return transformRead(this@transform.read(`in`))
}
}
}

View File

@ -377,7 +377,7 @@ class KConcreteTypeAdapter<T : Any> private constructor(
/** /**
* Добавляет поле с определённым адаптером * Добавляет поле с определённым адаптером
*/ */
fun <V> plain(field: KProperty1<T, V>, adapter: TypeAdapter<V>): Builder<T> { fun <V> add(field: KProperty1<T, V>, adapter: TypeAdapter<V>): Builder<T> {
types.add(PackedProperty(field, adapter)) types.add(PackedProperty(field, adapter))
return this return this
} }
@ -410,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), transformer = transformer)) types.add(PackedProperty(field, ListAdapter(type).nullSafe(), transformer = transformer))
return this return this
} }
@ -420,7 +420,7 @@ class KConcreteTypeAdapter<T : Any> private constructor(
* Список неизменяем (создаётся объект [ImmutableList]) * Список неизменяем (создаётся объект [ImmutableList])
*/ */
inline fun <reified V : Any> list(field: KProperty1<T, List<V>?>, noinline transformer: (List<V>?) -> List<V>? = { it }): Builder<T> { inline fun <reified V : Any> list(field: KProperty1<T, List<V>?>, noinline transformer: (List<V>?) -> List<V>? = { it }): Builder<T> {
return this.list(field, V::class.java, transformer) return add(field, ListAdapter(V::class.java).nullSafe())
} }
/** /**
@ -453,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))) types.add(PackedProperty(field, MapAdapter(keyType.java, valueType.java).nullSafe()))
return this return this
} }
@ -463,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))) types.add(PackedProperty(field, String2ObjectAdapter(valueType).nullSafe()))
return this return this
} }
@ -473,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))) types.add(PackedProperty(field, String2ObjectAdapter(valueType.java).nullSafe()))
return this return this
} }

View File

@ -8,18 +8,18 @@ import com.google.gson.stream.JsonToken
import com.google.gson.stream.JsonWriter import com.google.gson.stream.JsonWriter
import ru.dbotthepony.kstarbound.Starbound import ru.dbotthepony.kstarbound.Starbound
class ListAdapter<T>(private val type: Class<T>) : TypeAdapter<List<T>?>() { fun <T : Any> TypeAdapter<T>.asList(): TypeAdapter<List<T>> {
private val resolvedBound by lazy { Starbound.getTypeAdapter(type) } return ListAdapter(this)
}
override fun write(out: JsonWriter, value: List<T>?) { class ListAdapter<T : Any>(val elementAdapter: TypeAdapter<T>, val valueTransformer: (T) -> T = { it }) : TypeAdapter<List<T>>() {
constructor(type: Class<T>) : this(LazyTypeProvider(type))
override fun write(out: JsonWriter, value: List<T>) {
out.beginArray() out.beginArray()
if (value != null) { for (v in value) {
val resolvedBound = resolvedBound elementAdapter.write(out, v)
for (v in value) {
resolvedBound.write(out, v)
}
} }
out.endArray() out.endArray()
@ -29,15 +29,14 @@ class ListAdapter<T>(private val type: Class<T>) : TypeAdapter<List<T>?>() {
reader.beginArray() reader.beginArray()
val builder = ImmutableList.builder<T>() val builder = ImmutableList.builder<T>()
val resolvedBound = resolvedBound
while (reader.peek() != JsonToken.END_ARRAY) { while (reader.peek() != JsonToken.END_ARRAY) {
val readObject = resolvedBound.read(reader) ?: throw JsonSyntaxException("List does not accept nulls") val readObject = elementAdapter.read(reader) ?: throw JsonSyntaxException("List does not accept nulls")
builder.add(readObject as T) builder.add(valueTransformer(readObject))
} }
reader.endArray() reader.endArray()
return builder.build() return builder.build()
} }
} }

View File

@ -7,23 +7,17 @@ import com.google.gson.stream.JsonToken
import com.google.gson.stream.JsonWriter import com.google.gson.stream.JsonWriter
import ru.dbotthepony.kstarbound.Starbound import ru.dbotthepony.kstarbound.Starbound
class MapAdapter<K, V>(private val keyType: Class<K>, private val valueType: Class<V>) : TypeAdapter<Map<K, V>?>() { class MapAdapter<K, V>(val keyAdapter: TypeAdapter<K>, val valueAdapter: TypeAdapter<V>) : TypeAdapter<Map<K, V>>() {
private val resolvedKey by lazy { Starbound.getTypeAdapter(keyType) } constructor(keyType: Class<K>, valueType: Class<V>) : this(LazyTypeProvider(keyType), LazyTypeProvider(valueType))
private val resolvedValue by lazy { Starbound.getTypeAdapter(valueType) }
override fun write(out: JsonWriter, value: Map<K, V>?) { override fun write(out: JsonWriter, value: Map<K, V>) {
out.beginArray() out.beginArray()
if (value != null) { for ((k, v) in value) {
val resolvedKey = resolvedKey out.beginArray()
val resolvedValue = resolvedValue keyAdapter.write(out, k)
valueAdapter.write(out, v)
for ((k, v) in value) { out.endArray()
out.beginArray()
resolvedKey.write(out, k)
resolvedValue.write(out, v)
out.endArray()
}
} }
out.endArray() out.endArray()
@ -34,12 +28,9 @@ class MapAdapter<K, V>(private val keyType: Class<K>, private val valueType: Cla
val builder = ImmutableMap.builder<K, V>() val builder = ImmutableMap.builder<K, V>()
val resolvedKey = resolvedKey
val resolvedValue = resolvedValue
while (reader.peek() != JsonToken.END_ARRAY) { while (reader.peek() != JsonToken.END_ARRAY) {
reader.beginArray() reader.beginArray()
builder.put(resolvedKey.read(reader), resolvedValue.read(reader)) builder.put(keyAdapter.read(reader), valueAdapter.read(reader))
reader.endArray() reader.endArray()
} }
@ -47,4 +38,4 @@ class MapAdapter<K, V>(private val keyType: Class<K>, private val valueType: Cla
return builder.build() return builder.build()
} }
} }

View File

@ -0,0 +1,41 @@
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
fun <T> TypeAdapter<T>.asJsonObject(): TypeAdapter<Map<String, T>> {
return String2ObjectAdapter(this)
}
class String2ObjectAdapter<T>(val adapter: TypeAdapter<T>) : TypeAdapter<Map<String, T>>() {
constructor(type: Class<T>) : this(LazyTypeProvider(type))
override fun write(out: JsonWriter, value: Map<String, T>) {
out.beginObject()
for ((k, v) in value) {
out.name(k)
adapter.write(out, v)
}
out.endObject()
}
override fun read(reader: JsonReader): Map<String, T> {
val builder = ImmutableMap.builder<String, T>()
reader.beginObject()
while (reader.peek() != JsonToken.END_OBJECT) {
builder.put(Starbound.assetStringInterner.intern(reader.nextName()), adapter.read(reader))
}
reader.endObject()
return builder.build()
}
}

View File

@ -1,43 +0,0 @@
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()
}
}