JAX-RS with Jersey

Terms
resource method designator - annotation such as @GET, @PUT, @POST, @DELETE
sub-resource methods - methods annotated with @Path and also with resource method designators such as @GET or @POST
sub-resource locators - methods annotated with @Path but not with resource method designators such as @GET or @POST

Tips & Tricks
Jersey gives you an option to register so called model processor providers (org.glassfish.jersey.server.model.ModelProcessor). These providers are able to modify or enhance the application resource model during application deployment.

Use @InjectLink on an entity (returned by server) field in order to inject it with a link (intead of using a link header).

Do not use ApacheConnectorProvider nor GrizzlyConnectorProvider neither JettyConnectorProvider connector implementations with Jersey Multipart features. See Header modification issue warning for more details.

javax.activation.MimetypesFileTypeMap - utility for getting the MIME type of a file

@Produces({"application/xml; qs=0.9", "application/json"})
If client accepts both "application/xml" and "application/json" (equally), then a server always sends "application/json", since "application/xml" has a lower quality factor.

HttpHeaders, Request, UriInfo, SecurityContext can be injected into constructor or class fields of a singleton (using the @Context annotation).
For these objects the runtime will inject proxies which are able to simultaneously server more request.

The @FormParam annotation is special and may only be utilized on resource and sub-resource methods. This is because it extracts information from a request entity.

By default, the transport layer in Jersey is provided by HttpUrlConnection. This transport is implemented in Jersey via HttpUrlConnectorProvider that implements Jersey-specific Connector SPI. HttpUrlConnection by default restricts the use of some headers. In order to permit all headers to be sent the system property sun.net.http.allowRestrictedHeaders must be set to "true".

Sub-resource locator return types
@Path("/")
public ItemContentResource getItemContentResource() {
    // instance
    return new ItemContentResource();
}
@Path("kid1")
public Class getMySubResource1() {
    // Class
    return MySubResource1.class;
}
@Path("kid2")
public Resource getMySubResource() {
    // Resource (programmatic resource model return type)
    return Resource.from(MySubResource2.class);
}
@Path("kid5")
public MySubResource5 getMySubResource(@QueryParam("impl") String impl) {
    // Object (the way to support polymorphism)
    // @QueryParam("impl") won't be available into sub-sesource
    if (impl.equals("a")) {
        return new MySubResource5a(impl);
    } else {
        return new MySubResource5b(impl);
    }
}

Architecture (the usual usage)
invocating a jax-rs service
ClientBuilder builds Client (dealing with registration of providers, features, filter and interceptors).
Client builds WebTarget (dealing with the URI construction including query and matrix parameters, template values).
WebTarget builds Invocation.Builder (dealing with any except URI construction; deals with headers and cookies, filter-accesible properties).
Invocation.Builder builds Invocation/AsyncInvoker (dealing with the "actual call" and getting the result).
Invocation.Builder can behave also as SyncInvoker in order to do the "actual call".

javax.ws.rs.core.Response created by server
Response creates a ResponseBuilder while also being able to set the http status.
ResponseBuilder sets headers (status, link, lastModified, entity tag, location, etc), cookies, entity (+annotations).
ResponseBuilder then builds the Response.

javax.ws.rs.core.Response used by client
Response is obtained as a result of the "actual call" facilitated by Invocation.Builder.
Response provides headers, cookies and entity access (Response.readEntity(Class entityType, Annotation[] annotations)).
For reading the entity a MessageBodyReader in used based also on annotations provided to Response.readEntity().

Chunked Output
In Jersey you can use ChunkedOutput to send response to a client in chunks. 
This can be achived by returning ChunkedOutput from a resource method - this makes the method automatically asynchronous.
Then one writes T for the client using ChunkedOutput. After sending some T one should close the ChunkedOutput.

Client side one uses Response.readEntity in order to get a ChunkedInput from which reads T while not null.

