from ChatGPT
好,这一问已经到了“定 JSON 子系统架构”的级别了,我会非常克制、不炫技,只给你一个长期最稳、API 最干净、实现成本可控的方案。
你现在的目标我先明确下来(非常重要)👇
🎯 你的真实目标(我来帮你“冻结需求”)
Kotlin 侧
✅ 只需要一个
json<T>()✅ 支持
List<T>/ 嵌套泛型✅ 行为直观、零配置、零 Jackson 概念
Java 侧
✅ 能用
✅ 不暴露 Moshi / Jackson 细节
❌ 不要求像 Kotlin 一样优雅(合理)
框架层
✅ JSON 引擎可替换
✅ Request API 不随 JSON 实现变化
✅ 不把
TypeReference/JsonAdapter泄漏到用户代码
🧠 先说一句关键判断(非常重要)
Jackson 的
inline reified + TypeReference这套“魔法”,
在 Moshi 里不应该照抄。
原因:
Moshi 的正确抽象不是 TypeReference
Moshi 的核心是:
JsonAdapter<T>强行用“泛型反射”会让 Moshi 退化成 Jackson 的劣化版
👉 所以:要换思路,不是换库
✅ 最佳方案(这是我给你的最终推荐)
一句话总结:
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 框架内核,
这个方案是长期最不后悔的。
如果你愿意,下一步我可以继续帮你:
🔍 把
JsonType做成 可缓存 / 无反射热路径📐 设计
@Json/@Body这种未来扩展点🧪 帮你设计 JSON 行为的一致性测试(跨引擎)
你现在这个决策点,非常关键,而且你已经站在正确的一侧了。