Retrofit 结合 Moshi:将 JsonArray 转换为字符串
解决Moshi将JSON数组字段解析为原始字符串的问题
这个场景我之前处理过,核心思路是给Moshi编写一个自定义Json适配器,让它把原本应该解析成数组的字段直接转成原始JSON字符串。下面结合你的代码结构一步步实现:
1. 编写自定义Json适配器
这个适配器负责把JsonReader读取到的JSON数组(或任意JSON元素)转换成字符串,同时支持把字符串写回成JSON格式(如果需要上传的话):
class RawJsonStringAdapter { // 从JSON解析为字符串:读取整个JSON元素并转成原始字符串 @FromJson fun fromJson(reader: JsonReader): String { // readJsonValue()会读取当前位置的整个JSON元素(这里是数组),返回对应的Kotlin对象,再转成字符串 return reader.readJsonValue().toString() } // 把字符串写回JSON:将原始字符串解析为JSON值再写入 @ToJson fun toJson(writer: JsonWriter, rawJsonString: String?) { if (rawJsonString == null) { writer.nullValue() return } // 临时用Moshi把字符串解析回JSON对象,再写入到输出流 val jsonValue = Moshi.Builder().build().adapter(Any::class.java).fromJson(rawJsonString) writer.value(jsonValue) } }
2. 修改Book实体类
给params字段指定我们的自定义适配器,有两种方式:
方式一:直接用@JsonAdapter注解
直接在字段上绑定适配器:
data class Book( val id: String, val name: String, // 指定用自定义适配器解析这个字段 @JsonAdapter(RawJsonStringAdapter::class) val params: String )
方式二:用自定义注解(更通用)
如果多个字段都需要这种解析方式,可以定义一个注解,把适配器和注解关联:
// 定义一个限定符注解 @Retention(AnnotationRetention.RUNTIME) @JsonQualifier annotation class RawJson // 修改适配器,关联这个注解 class RawJsonStringAdapter { @FromJson @RawJson fun fromJson(reader: JsonReader): String { return reader.readJsonValue().toString() } @ToJson fun toJson(writer: JsonWriter, @RawJson rawJsonString: String?) { if (rawJsonString == null) { writer.nullValue() return } val jsonValue = Moshi.Builder().build().adapter(Any::class.java).fromJson(rawJsonString) writer.value(jsonValue) } }
然后Book类里用这个注解标记字段:
data class Book( val id: String, val name: String, @RawJson val params: String )
3. 配置Retrofit和Moshi实例
创建Moshi的时候一定要把自定义适配器添加进去,否则注解不会生效:
// 初始化带自定义适配器的Moshi val moshi = Moshi.Builder() .add(RawJsonStringAdapter()) // 关键:添加我们的适配器 .build() // 初始化Retrofit,使用配置好的Moshi val retrofit = Retrofit.Builder() .baseUrl("你的服务器基础地址") .addConverterFactory(MoshiConverterFactory.create(moshi)) .build()
4. 保持Retrofit接口不变
你的请求接口不需要修改,还是正常定义返回List<Book>:
interface BookApi { @GET("books") suspend fun getBooks(): List<Book> }
原理说明
当Moshi解析params字段时,会触发我们的fromJson方法:reader.readJsonValue()会一次性读取整个JSON数组(不管数组里的元素结构),然后转成原始的JSON字符串,这样params字段就会被赋值为服务器返回的数组原始文本了。
如果后续需要把params作为JSON数组上传回服务器,toJson方法会把字符串解析回JSON对象再写入,确保服务器能正确识别格式。
内容的提问来源于stack exchange,提问作者deadfish
相关产品推荐
相关产品推荐

