Code Generator for java code from asyncApi specs
The idea behind this generator is, to have a flexibel generator which reads asyncAPI specifications in and generates messages and DTOs into a configurable package structure. The resulting artefact are generated inherited or implenting a specific class or interface respectively. This allows that these generated artefacts can used within a specific framework of choice (hopefully)
GNU GENERAL PUBLIC LICENSE Version 3
| Option | Short Cut | Argument | Description |
|---|---|---|---|
| --input | -i | < file > | asyncapi.yaml with the async API specification default: src/resource/test/api/asyncapi.yaml |
| --output | -o | < directory > | root-Path for the generated java code |
| --package | -p | < package > | package prefix for the generated data default: ch.kochse.app.example.contract |
| --dto-package | -d | < package > | package suffix for the generated dto default: contract |
| --msg-package | -m | < package > | package suffix for the generated message default: contract |
| --contract-package | -c | < package > | package suffix for the generated |
| --domain | -- | < name > | name of the domain used for parent directory |
| --target | -- | java python | target language default: java (python not yet implemented) |
java -jar build/libs/asyncapi-generator-1.1.0.jar --output ./build/generated/src/main/java
--input ./src/test/resources/api/asyncapi.yaml --target java
-p ch.kochse.api.test --version v1.0.0
--package ch.kochse.app
--dto-package dto
--msg-package msg
--contract-package ctrct
Generating:
ch.kochse.app.ctrct.dto // for dtos
ch.kochse.app.ctrct.msg // for messages
ch.kochse.app.ctrct // for enums
There are predefined properties which control the generation process and which are stored in the application.properties file.
| Property-Key | Property-Value | Default | Description |
|---|---|---|---|
| CodeGen.Contract.Package | < name > | contract | package suffix appended after the package name |
| CodeGen.DTO.Package: | < name > | package suffix appended after the contract package name for DTO artefact | |
| CodeGen.Message.Package | < name > | package suffix appended after the contract package name for message artefact | |
| CodeGen.Enum.Package | < name > | package suffix appended after the contract package name for enumeration artefact | |
| CodeGen.DateType | < qualified class name > | java.time.LocalDateTime | Class used for format: date-time |
| CodeGen.Message.ParentClass | < qualified class name > | Parent class from which generated message artefacts are inherited | |
| CodeGen.MessageType.ParentInterface | < qualified class name > | Parent interface for generated MessageType classes used for implementation (no operations) | |
| CodeGen.Enum.ParentInterface | < qualified class name > | Parent interface for generated enum for implementation as type (no operation) | |
| CodeGen.DTO.ParentInterface | < qualified class name > | Parent interface for generated dto for implementation as type (no operation) |
See also: In the directory ./src/test/java/ch/kochse/lib/common/messaging/base you find example classes which can be used for the following properties:
- CodeGen.Message.ParentClass -> AMessage.java
- CodeGen.MessageType.ParentInterface -> IMessageType.java
- CodeGen.Enum.ParentInterface -> IEnum.java
- CodeGen.DTO.ParentInterface -> IDTO.java
This project uses the Gradle Build Tool to build and release artifacts. More specifics you find under Gradle Help
./gradlew clean build
dependencies {
asyncapiGen "ch.kochse.tools:asyncapi-generator:${asyncapi_generator_version}"
}
configurations {
asyncapiGen
compileOnly {
extendsFrom annotationProcessor
}
}
task generate (type: JavaExec) {
description 'AsyncApi-Generator for generating classes as contracts'
doFirst {
delete fileTree("src/main/java").matching {
include "**/*.java"
}
}
classpath = configurations.asyncapiGen
args = ['--spring.config.location=' + projectDir.toString() + '/src/main/resources/config/',
'--output', 'src/main/java',
'-p' ,'ch.kochse.hobby.garden.common.devicectrl',
'--version', scmVersion.version,
'--input', projectDir.toString() + '/src/main/resources/api/asyncapi.yaml'
]
}
compileJava {
dependsOn generate
}
The artifacts generated by this project are:
for each message specification a Message is generated
Input:
ReservationRspMsg:
messageId: ReservationRspMsg
name: Reservation Message
title: Greenhouse Reservation
summary: Inquiry of a reservation for growing some fruits or vegetables
contentType: application/json
payload:
properties:
completion:
$ref: '#/components/schemas/CompletionData'
description: Error Code according documentation
data:
$ref: '#/components/schemas/PlantingReservationRspDTO'
Output:
// *** THIS IS GENERATED CODE. DO NOT CHANGE IT, AS IT MIGHT GET OVERRIDEN WITH NEXT BUILD! ***
package ch.kochse.api.test.contract.msg;
import ch.kochse.api.test.contract.CompletionData;
import ch.kochse.api.test.contract.dto.PlantingReservationRspDTO;
import ch.kochse.lib.common.messaging.base.AMessage;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.lang.Override;
import java.lang.String;
public class ReservationRspMsg extends AMessage {
private CompletionData completion;
private PlantingReservationRspDTO data;
public ReservationRspMsg() {
super(TestMsgType.RESERVATION_RSP_MSG, "scmVersion.version");
}
/**
* Error Code according documentation
*/
@JsonProperty("completion")
public CompletionData getCompletion() {
return this.completion;
}
/**
* Error Code according documentation
*/
public void setCompletion(CompletionData pCompletion) {
completion = pCompletion;
}
/**
* Data
*/
@JsonProperty("data")
public PlantingReservationRspDTO getData() {
return this.data;
}
/**
* Data
*/
public void setData(PlantingReservationRspDTO pData) {
data = pData;
}
@Override
@JsonProperty("payload")
public PlantingReservationRspDTO payload() {
return this.data;
}
@Override
public void payload(PlantingReservationRspDTO pPayload) {
data = pPayload;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder("ReservationRspMsg:\n");
sb.append("completion=").append(String.valueOf(getCompletion())).append('\n');
sb.append("data=").append(String.valueOf(getData())).append('\n');
return sb.toString();
}
}
MessageType class generated which includes all messages and dtos as used for a factory
// *** THIS IS GENERATED CODE. DO NOT CHANGE IT, AS IT MIGHT GET OVERRIDEN WITH NEXT BUILD! ***
package ch.kochse.api.test.contract.msg;
import static ch.kochse.lib.common.messaging.base.IMessageType.messageType;
import ch.kochse.lib.common.messaging.base.IMessageType;
public interface TestMsgType extends IMessageType {
IMessageType RESERVATION_REQ_MSG = messageType("RESERVATION_REQ_MSG", ReservationReqMsg.class, ch.kochse.api.test.contract.dto.PlantingReservationReqDTO.class);
IMessageType RESERVATION_RSP_MSG = messageType("RESERVATION_RSP_MSG", ReservationRspMsg.class, ch.kochse.api.test.contract.dto.PlantingReservationRspDTO.class);
IMessageType ORDER_REQ_MSG = messageType("ORDER_REQ_MSG", OrderReqMsg.class, ch.kochse.api.test.contract.dto.PlantingOrderReqDTO.class);
IMessageType ORDER_RSP_MSG = messageType("ORDER_RSP_MSG", OrderRspMsg.class, ch.kochse.api.test.contract.dto.PlantingOrderRspDTO.class);
IMessageType CANCELLATION_REQ_MSG = messageType("CANCELLATION_REQ_MSG", CancellationReqMsg.class, ch.kochse.api.test.contract.dto.PlantingCancellationReqDTO.class);
IMessageType CANCELLATION_RSP_MSG = messageType("CANCELLATION_RSP_MSG", CancellationRspMsg.class, ch.kochse.api.test.contract.dto.PlantingCancellationRspDTO.class);
IMessageType STATUS_EVENT = messageType("STATUS_EVENT", StatusEvent.class, ch.kochse.api.test.contract.dto.PlantingStatusEvtDTO.class);
static boolean registerWithFactory() {
return true;
}
}
From each schema structure a dto is generated
Input:
PlantingReservationRspDTO:
type: object
properties:
reservationStatus:
$ref: '#/components/schemas/ReservationStatus'
reservationId:
type: string
description: 'reservation id of the reservation'
inquiryId:
type: string
description: 'uuid to correlate the reservation to one order'
productId:
type: string
description: 'product identifier'
productname:
type: string
description: 'short description such as name of the product'
expectedDelivery:
type: string
format: date-time
description: 'expected delivery date of the amount of the product'
planedDelivery:
type: string
format: date-time
description: 'requested delivery date of the amount of the product'
requiredQty:
type: number
description: 'requested quantity of product to grow and deliver'
expecteQty:
type: number
description: 'expected quantity of product to grow and deliver'
unit:
$ref: '#/components/schemas/ProductUnit'
description: 'quantity related unit of product'
deliveryMode:
$ref: '#/components/schemas/DeliveryMode'
description: 'defines if the delivery of an requested quantity has to be delivered in one or possibly parially'
minimalQuantity:
type: number
description: 'minimal quantity to reserve in case the complete quatity cannot be covered. Field only relevant in deliveryMode partial'
Output:
// *** THIS IS GENERATED CODE. DO NOT CHANGE IT, AS IT MIGHT GET OVERRIDEN WITH NEXT BUILD! ***
package ch.kochse.api.test.contract.dto;
import ch.kochse.api.test.contract.DeliveryMode;
import ch.kochse.api.test.contract.ProductUnit;
import ch.kochse.api.test.contract.ReservationStatus;
import ch.kochse.lib.common.messaging.base.IDTO;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.lang.Double;
import java.lang.Override;
import java.lang.String;
import java.time.LocalDateTime;
public class PlantingReservationRspDTO implements IDTO {
private ReservationStatus reservationStatus;
private String reservationId;
private String inquiryId;
private String productId;
private String productname;
private LocalDateTime expectedDelivery;
private LocalDateTime planedDelivery;
private Double requiredQty;
private Double expecteQty;
private ProductUnit unit;
private DeliveryMode deliveryMode;
private Double minimalQuantity;
public PlantingReservationRspDTO() {
}
/**
* ReservationStatus
*/
@JsonProperty("reservationStatus")
public ReservationStatus getReservationStatus() {
return this.reservationStatus;
}
/**
* ReservationStatus
*/
public void setReservationStatus(ReservationStatus pReservationStatus) {
reservationStatus = pReservationStatus;
}
// ---- 8><-----------
/**
* minimal quantity to reserve in case the complete quatity cannot be covered. Field only relevant in deliveryMode partial
*/
@JsonProperty("minimalQuantity")
public Double getMinimalQuantity() {
return this.minimalQuantity;
}
/**
* minimal quantity to reserve in case the complete quatity cannot be covered. Field only relevant in deliveryMode partial
*/
public void setMinimalQuantity(Double pMinimalQuantity) {
minimalQuantity = pMinimalQuantity;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder("PlantingReservationRspDTO:\n");
sb.append("reservationStatus=").append(String.valueOf(getReservationStatus())).append('\n');
sb.append("reservationId=").append(String.valueOf(getReservationId())).append('\n');
sb.append("inquiryId=").append(String.valueOf(getInquiryId())).append('\n');
sb.append("productId=").append(String.valueOf(getProductId())).append('\n');
sb.append("productname=").append(String.valueOf(getProductname())).append('\n');
sb.append("expectedDelivery=").append(String.valueOf(getExpectedDelivery())).append('\n');
sb.append("planedDelivery=").append(String.valueOf(getPlanedDelivery())).append('\n');
sb.append("requiredQty=").append(String.valueOf(getRequiredQty())).append('\n');
sb.append("expecteQty=").append(String.valueOf(getExpecteQty())).append('\n');
sb.append("unit=").append(String.valueOf(getUnit())).append('\n');
sb.append("deliveryMode=").append(String.valueOf(getDeliveryMode())).append('\n');
sb.append("minimalQuantity=").append(String.valueOf(getMinimalQuantity())).append('\n');
return sb.toString();
}
}
For each Enumeration defined
Input:
DeliveryMode:
type: string
enum:
- 'complete'
- 'parital'
- 'undefined'
description: 'defines if the delivery of an requested quantity has to be delivered in one or possibly parially'
Output:
// *** THIS IS GENERATED CODE. DO NOT CHANGE IT, AS IT MIGHT GET OVERRIDEN WITH NEXT BUILD! ***
package ch.kochse.api.test.contract;
import ch.kochse.lib.common.messaging.base.IEnum;
import java.lang.Exception;
/**
* Enum: defines if the delivery of an requested quantity has to be delivered in one or possibly parially
*/
public enum DeliveryMode implements IEnum {
COMPLETE,
PARITAL,
UNDEFINED;
public static DeliveryMode convert(IEnum pFrom) {
DeliveryMode retS = DeliveryMode.UNDEFINED;
try {
retS = valueOf(pFrom.name());
} catch(Exception pEx) {
}
return retS;
}
}