跳到正文
W Winse Blog
mobile dev 1 min read

conjure-dart 更新:别名类型 alias 代码生成实现

上次写 conjure-dart 还是去年底的事情了。整体而言,Conjure 功能已经比较稳定,所以改动不多。之前一直没有同步到主线,因为新功能实现代码已经升级到了 jdk-17,而我们工作中用的还是 jdk-11。

最近写新功能,准备整体切到 jdk-21,所以也就可以把 conjure-dart 代码同步到最新版本。相比之前的版本,官方进行了一轮大的重构,结构更清晰了,也带来了两个新的能力:

  1. 别名类型 alias 代码生成:通过为基础类型或对象类型定义别名,让类型根据“语义”,例如用 RoleId 替代 String,表达更直观更好理解。

  2. 接口异常描述: 接口代码生成支持两种返回方式:直接抛出异常;返回包装类型 IConjureResult<DATA, ERROR>,把错误包装在结果中。

这篇聚焦第一部分,别名类型 alias 在 Dart 代码生成实现思路,以及背后的取舍。

别名看似只是换个名字,从效果看影响更深远,让模型会说话:

  • 提升模型语义:从单纯的 String 到 RoleId,包含更多的表达信息。

  • 减低沟通成本:属性无需额外的解释,模型自带注释。

  • 增强协作和可维护性:统一心智锚点,避免混用误用。

基于这些明确的价值,别名 alias 代码生成还有很有意义和价值的。

官方别名类型 alias 生成对比:Typescript 和 Java

在写代码实现 Dart 版本之前,先来分析研究一下官方的实现,看看别名类型 alias 生成的代码:conjure-typescript 和 conjure-java。

conjure-typescript:轻量级

conjure-typescript 的别名实现比较简单。它只处理了内置的简单的类型。

它只是使用 type 创建了类型别名,不处理复杂类型,也没有封装任何逻辑。

这里处理代码实现起来很简单,但是不够通用,无法统一的处理所有类型。

conjure-java:彻底的统一

conjure-java 对别名的类型没限制,处理的非常彻底且统一。它创建了一个别名类,类里面封装了实际类型的 value 属性。

下面是 Java 生成的别名类,两个图对比可以看到不管是简单还是复杂类型,核心代码都一样的。

这种设计能写的这么统一得益于 Java 类型的反射,运行时 Jackson 根据标注可以拿到属性及其类型 去进行序列化和反序列化。

反序列化

序列化

conjure-dart 别名类型代码生成实现

在比较了两种生成结果后,决定让 conjure-dart 按 Java 的方式来生成别名类型。它更统一更完备,对模型中的别名类型全覆盖,它可能是一个简单类型,也可能是一个复杂的类,甚至于是集合类型。

在 Flutter 中 Dart 是不支持反射的,提前生成好 Dart 别名类核心代码,然后借助于 json_serializable 来生成序列化和反序列化代码。

别名代码生成初探

一开始想简单了,直接上手把内置简单类型和对象类型的效果代码写了出来。

简单的值类型很好处理,直接赋值就行了。

如果是对象,那就拆箱、装箱处理一下。

但是,还是 list、map、set 呢?写着想着就觉得不对劲了,这样写下去不就是手写的 json-serializable?倒不是自己写有多难,而是再造轮子自己可能考虑不够周全,也没有这个必要!

辗转反侧,夜不能寐,怎么把 json-serializable 用起来生成代码呢?

完美在转角

在睡了一觉后(可能吧),灵光乍现:让 json-serializable 直接生成别名类的序列化代码,我再从结果里面摘取 我要的就行了啊;反序列化时,先把数据拼接好,再传给到生成代码去反序列化。

朦朦胧胧,豁然开朗:大道至简,最简单的往往最优雅。生成的效果非常简洁,效果如下:

字符串别名

复杂对象别名(toJson需要多处理一下)

数组(集合)别名

Map引用别名类型,加自定义转换Converter

Dart的 json-serializable 一个限制,Map的键必须是 Dart 的内置简单类型。如果 Map 键是 alias 对象生成代码时会报错!

问AI,查文档,看源码,历经几番折腾,就差直接改 json-serializable 的源码了!最后,在文档中看到添加自定义 converter 标注类来实现Map key的转换。

于是写了一个纯静态方法的转换类,不需要实例化对象,轻量级的处理。效果如下:

注:Converter是用来处理接口请求返回值反序列化的。这又是另一个故事,暂按下不表。

上面通过手工的方式,把思路理得很清楚了,接下来结合AI把它转换成 code_builder 的代码就比较简单了。

在 GitHub 上讨论

欢迎通过 GitHub Issue 留言或反馈。每条讨论都会关联到对应文章的源文件路径。

2025-11-16-conjure-dart-更新:别名类型-alias-代码生成实现.md

Related posts