Wow 编译器
wow-compiler 是 KSP 处理器集合。它把限界上下文与聚合注解转换成机器可读元数据和 Kotlin 常量,让运行时、查询和接口模块消费同一份模型声明。
它不直接生成 OpenAPI 文档或 HTTP 路由。wow-openapi、wow-webflux 等运行时/构建组件会消费编译元数据并组装各自输出。
安装
plugins {
id("com.google.devtools.ksp")
}
dependencies {
ksp("me.ahoo.wow:wow-compiler")
}版本必须与应用的 Wow/Kotlin/KSP 组合对齐。具体依赖与 capability 选择见接入现有项目,本页不重复完整 Gradle 设置。
处理器与输出
三个 SymbolProcessorProvider 通过 ServiceLoader 注册:
| 处理器 | 主要输入 | 输出 | 消费者 |
|---|---|---|---|
MetadataSymbolProcessor | @BoundedContext、@AggregateRoot 及解析出的命令/事件 | META-INF/wow-metadata.json | MetadataSearcher、聚合解析、路由/Schema/OpenAPI 组件 |
AggregatesMetadataProcessor | 限界上下文与其包范围内的聚合 | 同 package 的 AggregatesMetadata.kt | 应用/框架需要类型安全聚合元数据时使用 |
QuerySymbolProcessor | 聚合的状态类型与嵌套属性 | <StateType>Properties.kt | 查询条件、排序和字段引用 |
这些是构建输出,不应手工编辑或提交。修改注解/领域类型后重新运行 KSP,让生成结果随源码更新。
META-INF/wow-metadata.json
资源按 context name 保存:
- context alias、description 与 package scopes;
- aggregate name、aggregate type 与 package scopes;
- 可选静态 tenant ID 与 ID generator name;
- 命令和事件类型名称集合。
wow-metadata.json 不单独保存状态聚合类型。命令聚合-状态聚合配对只出现在后续生成的 AggregatesMetadata.kt 中,作为 aggregateMetadata<CommandAggregateType, StateAggregateType>() 的两个类型参数。
MetadataSymbolProcessor 以 aggregating KSP output 写入该资源。运行时 MetadataSearcher 从 classpath 查找所有同名资源并合并;缺失某个模块的资源时,该模块的聚合/命令/事件不会凭反射自动完整恢复。
检查应用 artifact,而不是只检查源码目录:
jar tf build/libs/<application>.jar | grep 'META-INF/wow-metadata.json'最终路径和 JAR 名由应用构建决定;示例中的占位符不是可直接复制的固定命令。
AggregatesMetadata.kt
生成对象位于限界上下文 package,并为解析到的每个聚合提供类型化值:
object AggregatesMetadata {
val OrderAggregateMetadata = aggregateMetadata<Order, OrderState>()
}单类聚合的命令聚合-状态聚合类型相同;组合模式会保留两个不同类型参数。该文件方便代码引用已解析元数据,不是新的公共业务 API,也不替代 wow-metadata.json。
查询属性常量
QuerySymbolProcessor 遍历状态聚合属性,为非 Kotlin/Java 简单类型继续生成嵌套导航:
object OrderStateProperties {
const val ID = "id"
const val SHIPPING_ADDRESS = "shippingAddress"
const val SHIPPING_ADDRESS__CITY = "shippingAddress.city"
}常量名使用大写 snake case,嵌套常量以 __ 分隔,值使用点路径。递归解析用已添加集合停止重复属性导航;生成常量只减少手写拼写错误,不证明目标存储存在该字段或索引。
编译期与运行期失败
| 症状 | 优先检查 |
|---|---|
没有 wow-metadata.json | domain 模块是否应用 KSP、是否包含可解析注解、资源是否打入最终 artifact |
| 缺少某个聚合 | package scope、聚合注解、模块依赖与最终 classpath |
| Properties 常量过期 | clean 后重新运行 KSP,确认使用的是当前生成目录 |
| 运行时无法解析聚合元数据 | classpath 中资源合并结果与实际聚合 class 是否一致 |
| OpenAPI/route 缺失 | 先确认元数据,再检查 wow-openapi/wow-webflux 的 capability、条件与运行时注册 |
不要把生成目录缺失直接修成手写 metadata 文件;根因通常是 KSP 没运行、模块没被依赖或输出没打包。
验证
仓库编译测试直接检查三类输出:
./gradlew :wow-compiler:test --tests "me.ahoo.wow.compiler.metadata.MetadataSymbolProcessorTest"
./gradlew :wow-compiler:test --tests "me.ahoo.wow.compiler.aggregate.metadata.AggregatesMetadataSymbolProcessorTest"
./gradlew :wow-compiler:test --tests "me.ahoo.wow.compiler.query.QuerySymbolProcessorTest"应用验收还应检查最终 JAR 与实际 OpenAPI/route;编译器测试不证明应用已请求相应运行时 capability。
源码与相关页面
MetadataSymbolProcessorAggregatesMetadataProcessorQuerySymbolProcessor- OpenAPI:元数据如何进入接口合同
- JSON Schema:Schema 生成职责