# java-flexdto **Repository Path**: ssuiwp/java-flexdto ## Basic Information - **Project Name**: java-flexdto - **Description**: java type check map - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-11-03 - **Last Updated**: 2026-11-03 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # FlexDTO: Java Web DTO 爆炸治理与编译期契约推导系统 [![Java](https://img.shields.io/badge/Java-21%2B-blue.svg)](https://openjdk.org/) [![License](https://img.shields.io/badge/License-Apache%202.0-green.svg)](LICENSE) [![Maven](https://img.shields.io/badge/Build-Maven-orange.svg)](https://maven.apache.org/) 在复杂的企业级 Java Web 架构中,随着微服务调用与跨层传递字段的增多,系统往往面临 **DTO 爆炸(成百上千个冗余的 `XxxReq`/`XxxBo`/`XxxVo`)** 与 **方法签名爆炸(`

`)** 的两难困境。 **FlexDTO** 结合了运行时强类型双层存储容器与基于 `javac` AST 静态分析的**编译期调用链契约自动推导(Call-Graph Contract Inference)**,彻底打破 Java 名义类型系统的“不可能三角”: 1. **不写多余 DTO 类**:无需定义成百上千个结构高度重复的入参/领域对象。 2. **方法签名永远固定简短**:无论内部流转 5 个还是 50 个字段,方法入参永远固定为 `(FlexDto dto)`。 3. **编译期严格安全感知**:通过 `JavacPlugin` 静态分析全调用链路,一旦下游读取了上游未声明/未放入的字段,**在编译期即刻以精准的错误信息阻断构建**。 --- ## 目录结构 ```text java-flexdto/ ├── flexdto-core/ # 运行时核心模块 │ ├── SFunction.java # 强类型方法引用函数式接口 │ ├── LambdaMeta.java # Lambda 元数据提取容器 │ ├── LambdaUtils.java # 高性能反射解析 SerializedLambda 缓存 │ ├── FlexDto.java # 双层存储容器 (Entity Slot + Flex Fields) │ ├── FlexDtoSerializer.java # Jackson 序列化支持 │ └── FlexDtoDeserializer.java# Jackson 反序列化支持 ├── flexdto-compiler-plugin/ # 编译期 Javac 插件 (-Xplugin:FlexContractCheck) │ ├── FlexContractPlugin.java # JavacPlugin 入口与 TaskListener 注册 │ ├── FlexAstScanner.java # AST 扫描器 (捕捉 get/set/contract/pick 与调用链路) │ ├── ContractAnalyzer.java # 不动点迭代算法 (推导传递 Required 集并阻断契约缺失) │ ├── FieldRef.java # 字段引用归一化对象 (Order::getId, OrderVocab::riskScore) │ └── CallSite.java # 调用点快照与字段生产快照 ├── flexdto-idea-plugin/ # IntelliJ IDEA 专属插件 (实时红字标错 + Alt+Enter 修复) │ ├── FlexContractInspection.java # PSI 实时语法树检查器 (继承 LocalInspectionTool) │ ├── AddContractFieldQuickFix.java # Alt + Enter 快速修复动作 (实现 LocalQuickFix) │ ├── plugin.xml # 插件清单与扩展点注册 │ ├── build-plugin.sh # 一键编译与热部署脚本 (Bash) │ └── build-plugin.bat # 一键编译与热部署脚本 (Windows CMD) └── flexdto-sample/ # 三层架构完整样例与集成测试 ├── model/Order.java # 完整实体对象 (挂载入 Entity Slot) ├── model/OrderVocab.java # 散装非实体字段词汇表 (OrderVocab 接口) ├── manager/OrderManager.java # 底层 Manager (消费 riskScore) ├── service/OrderService.java # 中间业务层 Service (透传 dto 并计算 reviewTime) ├── controller/ReviewController.java # 顶层入口 (contract 契约声明与调用) └── ReviewControllerTest.java # 运行期端到端验证测试 ``` --- ## 核心设计与使用范式 ### 1. 双层存储设计(降噪防拆碎) 如果流程涉及 30 个属于同一个 `Order` 的固有字段,无需拆解为 30 个散装字段: * **强类型实体槽 (Entity Slot)**:整存整取已有的 Entity,`dto.putEntity(order)` / `dto.getEntity(Order.class)`。 * **散装动态字段 (Vocab Field)**:使用轻量级接口声明方法签名(例如 `OrderVocab`),通过方法引用 `dto.get(OrderVocab::riskScore)` 与 `dto.set(OrderVocab::reviewTime, ...)` 强类型读写。 ```java // 词汇表无需实现类,仅提供强类型方法引用 public interface OrderVocab { Integer riskScore(); Boolean canApprove(); LocalDateTime reviewTime(); String auditReason(); } ``` ### 2. 业务三层架构书写规范 ```java // 1. 最底层 Manager(第 3 层):读取实体固有金额与散装风控得分 public class OrderManager { public void verifyRisk(FlexDto dto) { BigDecimal price = dto.get(Order::getTotalPrice); Integer score = dto.get(OrderVocab::riskScore); // <-- 新增读取字段,无需改任何方法签名! if (price.compareTo(new BigDecimal("1000")) > 0 && score != null && score > 80) { dto.set(OrderVocab::auditReason, "高价值订单且风控评分偏高,触发人工复审"); } } } // 2. 中间层 Service(第 2 层):只管自己需要的字段,中途产生新字段并继续透传 public class OrderService { private final OrderManager orderManager = new OrderManager(); public void executeReview(FlexDto dto) { Long id = dto.get(Order::getId); Boolean canApprove = dto.get(OrderVocab::canApprove); dto.set(OrderVocab::reviewTime, LocalDateTime.now()); orderManager.verifyRisk(dto); // 直接透传,无需改方法入参 } } // 3. 顶层 Controller(第 1 层):声明前端契约 public class ReviewController { private final OrderService reviewService = new OrderService(); @PostMapping("/review") public FlexDto submitReview(@RequestBody FlexDto req) { // 声明前端入参提供的字段集 req.contract(Order::getId, Order::getTotalPrice, OrderVocab::canApprove, OrderVocab::riskScore); reviewService.executeReview(req); return req; } } ``` --- ## 编译期静态分析与精准拦截 在编译阶段,`FlexContractPlugin` 介入 `javac` 的 AST 分析,通过正向可用字段分析(Forward Available Fields)与逆向所需字段推导(Backward Required Fields)相结合,提供两大核心编译期检查: ### 维度 1:方法内直接读取未赋值/未声明字段拦截(Intra-Method Get-Before-Set) 对于本地新实例化的 `FlexDto`(`new FlexDto()`)或顶层入口参数(`@RequestBody FlexDto req`),在尚未通过 `set(...)`、`putEntity(...)`、`contract(...)` 赋值或声明之前直接调用 `get(...)`: ```java FlexDto req = new FlexDto() .putEntity(order) .set(OrderVocab::canApprove, true); // 试图读取未赋值过的 reviewTime: LocalDateTime time = req.get(OrderVocab::reviewTime); ``` **编译器直接拦截并报错**: ```plaintext [ERROR] ReviewControllerTest.java:[26] 契约缺失: 变量 req 尝试获取未赋值/未声明的字段 [OrderVocab::reviewTime] └── 消费位置: ReviewControllerTest.testSubmitReviewSuccess(ReviewControllerTest.java:26) └── 原因: 该字段从未被 set(...) 赋值,读取必然返回 null ``` ### 维度 2:跨方法调用链契约自动推导与拦截(Inter-Method Call-Graph Contract) 1. 提取每个方法的产出集 $\text{Produced}(m)$(`contract`、`set`、`pick`、`putEntity`)与消费集 $\text{SelfGet}(m)$(`dto.get(...)`)。 2. 通过**不动点迭代(Fixpoint Worklist)算法**沿调用树逆向推导传递依赖: $$\text{Required}(m) = \text{SelfGet}(m) \cup \bigcup_{c \in \text{Callees}(m)} \big(\text{Required}(c) \setminus \text{ProducedBeforeCall}(m, c)\big)$$ 3. 当上游入口未提供下游必需字段时,**直接中断编译并输出精准的定位与调用链路**: ```plaintext [ERROR] ReviewController.java:[15] 契约缺失: 调用 executeReview(req) 缺少必需字段 [OrderVocab::riskScore] └── 消费位置: OrderManager.verifyRisk(OrderManager.java:8) └── 调用链路: submitReview -> executeReview -> verifyRisk ``` --- ## 构建工具与 IDE 集成 ### 1. Maven 集成 (`pom.xml`) 在业务工程中引入 `flexdto-core` 并在 `maven-compiler-plugin` 中配置编译参数: ```xml com.flexdto flexdto-core 1.0.0 org.apache.maven.plugins maven-compiler-plugin 3.13.0 21 21 -Xplugin:FlexContractCheck com.flexdto flexdto-compiler-plugin 1.0.0 ``` ### 2. Gradle 集成 (`build.gradle`) ```groovy dependencies { implementation 'com.flexdto:flexdto-core:1.0.0' compileOnly 'com.flexdto:flexdto-compiler-plugin:1.0.0' } tasks.withType(JavaCompile) { options.compilerArgs += [ "-Xplugin:FlexContractCheck" ] } ``` ### 3. IntelliJ IDEA 实时编辑器高亮与一键修复插件(推荐) 类似 Lombok 插件的开发体验,我们为 IntelliJ IDEA 提供了专用的实时静态语法分析插件 `flexdto-idea-plugin`: * **0 编译等待,毫秒级实时红字标错**:无需按 `Ctrl+F9` 编译,直接在编辑器中对方法内未赋值读取(Get-Before-Set)或跨方法契约缺失(Call-Graph Contract)渲染**红色波浪线**。 * **Alt + Enter 快速修复 (Quick Fix)**:在被标红的跨方法调用点按下 `Alt + Enter`,一键将下游缺失字段自动追加到上游 `req.contract(...)` 契约声明中。 #### 安装与部署插件: 插件已编译并部署至本地用户插件目录: `C:\Users\Administrator\AppData\Roaming\JetBrains\IntelliJIdea2026.2\plugins\flexdto-idea-plugin\lib\flexdto-idea-plugin.jar` 若需重新编译或更新插件,只需在项目根目录下执行: ```bash ./flexdto-idea-plugin/build-plugin.sh # Git Bash # 或 flexdto-idea-plugin\build-plugin.bat # Windows CMD ``` 重启 IntelliJ IDEA 即可立即激活! --- ### 4. IntelliJ IDEA 编译器后台集成 (Javac Plugin) 若团队成员未安装 IDEA 插件,亦可在执行 **Build / Make Project** 时通过标准 `javac` 调用编译器插件拦截: 1. 打开 IDEA 设置:`Settings` -> `Build, Execution, Deployment` -> `Compiler` -> **`Java Compiler`**。 2. 确认 **Use compiler** 设置为 **`Javac`**。 3. 在 **Additional command line parameters** 中添加: ```plaintext -Xplugin:FlexContractCheck ``` 4. **使用效果**:按 `Ctrl + F9`(或 `Cmd + F9`)时,编译器在后台执行契约分析,若契约缺失直接在 **Build 窗口** 报错并支持双击跳转。 --- ## 运行与测试 在根目录下执行: ```bash mvn clean test ``` 各模块测试涵盖: * `FlexDtoTest`:验证实体槽整存整取、Getter 回退查找、字段裁剪提取、JSON 序列化与反序列化。 * `FlexContractPluginTest`:使用 Javac ToolProvider 验证契约完备通过与契约缺失时的精准拦截报错及链路还原。 * `ReviewControllerTest`:集成运行期 3 层业务架构的透传与业务计算验证。 --- ## License Notice 本项目遵循 [Apache License 2.0](LICENSE) 开源许可证。 ```text Copyright 2026 FlexDTO Authors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ``` 详情请参阅 [LICENSE](LICENSE) 与 [NOTICE](NOTICE) 文件。