from ChatGPT

好,这一问已经到了“定 JSON 子系统架构”的级别了,我会非常克制、不炫技,只给你一个长期最稳、API 最干净、实现成本可控的方案。

你现在的目标我先明确下来(非常重要)👇

🎯 你的真实目标(我来帮你“冻结需求”)

  1. Kotlin 侧

    • ✅ 只需要一个 json<T>()

    • ✅ 支持 List<T> / 嵌套泛型

    • ✅ 行为直观、零配置、零 Jackson 概念

  2. Java 侧

    • ✅ 能用

    • ✅ 不暴露 Moshi / Jackson 细节

    • ❌ 不要求像 Kotlin 一样优雅(合理)

  3. 框架层

    • ✅ JSON 引擎可替换

    • ✅ Request API 不随 JSON 实现变化

    • ✅ 不把 TypeReference / JsonAdapter 泄漏到用户代码

🧠 先说一句关键判断(非常重要)

Jackson 的 inline reified + TypeReference 这套“魔法”,
在 Moshi 里不应该照抄。

原因:

👉 所以:要换思路,不是换库

✅ 最佳方案(这是我给你的最终推荐)

一句话总结:

Colleen 内核只认 JsonCodec + JsonType
Kotlin 用 reified,Java 用显式 type,
Moshi/Jackson 都只是实现。

下面一步一步来。

一、定义「框架级 JSON 抽象」(关键一步)

1️⃣ JsonType<T> —— 类型描述(与你之前讨论完全一致)

abstract class JsonType<T> internal constructor()

注意:它什么都不暴露不出现 Moshi / Jackson它是“类型 token”,不是工具类

2️⃣ Kotlin 侧:零成本创建 JsonType

inline fun <reified T> jsonType(): JsonType<T> =
    object : JsonType<T>() {}

Kotlin 用户永远不关心它的内部。

3️⃣ Java 侧:提供清晰、有限的工厂

object JsonTypes {

    fun <T> of(clazz: Class<T>): JsonType<T> =
        object : JsonType<T>() {}

    fun <E> listOf(element: Class<E>): JsonType<List<E>> =
        object : JsonType<List<E>>() {}

    fun <K, V> mapOf(
        key: Class<K>,
        value: Class<V>
    ): JsonType<Map<K, V>> =
        object : JsonType<Map<K, V>>() {}
}

👉 Java API 的“笨”,是刻意的、可控的

二、定义 JSON SPI(内核只依赖这个)

interface JsonCodec {

    fun <T> decode(
        bytes: ByteArray,
        type: JsonType<T>
    ): T

    fun <T> encode(
        value: T,
        type: JsonType<T>
    ): ByteArray
}

⚠️ Request / Response 只认 JsonCodec

三、Moshi 实现(重点来了)

1️⃣ Moshi 实例(替代你之前的 ObjectMapper)

val moshi: Moshi = Moshi.Builder()
    .add(KotlinJsonAdapterFactory())
    .add(java.time.Instant::class.java, InstantJsonAdapter())
    // 你可以加 LocalDateTime / LocalDate
    .build()

对比 Jackson:没有 Module 地狱行为是“加什么有什么”

2️⃣ 关键:JsonType<T>java.lang.reflect.Type

这是 Moshi 的核心

inline fun <reified T> moshiType(): Type =
    Types.newParameterizedType(
        Any::class.java, // placeholder
        T::class.java
    )

但注意:真正正确的做法是用 Kotlin reified 捕获 Type

我们在 JsonType 内部存 Type。

3️⃣ 升级 JsonType<T>(只在内部)

abstract class JsonType<T> internal constructor(
    internal val type: Type
)

Kotlin 构造:

inline fun <reified T> jsonType(): JsonType<T> =
    object : JsonType<T>(typeOf<T>().javaType) {}

✔ 使用 kotlin-reflect
✔ Moshi 最推荐的方式

4️⃣ MoshiCodec 实现

class MoshiJsonCodec(
    private val moshi: Moshi
) : JsonCodec {

    override fun <T> decode(
        bytes: ByteArray,
        type: JsonType<T>
    ): T {
        val adapter = moshi.adapter<T>(type.type)
        return adapter.fromJson(bytes.decodeToString())
            ?: throw BadRequest("JSON body is empty")
    }

    override fun <T> encode(
        value: T,
        type: JsonType<T>
    ): ByteArray {
        val adapter = moshi.adapter<T>(type.type)
        return adapter.toJson(value).encodeToByteArray()
    }
}

👉 Moshi 被完整封装

四、Request API(你最关心的部分)

✅ Kotlin:只需要一个 json()

inline fun <reified T> Request.json(): T? {
    val bytes = body ?: return null
    return jsonCodec.decode(bytes, jsonType())
}

使用方式:

val user = req.json<User>()
val users = req.json<List<User>>()

✔ 一个方法
✔ 没有 mapper
✔ 没有库名

✅ Java:明确但干净

User user = req.json(
    JsonTypes.of(User.class)
);

List<User> users = req.json(
    JsonTypes.listOf(User.class)
);

✔ 不暴露 Moshi
✔ 不暴露 Jackson
✔ 不出现 TypeReference

五、对比你原来的 Jackson 方案

🧠 关键总结(一句话)

Jackson 的优势在“应用层”,Moshi 的优势在“框架内核层”。

你现在做的是 Web 框架内核
这个方案是长期最不后悔的。

如果你愿意,下一步我可以继续帮你:

你现在这个决策点,非常关键,而且你已经站在正确的一侧了