Skip to content

Commit

Permalink
feat: add annotations to the model generation (#12)
Browse files Browse the repository at this point in the history
* WIP, update to spec 2.0

* WIP, update to spec 2.0, remove definition of topic via extension

* working version for api 2.0

* add model generation

* Add support of Kafka generation

* update readme

* fix value ref, add jackson lib

* add validation annotations to schema

* fix no type case

* add annotation for jackson

* add description and examples to javadoc

* Update readme, move missed features block

* switch publish to subscribe and vice versa, because of wrong understanding of spec

* Fix consumed key, add key to publish operation

* move jackson and validation dependencies from kafka block

* fix README formatting

* mark annotations as done in README

* add support of multi-line description

* fix json in examples
  • Loading branch information
Tenischev authored Apr 24, 2020
1 parent 65512d2 commit 204618c
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 29 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#Java Spring generator
# Java Spring generator
_Use your AsyncAPI definition to generate java code to subscribe and publish messages_


Expand Down Expand Up @@ -120,7 +120,7 @@ See the list of features that are still missing in the component:
- [ ] support of Kafka is done based on clear "spring-kafka" library without integration like for mqtt or amqp
- [ ] generated code for protocols mqtt and amqp could be out of date. Please have a look to [application.yaml](template/src/main/resources/application.yml) and [AmqpConfig.java](partials/AmqpConfig.java), [MqttConfig.java](partials/MqttConfig.java)
- [ ] tests are not provided
- [ ] add annotation to the [model generation](template/src/main/java/com/asyncapi/model). Consider "@Valid", "@JsonProperty", "@Size", "@NotNull" e.t.c.
- [x] add annotation to the [model generation](template/src/main/java/com/asyncapi/model). Consider "@Valid", "@JsonProperty", "@Size", "@NotNull" e.t.c.
- [ ] [`parameters`](https://github.com/asyncapi/asyncapi/blob/master/versions/2.0.0/asyncapi.md#parametersObject) for topics are not supported
- [ ] [`server variables`](https://github.com/asyncapi/asyncapi/blob/master/versions/2.0.0/asyncapi.md#serverVariableObject) are not entirely supported
- [ ] [`security schemas`](https://github.com/asyncapi/asyncapi/blob/master/versions/2.0.0/asyncapi.md#securitySchemeObject) are not supported
Expand Down
31 changes: 31 additions & 0 deletions filters/all.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ module.exports = ({ Nunjucks }) => {
return 'double';
case 'binary':
return 'byte[]';
default:
return 'Object';
}
});

Expand All @@ -45,6 +47,35 @@ module.exports = ({ Nunjucks }) => {
console.error(str);
});

Nunjucks.addFilter('examplesToString', (ex) => {
let retStr = "";
ex.forEach(example => {
if (retStr !== "") {retStr += ", "}
if (typeof example == "object") {
try {
retStr += JSON.stringify(example);
} catch (ignore) {
retStr += example;
}
} else {
retStr += example;
}
});
return retStr;
});

Nunjucks.addFilter('splitByLines', (str) => {
if (str) {
return str.split(/\r?\n|\r/);
} else {
return "";
}
});

Nunjucks.addFilter('isRequired', (name, list) => {
return list && list.includes(name);
});

Nunjucks.addFilter('schemeExists', (collection, scheme) => {
return _.some(collection, {'scheme': scheme});
});
Expand Down
3 changes: 2 additions & 1 deletion template/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ dependencies {
{% endif -%}
{%- if asyncapi | isProtocol('kafka') %}
implementation('org.springframework.kafka:spring-kafka')
implementation('com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider')
{% endif -%}
implementation('com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider')
implementation('javax.validation:validation-api')
implementation('org.springframework.boot:spring-boot-starter-integration')
testImplementation('org.springframework.boot:spring-boot-starter-test')
}
4 changes: 4 additions & 0 deletions template/src/main/java/com/asyncapi/model/$$message$$.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package com.asyncapi.model;

{% if message.description() or message.examples()%}/**{% for line in message.description() | splitByLines %}
* {{ line | safe}}{% endfor %}{% if message.examples() %}
* Examples: {{message.examples() | examplesToString | safe}}{% endif %}
*/{% endif %}
public class {{messageName | camelCase | upperFirst}} {
{% set payloadName = message.payload().uid() | camelCase | upperFirst %}
private {{payloadName}} payload;
Expand Down
70 changes: 44 additions & 26 deletions template/src/main/java/com/asyncapi/model/$$schema$$.java
Original file line number Diff line number Diff line change
@@ -1,44 +1,62 @@
package com.asyncapi.model;

import javax.validation.constraints.*;
import javax.validation.Valid;
import com.fasterxml.jackson.annotation.JsonProperty;

{% if schema.description() or schema.examples() %}/**{% for line in schema.description() | splitByLines %}
* {{ line | safe}}{% endfor %}{% if schema.examples() %}
* Examples: {{schema.examples() | examplesToString | safe}}{% endif %}
*/{% endif %}
public class {{schemaName | camelCase | upperFirst}} {
{% for propName, prop in schema.properties() %}
{%- if prop.type() === 'object' %}
private {{prop.uid() | camelCase | upperFirst}} {{propName | camelCase}};
{% elif prop.type() === 'array' %}
private @Valid {{prop.uid() | camelCase | upperFirst}} {{propName | camelCase}};
{%- elif prop.type() === 'array' %}
{%- if prop.items().format() %}
private {{prop.items().format() | toJavaType}}[] {{propName | camelCase}}Array;
private @Valid {{prop.items().format() | toJavaType}}[] {{propName | camelCase}}Array;
{%- else %}
private {{prop.items().type() | toJavaType}}[] {{propName | camelCase}}Array;
{% endif %}
{% else %}
private @Valid {{prop.items().type() | toJavaType}}[] {{propName | camelCase}}Array;
{%- endif %}
{%- else %}
{%- if prop.format() %}
private {{prop.format() | toJavaType}} {{propName | camelCase}};
private @Valid {{prop.format() | toJavaType}} {{propName | camelCase}};
{%- else %}
private {{prop.type() | toJavaType}} {{propName | camelCase}};
private @Valid {{prop.type() | toJavaType}} {{propName | camelCase}};
{%- endif %}
{%- endif %}

{% endfor %}

{% for propName, prop in schema.properties() %}
{% set varName = propName | camelCase %}
{% set className = propName | camelCase | upperFirst %}
{% if prop.type() === 'object' %}
{% set propType = prop.uid() | camelCase | upperFirst %}
{% elif prop.type() === 'array' %}
{% set varName = propName | camelCase + 'Array' %}
{% if prop.items().format() %}
{% set propType = prop.items().format() | toJavaType + '[]' %}
{% else %}
{% set propType = prop.items().type() | toJavaType + '[]' %}
{% endif %}
{% else %}
{% if prop.format() %}
{% set propType = prop.format() | toJavaType %}
{% else %}
{% set propType = prop.type() | toJavaType %}
{% endif %}
{%- set varName = propName | camelCase %}
{%- set className = propName | camelCase | upperFirst %}
{%- if prop.type() === 'object' %}
{%- set propType = prop.uid() | camelCase | upperFirst %}
{%- elif prop.type() === 'array' %}
{%- set varName = propName | camelCase + 'Array' %}
{%- if prop.items().format() %}
{%- set propType = prop.items().format() | toJavaType + '[]' %}
{%- else %}
{%- set propType = prop.items().type() | toJavaType + '[]' %}
{%- endif %}
{%- else %}
{%- if prop.format() %}
{%- set propType = prop.format() | toJavaType %}
{%- else %}
{%- set propType = prop.type() | toJavaType %}
{%- endif %}
{%- endif %}

{% if prop.description() or prop.examples()%}/**{% for line in prop.description() | splitByLines %}
* {{ line | safe}}{% endfor %}{% if prop.examples() %}
* Examples: {{prop.examples() | examplesToString | safe}}{% endif %}
*/{% endif %}
@JsonProperty("{{propName}}")
{%- if propName | isRequired(schema.required()) %}@NotNull{% endif %}
{%- if prop.minLength() or prop.maxLength() or prop.maxItems() or prop.minItems() %}@Size({% if prop.minLength() or prop.minItems() %}min = {{prop.minLength()}}{{prop.minItems()}}{% endif %}{% if prop.maxLength() or prop.maxItems() %}{% if prop.minLength() or prop.minItems() %},{% endif %}max = {{prop.maxLength()}}{{prop.maxItems()}}{% endif %}){% endif %}
{%- if prop.pattern() %}@Pattern(regexp="{{prop.pattern()}}"){% endif %}
{%- if prop.minimum() %}@Min({{prop.minimum()}}){% endif %}{% if prop.exclusiveMinimum() %}@Min({{prop.exclusiveMinimum() + 1}}){% endif %}
{%- if prop.maximum() %}@Max({{prop.maximum()}}){% endif %}{% if prop.exclusiveMaximum() %}@Max({{prop.exclusiveMaximum() + 1}}){% endif %}
public {{propType}} get{{className}}() {
return {{varName}};
}
Expand Down

0 comments on commit 204618c

Please sign in to comment.