关于 dto-creator
dto-creator 是 Spring Agent Toolkit 中用于为实体生成 DTO 的技能,面向 Spring 项目开发者。它支持 Java 类、record、Lombok 和 Kotlin data class,并要求依据示例生成代码。
主要功能
- 01为实体创建 DTO
- 02支持 Java 类与 record
- 03支持 Lombok 和 Kotlin data class
- 04可配置字段、校验与关联 DTO
- 05需要 Spring MCP 工具及代码示例
适用场景
- 01为实体生成 API 数据传输对象
- 02选择实体字段并配置关联 DTO
- 03按项目语言和依赖确定 DTO 形式
MCP 相关
依赖 Amplicode IntelliJ 插件提供的 Spring MCP 服务,使用其项目摘要、依赖和实体信息工具。若工具不可用,技能要求先安装插件并连接 MCP。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ amplicode/ spring-skills --skill dto-creator安装后在 Claude Code 中输入/dto-creator确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
examples/_fragments/constructor/java/all-args.mdexamples/_fragments/equals-hashcode/java/equals-hashcode-hibernate.mdequals-hashcode.mdexamples/_fragments/fields/java-lombok.mdjava-record.mdjava.mdkotlin.mdexamples/_fragments/fluent-setters/java/fluent-setters.mdexamples/_fragments/getters-setters/java/getters.mdsetters.mdexamples/_fragments/javadoc/java/javadoc.mdexamples/_fragments/json-ignore/java/json-ignore.mdexamples/_fragments/lombok/lombok.mdexamples/_fragments/nested-class/java/nested-class.mdexamples/_fragments/nested-class/kotlin/nested-class.mdexamples/_fragments/serializable/java/serializable.mdexamples/_fragments/serializable/kotlin/serializable.mdexamples/_fragments/tostring/java/tostring.mdexamples/_skeletons/java/class.mdrecord.mdexamples/_skeletons/kotlin/class.mddata-class.mdreferences/java-lombok.mdjava-plain.mdjava-record.mdkotlin.mdsub-dto.mdvalidation.md详细介绍
预检:Spring MCP
此技能属于 Spring Agent Toolkit,旨在与 Spring MCP 服务(由 Amplicode IntelliJ 插件提供)配合使用。在进行任何操作之前,请检查工具列表中是否有 Spring MCP 工具——这些工具通过 amplicode MCP 服务提供(例如,get_project_summary、list_module_dependencies、get_entity_details);将 MCP 工具扁平化到工具列表中的运行环境,会在相同名称前使用 mcp__amplicode__ 前缀。
- 如果至少有一个 Amplicode 工具可用——MCP 已连接。继续执行以下技能。
- 如果没有可用工具——停止并调用
amplicode-install技能(随 Spring Agent Toolkit 一同提供)。它会安装 Amplicode 插件,并引导用户点击欢迎屏幕上的 «Настроить Spring Agent» 按钮,然后重启 MCP 客户端。完成后,MCP 工具即可使用——继续执行此技能。 - 如果技能列表中未注册
amplicode-install,请用用户使用的语言告知用户:"此技能需要 Amplicode IntelliJ 插件及其 MCP 服务。请从 https://amplicode.ru/marketplace 将其安装到 IntelliJ IDEA Ultimate/Community 或 GigaIDE 中,打开任意项目,点击 Amplicode 欢迎屏幕上的 «Настроить Spring Agent»,然后重启 MCP 客户端。"
DTO 创建器
为实体创建 DTO 类(Java 类、Java record、Java+Lombok 或 Kotlin 数据类),可包含选定属性、构造函数、getter/setter、equals/hashCode、toString 及可选功能。
重要:只能使用 examples/ 文件中的代码。如果没有匹配的示例——停止并询问用户。 重要:对于有固定选项的问题,优先使用
AskUserQuestion> 其同类工具 > 纯文本列表。没有交互式工具时,纯编号文本列表才是最后的选择。 **重要:运行步骤 1 之前,先阅读对话上下文。**步骤 2–7 中有一半的问题可能已在用户提示和之前的对话中得到回答。重复询问已说明的内容,是此技能显得缓慢的首要原因。 **步骤 7(mapper)在需要转换时自动执行。**如果根据上下文可以确定 DTO 将用于把实体转换为 DTO 或从 DTO 转换回实体的代码中(如 controller、service、端点替换等),此技能必须委托给mapper-creator——绝不能在代码中内联编写手动映射代码。mapper-creator技能负责决定实现方式(MapStruct、Custom、添加依赖);此技能只需进行委托。
默认值
| 选项 | 默认值 | 总是询问? | 备注 |
|---|---|---|---|
| entity | -- | YES | 主要分支:要为哪个实体创建 DTO |
| attributes | 实体的所有字段 | YES | 要包含哪些字段 |
| className | {EntityName}Dto | NO | 提出建议,仅需确认 |
| language | 来自 get_project_summary | NO | 自动检测 |
| variant | 根据语言和依赖自动确定 | YES | Java 类 / Java record / Java+Lombok / Kotlin |
| mutable | false | NO | 除非用户想要自定义,否则跳过 |
| allArgsConstructor | true | NO | 仅适用于纯 Java |
| equalsHashCode | true | NO | 仅适用于纯 Java |
| toString | true | NO | 仅适用于纯 Java |
| fluentSetters | false | NO | 仅当 mutable=true 时适用,仅适用于 Java |
| jsonIgnoreUnknownProperties | false | NO | 仅适用于 Java,且类路径中存在 Jackson 时 |
| serializableType | NoSerializable | NO | 很少需要 |
| packageName | 与实体相同的包 | NO | 自动检测 |
| subDtoType(每个 ToOne 关联) | 带有仅含 id 的子项的 FLAT | YES | 提供四种选项:New Class / New Nested Class / Existing Class / Flat。“Only ID”并非单独的选项——它是只勾选子实体 id 的 Flat。参见 references/sub-dto.md。 |
| subDtoType(每个 ToMany / 集合) | NEW_NESTED_CLASS | YES | 与 ToOne 相同的四种选项。集合也支持 Flat,并会生成复合复数形式字段,例如 Set<Integer> specialtyIds——参见 references/sub-dto.md。 |
| fieldNameOverride(每个字段) | 无 | NO | 按字段重命名 |
| extraValidations(每个字段) | 无 | NO | 用户添加的 jakarta 验证器,附加在继承的验证器之上 |
| removedValidations(每个字段) | 无 | NO | 从实体继承、但用户希望移除的约束 |
| indent | 来自 .editorconfig(回退为 4 个空格) | NO | 参见下文 § 缩进 |
智能默认值: 如果用户说“使用默认值”“全部使用默认值”“默认设置” 或类似表述,则跳过所有“总是询问?”为 NO 的问题。仅询问必答问题。
智能答案识别: 当用户提供一个值而非从编号列表中选择时,直接接受该值。例如:
- 问题“哪个实体?” -> 用户回答“Order” -> 这就是实体,无需再次询问
- 问题“变体?” -> 用户回答“record” -> 这就是 Java record,无需显示选项
- 如果用户在一条消息中提供多个答案 -> 全部接受,并跳过已回答的问题
- 绝不询问用户已经回答过的问题(即使是隐含回答)
批量提问: 当以下条件成立时,将紧密相关的问题合并到一次
AskUserQuestion 调用中(每次最多 4 个问题):
- 属于同一逻辑部分(例如,都是 Java 方法生成设置)
- 彼此之间不依赖答案
- 用户可以跳过,且有明显的默认值
规则:
- 每次
AskUserQuestion调用最多 3-4 个问题 - 将推荐选项标记为“(推荐)”并置于首位
- 绝不合并来自不同决策分支的问题
- 主要分支问题(实体选择、变体)始终单独提问
- 有选项时优先使用
AskUserQuestion;仅当该工具不可用时,才回退到纯文本列表
决策原则——先看上下文,再提问
在向用户提出任何问题之前,先尝试从已收集的上下文中推导答案:项目摘要、模块依赖、实体详情、软件包中的现有文件、本次对话的先前轮次,以及用户的原始提示。只有当上下文无法得出明确的默认选项,或选择确实取决于用户个人偏好时(例如选择哪个实体、哪些字段),才提问。
决策层级:
-
上下文明确无歧义 → 静默决定,切勿提问。 示例:从
get_project_summary获取语言和 JDK;从list_module_dependencies获取 Lombok / Jackson / Hibernate Validator;根据实体 FQN 确定软件包;根据{Entity}Dto确定 className;过滤反向引用@ManyToOne;自动选择子实体标量字段;当 JDK ≥ 16、没有 Lombok 且用户没有另行要求时,选择 record 而非普通类。 例外:绝不能静默决定 subDtoType——除非 USER 在自己的消息中明确说明了结构(而不是在 ARGUMENTS 中),否则至少必须遵循原则 2(单行确认)。 -
上下文有明显倾向 → 用一行说明决定和备选项,让用户选择更改或不作回应。 格式:
Will create `ScheduleTemplateDto` as a Java record with nested `SlotDto` (record). Alternatives: plain class, Lombok, separate file for SlotDto. OK?用户可以回答“ok” / “yes”或不作回应 → 接受;也可以指定其他选项 → 切换。这不同于编号问题格式——它是一条单独的确认语句。
-
上下文无法得出明确的默认选项 → 使用
AskUserQuestion(首选)或其同类工具提问,并将推荐选项放在首位。 如果可以使用AskUserQuestion,请使用带有preview字段的选项,让用户看到每个选项对应的具体代码结构。将推荐选项标记为(Recommended),并放在首位。如果没有可用的交互式选择工具,则改用纯文本列表。 绝不要迭代式提问(“要哪种变体?”→ 用户选择 → “要哪些字段?”→ ……),只要一次批量调用就能解决的问题就不要拆开问。 -
关键输入的上下文完全为空 → 直接提问。 适用于:选择哪个实体、选择哪些字段(当不是“全部”时)、用户本身的意图。
如何提问——优先使用 AskUserQuestion
必须提问时,优先使用 AskUserQuestion 工具(或其同类工具),而不是在响应正文中编写编号列表。仅当没有可用的交互式选择工具时,才改用纯文本。
此技能中 AskUserQuestion 调用的规则:
- 每次调用最多可包含 4 个彼此独立的问题(工具会将它们一并显示)。利用这一点,在一次往返中批量处理相关决策。
- 每个问题有 2–4 个选项。工具会自动添加一个供自由输入的“Other”选项——切勿手动添加。
- 将推荐选项放在首位,并在标签末尾添加
(Recommended)。 - 对“要包含哪些字段”或“要添加哪些验证器”等允许多个答案的问题,使用
multiSelect: true。 header是一个 12-char 的标签(例如“Variant”“Sub-DTO”“Fields”)。- 每个选项都应有一条说明,解释该选项的含义或后果(用一个简短句子)。
以下情况不应使用 AskUserQuestion:
- 没有可枚举选项的自由输入(例如任意类名、任意字段重命名)——使用纯文本提问。
- 原则 2 中的“单行确认”形式——这是一个有明确是/否答案的问题,不是枚举选项。
下面步骤 2–5 中基于界面的提问列表仅适用于情况 4,是一种后备方案,并非必须从头到尾执行的脚本。如果某个问题的答案已由原则 1–3 确定,就跳过该问题。忠实还原插件向导并非目标;确保生成正确才是目标。插件的 UI 能一次显示许多控件,而聊天界面做不到,因此此技能必须通过自行做出更多决定来弥补。
步骤 0 —— 优先查看对话上下文(必需,不调用工具)
在进行任何 MCP 调用、提出任何问题之前,重新阅读用户的提示和本次对话的先前消息,并提取其中已经说明的内容。此步骤无需耗费任何成本,却能避免此技能最常见的失败模式——询问用户已经提供过的信息。
在心中列出输入检查清单,并勾选用户已经明确或隐含提供的所有内容:
| 输入 | 在提示 / 上下文中查找 |
|---|---|
| 实体 | 类名(Vet、Owner、ScheduleTemplate);“用于 X”;IDE 中打开的文件;文件路径;本次对话中最近讨论的实体 |
| 用途 | “用于 REST”“用于 controller”“用于 API”“用于映射”“投影”“用于 service”——这会影响字段选择和是否询问映射器 |
| 字段 | “所有字段”“仅 id 和 name”“不含密码”“包含关联”“扁平” |
| 变体 | “record”“普通类”“Lombok”“data class”——也可由语言隐含:Kotlin → data class,无需提问 |
| 映射器 | “还要映射器”“带映射器”“仅 DTO”“不要映射器” |
| className | “命名为 OwnerSummaryDto”“类 Foo” |
| package | “放在 … 包中”“放在 controller 旁边” |
| 智能默认值 | “使用默认值”“全部使用默认设置”“默认设置”“照常” |
| 子 DTO 结构 | “嵌套”“单独的类”“仅 id”“扁平” |
| 项目先前信息 | 语言、JDK、依赖——如果本次对话中已经讨论过,就已知;无需重新获取 |
对于每个已明确或强烈隐含回答的输入:标记为已确定,并跳过步骤 2–7 中对应的问题。如果用户写了“为 Vet 创建 DTO”,就不要问“什么实体?”——答案是 Vet。如果用户写了“创建 record DtoX”,就不要问“Java record 还是 class?”——答案是 record。
对于每个尚未回答的输入:遵循下方的决策原则——先尝试从项目上下文中推断(步骤 1),然后再提问。
重要:参数 ≠ 用户意图。 提示底部的 ARGUMENTS 区块由调用助手编写,不是用户提供的内容。它可能包含助手自身的分析、假设或用户从未说明的字段级细节。判断用户“已经说过什么”时,只查看对话记录中的实际用户消息——绝不能把 ARGUMENTS 当作用户输入的替代品。特别是,不要仅仅因为 ARGUMENTS 描述了子 DTO 的结构,就跳过关于子 DTO 结构的问题。
步骤 0 是在心中完成的,不是工具调用。不要向用户宣布此步骤。不要写“步骤 0 已完成”。开始步骤 1 之前,只需在心中牢记用户已经提供的信息。
步骤 1 —— 收集最少的项目上下文(自动执行,不提问)
仅调用其结果会被后续步骤实际使用的 MCP 工具。不要“以防万一”而提前获取数据——这里的每个变量都必须有明确的下游用途。
| 工具 | 变量 | 用途 |
|---|---|---|
get_project_summary | language、jdkVersion、moduleName | language → 选择变体(步骤 4)和参考文件(java 或 kotlin);jdkVersion → canUseRecords = jdkVersion >= 16;moduleName → 消除多模块歧义 + 作为 list_module_dependencies 的参数 |
list_module_dependencies(moduleName) | presentDeps | 派生下方的标志——Lombok/Jackson/Validation 功能门控 |
步骤 1 到此为止。不要获取:
springBootVersion/bootMajor—— 没有分支逻辑依赖它们buildFile—— DTO 生成不会修改构建文件(无需添加依赖);DTO 只需要语言构造mainPackage—— DTO 的包名从实体的 FQN 派生,而不是从项目根目录派生list_application_properties_files/propsFile—— DTO 不会写入application.propertieslist_all_domain_entities—— 仅当用户未在提示词中指定实体时才需要。作为惰性回退,延后到步骤 2。get_entity_details/list_entity_dtos—— 需要先知道实体,而这会在步骤 2 中确定。延后到步骤 2。
派生变量(均来自 presentDeps 和 get_project_summary):
hasLombok=presentDeps包含lombokhasJackson=presentDeps包含jackson-databind或jackson-corehasValidation=presentDeps包含hibernate-validator、jakarta.validation-api或spring-boot-starter-validationcanUseRecords=language == JAVA且jdkVersion >= 16
如果是多模块项目(get_project_summary 中有多个模块):
询问要使用哪个模块。然后针对该模块重新调用 list_module_dependencies。
步骤 2 —— 选择实体
到步骤 0 时,你应该已经知道实体(如果用户提到了它)。
最常见的情况:用户写道“为 Vet 创建 DTO” → 实体为
Vet,跳过提问,直接进行下面的并行获取。
**惰性回退——仅当实体未知时:**调用
list_all_domain_entities(moduleName) → entities,然后通过
AskUserQuestion 提问(选项 = 列表中的实体名称,最多 4 个;如果实体超过
4 个,根据上下文选择最可能的 4 个,并注明用户可通过“Other”输入其他名称)。
这是唯一应调用 list_all_domain_entities 的地方。如果用户在提示词中指定了实体,不要调用它。
确定实体 FQN 后,并行调用:
| 工具 | 变量 | 用途 |
|---|---|---|
get_entity_details(entityFqn) | entityDetails | 步骤 3 的属性选择、关联分析、验证继承,以及每个变体参考中的生成顺序 |
此处不调用父实体的 list_entity_dtos(entityFqn)——它没有下游用途。子实体调用(list_entity_dtos(subEntityFqn))仍用于在 references/sub-dto.md 中检测 EXIST_CLASS,但属于惰性调用,按关联逐项执行,且仅在向用户提供 EXIST_CLASS 选项时触发。具体位置请参见 references/sub-dto.md。
DTO 名称冲突通过另一个惰性调用处理——list_existing_classes(package)——在步骤 6 的生成前立即触发(参见防幻觉检查清单)。它不属于步骤 2。
步骤 3 —— 选择属性
默认:包含每个标量属性和每个关联(采用 references/sub-dto.md 中的子 DTO 默认设置)。仅当上下文表明用户想要更精简的内容时才提问。
根据上下文做出决定(优先于提问)
使用第 0 步中记录的用途来选择合理的默认字段集:
| 用途信号 | 默认字段集 |
|---|---|
| “用于 REST”“用于 controller”“用于 API” | 所有标量字段 + 展开所有关联(ToMany 使用 NEW_NESTED_CLASS,ToOne 使用 FLAT id)——用户需要响应结构,包括关联数据 |
| “投影”“摘要”“列表视图”“用于列表” | 仅标量字段,ToOne 关联使用 Flat id,排除 ToMany |
| “用于映射”“用于 service”“用于存储的 DTO” | 所有标量字段 + 展开所有关联 |
| “仅 id 和 name” / 明确列出字段 | 仅包含用户指定的字段,不包含其他字段 |
| 没有用途信号 | 所有标量字段 + 展开所有关联(合理范围内最丰富的默认选项) |
如果所选默认选项符合用户的明显意图,不要提问。 直接生成。最多只能使用一句式确认格式(原则 2)说明所做的选择。
何时提问
仅在以下情况下提问:
- 用户明确表示“选择字段”/“询问字段”/“微调设置”,或
- 实体有很多字段,且用途信号模糊,同时用户没有说“使用默认设置”。
提问时,使用 AskUserQuestion,并设置 multiSelect: true:
| 问题 | 标题 | 选项(第一项为推荐选项) |
|---|---|---|
DTO {Entity}Dto 应包含哪些字段? | 字段 | 所有字段 + 关联(推荐)/ 仅标量字段 / 仅 id 和 name / 手动指定 |
对每个包含的关联,应用 references/sub-dto.md 中的子 DTO 默认设置。除非用户明确要求精细控制,否则不要逐个关联提问。
第 4 步——选择变体
遵循上文的决策原则。通常可根据上下文推断变体——主动提问应是例外,而非常规做法。
**如果 language=KOTLIN:**转至 references/kotlin.md。不要提问。
**如果 language=JAVA:**按以下方式决定。
| 上下文 | 操作 | 变体 |
|---|---|---|
hasLombok = true 且用户的提示明确提到 Lombok | 静默决定 | references/java-lombok.md |
canUseRecords = true 且 hasLombok = false,且用户没有要求可变性/setter/Lombok | 静默决定,并在原则 2 的一句式确认中说明 | references/java-record.md |
canUseRecords = false 且 hasLombok = false | 静默决定 | references/java-plain.md |
hasLombok = true 且 canUseRecords = true,且用户没有给出偏好 | 使用原则 2 的一句式确认格式:“将创建为 Java record(JDK ≥ 16,不使用 Lombok)。其他选项:普通类、Lombok。可以吗?” | 取决于回答 |
| 用户明确说“普通类”/“可变”/“带 setter” | 静默决定 | references/java-plain.md |
| 用户明确说“record” | 静默决定 | references/java-record.md |
| 用户明确说“Lombok” | 静默决定(仅当 hasLombok = true;否则发出警告并使用备用方案) | references/java-lombok.md |
仅当以上各行均不匹配,且用户没有说“使用默认设置”时,才退回到完整编号问题。即便如此,也优先采用原则 3 中“标明默认选项的所有变体”格式,而不是迭代提问。
将回答映射到变体:
- plain →
references/java-plain.md - record →
references/java-record.md - Lombok →
references/java-lombok.md
第 5 步——特定变体的问题
遵循所选参考文件中的特定变体问题。 仅当用户没有说“全部使用默认设置”时才提问。
步骤 6 -- 生成代码
-
确定目标路径:
src/main/{java|kotlin}/{packagePath}/{className}.{java|kt} -
遵循所选参考文件中的 生成顺序。
-
对于每个步骤:
如果是骨架(新文件):
- 读取
examples/_skeletons/中的骨架.md - 应用变量替换
- 使用 Write 工具创建文件
如果是片段:
- 读取
examples/_fragments/中的片段.md - 阅读插入点,了解应插入的位置
- 使用 Edit 工具在指定位置插入代码
- 应用变量替换
- 读取
-
变量替换规则:
{packageName}-> 来自实体包或用户选择{className}-> 来自用户或默认值{EntityName}Dto- 字段级变量 -> 来自实体详情
- 绝不替换 Variables 中未列出的内容
- 绝不添加示例中没有的导入、方法或代码
- FQN 处理(重要): 示例中包含 FQN(例如
java.util.Objects、java.util.List、jakarta.validation.constraints.NotNull)。编写 最终文件时,必须:- 将类主体中的每个 FQN 替换为其短名称
(例如,
java.util.Objects.hash(...)->Objects.hash(...),java.util.List<Integer>->List<Integer>,@jakarta.validation.constraints.NotNull->@NotNull)。 - 收集所有已缩短的 FQN,并在
package语句之后为其添加对应的import行,按字母顺序排序,不得重复。 java.lang中的类型(String、Integer、Object等)不得导入,且必须使用短名称。- 与 DTO 位于同一包中的类不得导入。
- Javadoc
{@link ...}引用——统一处理: 对所有形式的实体引用,在{@link …}中生成短名称 + import:顶层 Java 类、顶层 Java record、嵌套静态类、嵌套 record,以及独立文件中的子 DTO(NEW_CLASS)。不得区别处理。始终缩短实体引用,并始终添加对应的import行(除非实体位于同一包中)。 - 对导入分组为两个代码块,中间隔一个空行:
- 代码块 1 — 将所有第三方 / 项目导入放在一起:
jakarta.*、com.fasterxml.*、org.springframework.*、org.hibernate.*、项目包等(块内按字母顺序排列)。 - (空行)
- 代码块 2 —
java.*和javax.*(按字母顺序排列)。 不要将代码块 1 按包拆分为多个子块。 最终文件的主体中必须使用短名称(包括每个 Javadoc{@link …}),且顶部必须包含整洁、分组的导入块。
- 代码块 1 — 将所有第三方 / 项目导入放在一起:
- 将类主体中的每个 FQN 替换为其短名称
(例如,
-
对于子 DTO(subDtoType=NEW_CLASS):通过为子实体递归重复步骤 6.1-6.4,创建单独的文件。
-
对于嵌套类(subDtoType=NEW_NESTED_CLASS):在父 DTO 文件中添加内部类,然后按照相同的片段规则补全。
-
嵌套在 record 父类中 — 必须遵守: 当父 DTO 是 Java record 时,每个
NEW_NESTED_CLASS关联都必须在父 record 的主体中生成为嵌套的public record。技能不得仅仅因为 record 形式的片段看起来更短,就悄悄改用NEW_CLASS(单独文件)。完整流程见references/java-record.md步骤 6,以及examples/_fragments/nested-class/java/nested-class.md(“Java record” 变体)。如果这些说明看起来含糊不清,那是技能本身的问题——请修正文档,不要通过更改subDtoType来规避。
Step 7 -- Mapper(需要转换时自动执行)
根据上下文判断是否需要 Mapper,然后执行相应操作:
| 信号 | 操作 |
|---|---|
| 用户说了“only DTO”/“no mapper”/“without mapper” | 完全跳过 Step 7。不要提及 Mapper。 |
| 用户明确要求创建 Mapper(“and mapper”、“with mapper”、“create mapper too”) | 立即委派给 mapper-creator。 |
| 从上下文可以明确看出会进行实体↔DTO 转换(例如,用户要求在控制器/服务/端点中用 DTO 替换实体,或要求转换/映射/变换,DTO 用于 REST API 等) | 立即委派给 mapper-creator。转换不可避免;不创建 Mapper 就会被迫编写手动内联映射代码,这是绝不允许的。 |
| 上下文没有明确说明 DTO 的用途 | 跳过 Step 7。不要提及 Mapper。 |
重要: 绝不要编写手动映射代码(在控制器、服务或其他任何位置编写内联的 toDto/fromDto 方法)。如果需要转换,始终委派给 mapper-creator。该技能会决定实现策略(MapStruct、自定义 Mapper、添加依赖);此技能只负责委派。
绝不要因 Mapper 而调用 AskUserQuestion。如果需要委派,直接向
mapper-creator 技能提供 DTO 和实体信息——
不要询问用户是否确认委派。
缩进
该技能 MUST 检测项目的缩进风格,绝不要硬编码制表符 或空格。检测顺序:
- 项目根目录中的
.editorconfig(或目标文件所在目录的任意上级目录中的文件)。对于 Java 文件,查找[*.java]或[*]部分,并读取indent_style(tab或space)以及indent_size/tab_width。 - 同一包中的现有 Java 文件样本(或包含 Java 文件的最近
上级包)。检测缩进行的前导空白使用的是
\t还是空格,以及空格数量。 - 如果以上来源都无法得出明确结论,默认使用 4 个空格。(如果开发者明确偏好制表符,也可以默认使用制表符,但技能绝不能在没有说明的情况下擅自假定其中一种。)
无论选择哪种风格,都必须将其统一应用于每个生成代码片段的每一行(字段、构造函数、getter/setter、equals/hashCode、 toString、嵌套类/记录)。同一文件中绝不能混用制表符和空格。
按字段配置的选项
该技能必须支持以下按字段配置的选项:
- 重命名字段(
fieldNameOverride):DTO 字段名可以不同于 实体属性名。Mapper 仍会从原始属性映射。 - 添加校验(
extraValidations):用户可以在从实体继承的校验基础上,添加 jakarta/hibernate-validator 约束。允许的约束列表取决于字段类型——参见references/validation.md。 - 移除继承的校验(
removedValidations):用户可以移除来自实体字段的任意约束。 - 编辑注解参数(
message、min、max、regexp等):每个约束的所有参数都可以编辑。
除非用户明确要求“fine-tune field settings”、“per-field validation”或类似内容,否则绝不会出现这些选项。默认情况下,该技能只继承实体中的所有配置。
防幻觉检查清单
编写任何代码之前,请确认:
- 代码来自某个 examples/ 文件(注明具体文件)
- 仅替换了已声明的变量
- 未凭“已有知识”添加任何框架 API 调用
- 导入列表与示例完全一致
- 方法签名与示例完全一致
- 未添加注释或便捷方法
- 示例中的 FQN 在正文中已缩写,且在
package后添加了对应的import行 - 所有 Javadoc 格式——顶层类、顶层 record、嵌套静态类、嵌套 record、单独文件中的子 DTO——均使用短名称
{@link Pet},并添加匹配的import(除非实体位于同一包中)。规则统一,不得区别对待。 - 如果子 DTO 名称(单独文件或嵌套类)与目标包中已有的类冲突,自动添加数字后缀(例如
PetDto1)。该技能也必须这样做——生成前调用list_existing_classes(package),并依次追加1、2……直到名称不冲突。 - 生成 Java record 时,任何
NEW_NESTED_CLASS关联的内部类也必须是 record(而非静态类)。所有组件验证注解都应内联到 record 组件参数上(例如@NotBlank String firstName),而不是写在单独的字段声明上。 - 当
isJavaRecord = true时,该技能不得生成equals()、hashCode()、toString()、可变 setter 或链式 setter——record 会自动生成这些内容,且 record DTO 不应提供这些选项。 - 类级 Javadoc 必须是多行格式(
/**\n * DTO for {@link …}\n */),不得压缩为单行。 - Getter 和 setter 必须是多行格式(签名行、缩进的主体、结束花括号),不得写成单行。
- 在
mutable=true && fluentSetters=false模式下,getter 和 setter 必须交替排列(getX, setX, getY, setY, …),不得分组排列。 - 在
mutable=true模式下,必须同时生成无参构造函数和全参构造函数。 - 该技能不得将“仅 ID”作为单独选项提供——此选项不存在(ToOne 和 ToMany 均如此)。“仅关联 ID”的效果应通过**选择 Flat,并且仅勾选子实体的
id**来实现;该技能必须采用这种方式。 - 对于集合关联(
List<X>、Set<X>),必须提供 Flat,并生成复合复数形式的字段(Set<Integer> specialtyIds、List<Integer> petIds),前提是该技能会自动勾选子实体的标量字段。 - 从属性列表中过滤掉反向引用的
@ManyToOne字段(例如,创建PetDto时不提供Pet.owner)。 - 导入项按
jakarta.*/com.*/org.*/java.*分组,各组之间以空行分隔。 - 缩进应遵循项目检测到的样式(优先检查
.editorconfig,其次参照同一包中的现有文件,最后默认使用 4 个空格)。不得将制表符或空格写死。文件中的每个代码片段都必须统一应用该样式。 - Kotlin 不得添加
@JsonIgnoreProperties(仅适用于 Java) - Kotlin 中的验证注解使用
@field:前缀 - Kotlin DTO 中的 Java 类型必须转换为 Kotlin 类型