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

运行Kotlin代码触发Moshi的No JsonAdapter for LinkedHashMap报错,自定义适配器无效问题排查

解决Moshi报错:No JsonAdapter for java.util.LinkedHashMap<java.lang.String, java.lang.Object>

首先,你的问题核心出在自定义适配器的无效实现,以及代码中使用了Moshi默认不支持的类型(比如JSONObject和Any类型的Map值)。咱们一步步拆解:

1. 你的LinkedHashMapAdapter完全没起作用

你当前的适配器只是把输入的LinkedHashMap原样返回,没有任何实际的序列化/反序列化逻辑:

class LinkedHashMapAdapter {
    @ToJson
    fun arrayListToLinkedHashMap(list: LinkedHashMap<String,Any>): LinkedHashMap<String,Any> = list

    @FromJson
    fun arrayListFromLinkedHashMap(list: LinkedHashMap<String,Any>): LinkedHashMap<String,Any> = list
}

Moshi需要的是能处理LinkedHashMap<String, Any>中任意类型值的适配器——因为Any可能是字符串、数字、列表甚至嵌套Map,Moshi不知道怎么自动序列化这些不确定的类型。

正确的LinkedHashMapAdapter实现

你需要写一个能递归处理各种类型值的适配器,示例如下:

class LinkedHashMapAdapter {
    @ToJson
    fun toJson(writer: JsonWriter, map: LinkedHashMap<String, Any>) {
        writer.beginObject()
        for ((key, value) in map) {
            writer.name(key)
            writeValue(writer, value)
        }
        writer.endObject()
    }

    private fun writeValue(writer: JsonWriter, value: Any?) {
        when (value) {
            null -> writer.nullValue()
            is String -> writer.value(value)
            is Number -> writer.value(value)
            is Boolean -> writer.value(value)
            is List<*> -> {
                writer.beginArray()
                value.forEach { writeValue(writer, it) }
                writer.endArray()
            }
            is Map<*, *> -> toJson(writer, value as LinkedHashMap<String, Any>)
            // 如果还有自定义数据类,这里可以添加判断,比如is CartItem -> 用Moshi序列化它
            else -> throw IllegalArgumentException("Unsupported value type: ${value.javaClass.name}")
        }
    }

    @FromJson
    fun fromJson(reader: JsonReader): LinkedHashMap<String, Any> {
        val map = LinkedHashMap<String, Any>()
        reader.beginObject()
        while (reader.hasNext()) {
            map[reader.nextName()] = readValue(reader)
        }
        reader.endObject()
        return map
    }

    private fun readValue(reader: JsonReader): Any {
        return when (reader.peek()) {
            JsonReader.Token.BEGIN_OBJECT -> fromJson(reader)
            JsonReader.Token.BEGIN_ARRAY -> {
                val list = mutableListOf<Any>()
                reader.beginArray()
                while (reader.hasNext()) list.add(readValue(reader))
                reader.endArray()
                list
            }
            JsonReader.Token.STRING -> reader.nextString()
            JsonReader.Token.NUMBER -> reader.nextDouble() // 若需BigDecimal,可替换为BigDecimal(reader.nextString())
            JsonReader.Token.BOOLEAN -> reader.nextBoolean()
            JsonReader.Token.NULL -> {
                reader.nextNull()
                null ?: Any()
            }
            else -> throw IllegalArgumentException("Unsupported JSON token: ${reader.peek()}")
        }
    }
}

2. 替换JSONObject为数据类,避免不必要的麻烦

你的代码中将CartItem转为JSONObject存入列表,这会导致Moshi无法识别JSONObject类型(默认不支持org.json库的类型)。直接用CartItem数据类即可:

// 替换原来的setItems定义
val setItems = arrayListOf<CartItem>()
val getItemsInCart = itemsInCart.await()
if (getItemsInCart != null) {
    for (items in getItemsInCart){
        val newCartItem = CartItem().apply {
            id = items.id
            email = items.email
            productId = items.productId
        }
        setItems.add(newCartItem) // 直接添加CartItem,不用转JSONObject
    }
}
val params = HashMap<String, Any>()
params["PK"] = userPK
params["items"] = setItems

因为你已经添加了KotlinJsonAdapterFactory,Moshi可以自动序列化CartItem数据类,无需额外处理。

3. 优先使用Map接口而非具体实现类

Moshi默认支持Map接口的序列化,所以如果你的代码中不需要特定的Map实现(比如LinkedHashMap/HashMap),尽量用Map<String, Any>代替具体类,这样可以减少自定义适配器的需求:

// params改用Map接口
val params: Map<String, Any> = mapOf(
    "PK" to userPK,
    "items" to setItems
)

最后检查配置

确保你的Moshi配置中正确添加了适配器,并且顺序正确(自定义适配器放在KotlinJsonAdapterFactory前面不影响,但建议保持现有顺序即可):

private val moshi = Moshi.Builder()
    .add(LinkedHashMapAdapter())
    .add(BigDecimalAdapter)
    .add(KotlinJsonAdapterFactory())
    .build()

按照以上步骤修改后,应该就能解决你的报错问题了。

内容的提问来源于stack exchange,提问作者imin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 18:19:07