To make a resource available via essential, you at least have to annotate the class containing the resource methods with the @Path annotation. This annotation informs essential about the path leading to the resource.
A resource method itself must be annotated with one of the the HTTP method annotations (@Get, @Post, @Put, @Delete, etc.).
The (here optional) @Path parameter is used for a more granulated resource method lookup within the path of a resource. It is possible to declare several resource methods using the same (or none) @Path annotation as long as they are annotated with different HTTP method annotations.
A resource method must be declared public and return an object.
@Path("/wine") class WineResource { @Get public Wine chooseWine() { ... } @Post public Wine createWine() { ... } @Get @Path("/red") public Wine chooseRedWine() { ... } @Post @Path("/red") public Wine createRedWine() { ... } }
You can access request parameters in two ways: By initializing class properties (fields, getters and setters) and by initializing method parameters. As the first way is optional, the second one is required for all declared method parameters of a resource method.
Use the @Param annotation to inform essential about a property or method parameter to be initialized from a parameter. The value of @Param indicates the request parameter name. For fields, specifying this value is optional and the field's name will be used to identify the request parameter.
By the nature of Java, unfortunately the same is not possible for method parameters and therefor requires to explicitly designate the corresponding request parameter.
@Path("/wine") class WineResource { @Param public String colour; @Param("alc") private double alcohol; @Param private String[] ingredients; @Param private int amount; public int getAmount() { return amount; } public void setAmount(int amount) { this.amount = amount; } @Get public Wine chooseWine(@Param("region") String region) { ... } }
Not all parameters must be obtained from query or form parameters. They also maybe included within the request URL path. You can declare a path parameter by surrounding parts of the path with curly brackets.
This way, they work like placeholders for variable path parameters. You can access those parameters just like any other parameter using the @Param annotation.
@Path("/wine/{wineId}") class WineResource { @Param public int wineId; @Get @Path("/{cold}") public Wine chooseWine(@Param("cold") boolean cold) { ... } }
You can also add a regular expression to a placeholder, so it will only match against this regular expression. For example wineId:([0-9])+ will only match numbers with at least one figure.
If a static path and a variable path both match against the request path then the more exact match will be preferred. Generally, you should be careful when declaring path parameters to avoid confusion during the allocation process.
You can directly initialize fields and methods of type Collection, List, Set and Queue for primitives and virtual primitives (String, Date). Please make sure that a collection also specifies the desired generic type parameter.
@Path("/wine") class WineResource { @Get @Path("/regions") public Wine chooseByWineRegions(@Param("regions") List<int> regionsIds) { ... } }
Using @Body will directly access the body of a request. If the type of the annotated field or method parameter is of type "InputStream", then the original input stream of the request body will be used for initialization. In case the field or parameter is of type String, the the body is decoded and interpreted as a string.
In all other cases, the request body will be deserialized by essential to the given type by interpreting the content media type as it is given in the Content-Type header of the request.
@Path("/wine") class WineResource { @Post @Path("/text") public String createText(@Body String text) { ... } @Post @Path("/wine") public Wine createWine(@Body Wine wine) { ... } }
As you will have recognized, essential automatically deserializes primitive types and strings from parameters. More then this, you can also initialize objects in the same way. This will work for input values representing an object in XML or JSON format.
Deserialization is done by Consumers in essential. By default, essential uses a JAXB consumer to deserialize JSON and XML. This means that the non-primitive types of your annotated fields and method parameters should be annotated with the proper JAXB annotations.
In the case you want to use another consumer than the JAXB consumer, you can delegate the serialization process using the @Consumer annotation. The value of @Consumer specifies the consumer's class which shall be used for deserializing parameters.
@Path("/wine") @Consumer(Consumer.class) class WineResource { @Get @Path("/region") public Wine chooseByWineRegion(@Body WineRegion region) { ... } @Get @Path("/winemaker") @Consumer(ConsumerForWineMaker.class) public Wine chooseByWineMaker(@Body WineMaker maker) { ... } }
See also: Consumers.
The serialization of resource method results is automatically handled by essential. The result object will be forwarded to the default JAXB producer. This requires that the object's class must be annotated with the proper JAXB annotations (XML, JSON and HTML).
If you want to use another producer then the JAXB producer, you can delegate the serialization process via the @Producer annotation. The value of @Producer specifies the producer's class which shall be used for serializing the resource method result. This annotation works equivalent to the @Consumer annotation.
@Path("/wine") @Producer("Producer.class") class WineResource { @Get @Path("/{regionId}") public Wine chooseByRegion(@Param("{regionId]") int regionId) { ... } @Get @Path("/{wineId}/winemaker") @Consumer(ProducerForWineMaker.class) public WineMaker getWineMaker(@Param("{wineId}") int id) { ... } }
See also: Producers.
In some cases, also header values may be needed for logical operations, as it may be the case for the date or cookie header.
You can access header values using the @Header annotation and specifying the header name in the annotation's value.
@Path("/wine") class WineResource { @Header("Date") private String date; @Header("Cookie") private String[] cookies; @Get @Path("/choose") public String chooseWine(@Header("Accept-Language") String language) { ... } }
Moreover, the Authorization and Content-Type header have special sub-attributes and essential provides a convenient access to them.
@Path("/wine") class WineResource { @Header("Authorization#user") private String httpUser; @Header("Authorization#pass") private String httpPass; @Header("Content-Type#media") private String contentMedia; @Header("Content-Type#charset") private String contentCharset; }
As one can put own configuration properties into essential's configuration, essential provides the @Property annotation.
@Path("/wine") class WineResource { @Property("database.name") private String databaseName; @Property("database") private Map<String, String> databaseProperties; @Get @Path("/choose") public String chooseWine(@Property("language") String language) { ... } }
All annotations for resources can either be declared within a resource class or within an interface implemented by a resource class.
Annotations on the type level of an interface are handled as if they were annotated on the type level of an implementing class. Annotations on methods declared within an interface will be treated as if they were annotated an implemented method.
About that, annotations are inherited by super classes and super interfaces.
If an annotation is declared on a class as well as on its super class, essential will prefer the values of the lowest class in the inheritance hierarchy. The same is true for interfaces. Moreover, annotations in classes are always preferred over annotations in interfaces. For reasons of simpleness, we will only use direct class annotations in the following examples.
class > super class > interface > super interface