mp.jaxrs.jaxrs-applications.adoc Maven / Gradle / Ivy
The newest version!
///////////////////////////////////////////////////////////////////////////////
Copyright (c) 2021, 2024 Oracle and/or its affiliates.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
///////////////////////////////////////////////////////////////////////////////
= Jakarta REST
:description: Helidon MicroProfile Jakarta REST
:keywords: helidon, microprofile, micro-profile, jax-rs, applications, jakarta, rest
:rootdir: {docdir}/../..
include::{rootdir}/includes/mp.adoc[]
== Jakarta REST Applications
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.
NOTE: If an `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.
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.
NOTE: Helidon treats `@Path` and `@Provided` as bean-defining annotations but, as stated above,
`Application` subclasses may require additional annotations depending on the discovery mode
== 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`:
[source,java]
----
include::{sourcedir}/mp/jaxrs/JaxrsApplicationsSnippets.java[tag=snippet_2, indent=0]
----
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:
[source,yaml]
----
io.helidon.examples.MyApplication:
routing-path:
path: "/my-application"
----
The same configuration works for `.properties` file:
[source,properties]
----
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:
[source,properties]
----
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.
[source,java]
----
include::{sourcedir}/mp/jaxrs/JaxrsApplicationsSnippets.java[tag=snippet_1, indent=0]
----
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.