See: Description
Interface | Description |
---|---|
Model |
Class | Description |
---|---|
CamelCase | |
Case | |
ClassEnumerator |
Based on:
https://github.com/ddopson/java-class-enumerator
Which has the following license:
*****
This code was originally a snippet on StackOverflow, thus it has the following license:
http://creativecommons.org/licenses/by-sa/2.5/
I deduced this from http://meta.stackexchange.com/questions/25956/what-is-up-with-the-source-code-license-on-stack-overflow
Further, whatever rights I have accidentally retained unto my own person, I forfeit under the
[WTFPL](http://www.wtfpl.net/about/) to the extent that is compatible with the primary license and
does not contradict the primary license.
|
ClassModel |
A processed source.
|
CodeGen | |
CodeGenProcessor | |
Compiler | |
DataObjectModel | |
EnumModel |
A processed enum.
|
EnumValueInfo |
The value (member) of an enumeration model.
|
Generator | |
Helper | |
KebabCase | |
LowerCamelCase | |
MethodInfo | |
ModuleInfo |
Describes a module.
|
ModuleModel | |
PackageModel | |
ParamInfo | |
PropertyInfo |
Describes a property of a
data object model . |
ProxyMethodInfo | |
ProxyModel | |
QualifiedCase | |
Signature | |
SnakeCase | |
Template | |
TypeParamInfo | |
TypeParamInfo.Class | |
TypeParamInfo.Method |
Enum | Description |
---|---|
MethodKind | |
PropertyKind |
The kind of property.
|
Exception | Description |
---|---|
GenException |
@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 zero argument constructor
3. provide a constructor with the `io.vertx.core.json.JsonObject` argument
4. provide a copy constructor with the exact same type
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.ListVertxGen
.
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
`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
. 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.ListNullable
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 HandlerNullable
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.HandlerNullable
but not for `java.lang.Void`
. the `java.lang.Object` type is always nullable
. 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 `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 `HandlerTypeInfo
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.ListClassKind.SET
| `java.util.SetClassKind.MAP
| `java.util.MapClassKind.API
| any _api_ type
| ClassKind.DATA_OBJECT
| any _data object_ type
| ClassKind.HANDLER
| `io.vertx.core.HandlerClassKind.ASYNC_RESULT
| `io.vertx.core.AsyncResultClassKind.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).
=== 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.HandlerMethodInfo
`>`
| `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]
----
Copyright © 2016. All rights reserved.