From 4d44653e7ee182dfe8f113c38e629cd261b4f78d Mon Sep 17 00:00:00 2001 From: RicardoJiang <2868405029@qq.com> Date: Mon, 6 Nov 2023 16:38:56 +0800 Subject: [PATCH] MOD: jsonReader support Float, Array, Set and Map Type --- .../compiler/KudosFromJsonFunctionBuilder.kt | 19 ++++-- .../com/kanyun/kudos/compiler/KudosTests.kt | 12 ++++ .../testData/jsonReader/deserialize.kt | 4 +- .../jsonReader/deserializeArrayType.kt | 20 ++++++ .../jsonReader/deserializeFloatType.kt | 20 ++++++ .../testData/jsonReader/deserializeMapType.kt | 38 +++++++++++ .../testData/jsonReader/deserializeSetType.kt | 20 ++++++ kudos-compiler/testData/jsonReader/simple.kt | 4 +- .../json/reader/adapter/KudosJsonAdapter.kt | 67 ++++++++++++++----- 9 files changed, 179 insertions(+), 25 deletions(-) create mode 100644 kudos-compiler/testData/jsonReader/deserializeArrayType.kt create mode 100644 kudos-compiler/testData/jsonReader/deserializeFloatType.kt create mode 100644 kudos-compiler/testData/jsonReader/deserializeMapType.kt create mode 100644 kudos-compiler/testData/jsonReader/deserializeSetType.kt diff --git a/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/KudosFromJsonFunctionBuilder.kt b/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/KudosFromJsonFunctionBuilder.kt index 3440851..e37a16b 100644 --- a/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/KudosFromJsonFunctionBuilder.kt +++ b/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/KudosFromJsonFunctionBuilder.kt @@ -39,7 +39,6 @@ import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrField import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.expressions.IrBranch -import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.types.IrSimpleType @@ -147,7 +146,7 @@ internal class KudosFromJsonFunctionBuilder( ).first() } - private fun getNextValue(field: IrField): IrCall { + private fun getNextValue(field: IrField): IrExpression { return if (field.type.isSubtypeOfClass(context.irBuiltIns.stringClass)) { irCall(getJsonReaderNextSymbol("String")).apply { dispatchReceiver = irGet(jsonReader) @@ -164,6 +163,16 @@ internal class KudosFromJsonFunctionBuilder( irCall(getJsonReaderNextSymbol("Double")).apply { dispatchReceiver = irGet(jsonReader) } + } else if (field.type.isSubtypeOfClass(context.irBuiltIns.floatClass)) { + irCall( + pluginContext.referenceFunctions( + CallableId(FqName("kotlin.text"), Name.identifier("toFloat")), + ).first().owner, + ).apply { + extensionReceiver = irCall(getJsonReaderNextSymbol("String")).apply { + dispatchReceiver = irGet(jsonReader) + } + } } else if (field.type.isSubtypeOfClass(context.irBuiltIns.booleanClass)) { irCall(getJsonReaderNextSymbol("Boolean")).apply { dispatchReceiver = irGet(jsonReader) @@ -171,6 +180,8 @@ internal class KudosFromJsonFunctionBuilder( } else if ( field.type.isSubtypeOfClass(context.irBuiltIns.listClass) || field.type.isSubtypeOfClass(context.irBuiltIns.arrayClass) || + field.type.isSubtypeOfClass(context.irBuiltIns.setClass) || + field.type.isSubtypeOfClass(context.irBuiltIns.mapClass) || field.type.isSubtypeOfClass( pluginContext.referenceClass(KUDOS_JSON_ADAPTER_CLASS_ID)!!, ) @@ -196,7 +207,7 @@ internal class KudosFromJsonFunctionBuilder( if (typeArguments.isEmpty()) { return irCall( pluginContext.referenceProperties( - CallableId(FqName("kotlin.jvm"), Name.identifier("java")), + CallableId(FqName("kotlin.jvm"), Name.identifier("javaObjectType")), ).first().owner.getter!!, ).apply { extensionReceiver = kClassReference(type) @@ -225,7 +236,7 @@ internal class KudosFromJsonFunctionBuilder( 0, irCall( pluginContext.referenceProperties( - CallableId(FqName("kotlin.jvm"), Name.identifier("java")), + CallableId(FqName("kotlin.jvm"), Name.identifier("javaObjectType")), ).first().owner.getter!!, ).apply { extensionReceiver = kClassReference(type) diff --git a/kudos-compiler/src/test/java/com/kanyun/kudos/compiler/KudosTests.kt b/kudos-compiler/src/test/java/com/kanyun/kudos/compiler/KudosTests.kt index 6edf93b..8af1077 100644 --- a/kudos-compiler/src/test/java/com/kanyun/kudos/compiler/KudosTests.kt +++ b/kudos-compiler/src/test/java/com/kanyun/kudos/compiler/KudosTests.kt @@ -51,6 +51,18 @@ class KudosTests : TestBase() { @Test fun `jsonReader_deserialize`() = testBase() + @Test + fun `jsonReader_deserializeArrayType`() = testBase() + + @Test + fun `jsonReader_deserializeFloatType`() = testBase() + + @Test + fun `jsonReader_deserializeMapType`() = testBase() + + @Test + fun `jsonReader_deserializeSetType`() = testBase() + @Test fun `jsonReader_simple`() = testBase() } diff --git a/kudos-compiler/testData/jsonReader/deserialize.kt b/kudos-compiler/testData/jsonReader/deserialize.kt index a64b3a2..b89d79a 100644 --- a/kudos-compiler/testData/jsonReader/deserialize.kt +++ b/kudos-compiler/testData/jsonReader/deserialize.kt @@ -3,7 +3,7 @@ // FILE: Main.kt [MainKt#main] import com.kanyun.kudos.annotations.Kudos @Kudos -class Desc(val descDetail: String) +class Desc(val descDetail: String, val descId: Int) @Kudos class UserLazy(val id: Long, val name: String, val desc: Desc, val tags: List>) { @@ -21,7 +21,7 @@ class UserLazy(val id: Long, val name: String, val desc: Desc, val tags: List
  • ("""{"id": 10, "name": "John Claud", "desc": {"descDetail": "desc detail"}, "tags": [["tag1", "tag2"],["abc","def"]] }""") + deserialize("""{"id": 10, "name": "John Claud", "desc": {"descDetail": "desc detail", "descId": 123}, "tags": [["tag1", "tag2"],["abc","def"]] }""") } // EXPECT diff --git a/kudos-compiler/testData/jsonReader/deserializeArrayType.kt b/kudos-compiler/testData/jsonReader/deserializeArrayType.kt new file mode 100644 index 0000000..592d166 --- /dev/null +++ b/kudos-compiler/testData/jsonReader/deserializeArrayType.kt @@ -0,0 +1,20 @@ +// SOURCE +{{deserialize}} +// FILE: Main.kt [MainKt#main] +import com.kanyun.kudos.annotations.Kudos + +@Kudos +class User(val ids: Array) { + + override fun toString(): String { + return "User(ids[1]=${ids[1]})" + } +} + +fun main() { + deserialize("""{"ids": [123, 456]}""") +} + +// EXPECT +// FILE: MainKt.main.stdout +User(ids[1]=456) diff --git a/kudos-compiler/testData/jsonReader/deserializeFloatType.kt b/kudos-compiler/testData/jsonReader/deserializeFloatType.kt new file mode 100644 index 0000000..37b13b8 --- /dev/null +++ b/kudos-compiler/testData/jsonReader/deserializeFloatType.kt @@ -0,0 +1,20 @@ +// SOURCE +{{deserialize}} +// FILE: Main.kt [MainKt#main] +import com.kanyun.kudos.annotations.Kudos + +@Kudos +class User(val doubleId: Double, val floatId: Float) { + + override fun toString(): String { + return "User(doubleId=$doubleId, floatId=$floatId)" + } +} + +fun main() { + deserialize("""{"doubleId": 10.1234, "floatId": "10.1234"}""") +} + +// EXPECT +// FILE: MainKt.main.stdout +User(doubleId=10.1234, floatId=10.1234) diff --git a/kudos-compiler/testData/jsonReader/deserializeMapType.kt b/kudos-compiler/testData/jsonReader/deserializeMapType.kt new file mode 100644 index 0000000..c276bd0 --- /dev/null +++ b/kudos-compiler/testData/jsonReader/deserializeMapType.kt @@ -0,0 +1,38 @@ +// SOURCE +{{deserialize}} +// FILE: Main.kt [MainKt#main] +import com.kanyun.kudos.annotations.Kudos + +@Kudos +class User(val id: Int, val tag: String){ + override fun toString(): String { + return "User(id=${id}, tag=${tag})" + } +} + +@Kudos +class UserMap(val itemMap: Map) { + + override fun toString(): String { + return "UserMap(user2=${itemMap["user2"]})" + } +} + +fun main() { + deserialize("""{ + "itemMap": { + "user1": { + "id": 123, + "tag": "tag1" + }, + "user2": { + "id": 456, + "tag": "tag2" + } + } +}""") +} + +// EXPECT +// FILE: MainKt.main.stdout +UserMap(user2=User(id=456, tag=tag2)) diff --git a/kudos-compiler/testData/jsonReader/deserializeSetType.kt b/kudos-compiler/testData/jsonReader/deserializeSetType.kt new file mode 100644 index 0000000..58582ec --- /dev/null +++ b/kudos-compiler/testData/jsonReader/deserializeSetType.kt @@ -0,0 +1,20 @@ +// SOURCE +{{deserialize}} +// FILE: Main.kt [MainKt#main] +import com.kanyun.kudos.annotations.Kudos + +@Kudos +class User(val ids: Set) { + + override fun toString(): String { + return "User(ids=${ids})" + } +} + +fun main() { + deserialize("""{"ids": [123, 456, 123]}""") +} + +// EXPECT +// FILE: MainKt.main.stdout +User(ids=[123, 456]) diff --git a/kudos-compiler/testData/jsonReader/simple.kt b/kudos-compiler/testData/jsonReader/simple.kt index 9acf945..6e4c670 100644 --- a/kudos-compiler/testData/jsonReader/simple.kt +++ b/kudos-compiler/testData/jsonReader/simple.kt @@ -90,8 +90,8 @@ class Project : KudosValidator, KudosJsonAdapter { when { EQEQ(arg0 = tmp0, arg1 = "projectName") -> .#projectName = jsonReader.nextString() EQEQ(arg0 = tmp0, arg1 = "projectId") -> .#projectId = jsonReader.nextInt() - EQEQ(arg0 = tmp0, arg1 = "tags") -> .#tags = parseKudosObject(jsonReader = jsonReader, type = ParameterizedTypeImpl(type = KClass::class.(), typeArguments = arrayOf(elements = [KClass::class.()]))) - EQEQ(arg0 = tmp0, arg1 = "desc") -> .#desc = parseKudosObject(jsonReader = jsonReader, type = KClass::class.()) + EQEQ(arg0 = tmp0, arg1 = "tags") -> .#tags = parseKudosObject(jsonReader = jsonReader, type = ParameterizedTypeImpl(type = KClass::class.(), typeArguments = arrayOf(elements = [KClass::class.()]))) + EQEQ(arg0 = tmp0, arg1 = "desc") -> .#desc = parseKudosObject(jsonReader = jsonReader, type = KClass::class.()) else -> jsonReader.skipValue() } } diff --git a/kudos-json-reader/src/main/java/com/kanyun/kudos/json/reader/adapter/KudosJsonAdapter.kt b/kudos-json-reader/src/main/java/com/kanyun/kudos/json/reader/adapter/KudosJsonAdapter.kt index 38aa567..ba038c7 100644 --- a/kudos-json-reader/src/main/java/com/kanyun/kudos/json/reader/adapter/KudosJsonAdapter.kt +++ b/kudos-json-reader/src/main/java/com/kanyun/kudos/json/reader/adapter/KudosJsonAdapter.kt @@ -41,31 +41,64 @@ private fun parseKudosList(jsonReader: JsonReader, typeArguments: Array): return list } +private fun parseKudosArray(jsonReader: JsonReader, typeArguments: Array): Any { + val list = parseKudosList(jsonReader, typeArguments) + val array = java.lang.reflect.Array.newInstance(typeArguments[0] as Class<*>, list.size) + for (i in list.indices) { + java.lang.reflect.Array.set(array, i, list[i]) + } + return array +} + +private fun parseKudosMap(jsonReader: JsonReader, typeArguments: Array): Map { + val resultMap = mutableMapOf() + jsonReader.beginObject() + while (jsonReader.hasNext()) { + val key = jsonReader.nextName() + val value = parseKudosObject(jsonReader, typeArguments[1]) + resultMap[key] = value + } + jsonReader.endObject() + return resultMap +} + private fun parseKudosObjectInternal( jsonReader: JsonReader, type: Type, typeArguments: Array, ): Any { val value = when (type) { - String::class.java -> jsonReader.nextString() - Int::class.java -> jsonReader.nextInt() - Long::class.java -> jsonReader.nextLong() - Double::class.java -> jsonReader.nextDouble() - Boolean::class.java -> jsonReader.nextBoolean() - List::class.java -> parseKudosList(jsonReader, typeArguments) - Array::class.java -> parseKudosList(jsonReader, typeArguments).toTypedArray() + String::class.javaObjectType -> jsonReader.nextString() + Int::class.javaObjectType -> jsonReader.nextInt() + Long::class.javaObjectType -> jsonReader.nextLong() + Double::class.javaObjectType -> jsonReader.nextDouble() + Float::class.javaObjectType -> jsonReader.nextString().toFloat() + Boolean::class.javaObjectType -> jsonReader.nextBoolean() + List::class.javaObjectType -> parseKudosList(jsonReader, typeArguments) + Set::class.javaObjectType -> parseKudosList(jsonReader, typeArguments).toSet() + Map::class.javaObjectType -> parseKudosMap(jsonReader, typeArguments) else -> { - if (type is Class<*>) { - val adapter = type.getDeclaredConstructor().newInstance() - if (adapter is KudosJsonAdapter<*>) { - adapter.fromJson(jsonReader)!! - } else { - throw IllegalArgumentException("class ${type.name} must implement KudosJsonAdapter") - } - } else { - throw IllegalArgumentException("class ${type.typeName} must implement KudosJsonAdapter") - } + parseKudosObjectSpecial(jsonReader, type, typeArguments) } } return value } + +private fun parseKudosObjectSpecial( + jsonReader: JsonReader, + type: Type, + typeArguments: Array, +): Any { + return if (type.typeName.endsWith("[]")) { + parseKudosArray(jsonReader, typeArguments) + } else if (type is Class<*>) { + val adapter = type.getDeclaredConstructor().newInstance() + if (adapter is KudosJsonAdapter<*>) { + adapter.fromJson(jsonReader)!! + } else { + throw IllegalArgumentException("class ${type.name} must implement KudosJsonAdapter") + } + } else { + throw IllegalArgumentException("class ${type.typeName} must implement KudosJsonAdapter") + } +}