能否用JsonQualifier标注Map<String, List<T1>>?@ToJson函数报错求解
问题
- 能否使用
@JsonQualifier标注Map<String, List<T1>>? - 我实现的
@ToJson函数存在什么问题? - 运行时抛出
IllegalArgumentException:No @ToJson adapter for java.util.Map<java.lang.String, java.util.List> annotated [@CheckMap()],该如何解决?
需要解析的JSON结构如下:
"A" : [ { "a": [ {T1}, {T1}, {T1} ], "b": [ {T1}, {T1} ], "c": [ {T1}, {T1} ] }, { "d": [ {T1}, {T1} ], "e": [ {T1} ], "f": [ {T1}, {T1} ] } ]
注:a、b、c、d、e、f为任意名称,T1是映射为实体类的JSON对象,且必须使用适配器(无法像GSON那样直接自动处理)。
我的代码实现:
@Retention(AnnotationRetention.RUNTIME) @JsonQualifier annotation class CheckMap ... @JsonClass(generateAdapter = true) data class SomeElement( @CheckMap val s: Map<String, List<T1>> ) ... class CheckMapAdapter { @FromJson @CheckMap fun fromJson(foo: Map<String, List<T1>>): Map<String, List<T1>> { return foo } @ToJson fun toJson(@CheckMap test: Map<String, List<T1>>): String { return "something" } }
解答
关于@JsonQualifier标注Map<String, List<T1>>
完全可以用@JsonQualifier标注该泛型类型,但要保证适配器的方法签名和目标类型严格匹配,并且适配器要正确注册到Moshi实例中。
@ToJson函数的问题
你的@ToJson方法存在两个核心问题:
- 返回类型错误:Moshi要求
@ToJson方法返回的是Moshi能够直接序列化的类型(比如Map、List、带@JsonClass的实体类等),而不是直接返回String。直接返回字符串会让Moshi把它当作普通字符串值处理,无法匹配到原本的Map<String, List<T1>>类型适配器,导致报错。 - 缺少限定符注解:
@ToJson方法的返回值没有添加@CheckMap注解,Moshi无法将这个方法关联到带@CheckMap标注的目标类型上。
解决运行时错误的具体步骤
修正
@ToJson方法签名
如果只是需要对Map做自定义处理后再序列化,保持返回类型和输入一致即可,同时给返回值加上@CheckMap:@ToJson @CheckMap fun toJson(@CheckMap test: Map<String, List<T1>>): Map<String, List<T1>> { // 这里可以加入自定义逻辑,比如过滤无效元素、修改T1属性等 return test }如果需要完全手动控制JSON输出,可以使用
JsonWriter来构建内容:@ToJson fun toJson(writer: JsonWriter, @CheckMap test: Map<String, List<T1>>) { writer.beginObject() test.forEach { (key, t1List) -> writer.name(key) // 借助Moshi内置适配器序列化List<T1> val listAdapter = Moshi.Builder().build().adapter<List<T1>>( Types.newParameterizedType(List::class.java, T1::class.java) ) listAdapter.toJson(writer, t1List) } writer.endObject() }正确注册适配器
创建Moshi实例时必须将CheckMapAdapter添加进去,否则Moshi无法识别带@CheckMap的类型:val moshi = Moshi.Builder() .add(CheckMapAdapter()) .build()明确泛型类型信息
由于Kotlin泛型存在类型擦除问题,在获取适配器时最好明确指定泛型类型,避免匹配失败:val targetType = Types.newParameterizedType( Map::class.java, String::class.java, Types.newParameterizedType(List::class.java, T1::class.java) ) val adapter = moshi.adapter<Map<String, List<T1>>>(targetType) .withQualifier(CheckMap::class.java)
内容的提问来源于stack exchange,提问作者Brian Chu
相关产品推荐
相关产品推荐

