开发工具代码生成API设计【免费下载链接】swagger-codegenswagger-codegen contains a template-driven engine to generate documentation, API clients and server stubs in different languages by parsing your OpenAPI / Swagger definition.项目地址https://gitcode.com/gh_mirrors/sw/swagger-codegen点击查看免费下载导读本文以 swagger-codegen 仓库中 Java 客户端示例的模型文档 HasOnlyReadOnly.md 为切入点结合对应的 OpenAPI/Swagger 定义与 Java 源码实现深入剖析「全部属性均为只读readOnly」的模型在代码生成过程中的识别、文档呈现与访问器生成规则。读完本文你将掌握如何在 Swagger/OpenAPI 定义中声明 readOnly 属性、swagger-codegen 如何在模型文档中标注只读字段、hasOnlyReadOnly标志与readOnlyVars列表的底层计算逻辑以及为何生成的 Java 类只有 getter 而没有 setter。一、HasOnlyReadOnly 模型是什么HasOnlyReadOnly是 swagger-codegen 官方测试夹具fixture中的专用模型用于验证代码生成器对「全部属性均为只读」这类极端模型形态的处理能力。它只包含两个String类型的属性属性类型说明备注barString—[optional]fooString—[optional]注意这里的备注列只有[optional]没有[readonly]标记。这是本文后续要重点剖析的一个有趣细节——尽管该模型的全部属性在定义中都被标记为readOnly: true但其模型文档表格中并未输出[readonly]标注。该模型在仓库的多个版本定义中均有出现例如 v2 的 petstorefake.yaml 与 samplesServers.yaml以及 v3 的 petstore3fake.yaml 与 petstoreMixed3.yaml。以 v2 定义为例hasOnlyReadOnly: type: object properties: bar: type: string readOnly: true foo: type: string readOnly: true模型名 HasOnlyReadOnly 即 Has Only Read-Only (properties) 的缩写语义直白该模型的所有属性都只读。二、readOnly 属性在 Swagger/OpenAPI 定义中的声明方式2.1 属性级声明在 OpenAPI/Swagger 2.0 与 OpenAPI 3.x 中readOnly是一个布尔型的属性修饰符声明在 schema 属性的同一层级bar: type: string readOnly: true其语义如下readOnly: true表示该属性只能出现在响应response中不应出现在请求request体中该属性不可由客户端提交因此生成的客户端模型通常不为其生成 setter / 写方法默认值为false未声明时按可读写处理。2.2 与其他修饰符的组合在夹具中readOnly常与其他修饰符组合出现用于覆盖更多测试场景例如 v2 petstorefake.yaml 中的Name模型Name: description: Model for testing model name same as property name required: - name properties: name: type: integer format: int32 snake_case: readOnly: true type: integer format: int32 property: type: string 123Number: type: integer readOnly: true可以看到readOnly与type、format同级并列同一模型中也可以混排只读与非只读属性如ReadOnlyFirst模型同时含只读的bar与可读写的baz见 petstorefake.yaml。这些夹具共同组成了 swagger-codegen 对只读属性处理逻辑的回归测试集。三、生成文档表格pojo_doc.mustache 模板解析模型文档如本文主题的HasOnlyReadOnly.md并非手工编写而是由代码生成器根据模板渲染输出。对应的模板是 pojo_doc.mustache# {{classname}} ## Properties Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- {{#vars}}**{{name}}** | ... | {{description}} | {{^required}} [optional]{{/required}}{{#readOnly}} [readonly]{{/readOnly}} {{/vars}}表格的 Notes 列由两个条件片段拼接而成{{^required}} [optional]{{/required}}——当属性非必填时输出[optional]{{#readOnly}} [readonly]{{/readOnly}}——当属性标记为只读时输出[readonly]。该模板适用于所有语言变体的 pojo 文档生成不仅限于 Java同一模型在 bash、C#、Go、JavaScript、Perl、PHP、Python、Ruby、Swift 等客户端的docs/HasOnlyReadOnly.md均由它渲染。3.1 为什么本例没有[readonly]标注回到本文主题文档 HasOnlyReadOnly.md其 Notes 列只有[optional]没有[readonly]。这说明模板渲染时{{#readOnly}}条件为假——在 Mustache 模板中布尔值false与空值都会使区块不渲染。由此可以推断该文档是由一个未将isReadOnly透传到模板readOnly变量的版本生成的。也就是说这份样例文档是某一历史版本的生成产物而非按当前仓库源码重新生成的快照当前仓库中pojo_doc.mustache对只读属性的标注逻辑已演进详见下文第四节与第五节。这也提醒读者samples/目录下的生成物是「固定快照」不能仅凭它们断定代码生成器当前的行为需要结合modules/swagger-codegen中的源码与模板来判断。四、底层模型readOnlyVars 与 hasOnlyReadOnly 的计算逻辑4.1 CodegenProperty 的 isReadOnly 标记从 Swagger 定义到内部代码生成模型CodegenModel / CodegenProperty的转换由 DefaultCodegen.java 完成。isReadOnly字段的赋值逻辑如下DefaultCodegen.javaif (p.getReadOnly() ! null) { property.isReadOnly p.getReadOnly(); }即定义中显式给出readOnly布尔值时直接透传到内部模型CodegenProperty.isReadOnly。4.2 hasOnlyReadOnly 标志默认 true遇到可写属性才置 falseCodegenModel中专门定义了一个布尔标志hasOnlyReadOnlyCodegenModel.javapublic boolean hasOnlyReadOnly true; // true if all properties are read-only它的计算逻辑位于模型属性归集阶段DefaultCodegen.java// set models hasOnlyReadOnly to false if the property is read-only if (!Boolean.TRUE.equals(cp.isReadOnly)) { m.hasOnlyReadOnly false; }结合默认值true可知其语义为遍历模型全部属性一旦发现任何一个属性不是只读就将hasOnlyReadOnly置为false。因此全部属性只读 →hasOnlyReadOnly true只要存在一个可读写属性 →hasOnlyReadOnly false。这与模型名HasOnlyReadOnly的语义完全对应HasOnlyReadOnly模型的hasOnlyReadOnly必然为true而同时含bar只读与baz可读写的ReadOnlyFirst模型则为false。4.3 属性列表的划分readOnlyVars 与 readWriteVars在同一个归集循环中属性还会被划分进两个列表DefaultCodegen.java// if readonly, add to readOnlyVars (list of properties) if (Boolean.TRUE.equals(cp.isReadOnly)) { m.readOnlyVars.add(cp); } else { // else add to readWriteVars (list of properties) m.readWriteVars.add(cp); }两个列表的职责定义于 CodegenModel.javareadOnlyVars只读属性列表用于模板中「仅展示/仅反序列化」类逻辑readWriteVars可读写属性列表用于「请求体 / 可提交字段」类逻辑。对于HasOnlyReadOnly模型readOnlyVars包含bar与foo两个属性readWriteVars为空。五、Java 客户端readOnly 属性只生成 getter不生成 setter5.1 pojo.mustache 的条件渲染Java 客户端的模型模板为 pojo.mustache其中对每个属性变量做了三段式条件渲染链式fluent写入方法——仅在{{^isReadOnly}}时生成pojo.mustache{{#vars}} {{^isReadOnly}} public {{classname}} {{name}}({{{datatypeWithEnum}}} {{name}}) { this.{{name}} {{name}}; return this; } ... {{/isReadOnly}}getter——无条件生成pojo.mustachepublic {{{datatypeWithEnum}}} {{#isBoolean}}is{{/isBoolean}}{{getter}}() { return {{name}}; }setter——仅在{{^isReadOnly}}时生成pojo.mustache{{^isReadOnly}} public void {{setter}}({{{datatypeWithEnum}}} {{name}}) { this.{{name}} {{name}}; } {{/isReadOnly}}结论明确readOnly 属性保留 getter供响应读取但被模板显式跳过 fluent 写入方法与 setter从而保证客户端不会向服务端提交只读字段。5.2 生成的 HasOnlyReadOnly.java 实证以上规则在生成的 Java 类中得到了直接印证HasOnlyReadOnly.java 中两个字段均以JsonProperty声明L29-L33只生成了getBar()L40-L42与getFoo()L49-L51两个 getter没有任何 setter也没有链式写入方法equals/hashCode/toString均由Objects工具基于两个字段实现L54-L93。同样的「只有 getter、没有 setter」结构也出现在仓库中其他语言/变体的生成物中例如 HasOnlyReadOnly.swift、HasOnlyReadOnly.php、HasOnlyReadOnly.js以及服务端模型如 HasOnlyReadOnly.java说明该行为是生成器层面的通用约定而非特定语言特例。5.3 生成该示例的完整 CLI 命令HasOnlyReadOnly的 Java 示例位于samples/client/petstore/java/jersey2-java8其生成过程对应 swagger-codegen CLI 的典型用法以 v2 定义与 java 生成器为例java -jar modules/swagger-codegen-cli/target/swagger-codegen-cli.jar generate \ -i fixtures/immutable/specifications/v2/petstorefake.yaml \ -l java \ --library jersey2 \ --additional-properties java8true \ -o samples/client/petstore/java/jersey2-java8关键参数说明-i输入 Swagger/OpenAPI 定义文件v2 或 v3 均可本仓库同时维护 v2 夹具 与 v3 夹具-l java目标语言生成器--library jersey2选择 Jersey 2 客户端库变体jersey2-java8 即基于此并叠加 Java 8 特性--additional-properties java8true启用 Java 8 语法特性如java.time日期类型这正是 jersey2-java8 与 jersey2 示例的差异点-o输出目录。同一petstorefake.yaml定义在仓库中被反复用于生成 java/okhttp-gson、java/resttemplate、java/retrofit2 等十余种 Java 变体以及 Python、Ruby、Swift、Go 等其它语言客户端是验证「同一模型定义、多语言生成一致性」的核心夹具。六、如何验证与证据如果希望自行验证上述行为仓库提供了完整的证据链定义侧阅读 petstorefake.yaml 中hasOnlyReadOnly模型的readOnly: true声明文档侧对比本主题文档 HasOnlyReadOnly.md 与模板 pojo_doc.mustache 的 Notes 列拼接规则源码侧追踪 DefaultCodegen.java 中hasOnlyReadOnly与readOnlyVars/readWriteVars的赋值以及 pojo.mustache 对isReadOnly的条件渲染产物侧核对 HasOnlyReadOnly.java 只有 getter、没有 setter 的最终形态。七、小结HasOnlyReadOnly模型是 swagger-codegen 中一个设计精巧的边界测试用例它验证了以下核心行为定义层readOnly: true作为属性修饰符声明只读语义中间层DefaultCodegen将定义标记透传为CodegenProperty.isReadOnly并据此维护readOnlyVars/readWriteVars两个列表与hasOnlyReadOnly总标志模板层pojo.mustache对isReadOnly条件渲染只读属性仅生成 getter、跳过 setter 与链式写入方法产物层最终 Java 类只有getBar()/getFoo()天然符合「只读属性仅可读取、不可提交」的 API 契约。同时对比当前模板 pojo_doc.mustache 与历史快照文档的差异可以看出samples/中的生成物是固定快照理解 swagger-codegen 的真实行为应以modules/swagger-codegen下的源码与模板为准。读者如需在自己的项目中应用这一机制只需在 OpenAPI 定义中对服务端生成的字段标注readOnly: true即可获得「响应可读、请求不可提交」的客户端模型从代码层面杜绝客户端误提交只读字段的问题。赞分享开发工具代码生成API设计【免费下载链接】swagger-codegenswagger-codegen contains a template-driven engine to generate documentation, API clients and server stubs in different languages by parsing your OpenAPI / Swagger definition.项目地址https://gitcode.com/gh_mirrors/sw/swagger-codegen点击查看免费下载相关推荐swagger-codegen 中 readOnly 属性的生成机制以 C 客户端 HasOnlyReadOnly 模型为例swagger codegen 中 readOnly 属性的生成机制以 C 客户端 HasOnlyReadOnly 模型为例 HasOnlyReadOnly开发工具代码生成API设计Swagger Codegen 中的 readOnly 模型生成详解以 HasOnlyReadOnly 为例Swagger Codegen 中的 readOnly 模型生成详解以 HasOnlyReadOnly 为例 HasOnlyReadOnly 是 Swagge开发工具代码生成API设计swagger-codegen 生成 C 只读属性模型以 HasOnlyReadOnly 为例解读 readOnly 语义的实现swagger codegen 生成 C 只读属性模型以 HasOnlyReadOnly 为例解读 readOnly 语义的实现 导读 本文以 swagger开发工具代码生成API设计创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考