feat: Kotlin 语法约束——只当语法糖用,不当新范式用
新增 docs/13-kotlin-style.md,并把它落成可执行的构建门禁,而不是一份只能靠
自觉遵守的建议。两条准入标准:只当语法糖(不引入新的思维模型)、每条规则必须
说得出它挡住的具体故障。
- KotlinSyntaxScanTest(源码扫描):禁 !! / lateinit / suspend / kotlinx.coroutines
/ RxJava / Reactor / data class Entity。走源码文本而非 ArchUnit,是因为这些在
字节码上看不出来——!! 编译成 Intrinsics.checkNotNull(...) 调用,和其他 null
检查混在一起。
- ArchitectureRulesTest 加「禁止工具类」:只禁 Utils/Util/Helper/Common 四个
后缀,不禁 XxxManager——Spring 自身大量使用这个命名,一刀切会误伤。
- PersistedEntity + requiredId:把「从 repository 读出来的实体必有 id」变成
一个有名字的类型,替掉 AuthAppService / LocalSeedDataConfig 里 7 处 .id!!。
- 5 个 Entity 实现 PersistedEntity。
两条故意不自动强制的写进了文档:companion object 靠 review 判断(现存 14 处
用法均合法,硬规则只会误伤);Entity 可被 Hibernate 代理目前没守住——未 apply
kotlin("plugin.jpa"),Entity 是 final 类,fetch = LAZY 会静默降级为 eager,现
因为零懒加载关联而未暴露。
docs/01-project-structure.md 顺带补了 Gradle 版本行的双向约束说明;README 修正
了 12 篇→13 篇文档、10 条→11 条规则,并补上工具类禁名。
验证:./gradlew build -PexcludeIntegration 通过。ArchitectureRulesTest 11 项、
KotlinSyntaxScanTest、NativeQueryScanTest 全绿;两条新规则均以「植入一个故意
违规、确认它变红」的方式验证过不是空转。
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Code
parent
54f3b35245
commit
aca7487be2
+31
@@ -0,0 +1,31 @@
|
||||
package com.continental.retailapp.platform.persistence
|
||||
|
||||
/**
|
||||
* 带自增主键的实体,见 13-kotlin-style.md。
|
||||
*
|
||||
* 存在的唯一理由:把"这个实体有 id"这条不变量写成类型,替掉应用层里散落的主键强解包。
|
||||
*
|
||||
* 实体的 id 只在两种情况为 null——`new` 出来还没 persist,或者没 save 过。
|
||||
* 应用层拿到 Entity 时它必然已经落库:要么从 repository 读出来的,要么刚 save 过
|
||||
* (`GenerationType.IDENTITY` 会在 save 时立刻发出 INSERT 拿回 id)。那里要的是
|
||||
* [requiredId],不是可空的 `id`。
|
||||
*
|
||||
* 平台侧注意:`platform-web` 的 `IdempotencyRecordEntity` **不实现**这个接口——
|
||||
* platform-web 是公共基座,不反过来依赖 platform-persistence,它自己声明 id 即可。
|
||||
*/
|
||||
interface PersistedEntity {
|
||||
val id: Long?
|
||||
}
|
||||
|
||||
/**
|
||||
* 已落库实体的主键。
|
||||
*
|
||||
* 不满足不变量时抛 [IllegalStateException],报错里带类名——比 Kotlin 强解包
|
||||
* 抛出的那个没有上下文的 [NullPointerException] 好定位得多。
|
||||
*
|
||||
* **不要**在刚 `new` 出来、还没 persist 的实体上用。
|
||||
*/
|
||||
val PersistedEntity.requiredId: Long
|
||||
get() = id ?: throw IllegalStateException(
|
||||
"${javaClass.simpleName} 还没有 id:它既没从 repository 读出来,也没 save 过",
|
||||
)
|
||||
Reference in New Issue
Block a user