Server-Sent Events
This is the server side support for services which can be consumed from java script with EventSource.
The resource method should return org.glassfish.jersey.media.sse.EventOutput which is a ChunkedOutput - this makes the method automatically asynchronous. Then one uses EventOutput in order to write OutboundEvent which is a wrapper for the actual entity one wants to send. Finally one would close the EventOutput in order to end the communication.

Client side one gets a EventInput instance from where reads InboundEvent which is a wrapper for the actual entity sent by server. The connection is closed when null EventInput is received or InboundEvent.isClosed() returns true.
instead of getting an EventInput instance one could use EventSource then register an EventListener in order to receive InboundEvent.

security
Security information of a request is available by injecting a JAX-RS SecurityContext instance using @Context annotation.
You can define the access to resources using annotations from package javax.annotation.security defined by JSR-250 (PermitAll, RolesAllowed).

bean validation support
Jersey does not support, and doesn't validate, constraints placed on constructors and Bean Validation groups (only Default group is supported at the moment). Constraint annotations are allowed in resource method parameters, fields and property getters as well as resource classes, entity parameters and resource methods (return values). E.g. validation on resource method parameters:
@NotNull @FormParam("lastName") String lastName, @Email @FormParam("email") String email, @Valid User user.
The @Email annotation is defined as:
@Constraint(validatedBy = EmailValidator.class)
public @interface Email { ...
The constraint class is defined as:
public class EmailValidator implements ConstraintValidator { ...

Entity Data Filtering
Entity filtering is achived with:
- custom annotations (server and client side support)
- role-based Entity Filtering using (javax.annotation.security) annotations (server and client side support)
- dynamic and configurable query parameters
With custom annotations one uses @EntityFiltering meta-annotation to creates a custom annotation e.g. @UserDetailedView.
Then creates a response e.g.:
Response.ok().entity(new User(), isDetailed ? new Annotation[]{UserDetailedView.Factory.get()} : new Annotation[0]).build();
or 
simply annotates with @ProjectDetailedView the resource method.
Then the client shall receive an User entity populated only for the fields annotated with @UserDetailedView or not annotated at all with @EntityFiltering.
With role-based Entity Filtering using (javax.annotation.security) annotations one uses javax.annotation.security annotations same way as he would with custom annotations entity-filtering. Instances of security annotations can be created using SecurityAnnotations factory class that is part of the Jersey Entity Filtering API.
Entity Filtering based on dynamic and configurable query parameters allows one to specify the select query parameter in order to filter the entity's fields e.g. http://example.com/user/51234?select=name,surname,country.name -> here only name, surname, country.name fields from User entity shall be populated.

MVC Templates
Use @Template(templateName) on a resource method in order to define a template (jep, freemarker, mustache) processing the entity returned. 
Jersey will assign the entity instance to an attribute named model which can be user with e.g. ${model} in jsp or freemarker.
One could use @ErrorTemplate the same way where Bean Validation errors will be accessible with the attribute name error.

Configuration
jersey specific: org.glassfish.jersey.client.ClientConfig implements javax.ws.rs.core.Configurable, ...
jersey specific: org.glassfish.jersey.client.ResourceConfig implements javax.ws.rs.core.Configurable, ...
ClientConfig and ResourceConfig both use javax.ws.rs.core.Configurable's ergonomic methods in order to construct javax.ws.rs.core.Configuration.
While constructing javax.ws.rs.core.Configuration also ResourceConfig constructs javax.ws.rs.core.Application (main objective by the way).
ClientConfig aim is the construct of a javax.ws.rs.core.Configuration which further would be used by 
javax.ws.rs.client.ClientBuilder.newClient(Configuration configuration) to construct javax.ws.rs.client.Client.

Filters can be used when you want to modify any request or response parameters like headers.

Interceptors share a common API for the server and the client side. Whereas filters are primarily intended to manipulate request and response parameters like HTTP headers, URIs and/or HTTP methods, interceptors are intended to manipulate entities, via manipulating entity input/output streams.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.