-
Interface Summary
Interface |
Description |
Model |
|
-
-
-
Package io.vertx.codegen Description
= Vert.x Codegen
Vert.x Codegen is an annotation processing tool for processing Vert.x API and create API in different JVM lauguages.
Vert.x polyglot langs use code generation for creating https://en.wikipedia.org/wiki/Shim_(computing)[shim] for APIs,
that are thin wrappers in front of the API type.
A shim is the adaptation of a Vert.x API to a JVM language. A shim uses code generation to generate
wrappers in its own language delegating to the Vert.x API, code generation is based on Java annotation
processing.
== Vert.x API
A Vert.x API is a collection of Java types annotated with Codegen annotations that respect a set of constraints to
ensure easy portability of the API to most languages and enable an asynchronous programming model. Such collection
of API types are grouped in modules.
=== Modules
A module contains a collection of Vert.x API and data objects declarations, some shim uses modules for organizing
and loading the Vert.x api:
- the JavaScript shim uses https://en.wikipedia.org/wiki/CommonJS[CommonJS] modules
- the Ruby shim uses Ruby modules
- Ceylon uses Ceylon native modules
NOTE: so far in Java or Groovy the notion of module is not used because it delegates loading to classloaders.
Modules are declared by annotating a Java package with a
@ModuleGen
annotation.
[source,java]
----
@ModuleGen(name = "acme", groupPackage="com.acme")
package com.acme.myservice;
import io.vertx.codegen.annotations.ModuleGen;
----
The module _name_ is a namespace for shims that don't support package like naming, like JavaScript `acme-js`
or Ruby `acme`, whereas the _group package_ determines the created package, for instance
`com.acme.groovy.myservice` in Groovy. The group package must be a prefix of the annotated module.
Vert.x modules use the reserved name _vertx-XYZ_ and the reserved group package _io.vertx_.
An API module contains various Vert.x types annotated with
VertxGen
or
DataObject
.
NOTE: using Maven coordinates for name and group package is encouraged: the name corresponding to the
Maven _artifactId_ and the group package corresponding to the `groupId`.
=== Data objects
A Data object_ is a Java class with the only purpose to be a container for data. They are transformed
to and from Json.
In its simplest form, a data object is a Java class following these rules:
1. the class is annotated with
DataObject
2. provide a constructor with the `io.vertx.core.json.JsonObject` argument
A data object can also be an interface annotated with `@DataObject`, this is useful when multiple inheritance
is needed. For instance Vert.x Core defines the `KeyCertOptions` and `TrustOptions` data object interfaces and the
`JksOptions` is a data object class that implements both of them because a Java keystore provides support for both.
Data object can also inherit from other data objects. It inherits from the properties of the parent classes.
==== Data object properties
DataObject properties are declared via _getters_, _setters_ or _adders_:
.a getter and a setter
[source,java]
----
public String getHost() {
return host;
}
public WebServerOptions setHost(String host) {
this.host = host;
return this;
}
----
Here is the list of supported property single valued types:
1. any primitive or boxed primitive type
2. `java.lang.String`
3. `io.vertx.core.json.JsonObject` and `io.vertx.core.json.JsonArray`
4. the specific `io.vertx.core.buffer.Buffer` type providing support for byte array
5. Java enums
6. another data object
In addition a data object can also have multi-valued properties as a `java.util.List
`/`java.util.Set` or a
`java.util.Map` where the `` is a supported single valued type or `java.lang.Object`
that stands for anything converted by `io.vertx.core.json.JsonObject` and `io.vertx.core.json.JsonArray`.
List/set multi-valued properties can be declared via a _setter_ :
.a multi valued setter
[source,java]
----
public WebServerOptions setCertificates(List certificates) {
this.certificates = certificates;
return this;
}
----
Or an _adder_ :
.a multi valued adder
[source,java]
----
public WebServerOptions addCertificate(String certificate) {
this.certificates.add(certificate);
return this;
}
----
Map properties can only be declared with a _setter_.
NOTE: these examples uses a _fluent_ return types for providing a better API, this is not mandatory but
encouraged.
==== Json conversion
Vert.x requires data object to be convertible from json with the json argument constructor. Altough there
is no strict rules of mapping between the data object properties and the json structure, it is a good thing
to follow a common mapping for users using json data objects (like in JavaScript shim).
Json properties should be named after properties according to JavaBean conversion rules:
- a single valued property follows the JavaBean convention
- a multi valued property declared with a list setter follows the same convention
- a multi valued property declared with an adder must use a singular form and the json property name gets a trailing _s_
In all case, property names are _normalized_, i.e:
- _red_ -> _red_
- _Red_ -> _red_
- _URL_ -> _url_
- _URLFactory_ -> _urlFactory_
==== Jsonifiable data object
When a data object declares a `public JsonObject toJson()` method it can be converted to the json format
and is said _jsonifiable_. Vert.x API types have restriction in the declared method return types, a jsonifiable
data object can be used in Vert.x API method return types or handlers because it can be converted to a json
format, otherwise it is not permitted.
==== Data object converter
Vert.x requires only the conversion from json, but the conversion to json can be useful when the API uses
data objects as return types. The implementation of the data object / json conversion can be tedious and
error prone.
The data object / json conversion can be automated based on the rules given above. Vert.x Core allows to
generate auxilliary classes that implement the conversion logic. The generated converters handle the
type mapping as well as the json naming convention.
Converters are generated when the data object is annotated with `@DataObject(generateConverter=true)`. The
generation happens for the data object properties, not for the ancestor properties, unless `inheritConverter`
is set: `@DataObject(generateConverter=true,inheritConverter=true)`.
The converter is named by appending the `Converter` suffix to the data object class name, e.g,
`ContactDetails` -> `ContactDetailsConverter`. The generated converter has two static methods:
- `public static void fromJson(JsonObject json, ContactDetails obj)`
- `public static void toJson(ContactDetails obj, JsonObject json)`
The former should be used in the json constructor, the later in the `toJson` method.
[source,java]
----
public ContactDetails(JsonObject json) {
this();
ContactDetailsConverter.fromJson(json, this);
}
public JsonObject toJson() {
JsonObject json = new JsonObject();
ContactDetailsConverter.toJson(this, json);
return json;
}
----
=== Building types
A few types used throughout Vert.x API are not annotated with `@VertxGen` yet are used for building
the API:
- `io.vertx.core.Handler`
- `java.util.function.Function`
- `io.vertx.core.AsyncResult`
- `io.vertx.core.json.JsonObject`
- `io.vertx.core.json.JsonArray`
- `java.lang.Object`
- `java.lang.Throwable`
- `java.lang.Void`
- `java.lang.String`
- `java.util.List`
- `java.util.Set`
- `java.util.Map`
- primitive and boxed primitives
These types are usually handled natively by shims, for instance the `Handler` type is a function in JavaScript,
a block in Ruby, the same `Handler` in Groovy, a function in Ceylon, etc...
=== Generated types
An API type is a Java interface annotated with VertxGen
.
Vert.x provides a async / non blocking / polyglot programming model, code generated API shall follow some
rules to make this possible:
1. the API must be described as a set of Java interfaces, classes are not permitted
2. nested interfaces are not permitted
3. all interfaces to have generation performed on them must be annotated with the `io.vertx.codegen.annotations.VertxGen` annotation
4. fluent methods (methods which return a reference to `this`) must be annotated with the `io.vertx.codegen.annotations.Fluent` annotation
5. methods where the return value must be cached in the API shim must be annotated with the `io.vertx.codegen.annotations.CacheReturn` annotation
6. only certain types are allowed as parameter or return value types for any API methods
7. custom enums should be annotated with `@VertxGen`, although this is not mandatory to allow the usage of existing Java enums
8. nested enums are not permitted
9. default implementations are allowed
An API type can be generic or declare generic methods, type parameters must be unbounded, e.g
`` is forbidden.
In the perspective of codegen, Java types can be categorized as follow:
. _basic_ type : any primitive/boxed type or `java.lang.String`
. _json_ type : `io.vertx.core.json.JsonObject` or `io.vertx.core.json.JsonArray`
. _api_ type : any type annotated with `io.vertx.codegen.annotations.VertxGen`
. _data object_ type : any type annotated with `io.vertx.codegen.annotations.DataObject`
. _enum_ type : any Java enum
. _collection_ type : `java.util.List`, `java.util.Set` or `java.util.Map`
Parameterized types are supported but wildcards are not, that is the following type arguments declarations
are *forbidden*:
- `Foo>`
- `Foo extends Number>`
- `Foo super Number>`
Parameterized types are only supported for _api_ generic types and _collection_ types.
Type variables are allowed and carry a special meaning: a type variable is a dynamic form of a _basic_ type and
_json_ type.
==== Inheritance
_api_ type can extend other _api_ types.
An _api_ type can either be *concrete* or *abstract*, such information is important for languages not
supporting multiple class inheritance like Groovy:
- _api_ types annotated with VertxGen
`(concrete = false)` are meant to be
extended by *concrete* interfaces an can inherit from *abstract* interfaces only.
- _api_ types annotated with VertxGen
or VertxGen
`(concrete = true)`
are implemented directly by Vertx and can inherit at most one other *concrete* interface and any *abstract* interface
==== Method parameter types
The following method parameter types are allowed:
. any _basic_ type
. any _api_ type or parameterized _api_ type having type variable parameters
. any _json_ type
. the `java.lang.Throwable` type
. any _enum_ type
. any _data object_ type that is a non abstract class
. an https://docs.oracle.com/javase/tutorial/java/generics/bounded.html[unbounded type variable], i.e `T extends Number` or `T super Number` are not permitted
. `java.lang.Object`
. a `java.util.List`, `java.util.Set` or `java.util.Map` where `` can be a _basic_ type,
a _json_ type, an _API_ type. For list and set `V` can also be an _enum_ type or a _data object_ type
Callback parameters are allowed, i.e types declaring `io.vertx.core.Handler` or
`io.vertx.core.Handler>` where `` can be:
. the `java.lang.Void` type
. any _basic_ type
. any _API_ type
. any _json_ type
. the `java.lang.Throwable` type - only for `Handler`
. any _enum_ type
. any _data object_ type with a `toJson` method
. an https://docs.oracle.com/javase/tutorial/java/generics/bounded.html[unbounded type variable], i.e `T extends Number` or `T super Number` are not permitted
. a `java.util.List`, `java.util.Set` or `java.util.Map` where `` can be a _basic_ type,
a _json_ type. For list and set `V` can also be an _API_ type, an _enum_ type or a _data object_ type
Function parameters are allowed, i.e types declaring `java.util.function.Function` where `` is defined to
be same than for handlers and `` can be:
. any _basic_ type
. any _API_ type
. any _json_ type
. the `java.lang.Throwable` type
. any _enum_ type
. any _data object_ type that is a non abstract class
. an unbounded type variable
. a `java.util.List`, `java.util.Set` or `java.util.Map` where `` can be a _basic_ type,
a _json_ type. For list and set `V` can also be an _API_ type, an _enum_ type or a _data object_ type
==== Method return type
The following return types are allowed:
. `void` type
. any _basic_ type
. any _api_ type or parameterized _api_ type having type variable parameters
. any _json_ type
. the `java.lang.Throwable` type
. any _enum_ type
. any _data object_ type with a `toJson` method
. an https://docs.oracle.com/javase/tutorial/java/generics/bounded.html[unbounded type variable], i.e `T extends Number` or `T super Number` are not permitted
. a `java.util.List`, `java.util.Set` or `java.util.Map` where `` can be a _basic_ type,
a _json_ type. For list and set `V` can also be an _API_ type, an _enum_ type or a _data object_ type
. an `Handler` where T is is a among the method parameter types
. an `Handler>` where T is is a among the method parameter types
==== Method overloading
Some languages don't support method overloading at all. Ruby, JavaScript or Ceylon to name a few of them.
However the same restriction for Vert.x API would limit API usability.
To accomodate both, overloading is supported when there are no ambiguities between overloaded signatures.
When an API is analyzed an _overload check_ is performed to ensure there is no ambiguity.
Here is an example of possible ambiguity:
.an overload check failure
[source,java]
----
void add(int x, int y);
void add(double x, double y);
----
The JavaScript language use the type number in both cases: at runtime there is no possibility for the
JavaScript shim to know which method to use.
==== Nullable types
Null values have an impact on shim design:
- shims based on value types for dispatching overloaded methods fail for null values, for example a `foo(String)`
method overloaded by a `foo(Buffer)` method invoked with `foo(null)` cannot delegate to the correct underlying method in
JavaScript.
- some shims can leverage this information to provide a better API, for instance an `Optional` Java type or the
`String?` in Ceylon, etc...
Codegen provides the Nullable
annotations for annotating types.
Method return type can be Nullable
:
[source,java]
----
@Nullable String getAttribute(String name);
----
As well as method parameter type:
[source,java]
----
void close(@Nullable Handler closeHandler);
----
WARNING: type validation is a non goal of this feature, its purpose is to give hints to the shim
for generating correct code.
These rules apply to Nullable
types:
. primitive types cannot be Nullable
. method parameter type can be Nullable
. method return type can be Nullable
but not for Fluent
. `io.vertx.core.Handler` type argument can be Nullable
but not for
`java.lang.Void` or `io.vertx.core.AsyncResult`
. `io.vertx.core.Handler` type argument can be Nullable
but not for `java.lang.Void`
. the `java.lang.Object` type is always nullable
. the `` in `` parameter/return, `Handler` or `Handler>` is implicitly nullable
. the `java.lang.Object` parameter is implicitly nullable
. a method overriding another method `inherits` the Nullable
usage of the overriden method
. a method overriding another method cannot declare Nullable
in its types
In addition these rules apply to Nullable
type arguments:
. methods cannot declare generic api types with nullable type arguments, e.g ` void method(GenericApi api)` is not permitted
. methods can declare nullable collection, e.g `void method(List list)` is allowed
Besides these rules, nullable types of method parameters have an impact on method overloading: the parameter
at the same position cannot be Nullable
more than one time when the number
of method parameters is the same, e.g:
[source,java]
----
void write(@Nullable String s);
void write(@Nullable Buffer s);
----
is not permitted, however:
[source,java]
----
void write(@Nullable String s);
void write(@Nullable String s, String encoding);
----
is permitted because the number of parameters differs.
=== Static methods
Vert.x generated types allow _static_ methods, such methods often plays the role of factory. For instance
`Buffer` instance are obtained by the static method `Buffer.buffer()`, this method is translated to an equivalent
in the shim.
In Javascript:
[source,javascript]
----
var Buffer = require('vertx-js/buffer');
var buf = Buffer.buffer();
----
In Ruby:
[source,ruby]
----
require 'vertx/buffer'
buf = Vertx::Buffer.buffer()
----
In Groovy:
[source,groovy]
----
def buf = io.vertx.groovy.core.Buffer.buffer();
----
=== Ignored methods
Methods annotated with GenIgnore
are simply ignored by codegen, this
is useful when the API provides Java specific methods, for instance a method uses a type not permitted
by codegen.
== Shim proxies
A code generated API creates shim proxies delegating method invocation to the API.
.a simplified Buffer API
[source,java]
----
@VertxGen
public interface Buffer {
static Buffer buffer(String s) {
return new BufferImpl(s);
}
int length();
}
----
A JavaScript generated shim could look like:
.the JavaScript shim
[source,javascript]
----
var JBuffer = io.vertx.core.buffer.Buffer;
var Buffer = function(j_val) {
// delegate object
var j_buffer = j_val;
var that = this;
this.length = function() {
return j_buffer.length();
};
}
Buffer.buffer = function(s) {
return new Buffer(JBuffer.buffer(s));
}
module.exports = Buffer;
----
The static `buffer` method is translated into the `buffer` method of the `Buffer` module, this method
delegates the call to the Java static method and returns a `Buffer` proxy wrapping the returned buffer.
The instance `length` method is translated into the `length` method of the proxy instance, this method
delegates the call to the Java instance method of the proxied buffer and simply returns the value. The
Nashorn interoperability takes care of converting the `int` type to a JavaScript `Number`.
=== Return values
A shim implements several strategies when returning values from the Vert.x API:
1. a _basic_ value is usually handled by the shim interop
2. an _API_ value creates a proxy to wrap the value
3. a _json_ (object or array) value is translated to the shim equivalent
4. a jsonifiable _data object_ is converted to json or an equivalent
5. an _enum_ value is converted to a string or an equivalent
6. a _collection_ is usually translated to the shim equivalent
7. a `java.lang.Throwable` is usually translated to the shim equivalent
8. a type variable is converted dynamically converted to a _basic_ type or a _json_ type
9. an `Handler` value is what is used in the target language to represent an handler, when this handler is called
it invokes the handler with the value converted using the argument value rules
10. an `Handler>` value is what is used in the target language to represent an async result handler, when this handler
is _succeeded_ it invokes the handler with the `AsyncResult` wrapping the converted value using the argument value rules,
otherwise it invokes the handler with the `AsyncResult` wrapping the throwable
=== Argument values
A shim implements several strategies when passing values to the Vert.x API:
1. a _basic_ value is usually handled by the shim interop
2. an _API_ value is unwrapped from the shim proxy
3. a _json_ (object or array) value is translated from the shim equivalent
4. a _data object_ is instantiated from the shim equivalent by its `JsonObject` constructor
5. an _enum_ is converted from a string or an equivalent
6. a _collection_ is usually translated from the shim equivalent
7. a type variable or `java.lang.Object` is converted dynamically converted to a _basic_ type or a _json_ type
=== Argument handlers
Argument handlers have a special treatment as the handlers gets a callback.
Usually a shim creates a `io.vertx.core.Handler` instance whose `handle(E)` implementation
calls back the handler argument applying the return value conversion strategy.
For instance the `HttpClient#getNow` method:
[source,java]
----
void getNow(int port, String host, String requestURI, Handler responseHandler);
----
Can be translated to
[source,javascript]
----
function(port, host, requestURI, responseHandler) {
j_httpClient.getNow(port, host, requestURI, function(jVal) {
responseHandler(new HttpClientResponse(jVal));
}
}
----
The JavaScript code calling passes a `function(result)`:
[source,javascript]
----
vertx.setTimer(1000, function(id) {
// Timer fired
});
----
`AsyncResult` types also gets a specific treatment, for instance the `HttpServer#listen` method:
[source,java]
----
void listen(int port, String host, Handler> listenHandler);
----
Can be translated to
[source,javascript]
----
function(port, host, listenHandler) {
j_httpServer.listen(port, host, function(ar) {
if (ar.succeeded()) {
listenHandler(new HttpServer(ar.result()), null);
} else {
listenHandler(null, ar.cause());
}
}
}
----
The JavaScript code calling passes a `function(result, err)`:
[source,javascript]
----
server.listen(80, "localhost", function(result, err) {
if (result != null) {
// It worked
} else {
// It failed
}
});
----
=== Argument function
Function arguments are `java.util.function.Function` instances, they are usually mapped to the function
type in the target language or an equivalent.
=== Exceptions
todo
=== Method dispatching
When a shim does not support overloading, it needs to handle the dispatch itself to the Java method, usually
based on the argument types when invocation occurs.
todo provide example ?
== Codegen types
The TypeInfo
provides a codegen view of the Java type system.
A type info has a ClassKind
usually used to determine the conversion to apply:
[cols="1,4"]
.Class kinds
|===
| ClassKind.STRING
| `java.lang.String`
| ClassKind.PRIMITIVE
| any Java primitive type
| ClassKind.BOXED_PRIMITIVE
| any Java boxed primitive type
| ClassKind.ENUM
| any Java enum
| ClassKind.JSON_OBJECT
| `io.vertx.core.json.JsonObject`
| ClassKind.JSON_ARRAY
| `io.vertx.core.json.JsonArray`
| ClassKind.THROWABLE
| `java.lang.Throwable`
| ClassKind.VOID
| `java.lang.Void`
| ClassKind.OBJECT
| `java.lang.Object` or an unbounded type variable
| ClassKind.LIST
| `java.util.List`
| ClassKind.SET
| `java.util.Set`
| ClassKind.MAP
| `java.util.Map`
| ClassKind.API
| any _api_ type
| ClassKind.DATA_OBJECT
| any _data object_ type
| ClassKind.HANDLER
| `io.vertx.core.Handler`
| ClassKind.FUNCTION
| `java.util.function.Function`
| ClassKind.ASYNC_RESULT
| `io.vertx.core.AsyncResult`
| ClassKind.OTHER
| anything else
|===
The `TypeInfo` base class provides common type information
- TypeInfo.getKind()
the type ClassKind
- TypeInfo.getName()
the type name
- TypeInfo.getSimpleName()
the simple name
- TypeInfo.getErased()
returns the corresponding erased type
- TypeInfo.getRaw()
returns the raw type of a parameter type or this type
Besides it provides the TypeInfo.translateName(java.lang.String)
method to
translate the type name using a shim identifier, this is useful for shim using a hierarchical naming, for
instance the translated name of `io.vertx.core.eventbus.EventBus` for the `groovy` identifier is
`io.vertx.groovy.core.eventbus.EventBus`. The position where the identifier is applied is
determined by the ModuleGen.groupPackage()
value.
Several subclasses of `TypeInfo` provides specialization when needed:
- ClassTypeInfo
: a java class
- ApiTypeInfo
: `TypeInfo.Class` specialization for _api_ types
- EnumTypeInfo
: `TypeInfo.Class` specialization for _enum_ types
- ParameterizedTypeInfo
: a parameterized type
- PrimitiveTypeInfo
: a primitive type
- VoidTypeInfo
: `void` (and not `java.lang.Void`)
- TypeVariableInfo
: an unbounded type variable
== Codegen models
The codegen processor _validates_ annotated Java program elements (i.e type declaration) and _transforms_ them into models:
1. `ClassModel`
2. `DataObjectModel`
3. `EnumModel`
4. `PackageModel`
5. `ModuleModel`
6. `ProxyModel`
Models are processed by https://en.wikisource.org/wiki/MVEL_Language_Guide[MVEL] templates, when a template is executed it gets access to implicit properties
(i.e properties that are declared by the model).
For ClassModel and DataObjectModel, annotations on class and methods can be accessed too. For ModuleModel, annotations on package can be accessed.
=== Class model
For each Java interface annotated with VertxGen
a `ClassModel
` is created.
[cols="1,4"]
.Template properties
|===
| `importedTypes`
| the full list of used types including `java.lang.*` types as `ClassTypeInfo
` that are not in the same package
| `referencedTypes`
| the full list of used types including `java.lang.*` types as `ClassTypeInfo
`
| `referencedDataObjectTypes`
| the full list of used _data object_ types as `ClassTypeInfo
`
| `type`
| the type `ClassTypeInfo
` or `ParameterizedTypeInfo
`
| `typeParams`
| the list of class type params as `List<`TypeParamInfo.Class
`>`
| `concrete`
| a boolean value indicating if the model is _abstract_ or _concrete_
| `superTypes`
| all direct super types
| `concreteSuperType`
|the concrete direct super type or null
| `abstractSuperTypes`
| a list of all abstract direct super types
| `handlerSuperType`
| the type `io.vertx.core.Handler` when the type implements directly the `Handler` interface
| `methods`
| all the methods as `List<`MethodInfo
`>`
| `instanceMethods`
| all the instance methods as `List<`MethodInfo
`>`
| `staticMethods`
| all the static methods as `List<`MethodInfo
`>`
| `methodsByName`
| a map of methods keyed by name as `MapMethodInfo
`>>`
| `doc`
| the documentation as Doc
|===
todo method info / param info / type param info
=== Data object model
todo
=== Enum model
todo
=== Package model
todo
=== Module model
todo
=== Proxy model
todo
== Code generation
The CodeGenProcessor
is a Java Annotation Processor that validates and applies
_code generators_ on codegen models.
The processor is declared in the compiler configuration, here is a typical Maven configuration:
[source,xml]
----
maven-compiler-plugin
default-testCompile
io.vertx.codegen.CodeGenProcessor
-Acodegen.output=${project.basedir}/src/test <1>
----
<1> the base output directory for generated files
Code generators are determined from the classpath by looking at the `codegen.json` descriptors, there can
be several generators executed in the same compilation phase. The configuration of a code generator is
quite simple:
[source,json]
----
{
"name": "Groovy", <1>
"generators": [ { <2>
"kind": "class", <3>
"fileName": "'groovy/' + module.translateQualifiedName(fqn, 'groovy').replace('.', '/') + '.groovy'", <4>
"templateFileName": "vertx-groovy/template/groovy.templ" <5>
} ]
}
----
<1> the processor name
<2> an array of generators
<3> the kind of model the generator process : _class_, _dataObject_, _enum_, _package_, _module_, _proxy_
<4> the MVEL expression of the generated file
<5> the MVEL template file name
=== Templating
Templates are written in the MVEL language, documented here.
Some characters have a special meaning:
- the tab char is used for formatting purpose and is removed
- the *\n* sequence has the same meaning than in a Java string literal
=== Incremental templating
Incremental templating allows the same template to process several models and create a single result. This is
useful when several sources files needs to generate a same file and the output is the result of the models. To
achieve incremental processing, a generator must declares `"incremental": true` in its descriptor.
During the processing phase, the codegen processors collects all the files generated by incremental templates
and groups them by file name. Obviously, the _fileName_ expression of the generator needs to return an appropriate
string.
At the end of the processing phase, templates are invoked for each model, pretty much like the normal templating but
with the following differences:
- the variable `incrementalIndex` gives the sequence number of the current model, starting at 0
- the variable `incrementalSize` gives the total number of models processed by the template
- the variable `session` is a map provided that allows the template to maintain state
- the generated content are appended instead of overwritten
For instance the template:
[source]
----
@if{incrementalIndex==0}
\n
\n
\n
@end{}
- @{type.name}
\n
@if{incrementalIndex==incrementalSize-1}
\n
\n
\n
@end{}
----
With `codegen.json`:
[source,json]
----
{
"name": "index",
"generators": [ {
"kind": "class",
"incremental": true,
"fileName": "'index.html'",
"templateFileName": "html-index.templ"
} ]
}
----
Generates an HTML page with the name of all the API classes.