paint-brush
故事能够组织架构:从故事word文件自功转化 DTO 通过@dstepanov
2,724 讀數
2,724 讀數

事件驱动架构:从事件文档自动生成 DTO

所经 Stepanov Dmitrii20m2022/09/22
Read on Terminal Reader
Read this story w/o Javascript

太長; 讀書

AsyncAPI 是一项开源计划,旨在改善事件驱动架构 (EDA) 的当前状态 AsyncApi 有多个工具可让您从代码生成文档。在本文中,我想告诉您我是如何解决以下任务的,即使用 springwolf 生成的 JSON 文档生成 DTO。
featured image - 事件驱动架构:从事件文档自动生成 DTO
Stepanov Dmitrii HackerNoon profile picture


在系统開發的时候中,在工程的早期时候周期一般被强化的一种十分必要的事儿是 API pdf文件。这家故障 的避免计划书之五是自主转成pdf文件的三层架构。


在将内容区域划分为微工作并的适用群体事件真相驱动安装架构部署的原因下,工作之間的互交是的适用利用传闻销售商接入的群体事件真相来整合的。


要在事件驱动架构的情况下生成文档,有 。 AsyncAPI 是一项开源计划,旨在改善事件驱动架构 (EDA) 的当前状态。 AsyncApi 有几个 Java 工具,可让您从代码生成文档。在本文中,我描述了如何设置这些springwolf工具之一。


在文中中,可能告诉你您我是该如何处理好下神器任务的,即是用 springwolf 自动生产的 JSON pdf文件自动生产 DTO。

问题

