diff --git a/app/build/generated/ksp/debug/kotlin/rxhttp/wrapper/param/BaseRxHttp.kt b/app/build/generated/ksp/debug/kotlin/rxhttp/wrapper/param/BaseRxHttp.kt index 7c5b72f0..d8692189 100644 --- a/app/build/generated/ksp/debug/kotlin/rxhttp/wrapper/param/BaseRxHttp.kt +++ b/app/build/generated/ksp/debug/kotlin/rxhttp/wrapper/param/BaseRxHttp.kt @@ -69,7 +69,7 @@ public abstract class BaseRxHttp : ITag, CallFactory { } public fun toObservableResponse(type: Type): ObservableCall = - toObservable(wrapResponseParser(type)) + toObservable(wrapResponseParser(type)) public fun toObservableResponse(type: Class): ObservableCall = toObservableResponse(type as Type) diff --git a/app/build/generated/ksp/debug/kotlin/rxhttp/wrapper/param/RxHttpExtension.kt b/app/build/generated/ksp/debug/kotlin/rxhttp/wrapper/param/RxHttpExtension.kt index 8754f2a4..b2e83792 100644 --- a/app/build/generated/ksp/debug/kotlin/rxhttp/wrapper/param/RxHttpExtension.kt +++ b/app/build/generated/ksp/debug/kotlin/rxhttp/wrapper/param/RxHttpExtension.kt @@ -22,7 +22,7 @@ public inline fun BaseRxHttp.toObservableResponse(): ObservableCall< toObservableResponse(javaTypeOf()) public inline fun CallFactory.toAwaitResponse(): CallAwait = - toAwait(BaseRxHttp.wrapResponseParser(javaTypeOf())) + toAwait(BaseRxHttp.wrapResponseParser(javaTypeOf())) public inline fun CallFactory.toFlowResponse(): CallFlow = - toFlow(BaseRxHttp.wrapResponseParser(javaTypeOf())) + toFlow(BaseRxHttp.wrapResponseParser(javaTypeOf())) diff --git a/app/src/test/java/com/rxhttp/compiler/KspProcessorTest.kt b/app/src/test/java/com/rxhttp/compiler/KspProcessorTest.kt index 6a9349a1..e92f661e 100644 --- a/app/src/test/java/com/rxhttp/compiler/KspProcessorTest.kt +++ b/app/src/test/java/com/rxhttp/compiler/KspProcessorTest.kt @@ -4,8 +4,7 @@ import com.google.devtools.ksp.processing.CodeGenerator import com.google.devtools.ksp.processing.Resolver import com.google.devtools.ksp.symbol.KSAnnotated import com.google.devtools.ksp.symbol.KSClassDeclaration -import com.squareup.kotlinpoet.ksp.toTypeName -import com.squareup.kotlinpoet.ksp.toTypeParameterResolver +import com.rxhttp.compiler.ksp.getParserTypeParam import com.tschuchort.compiletesting.KotlinCompilation import com.tschuchort.compiletesting.SourceFile import com.tschuchort.compiletesting.symbolProcessorProviders @@ -51,23 +50,12 @@ class KspProcessorTest { override fun process(resolver: Resolver): List { resolver.getSymbolsWithAnnotation(Parser::class.java.name).forEach { if (it is KSClassDeclaration) { - it.test() + val parserTypeParam = it.getParserTypeParam() + println("parserTypeParam=$parserTypeParam") } } return emptyList() } - - private fun KSClassDeclaration.test() { -// val typeName = -// asStarProjectedType().toTypeName(typeParameters.toTypeParameterResolver()) -// println("typeName=$typeName") - superTypes.forEach { - val typeName = - it.toTypeName(it.resolve().declaration.typeParameters.toTypeParameterResolver()) - println("typeName=$typeName") - (it.resolve().declaration as KSClassDeclaration).test() - } - } } private fun sourceFiles(): List { @@ -75,17 +63,23 @@ class KspProcessorTest { val entityPath = "src/main/java/com/example/httpsender/entity" val annotationPrefix = "../rxhttp-annotation/src/main/java/rxhttp/wrapper/annotation" val parserPrefix = "../rxhttp/src/main/java/rxhttp/wrapper/parse" + val testPrefix = "src/test/java/com/rxhttp/compiler" return mutableListOf( - "$kotlinPath/ResponseParser.kt", +// "$kotlinPath/ResponseParser.kt", "$entityPath/Response.java", "$parserPrefix/TypeParser.java", "$parserPrefix/Parser.java", + "$parserPrefix/TypeParser.java", "$annotationPrefix/Converter.java", "$annotationPrefix/DefaultDomain.java", "$annotationPrefix/Domain.java", "$annotationPrefix/OkClient.java", "$annotationPrefix/Param.java", "$annotationPrefix/Parser.java", + "$testPrefix/TestParser1.kt", + "$testPrefix/TestParser2.kt", + "src/main/java/com/example/httpsender/entity/User.java", + "../rxhttp/src/main/java/rxhttp/wrapper/callback/Consumer.java" ).map { SourceFile.fromPath(File(it)) } } diff --git a/app/src/test/java/com/rxhttp/compiler/TestParser1.kt b/app/src/test/java/com/rxhttp/compiler/TestParser1.kt new file mode 100644 index 00000000..885c9c2b --- /dev/null +++ b/app/src/test/java/com/rxhttp/compiler/TestParser1.kt @@ -0,0 +1,16 @@ +package com.rxhttp.compiler + +import rxhttp.wrapper.parse.TypeParser + +/** + * User: ljx + * Date: 2023/8/28 + * Time: 11:12 + */ +open class TestParser1 : TypeParser { + + protected constructor() : super() + override fun onParse(response: okhttp3.Response): F { + TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/app/src/test/java/com/rxhttp/compiler/TestParser2.kt b/app/src/test/java/com/rxhttp/compiler/TestParser2.kt new file mode 100644 index 00000000..30bd6772 --- /dev/null +++ b/app/src/test/java/com/rxhttp/compiler/TestParser2.kt @@ -0,0 +1,32 @@ +package com.rxhttp.compiler + +import com.example.httpsender.entity.Response +import com.example.httpsender.entity.User +import rxhttp.wrapper.annotation.Parser +import rxhttp.wrapper.callback.Consumer +import java.lang.reflect.Type + +/** + * User: ljx + * Date: 2023/8/28 + * Time: 11:12 + */ +@Parser(name = "test") +class TestParser2: TestParser1?, C>, + rxhttp.wrapper.parse.Parser?> { + + protected constructor() : super() + + constructor(typeT: Type, typeF: Type, typeS: Type) + + override fun onParse(response: okhttp3.Response): Response { + TODO("Not yet implemented") +// return null +// return super.onParse(response) + } + +// override fun accept(t: User) { +// TODO("Not yet implemented") +// } + +} \ No newline at end of file diff --git a/rxhttp-compiler/src/main/java/com/rxhttp/compiler/ksp/Ksp.kt b/rxhttp-compiler/src/main/java/com/rxhttp/compiler/ksp/Ksp.kt index 27910710..53f272cf 100644 --- a/rxhttp-compiler/src/main/java/com/rxhttp/compiler/ksp/Ksp.kt +++ b/rxhttp-compiler/src/main/java/com/rxhttp/compiler/ksp/Ksp.kt @@ -22,6 +22,7 @@ import com.google.devtools.ksp.symbol.Origin import com.rxhttp.compiler.K_ARRAY_TYPE import com.rxhttp.compiler.K_TYPE import com.squareup.javapoet.JavaFile +import com.squareup.kotlinpoet.ANY import com.squareup.kotlinpoet.AnnotationSpec import com.squareup.kotlinpoet.BOOLEAN import com.squareup.kotlinpoet.BOOLEAN_ARRAY @@ -165,6 +166,59 @@ fun KSClassDeclaration.findOnParserFunReturnType(): TypeName? { return ksFunction?.returnType?.toTypeName(typeParameters.toTypeParameterResolver()) } +/** + * 获取Parser接口实际泛型类型 + * @param typeNameMap key 类自身声明的泛型名称,如XxxParser value 子类(实现类)传递的真实泛型类型, 如 AParser : XxxParser, Book> + */ +fun KSClassDeclaration.getParserTypeParam(typeNameMap: Map? = null): TypeName? { + val className = qualifiedName?.asString() + val parserName = "rxhttp.wrapper.parse.Parser" + val typeParserName = "rxhttp.wrapper.parse.TypeParser" + val typeParameters = typeParameters + if (parserName == className || typeParserName == className) { + return typeNameMap?.get(typeParameters.first().name.asString()) + } + val typeParamResolver = typeParameters.toTypeParameterResolver() + for (superType in superTypes) { //superTypes 包含父类及直接实现的接口 + val typeName = superType.toTypeName(typeParamResolver) //引用的父类类型 + if (typeName == ANY) continue + val ksDeclaration = superType.resolve().declaration //声明的父类类型 + if (typeName is ParameterizedTypeName) { + //将泛型类型转换为子类传递的类型 + val typeNames = typeName.typeArguments.map { it.convert(typeNameMap) } + val ksTypeParameters = ksDeclaration.typeParameters //获取类自身声明的泛型列表 + var i = 0 + val newTypeNameMap = ksTypeParameters.associate { + it.name.asString() to typeNames[i++] + } + val answer = (ksDeclaration as KSClassDeclaration).getParserTypeParam(newTypeNameMap) + if (answer != null) { + return answer + } + } else { + (ksDeclaration as KSClassDeclaration).getParserTypeParam() + } + } + return null +} + +fun TypeName.convert(typeNameMap: Map? = null): TypeName { + if (typeNameMap == null) return this + return when (this) { + is TypeVariableName -> { + val typeName = typeNameMap[name] + return typeName?.copy(typeName.isNullable || isNullable) ?: this + } + + is ParameterizedTypeName -> { + rawType.parameterizedBy(typeArguments.map { it.convert(typeNameMap) }) + .copy(isNullable) + } + + else -> this + } +} + fun ParameterSpec.isVararg() = modifiers.contains(KModifier.VARARG) fun KSClassDeclaration.getPublicConstructors() = getConstructors().filter { it.isPublic() } diff --git a/rxhttp-compiler/src/main/java/com/rxhttp/compiler/ksp/ParserVisitor.kt b/rxhttp-compiler/src/main/java/com/rxhttp/compiler/ksp/ParserVisitor.kt index 01477965..7c6de8e0 100644 --- a/rxhttp-compiler/src/main/java/com/rxhttp/compiler/ksp/ParserVisitor.kt +++ b/rxhttp-compiler/src/main/java/com/rxhttp/compiler/ksp/ParserVisitor.kt @@ -106,7 +106,7 @@ private fun KSClassDeclaration.getToObservableXxxFun( ): List { val funList = arrayListOf() //onParser方法返回类型 - val onParserFunReturnType = findOnParserFunReturnType() ?: return emptyList() + val onParserFunReturnType = getParserTypeParam() ?: return emptyList() val typeVariableNames = typeParameters.map { it.toTypeVariableName() } val typeCount = typeVariableNames.size //泛型数量 val customParser = toClassName() @@ -139,7 +139,7 @@ private fun KSClassDeclaration.getToObservableXxxFun( val toObservableXxxFunBody = if (typeCount == 1 && onParserFunReturnType is TypeVariableName) { val paramNames = typeParameterSpecs.toParamNames() - CodeBlock.of("return toObservable(%M$types($paramNames))", wrapCustomParser) + CodeBlock.of("return toObservable(%M($paramNames))", wrapCustomParser) } else { val paramNames = typeParameterSpecs.toParamNames(originParameterSpecs, typeCount) CodeBlock.of("return toObservable(%T$types($paramNames))", customParser) diff --git a/rxhttp-compiler/src/main/java/com/rxhttp/compiler/ksp/RxHttpExtensions.kt b/rxhttp-compiler/src/main/java/com/rxhttp/compiler/ksp/RxHttpExtensions.kt index fdd9c932..4eaf3f09 100644 --- a/rxhttp-compiler/src/main/java/com/rxhttp/compiler/ksp/RxHttpExtensions.kt +++ b/rxhttp-compiler/src/main/java/com/rxhttp/compiler/ksp/RxHttpExtensions.kt @@ -52,7 +52,7 @@ class RxHttpExtensions(private val logger: KSPLogger) { val typeVariableNames = ksClass.typeParameters.map { it.toTypeVariableName().copy(reified = true) } - val onParserFunReturnType = ksClass.findOnParserFunReturnType() ?: return + val onParserFunReturnType = ksClass.getParserTypeParam() ?: return val typeCount = typeVariableNames.size //泛型数量 val customParser = ksClass.toClassName() @@ -101,7 +101,7 @@ class RxHttpExtensions(private val logger: KSPLogger) { if (typeCount == 1 && onParserFunReturnType is TypeVariableName) { val baseRxHttp = ClassName(rxHttpPackage, "BaseRxHttp") val wrapFun = "%T.wrap${customParser.simpleName}" - funBody = "return %M($wrapFun$types($finalParams))" + funBody = "return %M($wrapFun($finalParams))" baseRxHttp } else { var params = finalParams