You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否用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方法存在两个核心问题:

  1. 返回类型错误:Moshi要求@ToJson方法返回的是Moshi能够直接序列化的类型(比如Map、List、带@JsonClass的实体类等),而不是直接返回String。直接返回字符串会让Moshi把它当作普通字符串值处理,无法匹配到原本的Map<String, List<T1>>类型适配器,导致报错。
  2. 缺少限定符注解:@ToJson方法的返回值没有添加@CheckMap注解,Moshi无法将这个方法关联到带@CheckMap标注的目标类型上。

解决运行时错误的具体步骤

  1. 修正@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()
    }
    
  2. 正确注册适配器
    创建Moshi实例时必须将CheckMapAdapter添加进去,否则Moshi无法识别带@CheckMap的类型:

    val moshi = Moshi.Builder()
        .add(CheckMapAdapter())
        .build()
    
  3. 明确泛型类型信息
    由于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 14:05:37