spring wolf 转换的表格节构内容如下一样:


 { "service": { "serviceVersion": "2.0.0", "info": { //block with service info }, "servers": { "kafka": { //describe of kafka connection } }, "channels": { "kafka-channel": { "subscribe": { //... "message": { "oneOf": [ { "name": "pckg.test.TestEvent", "title": "TestEvent", "payload": { "$ref": "#/components/schemas/TestEvent" } } ] } }, //... } }, "components": { "schemas": { "TestEvent": { //jsonschema of component } } } } }


因文件中操作 jsonschema 来描述英文模块,,因此我选择操作库来解決这家故障。或许,在试用开展我的行动计划的环节中,我遭遇到了几故障:


  • 您需要额外解析 JSON 文档以提取描述组件的对象。由于 jsonschema2pojo 将 jsonschema 对象作为输入,因此它们位于 components 块中。
  • jsonschema2pojo 不能很好地处理多态性,并且不能处理来自 AsyncAPI 中 oneOf 块的标准引用。继承的描述需要 schema 中的特殊字段(extends.javaType),不能简单的添加到 AsyncAPI 文档中。
  • 由于在我们的案例中生成的类应该用于反序列化来自代理的消息,因此有必要添加描述描述符和子类型的 Jackson 注释。


一切这话题造成 我要求在 jsonschema2pojo 上实现目标我的再生器,它将从文件中转化成必要条件的的信息,扶持多态性,并移除 Jackson 标注。后果一个 Gradle 组件怎么安装,您就能够用它用到 springwolf API 为您的创业项目出现 DTO 类。反驳来,我将战胜困难操作步骤怎样为文件类注解甚至怎样用到组件怎么安装。

文档设置

在那里,想必充分考虑一些非最原始品类(如 Enum 和 Map)何时能绘制的细节处。和还分析了多态性的必备动作图片。


给.我看下部的信息内容:


 @Getter @Setter @NoArgsConstructor @AllArgsConstructor public class TestEvent implements Serializable { private String id; private LocalDateTime occuredOn; private TestEvent.ValueType valueType; private Map<String, Boolean> flags; private String value; public enum ValueType { STRING("STRING"), BOOLEAN("BOOLEAN"), INTEGER("INTEGER"), DOUBLE("DOUBLE"); private final String value; public ValueType(String value) { this.value = value; } } }


相应消息提醒的 jsonschema 如下图甲中图甲中:


 { "service": { //... "components": { "schemas": { "TestEvent": { "type": "object", "properties": { "id": { "type": "string", "exampleSetFlag": false }, "occuredOn": { "type": "string", "format": "date-time", "exampleSetFlag": false }, "valueType": { "type": "string", "exampleSetFlag": false, "enum": [ "STRING", "BOOLEAN", "INTEGER", "DOUBLE" ] }, "flags": { "type": "object", "additionalProperties": { "type": "boolean", "exampleSetFlag": false }, "exampleSetFlag": false }, "value": { "type": "string", "exampleSetFlag": false } }, "example": { "id": "string", "occuredOn": "2016-07-20T15:49:04", "valueType": "STRING", "flags": { "additionalProp1": true, "additionalProp2": true, "additionalProp3": true } }, "exampleSetFlag": true } } } } }


在生成 DTO 类时,我们会得到如下的类结构。您可以看到 Enum 的处理方式与原始版本一样,但是Map<String, Boolean>类型的集合已变成单独的类 Flags 并且集合本身的整个值将落入Flags.additionalProperties字段中。


 package pckg.test; // import @JsonInclude(JsonInclude.Include.NON_NULL) @JsonPropertyOrder({ "id", "occuredOn", "valueType", "flags", "value" }) @Generated("jsonschema2pojo") public class TestEvent implements Serializable { @JsonProperty("id") private String id; @JsonProperty("occuredOn") private LocalDateTime occuredOn; @JsonProperty("valueType") private TestEvent.ValueType valueType; @JsonProperty("flags") private Flags flags; @JsonProperty("value") private String value; @JsonIgnore private Map<String, Object> additionalProperties = new LinkedHashMap<String, Object>(); private final static long serialVersionUID = 73777748L; // Getters ans Setters @Generated("jsonschema2pojo") public enum ValueType { STRING("STRING"), BOOLEAN("BOOLEAN"), INTEGER("INTEGER"), DOUBLE("DOUBLE"); private final String value; private final static Map<String, TestEvent.ValueType> CONSTANTS = new HashMap<String, TestEvent.ValueType>(); static { for (TestEvent.ValueType c: values()) { CONSTANTS.put(c.value, c); } } ValueType(String value) { this.value = value; } @Override public String toString() { return this.value; } @JsonValue public String value() { return this.value; } @JsonCreator public static TestEvent.ValueType fromValue(String value) { TestEvent.ValueType constant = CONSTANTS.get(value); if (constant == null) { throw new IllegalArgumentException(value); } else { return constant; } } } } @JsonInclude(JsonInclude.Include.NON_NULL) @JsonPropertyOrder({ }) @Generated("jsonschema2pojo") public class Flags implements Serializable { @JsonIgnore private Map<String, Boolean> additionalProperties = new LinkedHashMap<String, Boolean>(); private final static long serialVersionUID = 74717740L; //getters and setters }

多态性

现今我能们查看咋样能提供多态性页面。当企业希望向一款 经销题目接收很多个新消息子类并给所有子类推动企业的侦听器时,是有关系的。


因而,我们的要求在供应者目录中填加是一个父类,并明年自 swagger 的 @Schema 注解填加到它。


 @NoArgsConstructor(access = AccessLevel.PROTECTED) @AllArgsConstructor @Getter @Setter(AccessLevel.PROTECTED) @EqualsAndHashCode @JsonTypeInfo( use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type", visible = true, defaultImpl = ChangedEvent.class ) @JsonSubTypes(value = { @JsonSubTypes.Type(name = ChangedEvent.type, value = ChangedEvent.class), @JsonSubTypes.Type(name = DeletedEvent.type, value = DeletedEvent.class) }) @JsonIgnoreProperties(ignoreUnknown = true) @Schema(oneOf = {ChangedEvent.class, DeletedEvent.class}, discriminatorProperty = "type", discriminatorMapping = { @DiscriminatorMapping(value = ChangedEvent.type, schema = ChangedEvent.class), @DiscriminatorMapping(value = DeletedEvent.type, schema = DeletedEvent.class), }) public abstract class DomainEvent { @Schema(required = true, nullable = false) private String id; @JsonSerialize(using = LocalDateTimeSerializer.class) @JsonDeserialize(using = LocalDateTimeDeserializer.class) @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime occuredOn = LocalDateTime.now(); public abstract String getType(); } /** * Subtype ChangedEvent */ public class ChangedEvent extends DomainEvent implements Serializable { public static final String type = "CHANGED_EVENT"; private String valueId; private String value; } /** * Subtype DeletedEvent */ public class DeletedEvent extends DomainEvent implements Serializable { public static final String type = "DELETED_EVENT"; private String valueId; }


在这一种问题下,文件中对构件的分析会發生以下转变 :


 "components": { "schemas": { "ChangedEvent": { "type": "object", "properties": { "id": { "type": "string", "exampleSetFlag": false }, "occuredOn": { "type": "string", "format": "date-time", "exampleSetFlag": false }, "value": { "type": "string", "exampleSetFlag": false }, "valueId": { "type": "string", "exampleSetFlag": false }, "type": { "type": "string", "exampleSetFlag": false } }, "example": { "id": "string", "occuredOn": "2016-07-20T15:49:04", "value": "string", "valueId": "string", "type": "CHANGED_EVENT" }, "exampleSetFlag": true }, "DeletedEvent": { "type": "object", "properties": { "id": { "type": "string", "exampleSetFlag": false }, "occuredOn": { "type": "string", "format": "date-time", "exampleSetFlag": false }, "valueId": { "type": "string", "exampleSetFlag": false }, "type": { "type": "string", "exampleSetFlag": false } }, "example": { "id": "string", "occuredOn": "2016-07-20T15:49:04", "valueId": "string", "type": "DELETED_EVENT" }, "exampleSetFlag": true }, "DomainEvent": { "type": "object", "properties": { "id": { "type": "string", "exampleSetFlag": false }, "occuredOn": { "type": "string", "format": "date-time", "exampleSetFlag": false }, "type": { "type": "string", "exampleSetFlag": false } }, "example": { "id": "string", "occuredOn": "2016-07-20T15:49:04", "type": "string" }, "discriminator": { "propertyName": "type", "mapping": { "CHANGED_EVENT": "#/components/schemas/ChangedEvent", "DELETED_EVENT": "#/components/schemas/DeletedEvent" } }, "exampleSetFlag": true, "oneOf": [ { "$ref": "#/components/schemas/ChangedEvent", "exampleSetFlag": false }, { "$ref": "#/components/schemas/DeletedEvent", "exampleSetFlag": false } ] } } }


以后,插件机将注重源于 oneOf 块的跳转和讲述的甄别器。最终结果,大家得到了一下类结构类型。


 package pckg.test; // import @JsonInclude(JsonInclude.Include.NON_NULL) @JsonPropertyOrder({ "id", "occuredOn", "type" }) @Generated("jsonschema2pojo") @JsonTypeInfo(property = "type", use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, visible = true) @JsonSubTypes({ @JsonSubTypes.Type(name = "CHANGED_EVENT", value = ChangedEvent.class), @JsonSubTypes.Type(name = "DELETED_EVENT", value = DeletedEvent.class) }) public class DomainEvent implements Serializable { @JsonProperty("id") protected String id; @JsonProperty("occuredOn") protected LocalDateTime occuredOn; @JsonProperty("type") protected String type; @JsonIgnore protected Map<String, Object> additionalProperties = new LinkedHashMap<String, Object>(); protected final static long serialVersionUID = 46991903L; //getters and setters } // import @JsonInclude(JsonInclude.Include.NON_NULL) @JsonPropertyOrder({ "id", "occuredOn", "valueId", "type" }) @Generated("jsonschema2pojo") public class DeletedEvent extends DomainEvent implements Serializable { @JsonProperty("id") private String id; @JsonProperty("occuredOn") private LocalDateTime occuredOn; @JsonProperty("valueId") private String valueId; @JsonProperty("type") private String type; @JsonIgnore private Map<String, Object> additionalProperties = new LinkedHashMap<String, Object>(); private final static long serialVersionUID = 73263837L; // getters and setters } package pckg.test; //import @JsonInclude(JsonInclude.Include.NON_NULL) @JsonPropertyOrder({ "id", "occuredOn", "value", "type" }) @Generated("jsonschema2pojo") public class ChangedEvent extends DomainEvent implements Serializable { @JsonProperty("id") private String id; @JsonProperty("occuredOn") private LocalDateTime occuredOn; @JsonProperty("value") private String value; @JsonProperty("type") private String type; @JsonIgnore private Map<String, Object> additionalProperties = new LinkedHashMap<String, Object>(); private final static long serialVersionUID = 5446866391322866265L; //getters and setters }


插件设置

要相连接3d插件,可以将其添加图片到 gradle.build 压缩文件中并规定运作:
  • 文本夹代替形成 DTO
  • 课程改革培训包
  • springwolf 文档文件 URL
  • 文件中的根简称,一般是服务项目的简称


plugins { id 'io.github.stepanovd.springwolf2dto' version '1.0.1-alpha' } springWolfDoc2DTO{ url = '//localhost:8080/springwolf/docs' targetPackage = 'example.package' documentationTitle = 'my-service' targetDirectory = project.layout.getBuildDirectory().dir("generated-sources") }


应用 bash 指令作业任務:


 ./gradle -q generateDTO

结论

在本文中,我描述了如何使用springwolfdocs2dto插件基于 AsyncApi 文档生成新的 DTO 类。同时,新的类将根据原始继承并包含杰克逊注释以进行正确的反序列化。我希望你发现这个插件对你有用。


바카라사이트 바카라사이트 온라인바카라