# JAX-RS

JAX-RS is a specification, a set of interfaces and annotations offered by Java EE. Well-known Implementations are [RESTEasy](http://resteasy.jboss.org/) and [Jersey](https://jersey.java.net/).�

{% file src="/files/-Ly36ZlmPOQh3OgGMAH4" %}
JAX-RS 2.1 Specification
{% endfile %}

## Applications

JAX-RS application has \[1..] resources and \[0..] providers.

**Configuration:** via application-supplied subclass of `Application`.

### Publications

Applications are published in diff ways:&#x20;

1. if app runs in Java SE environment
2. within container (is packed as .war file)&#x20;
   1. app classes are packaged in `WEB-INF/classes` or `WEB-INF/lib` and required libs are packaged in `WEB-INF/lib`&#x20;

![](/files/-LxvJkhGbjatStQzxdt_)

## Resources

Is a POJO that has at least one method annotated with `@Path` or a request method designator.

By **default** a **new** **resource** class **instance** is **created** for **each request** to that resource.

![](http://www.plantuml.com/plantuml/svg/LSyxqi8m30JWtgVGfFaVCxa2auFGAFQI61pBo7BEZw40Kk-tUapLMArjoVsGeafJ3_AIgsdp5YMxt_y_6ZKkguqd6jwHA9rphEGv9OJ1VOZYtb0DWG8ASa3s4RLhLb3CLtWx5hWKbQAH3RJ1LWclqTtkSZjIcPzrwY7l71FF2TrUH6dnNwxVxAQ-kl_r0000)

### Resource methods

JAX-RS resource method designators: @GET, @POST, @PUT, @DELETE, @PATCH, @HEAD, @OPTIONS

Methods must be `public`.

Method parameters are mapped from the request according to the semantics of annotation:

* @MatrixParam - extracts the value of URI matrix parameter
  * Matrix parameters are name-value pairs embedded within the path of a URI string
  * e.g. `http://example.cars.com/mercedes/e55;color=black/2006`
  * `color=black` is matrix parameter
* @QueryParam - extracts the value of URI query parameter
* @PathParam - extracts the value of URI template parameter
* @CookieParam - extracts the value of a cookie
* @HeaderParam - extracts the value of header
* @FormParam
* @Context - injects an instance of supported resource. :warning: TODO investigate later
* `@DefaultValue` is used to supply a default value for parameter
* `@Encode` is used to disable auto URI decoding of param value

### Return type

* `void` - results in an empty entity body with **204** status code
  * **204 status code** means that the request was received and understood, but that there is no need to send any data back
* `Response`&#x20;
  * entity property of *Response* -mapped-> entity **body**
  * status property of *Response* -mapped-> status **code**
  * ```
    if (Response == null) {
        status_code = 204;
    } 

    if (Response.status is NOT set) {
        if (Response.entity != null) {
            status_code = 200;
        }                
        if (Response.entity == null) {
            status_code = 204;
        }                
    }
    ```
  * use `Response` to provide metadata; use `ResponseBuilder`;
* `GenericEntity`&#x20;
  * *Entity* property of *GenericEntity* -mapped-> entity **body**
  * ```
    if (GenericEntity == null) {
        status_code = 204;
    }
    if (GenericEntity != null) {
        status_code = 200;
    }
    }}}
    ```
* `Other`&#x20;
  * returned instance -mapped-> entity **body**
  * ```
    if (class is anonymous inner class) {
        use super class;
    }
    ```
  * ```
    if (return_value == null) {
        status_code = 204;
    } else {
        status_code = 200;
    }
    ```

![](/files/-Ly-6ZfNMWz4_ZFxU82Z)

To illustrate consider a method that always returns an instance of ArrayList\<String> (directly or wrapped).

![](/files/-Ly-763SyP72xzlqz8-J)

### Exceptions

```
// map WebApplicationException to response
exceptionProvider = exceptionMappingProvider<WebApplicationException>

if (!exception.response.contains(entity) && exceptionProvider.isAvailable()) {
    Response instance = exceptionProvider.create();        
} else {
    use exception.response directly
}
// finished
```

```
exceptionProvider = exceptionMappingProvider<? super CurrentException>

if (exceptionProvider.isAvailable()) {
    
    try {
        Response instance = exceptionProvider.create();        
    } catch () {
        return server_error_response(status code 500) to client
    }
}
```

```
if (unchecked_exception not_mapped) {
    re-throw and propagate to underlying container
} 

if (checked_exception not_mapped 
    && checked_exception cannot_be_thrown_directly) {
     
    wrappedException = container_specific_exception.wrap(checked_exception)
    throw to underlying container           
}    
```

* Servlet-based implementation wrapper `ServletException`&#x20;
* JAX-WS Provider-based implementation wrapper `WebServiceException`&#x20;

### HEAD and OPTIONS

```
// how HEAD requests are handled
if (method.annotatedWith(HEAD) is present) {
    call method
} else {
    call method.annotatedWith(GET)
    discard returned entity
    
    // Performance risk if entity creation is expensive
}
```

```
// how OPTIONS requests are handled
if (method.annotatedWith(OPTIONS) is present) {
    call method
} else {
    generate response using metadata provided by JAX-RS annotations 
        on matching class and its methods
}
```

## URI Templates

```
@Path("widgets/{id}")
public class Widget {
... }
```

:bulb: This is a relative path with a combination of deployment context and application path `@ApplicationPath` .

`@Path("widget list/{id}")` equivalent to `@Path("widget%20list/{id}")` (encoded automatically).

:bulb: Annotation value can be a regex, e.g.

```
@Path("widgets/{path:.+}")
public class Widget {
... }
```

any request starting with `widgets` and containing at least one more path segment will match. E.g. `widgets/small/a` => the value of path will be `small/a`

### Sub Resources

Methods of resource class annotated by `@Path` are either:

* sub-resource methods => handle HTTP request **directly**&#x20;
* sub-resource locators => return an object or class that will handle HTTP request
  * may have all the same parameters as a normal resource method, except they must not have entity parameter

```
@Path("widgets")
public class WidgetsResource {
 
    @GET
    @Path("offers")
    public WidgetList getDiscounted() {...} // sub-resource method
    
    @Path("{id}")
    public WidgetResource findWidget(@PathParam("id") String id) {
      return new WidgetResource(id);
    } 
}

public class WidgetResource {
    public WidgetResource(String id) {...}
    
    @GET
    public Widget getDetails() {...}
}
```

## Media type capabilities

* @Consumes
* @Produces

Can be applied to resource `method`(**overrides** specified on class and on provider), resource `class`, entity `provider`.

:bulb: Default is `"*/*"`

```
@Path("widgets")
@Produces("application/widgets+xml")
public class WidgetsResource {

    @GET
    public Widgets getAsXML() {...}
    // response media type is "application/widgets+xml", taken from WidgetsProvider
    
    @GET
    @Produces("text/html")
    public String getAsHtml() {...}
    // String containg "text/html" will be returned, written by default impl of
    // MessageBodyWriter<String>

    @POST
    @Consumes("application/widgets+xml")
    public void addWidget(Widget widget) {...}
    // Value of widget will be mapped from request entity using WidgetProvider
}

@Provider
@Produces("application/widgets+xml")
public class WidgetsProvider implements MessageBodyWriter<Widgets> {...}

@Provider
@Consumes("application/widgets+xml")
public class WidgetProvider implements MessageBodyReader<Widget> {...}
```

### Multiple media types

When accepting multiple media types **client** may indicate preference by using relative quality factor `q parameter` (`q-value` ). `Q-value` is \[0..1]&#x20;

* 0 - undesired
* 1 - highly desired (default value)

Example for above code: GET with header Accept: "text/html; q=1, application/widgets+xml; q=0.8" will match `getAsHtml` instead of `getAsXML` because of q.

A **server** can also indicate media type preference using the `qs` parameter.

```
@Path("widgets2")
public class WidgetsResource2 {

    @GET
    @Produces("application/xml; qs=1", "application/json; qs=0.75")
    public Widgets getWidget() {...}
}
```

With `GET` request with header Accept: "application/\*; q=0.5" => media type `application/xml` is selected due to higher `qs` value.

![](http://www.plantuml.com/plantuml/svg/VSunhi8m48JXtgUOxbMvG8gdH3I82W45hMMFYANOZdRNaRWz5WqLrF_gsvdKl5ZBg_j3PamUzjoes1KBVQIe2sjYCGp_KCfEmOZZEusOG-1chbGZ93qM6v6zXOKAgvZEKcCBL9pc-t2vkb_KeHRhRRZrzr_1VgGjVy299VRjBm00)

```
if (@Produces.value != request Accept header) {
    sub-resource method is not invoked
}

if (@Consumes.value != request Content-Type header) {
    sub-resource method is not invoked    
}
```

## Annotation inheritance

:warning: For consistency with other Java EE specifications, it is recommended to always repeat annotations instead of relying on annotation inheritance.

```
public interface ReadOnlyAtomFeed {
     @GET @Produces("application/atom+xml")
     Feed getFeed();
}
     
@Path("feed")
public class ActivityLog implements ReadOnlyAtomFeed {
     public Feed getFeed() {...}
}
```

`ActivityLog.getFeed()` inherits `@GET` and `@Produces` from the interface.

:warning: But, conversely&#x20;

```
@Path("feed")
public class ActivityLog implements ReadOnlyAtomFeed {
    @Produces("application/atom+xml")
    public Feed getFeed() {...}
}
```

In the above case @GET annotation from ReadOnlyAtomFeed.getFeed() is not inherited. Because

> If a subclass or implementation method has any JAX-RS annotations then all of the annotations on the superclass or interface method are ignored

## Providers

Annotation `@Provider` is used by JAX-RS runtime to automatically discover provider classes via mechanisms such as class scanning.

* Provider must have public constructor
* Constructor may include parameter annotated with `@Context`
* Providers may be annotated with `@Priority`. `@Priority(1)` > `@Priority(10)`
* Default priority for application-supplied providers is `javax.ws.rs.Priorities.USER`

```
/**
* User-level filter/interceptor priority.
*/
public static final int USER = 5000;
```

### MessageBodyReader

Message entity body -> Java type

* implement `MessageBodyReader`
* annotate with `@Provider` (for automatic discovery)

`MessageBodyReader` always operate on **decoded** HTTP entity **body** (decoded by *container* or *JAX-RS* runtime).

#### How entity body is mapped to Java method parameter:

```
var media_type = request.Content_Type
if (media_type == null) {
    media_type = application/octet_stream
}

-----------------

Identify Java type of sub-resource method parameter

-----------------

Select set of MessageBodyReader that support media_type

-----------------

for (MessageBodyReader reader : set) {
    if (reader.isReadable()) {
        if (more readers suitable) {
            choose reader with highest priority
            reader.readFrom(entity_body) 
            done
        }
    }
}
server throw NotSupportedException (415 status) + no entity
client generate ProcessingException
```

### MessageBodyWriter

`javax.ws.rs.ext.MessageBodyWriter`&#x20;

Contract for a provider that supports the conversion of a Java type to a stream.

A `MessageBodyWriter` implementation may be annotated with `@javax.ws.rs.Produces` to restrict the media types for which it will be considered suitable.

Providers implementing `MessageBodyWriter` contract must be either programmatically registered in a JAX-RS runtime or must be annotated with `@javax.ws.rs.ext.Provider` annotation to be automatically discovered by the JAX-RS runtime during a provider scanning phase.

Steps for mapping return value to message entity body:

```
var object = what_will_be_mapped_to_message_entity_body()

if (object instanceof <? extends Response>) {
    object = Response.entity
} else {
    object
}

-----------------

var media_type = determine()

-----------------

Select set of MessageBodyWriter that support object and media type of message body

-----------------

sort set (TODO criteria)

-----------------

for (MessageBodyWriter writer : set) {
    if (writer.isWriteable()) {
        if (more writers suitable) {
            choose writer with highest priority
            writer.writeTo()
            done
        }
    }
}
server generates InternalServerErrorException (status 500) + no entity
client generate ProcessingException
```

### Media type capabilities

Readers and writers may restrict media types they support using `@Consumes` and `@Produces`. Absence of annotation means `"*/*"`.

### ExceptionMapper

must **implement** `javax.ws.rs.ext.ExceptionMapper`

Contract for a provider that maps Java exceptions (checker or runtime) to `javax.ws.rs.core.Response`. If **>1** exception providers are applicable => use with highest **priority**.

Providers implementing `ExceptionMapper` contract must be either programmatically registered in a JAX-RS runtime or must be annotated with `@javax.ws.rs.ext.Provider` annotation to be automatically **discovered** by the JAX-RS runtime during a provider scanning phase.

## Client API

`javax.ws.rs.client`&#x20;

## Filters

Filters execute code at an extension point but **without wrapping a method invocation**.

`@Provider`

```java
public interface ClientRequestFilter {    // for client 
    void filter(ClientRequestContext requestContext) throws IOException;
}
// before HTTP request is delivered to the network

public interface ClientResponseFilter {    // for client 
    void filter(ClientRequestContext requestContext,
        ClientResponseContext responseContext) throws IOException;
}
// is executed upon receiving a server response
                   
public interface ContainerRequestFilter {    // for server
    void filter(ContainerRequestContext requestContext) throws IOException;
}
// is executed upon receiving a request from a client

public interface ContainerResponseFilter {    // for server
    void filter(ContainerRequestContext requestContext,
        ContainerResponseContext responseContext) throws IOException;
}
// before HTTP response is delivered to the network
```

Filters are grouped in `Filter chain` . There is a separate filter chain for each extension point (e.g. `ClientRequest`, `ClientResponse`, `ContainerRequest`, `ContainerResponse`, `PreMatchContainerRequest`).&#x20;

![](http://www.plantuml.com/plantuml/svg/SoWkIImgAStDuU8AJYqgIosABqejBiZFAqvLqBLJY7REoKpDAubLi5A0i8AWacwPEIMfHGeQoHc9cNcQN1uX8G7noOavEGeskZcfQIMws7GMbgOMbw1fv798pKi1sWu0)

`ContainerRequestFilter` annotated by **@PreMatching** executed upon receiving client request but **before a resource method is matched**.

## Interceptors

Entity interceptors **wrap** around a method **invocation** at a specific extension point.

`@Provider`

```java
public interface ReaderInterceptor {
    Object aroundReadFrom(ReaderInterceptorContext context)
        throws java.io.IOException, javax.ws.rs.WebApplicationException;
}       
```

Reader interceptor wraps around calls to `MessageBodyReader` readFrom().

```java
public interface WriterInterceptor {
    void aroundWriteTo(WriterInterceptorContext context)
        throws java.io.IOException, javax.ws.rs.WebApplicationException;
} 
```

Writer interceptor wraps around calls to `MessageBodyWriter` writeTo().

## Binding

### Global

A filter/interceptor that has no annotations is assumed to be bound globally => applies to all resource methods in application (well either `Provider` or register manually in Application)

### Name binding

```java
@Provider
@MyLogged
class LoggingFilter implements ContainerRequestFilter{...}

@Provider
@MyAuthenticated
class AuthenticationFilter implements ContainerRequestFilter{...}


@Path("*/*")
public class MyResource {
    @MyLogged @MyAuthenticated
    @GET
    public String hello() {...}
}

@NameBinding
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(value = RetentionPolicy.RUNTIME)
public @interface MyLogged { }

@NameBinding
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(value = RetentionPolicy.RUNTIME)
public @interface MyAuthenticated { }
```

## JAX-RS request processing cycle

![](http://www.plantuml.com/plantuml/svg/TP5DQiCm48NtFiMGJN_0LoWfsHKAnLcq46UXoY-sG1wvet5BRjyXjMaBoavelk_fITfcTQBp6AiRUdfygviz2JvcPAL9aaVEWNloPnzHtTxVKIsX7xH-eCCk1h2kz94sBu9wTEe7CrhsYTK5XhIy1fv2LCYcMZDCILclENbAd56G6hWEGYq7jed7fEdV_DbAknxqdhgpKNB13VXnSvhDiVqHEgJE5h_tNA3TMeDAFI9EbsDU9MYXXerBBRwC_giVzf1Fqvib_qZskjKMtDbVV0C0)

## Open questions:

* How JAX-RS configuration is done?
*


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://amartyushov.gitbook.io/tech/specifications/jax-rs.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
