Content

Overview

In this section, we shall distinguish the notion of a JAX-RS Application subclass from a Helidon application. As we shall learn shortly, the latter may include zero or more of the former.

The JAX-RS specification 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 JAX-RS application. Unless otherwise stated by the runtime environment in which the JAX-RS application runs, every JAX-RS application must include exactly one Application subclass.

Helidon provides an extension to JAX-RS 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 JAX-RS 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 JAX-RS 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. Note that if your 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):

  1. Collect all beans that extend Application
  2. Collect all beans annotated with @Path
  3. 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.

Helidon treats @Path and @Provider as bean-defining annotations but, as stated above, Application subclasses may require additional annotations depending on the discovery mode.

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.

As noted above, the JAX-RS Application class exposes the getSingletons method which returns instances of resources, providers, or features. Currently Helidon can invoke this method multiple times. You should expect multiple invocations of the getSingletons method. If you want to return the same instances on all calls, then cache the values yourself.

Setting 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 {

}
Copied

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"
Copied

The same configuration works for .properties file:

io.helidon.examples.MyApplication.routing-path.path=/my-application
Copied

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
Copied

Usage

JAX-RS provides access to the Application subclass instance via injection using @Context. This form of access is still supported in Helidon but is insufficient 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.

import io.helidon.webserver.ServerRequest;

@Path("myresource")
public class MyResource {

    @GET
    public void get(@Context ServerRequest serverRequest) {
        Application app = serverRequest.context().get(Application.class).get();
    }
}
Copied

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

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.

Configuration

Your application can use the MicroProfile Config or Helidon Config (or both). MicroProfile Config offers portability to other MicroProfile servers. Helidon Config supports a full tree structure, including repeating elements.

You can inject values that the application can access from both MicroProfile Config and from Helidon Config.

JAX-RS - inject a single config property
@Inject
public MyResource(@ConfigProperty(name="app.name") String appName) {
    this.applicationName = appName;
}
Copied

You can also inject the whole configuration instance, either io.helidon.config.Config or org.eclipse.microprofile.config.Config.

JAX-RS - inject config
@Inject
public MyResource(Config config) {
    this.config = config;
}
Copied