JAX-RS
Overview
The Jakarta REST specification (formerly JAX-RS) defines the notion of an
Application subclass whose methods return resource and provider classes,
singletons and properties. This is the mechanism developers can use to define
what comprises a REST application. Unless otherwise stated by the runtime
environment in which the application runs, every REST application must include
exactly one Application subclass.
Helidon provides an extension to Jakarta REST in which 0 or more Application
subclasses are allowed. If no Application subclasses are provided, then a
so-called synthetic subclass will be created automatically. This synthetic
subclass shall include all resource and provider classes discovered by Helidon.
Most Helidon applications should simply rely on this mechanism in accordance to
convention over configuration practices.
Discovery of REST Beans
CDI scanning is controlled by the bean-discovery-mode attribute in beans.xml
files — the default value for this attribute is annotated. In the default
mode, CDI scans for beans decorated by bean-defining annotations such as
@ApplicationScoped, @RequestScoped, etc.
With the help of CDI, Helidon looks for REST Application subclasses in your
Helidon application. If none are found, a synthetic application will be created
by gathering all resources and providers found during the discovery phase.
Application subclass has no bean-defining annotations, and bean
discovery is set to the default annotated value, it will be ignored.The discovery phase is carried out as follows (in no particular order):
- Collect all beans that extend
Application - Collect all beans annotated with
@Path - Collect all beans annotated with
@Provider
If no Application subclasses are found, create a synthetic Application
subclass that includes all beans gathered in steps (2) and (3) and set the
application path to be "/" —this is the path normally defined using the
@ApplicationPath annotation. If one or more Application subclasses are
found, call the getClasses and getSingletons methods in each subclass using
the collections in steps (2) and (3) only as defaults, i.e. if these methods
both return empty sets.
@Path and @Provider as bean-defining annotations but, as
stated above, Application subclasses may require additional annotations
depending on the discovery modeSetting Application Path
The application path, also known as context root, is the base URI used to serve
all resource URIs provided by @Path annotation. This section describes how to
set it with an annotation or configuration file.
When an Application subclass is provided, use the @ApplicationPath:
@ApplicationPath("/my-application")
public class MyApplication extends Application {
}
The served resources can be reached through /my-application/{myResources}
endpoint. It can be overridden by configuration file.
Example of custom application path using .yaml file:
io.helidon.examples.MyApplication:
routing-path:
path: "/my-application"
The same configuration works for .properties file:
io.helidon.examples.MyApplication.routing-path.path=/my-application
If an Application is not provided, a synthetic subclass is created and can
be configured using this property:
jakarta.ws.rs.core.Application.routing-path.path=/my-application
Access to Application Instances
Jakarta REST provides access to the Application subclass instance via
injection using @Context. This form of access is still supported in Helidon
but this is not enough if two or more subclasses are present. Given that support
for two or more Application subclasses is a Helidon extension, a new mechanism
is provided via the ServerRequest 's context object as shown next.
@Path("myresource")
public class MyResource {
@GET
public void get(@Context ServerRequest serverRequest) {
Application app = serverRequest.context().get(Application.class).get();
}
}
This approach effectively moves the scope of Application subclass instances to
request scope in order to access the correct subclass for the resource method
being executed.
Injection Managers in Helidon
The Oracle implementation of Jakarta REST, known as Jersey, does not currently
provide support for multiple Application subclasses. As a result, it creates a
single internal injection manager for your entire application, but this is
insufficient when multiple Application subclasses are present. Helidon creates
a separate injection manager for each Application subclass, and a single
parent injection manager for your application. Each Application subclass
injection manager delegates to the parent injection manager.
Due to an implementation strategy in Jersey, ParamConverterProvider 's must be
registered in the parent manager for proper registration and initialization.
Thus, providers of this type will be shared and accessible by all Application
subclasses, even if your code tries to limit their access. This is likely to
change in future versions of Jersey/Helidon and does not typically impact how
your application runs.