Annotations
Using a few lines of code, activate and configure the VLINGO XOOM components.
There's an API defacto standard that developers always deserve freedom of choice in terms of either crafting each part of their own code, or to accelerate the development steps by taking advantage of default configurations and shorthand elements. The VLINGO XOOM platform aims to provide technical autonomy, no matter the strategy you choose, even allowing the combination of both.
Generally speaking, VLINGO XOOM annotations fit well when you want more succinct code. From the application initialization to the persistence resources, we provide a brief description of each annotation.
Annotation
Description
@Xoom
Its main purpose is to instantiate and setup essential elements of a VLINGO XOOM application or microservice:
@ResourceHandlers
@AutoDispatch
Provides a faster and straightforward way to dispatch REST requests to the domain model.
@Persistence
@EnableQueries
@Projections / @Projection
@Adapters /
@Adapter
@DataObjects
Enables the auto-creation of database tables for data objects.
When using any kind of IDEs, be aware that they usually do not evaluate compile-time annotations as soon as you declare it or immediately when you open a project with an IDE for the first time. In this case, IDEs may notify one or more compilation errors. That can be easily avoided just by building your project when you first open it or at the time you declare annotation(s).
For a practical understanding of annotations, the next section brings more details.
@Xoom
@Xoom
It's widely known that the starting point of any Java program is a static main()
method. In addition, when creating of a VLINGO XOOM application or microservice, we must instantiate World
, and pass it to other classes that use it for actors operation. So, that's what the @Xoom
annotation mainly provides.
An
Initializer
class with a staticmain()
method, which is the hook for JVM in the application executionCreation of
World
andStage
with theAddressFactory
option, making theStage
instance accessible for classes that requestActor
operations directly from it
Besides that, @Xoom
takes care of reading the properties file with the Mailbox
definition and starts a XOOM HTTP server. All of those tasks are achieved simply by annotating a basic class.
The application name
attribute is the minimal information for running application with @Xoom
but there are also other attributes. Here's the full list.
Attribute
Type
Description
Required
name
String
Sets the application name.
Yes
blocking
Boolean
True or false for respectively synchronous or asynchronous actor messaging. The default value is false.
No
addressFactory
Annotation
Sets the AddressFactory
type: BASIC
, UUID
, GRID
; and IdentityGenerator
type:RANDOM
, TIME_BASED
, NAME_BASED
No
The next code snippet shows the @Xoom
attributes with non-default values.
Often, application initialization tasks need to be refined by some handwritten code. In the case where this is needed when using the @Xoom annotation, an initializer class may implement the interface io.vlingo.xoom.turbo.XoomInitializationAware
.
@ResourceHandlers
@ResourceHandlers
This is a @Xoom
-related annotation for REST resources initialization. First, your custom resource class must extend io.vlingo.xoom.http.resource.DynamicResourceHandler
. This resource class should implement a constructor that takes a Stage
instance parameter. The resource class must also implement a routes()
method, through which fluent route mappings are possible, see XOOM HTTP.
To wire an instance of an InsuranceResource
, annotate the initializer class providing the package containing the REST resource classes.
Optionally you may decide to provide a number of resource classes instead of the package name.
As described below, @ResourceHandlers
supports two optional attributes, but only one must be set.
Attribute
Type
Description
Required
value
Class <? extends DynamicResourceHandler> []
An array of DynamicResourceHandler
subclasses.
No
packages
String []
An array of Java package
names that each contains some number of DynamicResourceHandler
subclasses.
No
@AutoDispatch
@AutoDispatch
Often, a considerable part of the effort while building an application is not on its vital elements but on recurrent and straightforward tasks such as mapping logic, components configuration, and general application settings. Facing this discrepancy, @AutoDispatch
enables you to invest less in writing REST resources and broker/bus exchange message listeners so that you are able to focus on the core of your application, that is, the domain model.
The next code snippet shows how this convenient annotation transforms your REST resource implementation:
Yes, an interface with only abstract methods is the primary piece for implementing an@AutoDispatch
resource. Now, following the order of how each annotation is placed in the code, let's understand how it works.
@AutoDispatch
@AutoDispatch
Starting with @AutoDispatch
, which is the root annotation and accepts these values:
Attribute
Type
Description
Required
path
String
URI root path
Yes
handlers
Class<?>
A mapping configuration class relating aggregate/queries methods and its indexes.
Yes
Here we open a parenthesis to clarify the ProductResourceHandlers
class, declared in the @AutoDispatch
handler attribute in the previous code snippet. Looking at it, we can see the aggregate methods to which REST requests are going to be forwarded.
The HandlerEntry
relates an integer index to a function that invokes an aggregate method. Through that index, an aggregate/queries method can be set as the handler of a specific route as showed in the ProductResource
interface:
The return type of the mapped method, along with the types of its parameters are respectively defined by the HandlerEntry
generics. In other words, the first generic type, from left to right, is always the method return type, so, in the HandlerEntry
corresponding to the Product Registration,Completes<ProductState>
is the return type when Product.register
is invoked while Stage
and ProductData
are the parameter types.
Usually, the generic types of a HandlerEntry
match with the parameter types supported by its corresponding route. However, in the previous example, Stage
is also a required parameter but it's not in the route signature. Fortunately, at compile-time, Stage
and Logger
are automatically included as an instance member in the auto-dispatch resource class. Just be aware that, for accessing any instance member inside a HandlerEntry
function, you need always to use the $ + memberName
pattern (e.g $stage
, $logger
).
Regarding the supported number of parameters, HandlerEntry
is served by a set of interfaces for parameter type declaration which allow you to inform two to five parameter types:
If your application only have@AutoDispatch
resources, you are freed from annotating your bootstrap class with @ResourceHandlers
.
@Model / @Queries
@Model / @Queries
The @Model
and @Queries
class-level annotations meets the condition that a @AutoDispatch
route must perform operations on a specific aggregate entity or read data from a query actor. That implies you have to use at least one of these annotations and, at most, one of each. Here's the supported field list:
Attribute
Type
Description
Required
protocol
Class<?>
The aggregate / queries protocol (interface) class
true
actor
Class<? extends EntityActor/ Actor>
true
data
Class<?>
The adapted model type to be serialized in the response body. Only supported in the @Model annotation.
true
Note that, using @Queries
, you are able to access the queries actor inside the HandlerEntry function through the instance member named as $queries
:
@Route
@Route
The @Route
annotation has to be used at method-level mainly declaring a HTTP method. Optionally, you may inform a relative URI subpath and its handler index.
Attribute
Type
Description
Required
method
io.vlingo.xoom.http.Method
The supported HTTP method for a route
Yes
path
String
The route subpath relative to the root path. If not informed, the root path is set by default.
No
handler
int
The index of the handler that will be invoked. If not informed, the annotated method must be concrete.
No
@ResponseAdapter
@ResponseAdapter
Also, a method-level annotation that enables a function call to adapt the request output. It only supports a single attribute.
Attribute
Type
Description
Required
handler
int
The index of the handler that will be invoked to adapt the request output.
Yes
@Id
@Id
This useful annotation is applied to an entity id present in the route parameter. Under the hood, @Id
indicates a route operation that is performed on an existing entity and makes VLINGO/XOOM responsible for loading it. So, the benefit is that you can just take care of using the loaded entity inside the HandlerEntry
function.
Let's go back to ProductResource
and see how it works:
The code slice above shows /profit-margin route which has an id parameter properly annotated with @Id
. Afterwards, its handler function is much simpler because it's benefited by the auto-loaded entity:
Finally, here, the product
parameter is exactly the corresponding entity to the id passed in the route parameter.
@Body
@Body
Annotating a route parameter with @Body
simply tells XOOM HTTP to deserialize the request payload into that parameter. In the following example, the payload is deserialized into a ProductData
object.
@Persistence
@Persistence
Regarding persistence configuration, through the onInit()
method you can choose to manually create the code for the application infrastructure, as in the Hello, World example.
Alternatively, adopt@Persistence
for a more succinct way to set up the persistence. By using that annotation, VLINGO XOOM supports auto-configuration of:
The selected
Storage Type
for the Domain Model;When using CQRS, a
State Store
for the Query Model and the selectedStorage Type
for the Command Model;Datasource connection, including schema/tables creation;
The example below shows how to enable persistence auto-configuration.
The next table describes @Persistence
attributes:
Attribute
Type
Description
Required
basePackage
String
The project's base package
true
storageType
StorageType
true
cqrs
Boolean
false
The database credentials and other configuration parameters can be informed in three ways:
vlingo-xoom.properties
Environment variables;
Combining both;
The supported properties and environment variables are listed below:
Property Name
Environment Variable
Description
Required
database
VLINGO_XOOM_DATABASE
Database Type*. If IN_MEMORY, other properties are not required.
true
database.name
VLINGO_XOOM_DATABASE_NAME
Schema name.
true
database.driver
VLINGO_XOOM_DATABASE_DRIVER
The qualified class name of JDBC Driver
true
database.url
VLINGO_XOOM_DATABASE_URL
Connection URL
true
database.username
VLINGO_XOOM_DATABASE_USERNAME
Database username
true
database.password
VLINGO_XOOM_DATABASE_PASSWORD
Password
false
database.originator
VLINGO_XOOM_DATABASE_ORIGINATOR
Id for the data origin
true
*Supported Database types: IN_MEMORY, POSTGRES, HSQLDB, MYSQL, YUGA_BYTE
.
In case of CQRS, you can inform parameters of the Query Model Database just adding "query" before the word "database". For instance, the property database
becomes query.database
, the environment variable VLINGO_XOOM_DATABASE
becomes VLINGO_XOOM_QUERY_DATABASE.
Here's an example of a database configuration in the vlingo-xoom.properties
:
The following annotations are children of @Persistence
and can be only used along with it.
@EnableQueries
@EnableQueries
is an annotation correlated to @Persistence
and provides the proper way to make VLINGO XOOM responsible for handling your query actor implementations. In other words, using this essential annotation, these implementations become a QueryStateStoreProvider
property, so we only need to take care of accessing it and using it. For a practical understanding, take a look at the following configuration class:
@EnableQueries
only accepts a combination of actor/protocol classes surrounded by the@QueriesEntry
annotation which supports the following types:
Attribute
Type
Description
Required
protocol
Class<?>
TheQueriesActor
protocol class
true
actor
Class<?>[]
An Array
of supported DomainEvents
true
Having the @EnableQueries
properly configured, which also includes the attribute cqrs
of@Persistence
set to true, makes the compile-time generated QueryStateStoreProvider
the holder of all mapped queries actors. So, as an illustration, let's say we need to use the CustomerQueries
serving a rest resource:
@Projections
When using CQRS, @Projections
relates the projections to their supported events, so DomainEvents
can be projected into the Query Model.
@Projections
accepts only a list of @Projection
with a pair of attributes:
Attribute
Type
Description
Required
actor
Class<? extends
StateStoreProjectionActor>
AProjectionActor
class
true
becauseOf
Class<?>[]
An Array
of supported DomainEvents
true
@Adapters
Add @Adapters
for Aggregate/Entity state translation, so the object state within a service or application can be serialized to be persisted, and vice-versa. Here's how to set up:
Keep in mind that @Adapters
and @Projections
are not dependent but both can be naturally used together as follows:
@DataObjects
With @DataObjects
, VLINGO XOOM can also take care of the creation of database tables for data objects, which are commonly used for holding your query model data. All you need to do is to map the data objects as demonstrated below:
Once data objects are mapped, if the database tables do not already exist, it will be automatically created during the application startup.
Last updated