运行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
相关产品推荐
相关产品推荐

