Skip to content

Commit

Permalink
修复解析器onParse方法返回可空类型时,ksp编译报错问题 #456
Browse files Browse the repository at this point in the history
  • Loading branch information
liujingxing committed Sep 21, 2023
1 parent d8aa537 commit 4a6eee6
Show file tree
Hide file tree
Showing 8 changed files with 119 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public abstract class BaseRxHttp : ITag, CallFactory {
}

public fun <T> toObservableResponse(type: Type): ObservableCall<T> =
toObservable(wrapResponseParser<T>(type))
toObservable(wrapResponseParser(type))

public fun <T> toObservableResponse(type: Class<T>): ObservableCall<T> =
toObservableResponse<T>(type as Type)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public inline fun <reified T> BaseRxHttp.toObservableResponse(): ObservableCall<
toObservableResponse<T>(javaTypeOf<T>())

public inline fun <reified T> CallFactory.toAwaitResponse(): CallAwait<T> =
toAwait(BaseRxHttp.wrapResponseParser<T>(javaTypeOf<T>()))
toAwait(BaseRxHttp.wrapResponseParser(javaTypeOf<T>()))

public inline fun <reified T> CallFactory.toFlowResponse(): CallFlow<T> =
toFlow(BaseRxHttp.wrapResponseParser<T>(javaTypeOf<T>()))
toFlow(BaseRxHttp.wrapResponseParser(javaTypeOf<T>()))
26 changes: 10 additions & 16 deletions app/src/test/java/com/rxhttp/compiler/KspProcessorTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -51,41 +50,36 @@ class KspProcessorTest {
override fun process(resolver: Resolver): List<KSAnnotated> {
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<SourceFile> {
val kotlinPath = "src/main/java/com/example/httpsender/parser"
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)) }
}

Expand Down
16 changes: 16 additions & 0 deletions app/src/test/java/com/rxhttp/compiler/TestParser1.kt
Original file line number Diff line number Diff line change
@@ -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<T, F, S> : TypeParser<F> {

protected constructor() : super()
override fun onParse(response: okhttp3.Response): F {
TODO("Not yet implemented")
}
}
32 changes: 32 additions & 0 deletions app/src/test/java/com/rxhttp/compiler/TestParser2.kt
Original file line number Diff line number Diff line change
@@ -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<A, B, C>: TestParser1<A, Response<B?>?, C>,
rxhttp.wrapper.parse.Parser<Response<B?>?> {

protected constructor() : super()

constructor(typeT: Type, typeF: Type, typeS: Type)

override fun onParse(response: okhttp3.Response): Response<B?> {
TODO("Not yet implemented")
// return null
// return super.onParse(response)
}

// override fun accept(t: User) {
// TODO("Not yet implemented")
// }

}
54 changes: 54 additions & 0 deletions rxhttp-compiler/src/main/java/com/rxhttp/compiler/ksp/Ksp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -165,6 +166,59 @@ fun KSClassDeclaration.findOnParserFunReturnType(): TypeName? {
return ksFunction?.returnType?.toTypeName(typeParameters.toTypeParameterResolver())
}

/**
* 获取Parser接口实际泛型类型
* @param typeNameMap key 类自身声明的泛型名称,如XxxParser<A, B> value 子类(实现类)传递的真实泛型类型, 如 AParser<A> : XxxParser<User<A>, Book>
*/
fun KSClassDeclaration.getParserTypeParam(typeNameMap: Map<String, TypeName>? = 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<String, TypeName>? = 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() }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ private fun KSClassDeclaration.getToObservableXxxFun(
): List<FunSpec> {
val funList = arrayListOf<FunSpec>()
//onParser方法返回类型
val onParserFunReturnType = findOnParserFunReturnType() ?: return emptyList()
val onParserFunReturnType = getParserTypeParam() ?: return emptyList()
val typeVariableNames = typeParameters.map { it.toTypeVariableName() }
val typeCount = typeVariableNames.size //泛型数量
val customParser = toClassName()
Expand Down Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 4a6eee6

Please sign in to comment.