From f869895d6b4daaa41dbe37268183913ecf16a8c9 Mon Sep 17 00:00:00 2001 From: RicardoJiang <2868405029@qq.com> Date: Fri, 17 Nov 2023 15:00:53 +0800 Subject: [PATCH 1/2] ADD: Kudos function switch --- .../json/reader/KudosAndroidJsonReader.kt | 21 +++- .../com/kanyun/kudos/annotations/Kudos.kt | 2 +- .../compiler/KudosCompilerPluginRegistrar.kt | 8 +- .../kudos/compiler/KudosIrClassTransformer.kt | 8 +- .../compiler/KudosIrGenerationExtension.kt | 6 +- .../kudos/compiler/KudosIrTransformer.kt | 3 +- .../com/kanyun/kudos/compiler/KudosNames.kt | 2 + .../k1/KudosSyntheticResolveExtension.kt | 37 +++++-- .../k2/KudosFirDeclarationGenerator.kt | 13 ++- .../compiler/k2/KudosFirExtensionRegistrar.kt | 11 +- .../KudosFirSupertypeGenerationExtension.kt | 62 ++++++++--- .../kanyun/kudos/compiler/options/Options.kt | 32 ++++++ .../com/kanyun/kudos/compiler/KudosTests.kt | 6 ++ .../kanyun/kudos/compiler/base/TestBase.kt | 1 + kudos-compiler/testData/gson/annotation.kt | 44 ++++++++ .../testData/jsonReader/annotation.kt | 100 ++++++++++++++++++ kudos-compiler/testData/jsonReader/simple.kt | 4 +- .../com/kanyun/kudos/gradle/KudosExtension.kt | 1 + .../kanyun/kudos/gradle/KudosGradlePlugin.kt | 8 +- .../java/com/kanyun/kudos/gson/KudosGson.kt | 2 + .../kanyun/kudos/jackson/KudosObjectMapper.kt | 2 + 21 files changed, 326 insertions(+), 47 deletions(-) create mode 100644 kudos-compiler/testData/gson/annotation.kt create mode 100644 kudos-compiler/testData/jsonReader/annotation.kt diff --git a/kudos-android-json-reader/src/main/java/com/kanyun/kudos/json/reader/KudosAndroidJsonReader.kt b/kudos-android-json-reader/src/main/java/com/kanyun/kudos/json/reader/KudosAndroidJsonReader.kt index a860f74..0f8e959 100644 --- a/kudos-android-json-reader/src/main/java/com/kanyun/kudos/json/reader/KudosAndroidJsonReader.kt +++ b/kudos-android-json-reader/src/main/java/com/kanyun/kudos/json/reader/KudosAndroidJsonReader.kt @@ -19,17 +19,23 @@ package com.kanyun.kudos.json.reader import android.util.JsonReader import com.kanyun.kudos.json.reader.adapter.KudosJsonAdapter import com.kanyun.kudos.json.reader.adapter.parseKudosObject +import java.io.BufferedReader +import java.io.InputStream import java.lang.reflect.Type object KudosAndroidJsonReader { inline fun <reified T> fromJson(json: String): T { - return fromJson(json, T::class.java) + return fromJson(json.reader().buffered(), T::class.java) } - fun <T> fromJson(json: String, clazz: Class<T>): T { + inline fun <reified T> fromJson(inputStream: InputStream): T { + return fromJson(inputStream.bufferedReader(), T::class.java) + } + + fun <T> fromJson(bufferReader: BufferedReader, clazz: Class<T>): T { val adapter = clazz.getDeclaredConstructor().newInstance() return if (adapter is KudosJsonAdapter<*>) { - val jsonReader = JsonReader(json.reader()) + val jsonReader = JsonReader(bufferReader) adapter.fromJson(jsonReader) as T } else { throw IllegalArgumentException("class ${clazz.name} must implement KudosJsonAdapter") @@ -37,7 +43,14 @@ object KudosAndroidJsonReader { } fun <T> fromJson(json: String, type: Type): T { - val jsonReader = JsonReader(json.reader()) + val jsonReader = JsonReader(json.reader().buffered()) + return parseKudosObject(jsonReader, type) as T + } + + fun <T> fromJson(inputStream: InputStream, type: Type): T { + val jsonReader = JsonReader(inputStream.bufferedReader()) return parseKudosObject(jsonReader, type) as T } } + +const val KUDOS_ANDROID_JSON_READER: Int = 3 diff --git a/kudos-annotations/src/main/java/com/kanyun/kudos/annotations/Kudos.kt b/kudos-annotations/src/main/java/com/kanyun/kudos/annotations/Kudos.kt index c6c3874..cdc51bd 100644 --- a/kudos-annotations/src/main/java/com/kanyun/kudos/annotations/Kudos.kt +++ b/kudos-annotations/src/main/java/com/kanyun/kudos/annotations/Kudos.kt @@ -21,4 +21,4 @@ package com.kanyun.kudos.annotations */ @Retention(AnnotationRetention.BINARY) @Target(AnnotationTarget.CLASS, AnnotationTarget.TYPE) -annotation class Kudos +annotation class Kudos(vararg val value: Int) diff --git a/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/KudosCompilerPluginRegistrar.kt b/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/KudosCompilerPluginRegistrar.kt index f0090db..419dfca 100644 --- a/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/KudosCompilerPluginRegistrar.kt +++ b/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/KudosCompilerPluginRegistrar.kt @@ -46,11 +46,11 @@ class KudosCompilerPluginRegistrar : CompilerPluginRegistrar() { configuration.get(NoArgConfigurationKeys.PRESET)?.forEach { preset -> NoArgPluginNames.SUPPORTED_PRESETS[preset]?.let { noArgAnnotations += it } } - - IrGenerationExtension.registerExtension(KudosIrGenerationExtension()) - SyntheticResolveExtension.registerExtension(KudosSyntheticResolveExtension()) + val kudosAnnotationValueMap = hashMapOf<String, List<Int>>() + IrGenerationExtension.registerExtension(KudosIrGenerationExtension(kudosAnnotationValueMap)) + SyntheticResolveExtension.registerExtension(KudosSyntheticResolveExtension(kudosAnnotationValueMap)) StorageComponentContainerContributor.registerExtension(KudosComponentContainerContributor(noArgAnnotations)) - FirExtensionRegistrarAdapter.registerExtension(KudosFirExtensionRegistrar(noArgAnnotations)) + FirExtensionRegistrarAdapter.registerExtension(KudosFirExtensionRegistrar(noArgAnnotations, kudosAnnotationValueMap)) } override val supportsK2: Boolean diff --git a/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/KudosIrClassTransformer.kt b/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/KudosIrClassTransformer.kt index 3d49107..f8e0286 100644 --- a/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/KudosIrClassTransformer.kt +++ b/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/KudosIrClassTransformer.kt @@ -63,6 +63,7 @@ import org.jetbrains.kotlin.ir.types.starProjectedType import org.jetbrains.kotlin.ir.types.typeOrNull import org.jetbrains.kotlin.ir.types.typeWith import org.jetbrains.kotlin.ir.util.SYNTHETIC_OFFSET +import org.jetbrains.kotlin.ir.util.classId import org.jetbrains.kotlin.ir.util.constructors import org.jetbrains.kotlin.ir.util.copyTo import org.jetbrains.kotlin.ir.util.defaultType @@ -86,17 +87,20 @@ class KudosIrClassTransformer( private val context: IrPluginContext, private val irClass: IrClass, private val noArgConstructors: MutableMap<IrClass, IrConstructor>, + private val kudosAnnotationValueMap: HashMap<String, List<Int>>, ) { private val defaults = HashSet<String>() fun transform() { - if (Options.gson()) { + if (Options.isGsonEnabled(kudosAnnotationValueMap, irClass.classId?.asString())) { generateJsonAdapter() } generateNoArgConstructor() val validatorFunction = generateValidator() - generateFromJson(validatorFunction) + if (Options.isAndroidJsonReaderEnabled(kudosAnnotationValueMap, irClass.classId?.asString())) { + generateFromJson(validatorFunction) + } } private fun generateJsonAdapter() { diff --git a/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/KudosIrGenerationExtension.kt b/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/KudosIrGenerationExtension.kt index 0a8459c..a45b8b1 100644 --- a/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/KudosIrGenerationExtension.kt +++ b/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/KudosIrGenerationExtension.kt @@ -21,9 +21,11 @@ import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.visitors.acceptVoid -class KudosIrGenerationExtension : IrGenerationExtension { +class KudosIrGenerationExtension( + private val kudosAnnotationValueMap: HashMap<String, List<Int>>, +) : IrGenerationExtension { override fun generate(moduleFragment: IrModuleFragment, pluginContext: IrPluginContext) { - moduleFragment.acceptVoid(KudosIrTransformer(pluginContext)) + moduleFragment.acceptVoid(KudosIrTransformer(pluginContext, kudosAnnotationValueMap)) } } diff --git a/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/KudosIrTransformer.kt b/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/KudosIrTransformer.kt index 20fbcd0..c9d4573 100644 --- a/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/KudosIrTransformer.kt +++ b/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/KudosIrTransformer.kt @@ -29,6 +29,7 @@ import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid */ class KudosIrTransformer( private val context: IrPluginContext, + private val kudosAnnotationValueMap: HashMap<String, List<Int>>, ) : IrElementVisitorVoid { private val noArgConstructors = mutableMapOf<IrClass, IrConstructor>() @@ -41,6 +42,6 @@ class KudosIrTransformer( if (declaration.kind != ClassKind.CLASS) return if (!declaration.hasKudosAnnotation()) return - KudosIrClassTransformer(context, declaration, noArgConstructors).transform() + KudosIrClassTransformer(context, declaration, noArgConstructors, kudosAnnotationValueMap).transform() } } diff --git a/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/KudosNames.kt b/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/KudosNames.kt index f3dd1d4..31d9633 100644 --- a/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/KudosNames.kt +++ b/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/KudosNames.kt @@ -39,6 +39,7 @@ object KudosNames { val ADAPTER_FACTORY_NAME = FqName("com.kanyun.kudos.gson.adapter.KudosReflectiveTypeAdapterFactory") // ClassId + val KUDOS_ANNOTATION_CLASS_ID = ClassId(FqName("com.kanyun.kudos.annotations"), Name.identifier("Kudos")) val KUDOS_VALIDATOR_CLASS_ID = ClassId(FqName("com.kanyun.kudos.validator"), Name.identifier("KudosValidator")) val KUDOS_JSON_ADAPTER_CLASS_ID = ClassId(FqName("com.kanyun.kudos.json.reader.adapter"), Name.identifier("KudosJsonAdapter")) val JSON_READER_CLASS_ID = ClassId.fromString("android/util/JsonReader") @@ -50,6 +51,7 @@ object KudosNames { val JSON_TOKEN_NULL_CALLABLE_ID = CallableId(FqName("android.util"), FqName("JsonToken"), Name.identifier("NULL")) // Name.identifier + val KUDOS_VALUE_IDENTIFIER = Name.identifier("value") val KUDOS_FROM_JSON_IDENTIFIER = Name.identifier("fromJson") val JSON_READER_IDENTIFIER = Name.identifier("jsonReader") val KUDOS_FIELD_STATUS_MAP_IDENTIFIER = Name.identifier("kudosFieldStatusMap") diff --git a/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/k1/KudosSyntheticResolveExtension.kt b/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/k1/KudosSyntheticResolveExtension.kt index b412d27..54900dc 100644 --- a/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/k1/KudosSyntheticResolveExtension.kt +++ b/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/k1/KudosSyntheticResolveExtension.kt @@ -25,6 +25,8 @@ import com.kanyun.kudos.compiler.KudosNames.KUDOS_NAME import com.kanyun.kudos.compiler.KudosNames.KUDOS_VALIDATOR import com.kanyun.kudos.compiler.KudosNames.KUDOS_VALIDATOR_CLASS_ID import com.kanyun.kudos.compiler.k1.symbol.FromJsonFunctionDescriptorImpl +import com.kanyun.kudos.compiler.options.Options +import com.kanyun.kudos.compiler.utils.safeAs import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor @@ -35,6 +37,8 @@ import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl import org.jetbrains.kotlin.js.descriptorUtils.getKotlinTypeFqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.constants.IntValue +import org.jetbrains.kotlin.resolve.descriptorUtil.classId import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.extensions.SyntheticResolveExtension import org.jetbrains.kotlin.types.KotlinType @@ -44,7 +48,9 @@ import org.jetbrains.kotlin.types.TypeAttributes import org.jetbrains.kotlin.types.TypeProjectionImpl import org.jetbrains.kotlin.types.typeUtil.supertypes -class KudosSyntheticResolveExtension : SyntheticResolveExtension { +class KudosSyntheticResolveExtension( + private val kudosAnnotationValueMap: HashMap<String, List<Int>>, +) : SyntheticResolveExtension { override fun addSyntheticSupertypes( thisDescriptor: ClassDescriptor, @@ -52,6 +58,11 @@ class KudosSyntheticResolveExtension : SyntheticResolveExtension { ) { if (thisDescriptor.kind != ClassKind.CLASS) return if (thisDescriptor.annotations.hasAnnotation(KUDOS_NAME)) { + val kudosAnnotation = thisDescriptor.annotations.findAnnotation(KUDOS_NAME) + val annotationValues = kudosAnnotation?.allValueArguments?.values?.firstOrNull()?.value?.safeAs<List<IntValue>>()?.map { + it.value + } + kudosAnnotationValueMap[thisDescriptor.classId?.asString() ?: ""] = annotationValues ?: emptyList() val superTypeNames = supertypes.asSequence().flatMap { listOf(it) + it.supertypes() }.map { @@ -68,21 +79,25 @@ class KudosSyntheticResolveExtension : SyntheticResolveExtension { ), ) } - if (KUDOS_JSON_ADAPTER !in superTypeNames) { - val kudosJsonAdapter = thisDescriptor.module.findClassAcrossModuleDependencies(KUDOS_JSON_ADAPTER_CLASS_ID)!! - supertypes.add( - KotlinTypeFactory.simpleNotNullType( - TypeAttributes.Empty, - kudosJsonAdapter, - listOf(TypeProjectionImpl(thisDescriptor.defaultType)), - ), - ) + if (Options.isAndroidJsonReaderEnabled(kudosAnnotationValueMap, thisDescriptor.classId?.asString())) { + if (KUDOS_JSON_ADAPTER !in superTypeNames) { + val kudosJsonAdapter = thisDescriptor.module.findClassAcrossModuleDependencies(KUDOS_JSON_ADAPTER_CLASS_ID)!! + supertypes.add( + KotlinTypeFactory.simpleNotNullType( + TypeAttributes.Empty, + kudosJsonAdapter, + listOf(TypeProjectionImpl(thisDescriptor.defaultType)), + ), + ) + } } } } override fun getSyntheticFunctionNames(thisDescriptor: ClassDescriptor): List<Name> { - if (thisDescriptor.annotations.hasAnnotation(KUDOS_NAME)) { + if (Options.isAndroidJsonReaderEnabled(kudosAnnotationValueMap, thisDescriptor.classId?.asString()) && + thisDescriptor.annotations.hasAnnotation(KUDOS_NAME) + ) { return listOf(KUDOS_FROM_JSON_IDENTIFIER) } return super.getSyntheticFunctionNames(thisDescriptor) diff --git a/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/k2/KudosFirDeclarationGenerator.kt b/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/k2/KudosFirDeclarationGenerator.kt index 82a5c9f..0664ca7 100644 --- a/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/k2/KudosFirDeclarationGenerator.kt +++ b/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/k2/KudosFirDeclarationGenerator.kt @@ -20,6 +20,7 @@ import com.kanyun.kudos.compiler.KudosNames.JSON_READER_CLASS_ID import com.kanyun.kudos.compiler.KudosNames.JSON_READER_IDENTIFIER import com.kanyun.kudos.compiler.KudosNames.KUDOS_FROM_JSON_IDENTIFIER import com.kanyun.kudos.compiler.KudosNames.KUDOS_NAME +import com.kanyun.kudos.compiler.options.Options import org.jetbrains.kotlin.GeneratedDeclarationKey import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.fir.FirSession @@ -48,8 +49,10 @@ import org.jetbrains.kotlin.name.CallableId import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.utils.addToStdlib.runIf -class KudosFirDeclarationGenerator(session: FirSession) : - FirDeclarationGenerationExtension(session) { +class KudosFirDeclarationGenerator( + session: FirSession, + private val kudosAnnotationValueMap: HashMap<String, List<Int>>, +) : FirDeclarationGenerationExtension(session) { companion object { private val PREDICATE = LookupPredicate.create { @@ -71,8 +74,10 @@ class KudosFirDeclarationGenerator(session: FirSession) : } override fun getCallableNamesForClass(classSymbol: FirClassSymbol<*>): Set<Name> { - if (classSymbol in matchedClasses) { - return kudosMethodsNames + if (Options.isAndroidJsonReaderEnabled(kudosAnnotationValueMap, classSymbol.classId.toString())) { + if (classSymbol in matchedClasses) { + return kudosMethodsNames + } } return super.getCallableNamesForClass(classSymbol) } diff --git a/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/k2/KudosFirExtensionRegistrar.kt b/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/k2/KudosFirExtensionRegistrar.kt index 7226f8d..dedfe74 100644 --- a/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/k2/KudosFirExtensionRegistrar.kt +++ b/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/k2/KudosFirExtensionRegistrar.kt @@ -17,19 +17,26 @@ package com.kanyun.kudos.compiler.k2 import org.jetbrains.kotlin.fir.analysis.extensions.FirAdditionalCheckersExtension +import org.jetbrains.kotlin.fir.extensions.FirDeclarationGenerationExtension import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar +import org.jetbrains.kotlin.fir.extensions.FirSupertypeGenerationExtension /** * Created by Benny Huo on 2023/8/21 */ class KudosFirExtensionRegistrar( private val noArgAnnotations: List<String>, + private val kudosAnnotationValueMap: HashMap<String, List<Int>>, ) : FirExtensionRegistrar() { override fun ExtensionRegistrarContext.configurePlugin() { +FirAdditionalCheckersExtension.Factory { session -> KudosFirCheckers(session, noArgAnnotations) } - +::KudosFirSupertypeGenerationExtension - +::KudosFirDeclarationGenerator + +FirSupertypeGenerationExtension.Factory { session -> + KudosFirSupertypeGenerationExtension(session, kudosAnnotationValueMap) + } + +FirDeclarationGenerationExtension.Factory { session -> + KudosFirDeclarationGenerator(session, kudosAnnotationValueMap) + } } } diff --git a/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/k2/KudosFirSupertypeGenerationExtension.kt b/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/k2/KudosFirSupertypeGenerationExtension.kt index 37fa4b8..843ce0a 100644 --- a/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/k2/KudosFirSupertypeGenerationExtension.kt +++ b/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/k2/KudosFirSupertypeGenerationExtension.kt @@ -16,20 +16,29 @@ package com.kanyun.kudos.compiler.k2 +import com.kanyun.kudos.compiler.KudosNames.KUDOS_ANNOTATION_CLASS_ID import com.kanyun.kudos.compiler.KudosNames.KUDOS_JSON_ADAPTER_CLASS_ID import com.kanyun.kudos.compiler.KudosNames.KUDOS_NAME import com.kanyun.kudos.compiler.KudosNames.KUDOS_VALIDATOR_CLASS_ID +import com.kanyun.kudos.compiler.options.Options +import com.kanyun.kudos.compiler.utils.safeAs import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.FirTypeAlias +import org.jetbrains.kotlin.fir.declarations.getAnnotationByClassId import org.jetbrains.kotlin.fir.declarations.utils.classId +import org.jetbrains.kotlin.fir.expressions.FirAnnotation +import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall +import org.jetbrains.kotlin.fir.expressions.FirPropertyAccessExpression +import org.jetbrains.kotlin.fir.expressions.arguments import org.jetbrains.kotlin.fir.extensions.FirDeclarationPredicateRegistrar import org.jetbrains.kotlin.fir.extensions.FirSupertypeGenerationExtension import org.jetbrains.kotlin.fir.extensions.predicate.DeclarationPredicate import org.jetbrains.kotlin.fir.extensions.predicateBasedProvider +import org.jetbrains.kotlin.fir.references.impl.FirSimpleNamedReference import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.scopes.impl.toConeType import org.jetbrains.kotlin.fir.symbols.SymbolInternals @@ -49,6 +58,7 @@ import org.jetbrains.kotlin.name.ClassId */ class KudosFirSupertypeGenerationExtension( session: FirSession, + private val kudosAnnotationValueMap: HashMap<String, List<Int>>, ) : FirSupertypeGenerationExtension(session) { private val hasKudos = DeclarationPredicate.create { @@ -66,6 +76,9 @@ class KudosFirSupertypeGenerationExtension( ): List<FirResolvedTypeRef> { var hasValidator = false var hasJsonAdapter = false + val annotationValues = classLikeDeclaration.symbol.resolvedAnnotationsWithArguments.getAnnotationByClassId(KUDOS_ANNOTATION_CLASS_ID, session) + ?.getIntArrayArgument() + kudosAnnotationValueMap[classLikeDeclaration.classId.toString()] = annotationValues ?: emptyList() for (superTypeRef in resolvedSupertypes) { val superType = superTypeRef.type val superTypeClassIds = superType.allSuperTypeClassIds() @@ -86,19 +99,21 @@ class KudosFirSupertypeGenerationExtension( ) } } - if (!hasJsonAdapter) { - val genericType = ConeClassLikeTypeImpl( - ConeClassLikeLookupTagImpl(classLikeDeclaration.classId), - classLikeDeclaration.typeParameters.map { - it.toConeType() - }.toTypedArray(), - false, - ) - firTypeRefList += buildResolvedTypeRef { - type = KUDOS_JSON_ADAPTER_CLASS_ID.constructClassLikeType( - arrayOf(genericType), - isNullable = false, + if (Options.isAndroidJsonReaderEnabled(kudosAnnotationValueMap, classLikeDeclaration.classId.toString())) { + if (!hasJsonAdapter) { + val genericType = ConeClassLikeTypeImpl( + ConeClassLikeLookupTagImpl(classLikeDeclaration.classId), + classLikeDeclaration.typeParameters.map { + it.toConeType() + }.toTypedArray(), + false, ) + firTypeRefList += buildResolvedTypeRef { + type = KUDOS_JSON_ADAPTER_CLASS_ID.constructClassLikeType( + arrayOf(genericType), + isNullable = false, + ) + } } } return firTypeRefList @@ -134,4 +149,27 @@ class KudosFirSupertypeGenerationExtension( else -> null } } + + private fun FirAnnotation.getIntArrayArgument(): List<Int>? { + if (this !is FirAnnotationCall) return null + return arguments.mapNotNull { + when (it.safeAs<FirPropertyAccessExpression>()?.calleeReference?.safeAs<FirSimpleNamedReference>()?.name?.asString()) { + "KUDOS_ANDROID_JSON_READER" -> { + Options.KUDOS_ANDROID_JSON_READER + } + + "KUDOS_GSON" -> { + Options.KUDOS_GSON + } + + "KUDOS_JACKSON" -> { + Options.KUDOS_JACKSON + } + + else -> { + null + } + } + } + } } diff --git a/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/options/Options.kt b/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/options/Options.kt index a343b54..93679a8 100644 --- a/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/options/Options.kt +++ b/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/options/Options.kt @@ -18,6 +18,10 @@ package com.kanyun.kudos.compiler.options object Options { + const val KUDOS_GSON = 1 + const val KUDOS_JACKSON = 2 + const val KUDOS_ANDROID_JSON_READER = 3 + @JvmField val gson = Option( "gson", @@ -34,9 +38,37 @@ object Options { "<true/false>", ) + @JvmField + val androidJsonReader = Option( + "androidJsonReader", + false, + "Whether to enable the support for AndroidJsonReader.", + "<true/false>", + ) + val all = Options::class.java.declaredFields.filter { it.type == Option::class.java }.map { it.get(null) as Option<*> } + + fun isGsonEnabled(kudosAnnotationValueMap: HashMap<String, List<Int>>, className: String?): Boolean { + if (className.isNullOrEmpty()) return false + val annotationValue = kudosAnnotationValueMap[className] + return if (annotationValue.isNullOrEmpty()) { + gson() + } else { + annotationValue.contains(KUDOS_GSON) + } + } + + fun isAndroidJsonReaderEnabled(kudosAnnotationValueMap: HashMap<String, List<Int>>, className: String?): Boolean { + if (className.isNullOrEmpty()) return false + val annotationValue = kudosAnnotationValueMap[className] + return if (annotationValue.isNullOrEmpty()) { + androidJsonReader() + } else { + annotationValue.contains(KUDOS_ANDROID_JSON_READER) + } + } } 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 93bb0c6..e5056c1 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 @@ -45,12 +45,18 @@ class KudosTests : TestBase() { @Test fun `common_validator`() = testBase() + @Test + fun `gson_annotation`() = testBase() + @Test fun `gson_jsonAdapterCheck`() = testBase() @Test fun `gson_notNull`() = testBase() + @Test + fun `jsonReader_annotation`() = testBase() + @Test fun `jsonReader_deserialize`() = testBase() diff --git a/kudos-compiler/src/test/java/com/kanyun/kudos/compiler/base/TestBase.kt b/kudos-compiler/src/test/java/com/kanyun/kudos/compiler/base/TestBase.kt index 4ba48aa..ab2d483 100644 --- a/kudos-compiler/src/test/java/com/kanyun/kudos/compiler/base/TestBase.kt +++ b/kudos-compiler/src/test/java/com/kanyun/kudos/compiler/base/TestBase.kt @@ -109,6 +109,7 @@ open class TestBase { } private fun jsonReaderDeserialize(): String { + Options.androidJsonReader.set(true) return """ // FILE: JsonReader.kt import com.kanyun.kudos.json.reader.KudosAndroidJsonReader diff --git a/kudos-compiler/testData/gson/annotation.kt b/kudos-compiler/testData/gson/annotation.kt new file mode 100644 index 0000000..d318861 --- /dev/null +++ b/kudos-compiler/testData/gson/annotation.kt @@ -0,0 +1,44 @@ +// SOURCE +// FILE: Main.kt +package com.kanyun.kudos.test + +import com.kanyun.kudos.annotations.Kudos +import com.kanyun.kudos.gson.KUDOS_GSON + +@Kudos(KUDOS_GSON) +class Desc(val descDetail: String) + +@Kudos(KUDOS_GSON) +class Project(val projectName: String, val projectId: Int, val tags: List<String>,val desc: Desc) + +// EXPECT +// FILE: compiles.log +OK +// FILE: Main.kt.ir +package com.kanyun.kudos.test +@Kudos(value = 1) +@JsonAdapter(value = KudosReflectiveTypeAdapterFactory::class) +class Desc(val descDetail: String) : KudosValidator { + constructor{ + ctor<Any>() + init<Desc>() + } + override fun validate(status: Map<String, Boolean>) { + validateField("descDetail", status) + } +} +@Kudos(value = 1) +@JsonAdapter(value = KudosReflectiveTypeAdapterFactory::class) +class Project(val projectName: String, val projectId: Int, val tags: List<String>, val desc: Desc) : KudosValidator { + constructor{ + ctor<Any>() + init<Project>() + } + override fun validate(status: Map<String, Boolean>) { + validateField("projectName", status) + validateField("projectId", status) + validateField("tags", status) + validateField("desc", status) + validateCollection("tags", <this>.tags, "List") + } +} \ No newline at end of file diff --git a/kudos-compiler/testData/jsonReader/annotation.kt b/kudos-compiler/testData/jsonReader/annotation.kt new file mode 100644 index 0000000..a57a9f0 --- /dev/null +++ b/kudos-compiler/testData/jsonReader/annotation.kt @@ -0,0 +1,100 @@ +// SOURCE +// FILE: Main.kt +package com.kanyun.kudos.test + +import com.kanyun.kudos.annotations.Kudos +import com.kanyun.kudos.json.reader.KUDOS_ANDROID_JSON_READER + +@Kudos(KUDOS_ANDROID_JSON_READER) +class Desc(val descDetail: String) + +@Kudos(KUDOS_ANDROID_JSON_READER) +class Project(val projectName: String, val projectId: Int, val tags: List<String>,val desc: Desc) + +// EXPECT +// FILE: compiles.log +OK +// FILE: Main.kt.ir +package com.kanyun.kudos.test +@Kudos(value = 3) +class Desc(val descDetail: String) : KudosValidator, KudosJsonAdapter<Desc> { + override fun fromJson(jsonReader: JsonReader): Desc { + jsonReader.beginObject() + while (jsonReader.hasNext()) { + val tmp0 = jsonReader.nextName() + if (jsonReader.peek() == JsonToken.NULL) { + jsonReader.skipValue() + continue + } + when { + tmp0 == "descDetail" -> { + <this>.descDetail = jsonReader.nextString() + <this>.kudosFieldStatusMap.put("descDetail", <this>.descDetail != null) + } + else -> { + jsonReader.skipValue() + } + } + } + jsonReader.endObject() + validate(<this>.kudosFieldStatusMap) + return <this> + } + constructor{ + ctor<Any>() + init<Desc>() + } + override fun validate(status: Map<String, Boolean>) { + validateField("descDetail", status) + } + private var kudosFieldStatusMap: Map<String, Boolean> = hashMapOf() +} +@Kudos(value = 3) +class Project(val projectName: String, val projectId: Int, val tags: List<String>, val desc: Desc) : KudosValidator, KudosJsonAdapter<Project> { + override fun fromJson(jsonReader: JsonReader): Project { + jsonReader.beginObject() + while (jsonReader.hasNext()) { + val tmp0 = jsonReader.nextName() + if (jsonReader.peek() == JsonToken.NULL) { + jsonReader.skipValue() + continue + } + when { + tmp0 == "projectName" -> { + <this>.projectName = jsonReader.nextString() + <this>.kudosFieldStatusMap.put("projectName", <this>.projectName != null) + } + tmp0 == "projectId" -> { + <this>.projectId = jsonReader.nextInt() + <this>.kudosFieldStatusMap.put("projectId", <this>.projectId != null) + } + tmp0 == "tags" -> { + <this>.tags = parseKudosObject(jsonReader, ParameterizedTypeImpl(List<String>::class.javaObjectType, arrayOf(String::class.javaObjectType))) + <this>.kudosFieldStatusMap.put("tags", <this>.tags != null) + } + tmp0 == "desc" -> { + <this>.desc = parseKudosObject(jsonReader, Desc::class.javaObjectType) + <this>.kudosFieldStatusMap.put("desc", <this>.desc != null) + } + else -> { + jsonReader.skipValue() + } + } + } + jsonReader.endObject() + validate(<this>.kudosFieldStatusMap) + return <this> + } + constructor{ + ctor<Any>() + init<Project>() + } + override fun validate(status: Map<String, Boolean>) { + validateField("projectName", status) + validateField("projectId", status) + validateField("tags", status) + validateField("desc", status) + validateCollection("tags", <this>.tags, "List") + } + private var kudosFieldStatusMap: Map<String, Boolean> = hashMapOf() +} \ No newline at end of file diff --git a/kudos-compiler/testData/jsonReader/simple.kt b/kudos-compiler/testData/jsonReader/simple.kt index 01192d3..77a24be 100644 --- a/kudos-compiler/testData/jsonReader/simple.kt +++ b/kudos-compiler/testData/jsonReader/simple.kt @@ -15,7 +15,7 @@ class Project(val projectName: String, val projectId: Int, val tags: List<String OK // FILE: Main.kt.ir package com.kanyun.kudos.test -@Kudos +@Kudos(value = ) class Desc(val descDetail: String) : KudosValidator, KudosJsonAdapter<Desc> { override fun fromJson(jsonReader: JsonReader): Desc { jsonReader.beginObject() @@ -48,7 +48,7 @@ class Desc(val descDetail: String) : KudosValidator, KudosJsonAdapter<Desc> { } private var kudosFieldStatusMap: Map<String, Boolean> = hashMapOf() } -@Kudos +@Kudos(value = ) class Project(val projectName: String, val projectId: Int, val tags: List<String>, val desc: Desc) : KudosValidator, KudosJsonAdapter<Project> { override fun fromJson(jsonReader: JsonReader): Project { jsonReader.beginObject() diff --git a/kudos-gradle-plugin/src/main/java/com/kanyun/kudos/gradle/KudosExtension.kt b/kudos-gradle-plugin/src/main/java/com/kanyun/kudos/gradle/KudosExtension.kt index 88fa835..9830bc2 100644 --- a/kudos-gradle-plugin/src/main/java/com/kanyun/kudos/gradle/KudosExtension.kt +++ b/kudos-gradle-plugin/src/main/java/com/kanyun/kudos/gradle/KudosExtension.kt @@ -22,4 +22,5 @@ package com.kanyun.kudos.gradle open class KudosExtension { var gson: Boolean = false var jackson: Boolean = false + var androidJsonReader: Boolean = false } diff --git a/kudos-gradle-plugin/src/main/java/com/kanyun/kudos/gradle/KudosGradlePlugin.kt b/kudos-gradle-plugin/src/main/java/com/kanyun/kudos/gradle/KudosGradlePlugin.kt index 1021100..bfefec4 100644 --- a/kudos-gradle-plugin/src/main/java/com/kanyun/kudos/gradle/KudosGradlePlugin.kt +++ b/kudos-gradle-plugin/src/main/java/com/kanyun/kudos/gradle/KudosGradlePlugin.kt @@ -46,8 +46,9 @@ open class KudosGradlePlugin : KotlinCompilerPluginSupportPlugin { if (kudosExtension.jackson) { config += "${BuildConfig.KOTLIN_PLUGIN_GROUP}:kudos-jackson:${BuildConfig.KOTLIN_PLUGIN_VERSION}" } - // TODO: Add json reader config - config += "${BuildConfig.KOTLIN_PLUGIN_GROUP}:kudos-android-json-reader:${BuildConfig.KOTLIN_PLUGIN_VERSION}" + if (kudosExtension.androidJsonReader) { + config += "${BuildConfig.KOTLIN_PLUGIN_GROUP}:kudos-android-json-reader:${BuildConfig.KOTLIN_PLUGIN_VERSION}" + } config += "${BuildConfig.KOTLIN_PLUGIN_GROUP}:kudos-annotations:${BuildConfig.KOTLIN_PLUGIN_VERSION}" config += "${BuildConfig.KOTLIN_PLUGIN_GROUP}:kudos-runtime:${BuildConfig.KOTLIN_PLUGIN_VERSION}" } @@ -76,6 +77,9 @@ open class KudosGradlePlugin : KotlinCompilerPluginSupportPlugin { if (kudosExtension.jackson) { options += SubpluginOption("jackson", "true") } + if (kudosExtension.androidJsonReader) { + options += SubpluginOption("androidJsonReader", "true") + } return project.provider { options } } } diff --git a/kudos-gson/src/main/java/com/kanyun/kudos/gson/KudosGson.kt b/kudos-gson/src/main/java/com/kanyun/kudos/gson/KudosGson.kt index c99a31d..dee29fa 100644 --- a/kudos-gson/src/main/java/com/kanyun/kudos/gson/KudosGson.kt +++ b/kudos-gson/src/main/java/com/kanyun/kudos/gson/KudosGson.kt @@ -29,3 +29,5 @@ fun kudosGsonBuilder(): GsonBuilder { fun kudosGson(): Gson { return kudosGsonBuilder().create() } + +const val KUDOS_GSON: Int = 1 diff --git a/kudos-jackson/src/main/java/com/kanyun/kudos/jackson/KudosObjectMapper.kt b/kudos-jackson/src/main/java/com/kanyun/kudos/jackson/KudosObjectMapper.kt index 611697a..752b5d4 100644 --- a/kudos-jackson/src/main/java/com/kanyun/kudos/jackson/KudosObjectMapper.kt +++ b/kudos-jackson/src/main/java/com/kanyun/kudos/jackson/KudosObjectMapper.kt @@ -42,3 +42,5 @@ fun kudosObjectMapper( } return ObjectMapper(jf, sp, deserializationContext) } + +const val KUDOS_JACKSON: Int = 2 From 3982940e66dc3d80796276aee9e350961085eda7 Mon Sep 17 00:00:00 2001 From: RicardoJiang <2868405029@qq.com> Date: Tue, 21 Nov 2023 11:11:42 +0800 Subject: [PATCH 2/2] MOD: throw exception when unkown annotation --- .../com/kanyun/kudos/json/reader/KudosAndroidJsonReader.kt | 4 ++-- .../kudos/compiler/k1/KudosSyntheticResolveExtension.kt | 3 +++ .../compiler/k2/KudosFirSupertypeGenerationExtension.kt | 6 +++--- .../main/java/com/kanyun/kudos/compiler/options/Options.kt | 1 + 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/kudos-android-json-reader/src/main/java/com/kanyun/kudos/json/reader/KudosAndroidJsonReader.kt b/kudos-android-json-reader/src/main/java/com/kanyun/kudos/json/reader/KudosAndroidJsonReader.kt index 0f8e959..4bdd8aa 100644 --- a/kudos-android-json-reader/src/main/java/com/kanyun/kudos/json/reader/KudosAndroidJsonReader.kt +++ b/kudos-android-json-reader/src/main/java/com/kanyun/kudos/json/reader/KudosAndroidJsonReader.kt @@ -32,10 +32,10 @@ object KudosAndroidJsonReader { return fromJson(inputStream.bufferedReader(), T::class.java) } - fun <T> fromJson(bufferReader: BufferedReader, clazz: Class<T>): T { + fun <T> fromJson(bufferedReader: BufferedReader, clazz: Class<T>): T { val adapter = clazz.getDeclaredConstructor().newInstance() return if (adapter is KudosJsonAdapter<*>) { - val jsonReader = JsonReader(bufferReader) + val jsonReader = JsonReader(bufferedReader) adapter.fromJson(jsonReader) as T } else { throw IllegalArgumentException("class ${clazz.name} must implement KudosJsonAdapter") diff --git a/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/k1/KudosSyntheticResolveExtension.kt b/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/k1/KudosSyntheticResolveExtension.kt index 54900dc..aba1964 100644 --- a/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/k1/KudosSyntheticResolveExtension.kt +++ b/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/k1/KudosSyntheticResolveExtension.kt @@ -60,6 +60,9 @@ class KudosSyntheticResolveExtension( if (thisDescriptor.annotations.hasAnnotation(KUDOS_NAME)) { val kudosAnnotation = thisDescriptor.annotations.findAnnotation(KUDOS_NAME) val annotationValues = kudosAnnotation?.allValueArguments?.values?.firstOrNull()?.value?.safeAs<List<IntValue>>()?.map { + if (it.value !in Options.validAnnotationList) { + throw IllegalArgumentException("unknown annotation argument ${it.value}") + } it.value } kudosAnnotationValueMap[thisDescriptor.classId?.asString() ?: ""] = annotationValues ?: emptyList() diff --git a/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/k2/KudosFirSupertypeGenerationExtension.kt b/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/k2/KudosFirSupertypeGenerationExtension.kt index 843ce0a..076aca5 100644 --- a/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/k2/KudosFirSupertypeGenerationExtension.kt +++ b/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/k2/KudosFirSupertypeGenerationExtension.kt @@ -152,8 +152,8 @@ class KudosFirSupertypeGenerationExtension( private fun FirAnnotation.getIntArrayArgument(): List<Int>? { if (this !is FirAnnotationCall) return null - return arguments.mapNotNull { - when (it.safeAs<FirPropertyAccessExpression>()?.calleeReference?.safeAs<FirSimpleNamedReference>()?.name?.asString()) { + return arguments.map { + when (val annotationValue = it.safeAs<FirPropertyAccessExpression>()?.calleeReference?.safeAs<FirSimpleNamedReference>()?.name?.asString()) { "KUDOS_ANDROID_JSON_READER" -> { Options.KUDOS_ANDROID_JSON_READER } @@ -167,7 +167,7 @@ class KudosFirSupertypeGenerationExtension( } else -> { - null + throw IllegalArgumentException("unknown annotation argument $annotationValue") } } } diff --git a/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/options/Options.kt b/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/options/Options.kt index 93679a8..28365fb 100644 --- a/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/options/Options.kt +++ b/kudos-compiler/src/main/java/com/kanyun/kudos/compiler/options/Options.kt @@ -21,6 +21,7 @@ object Options { const val KUDOS_GSON = 1 const val KUDOS_JACKSON = 2 const val KUDOS_ANDROID_JSON_READER = 3 + val validAnnotationList = listOf(KUDOS_GSON, KUDOS_JACKSON, KUDOS_ANDROID_JSON_READER) @JvmField val gson = Option(