Apollo Kotlin GraphQL使用Fragment时Moshi转换无法识别Fragment类型
解决Apollo Kotlin中Fragment在Moshi转换时的字段映射问题
问题核心
使用Fragment编写GraphQL查询后,Apollo生成的Kotlin类会将Fragment字段包装在userDataFields嵌套对象中,但实际API返回的响应是平铺展开Fragment字段(GraphQL服务器会自动内联展开Fragment),导致纯Moshi解析时找不到userDataFields字段,最终该属性为null。
解决方案
1. 使用Apollo Kotlin自带的响应解析器(推荐)
Apollo内置了专门处理GraphQL响应(包括Fragment映射)的解析逻辑,不需要用纯Moshi解析。单元测试中可以直接用Apollo提供的工具来解析JSON响应:
// 读取本地JSON文件内容 val jsonString = File("your-json-file-path").readText() // 创建ApolloClient实例(测试无需真实服务器地址) val apolloClient = ApolloClient.Builder() .serverUrl("http://dummy-url.com") .build() // 用Apollo的JsonParser解析响应到生成的Data类 val data = apolloClient.apolloStore.jsonParser.parse( UserDetailsSearchQuery.Data.serializer(), jsonString )
这种方式会自动处理Fragment的字段映射,将平铺的JSON字段正确填充到userDataFields中。
2. 修改Apollo代码生成配置,取消Fragment字段嵌套
如果坚持要用纯Moshi解析,可以修改Apollo的Gradle配置,让生成的Kotlin类直接平铺Fragment字段,避免嵌套:
在模块的build.gradle.kts(或build.gradle)中添加:
apollo { generateKotlinModels.set(true) // 使用flat模式生成模型,Fragment字段会直接合并到父类中 codegenModels.set("flat") }
重新生成代码后,FetchData类会直接包含id、name、profile等字段,不再有userDataFields嵌套对象,此时用Moshi解析平铺的JSON就能正常映射。
3. 自定义Moshi Adapter手动映射字段
如果无法修改配置或使用Apollo解析器,可以编写自定义Moshi Adapter,将平铺的JSON字段手动组装到userDataFields中:
class FetchDataAdapter(private val moshi: Moshi) { private val profileAdapter = moshi.adapter(Profile::class.java) @FromJson fun fromJson(json: Map<String, Any?>): FetchData { return FetchData( __typename = json["__typename"] as String, userDataFields = UserDataFields( id = json["id"] as String, name = json["name"] as String, profile = profileAdapter.fromJsonValue(json["profile"] as Map<String, Any?>)!! ) ) } }
然后在构建Moshi时添加这个Adapter:
val moshi = Moshi.Builder() .add(KotlinJsonAdapterFactory()) .add(FetchDataAdapter(Moshi.Builder().add(KotlinJsonAdapterFactory()).build())) .build() // 之后用这个Moshi解析即可 val mockResponse = typeFromLocalJson<UserDetailsSearchQuery.Data>( "your-json-file-path", moshi ).getOrHandle { throw it }
内容的提问来源于stack exchange,提问作者skv1996
相关产品推荐
相关产品推荐

