🔏
Tech
  • 🟢App aspects
    • Software architecture
      • Caching
      • Anti-patterns
      • System X-ability
      • Coupling
      • Event driven architecture
        • Command Query Responsibility Segregation (CQRS)
        • Change Data Capture (CDC)
      • Distributed transactions
      • App dev notes
        • Architecture MVP
      • TEMP. Check list
      • Hexagonal arch
      • Communication
        • REST vs messaging
        • gRPC
        • WebSocket
      • Load balancers
      • Storage limits
      • Event storming
    • Authentication
    • Deployment strategy
  • Databases
    • Classification
    • DB migration tools
    • PostreSQL
    • Decision guidance
    • Index
      • Hash indexes
      • SSTable, LSM-Trees
      • B-Tree
      • Engines, internals
    • Performance
  • System design
    • Interview preparation
      • Plan
        • Instagram
        • Tinder
        • Digital wallet
        • Dropbox
        • Live video streaming
        • Uber
        • Whatsup
        • Tiktok
        • Twitter
        • Proximity service
    • Algorithms
    • Acronyms
  • 🟢Programming languages
    • Java
      • Features
        • Field hiding
        • HashCode() and Equals()
        • Reference types
        • Pass by value
        • Atomic variables
      • Types
      • IO / NIO
        • Java NIO
          • Buffer
          • Channel
        • Java IO: Streams
          • Input streams
            • BufferedInputStream
            • DataInputStream
            • ObjectInputStream
            • FilterInputStream
            • ByteArrayInputStream
        • Java IO: Pipes
        • Java IO: Byte & Char Arrays
        • Java IO: Input Parsing
          • PushbackReader
          • StreamTokenizer
          • LineNumberReader
          • PushbackInputStream
        • System.in, System.out, System.error
        • Java IO: Files
          • FileReader
          • FileWriter
          • FileOutputStream
          • FileInputStream
      • Multithreading
        • Thread liveness
        • False sharing
        • Actor model
        • Singleton
        • Future, CompletableFuture
        • Semaphore
      • Coursera: parallel programming
      • Coursera: concurrent programming
      • Serialization
      • JVM internals
      • Features track
        • Java 8
      • Distributed programming
      • Network
      • Patterns
        • Command
      • Garbage Collectors
        • GC Types
        • How GC works
        • Tools for GC
    • Kotlin
      • Scope functions
      • Inline value classes
      • Coroutines
      • Effective Kotlin
    • Javascript
      • Javascript vs Java
      • TypeScript
    • SQL
      • select for update
    • Python
      • __init.py__
  • OS components
    • Network
      • TCP/IP model
        • IP address in action
      • OSI model
  • 🟢Specifications
    • JAX-RS
    • REST
      • Multi part
  • 🟢Protocols
    • HTTP
    • OAuth 2.0
    • LDAP
    • SAML
  • 🟢Testing
    • Selenium anatomy
    • Testcafe
  • 🟢Tools
    • JDBC
      • Connection pool
    • Gradle
    • vim
    • git
    • IntelliJ Idea
    • Elastic search
    • Docker
    • Terraform
    • CDK
    • Argo CD
      • app-of-app setup
    • OpenTelemetry
    • Prometheus
    • Kafka
      • Consumer lag
  • 🟢CI
    • CircleCi
  • 🟢Platforms
    • AWS
      • VPC
      • EC2
      • RDS
      • S3
      • IAM
      • CloudWatch
      • CloudTrail
      • ELB
      • SNS
      • Route 53
      • CloudFront
      • Athena
      • EKS
    • Kubernetes
      • Networking
      • RBAC
      • Architecture
      • Pod
        • Resources
      • How to try
      • Kubectl
      • Service
      • Tooling
        • ArgoCD
        • Helm
        • Istio
    • GraalVM
    • Node.js
    • Camunda
      • Service tasks
      • Transactions
      • Performance
      • How it executes
  • 🟢Frameworks
    • Hibernate
      • JPA vs Spring Data
    • Micronaut
    • Spring
      • Security
      • JDBC, JPA, Hibernate
      • Transactions
      • Servlet containers, clients
  • 🟢Awesome
    • Нейробиология
    • Backend
      • System design
    • DevOps
    • Data
    • AI
    • Frontend
    • Mobile
    • Testing
    • Mac
    • Books & courses
      • Path: Java Concurrency
    • Algorithms
      • Competitive programming
    • Processes
    • Finance
    • Electronics
  • 🟢Electronics
    • Arduino
    • IoT
  • Artificial intelligence
    • Artificial Intelligence (AI)
  • 🚀Performance
    • BE
  • 📘Computer science
    • Data structures
      • Array
      • String
      • LinkedList
      • Tree
    • Algorithms
      • HowTo algorithms for interview
  • 🕸️Web dev (Frontend)
    • Trends
    • Web (to change)
  • 📈Data science
    • Time series
Powered by GitBook
On this page
  • Applications
  • Publications
  • Resources
  • Resource methods
  • Return type
  • Exceptions
  • HEAD and OPTIONS
  • URI Templates
  • Sub Resources
  • Media type capabilities
  • Multiple media types
  • Annotation inheritance
  • Providers
  • MessageBodyReader
  • MessageBodyWriter
  • Media type capabilities
  • ExceptionMapper
  • Client API
  • Filters
  • Interceptors
  • Binding
  • Global
  • Name binding
  • JAX-RS request processing cycle
  • Open questions:

Was this helpful?

  1. 🟢Specifications

JAX-RS

PreviousOSI modelNextREST

Last updated 5 years ago

Was this helpful?

JAX-RS is a specification, a set of interfaces and annotations offered by Java EE. Well-known Implementations are RESTEasy and Jersey.

Applications

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

Configuration: via application-supplied subclass of Application.

Publications

Applications are published in diff ways:

  1. if app runs in Java SE environment

  2. within container (is packed as .war file)

    1. app classes are packaged in WEB-INF/classes or WEB-INF/lib and required libs are packaged in WEB-INF/lib

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.

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. ⚠️ 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

    • 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

    • Entity property of GenericEntity -mapped-> entity body

    • if (GenericEntity == null) {
          status_code = 204;
      }
      if (GenericEntity != null) {
          status_code = 200;
      }
      }}}
  • Other

    • 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;
      }

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

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

  • JAX-WS Provider-based implementation wrapper WebServiceException

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 {
... }

💡 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).

💡 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

  • 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.

💡 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]

  • 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.

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

⚠️ 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.

⚠️ But, conversely

@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

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

Filters

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

@Provider

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).

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

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

Reader interceptor wraps around calls to MessageBodyReader readFrom().

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

@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

Open questions:

  • How JAX-RS configuration is done?

451KB
jaxrs-2_1-final-spec.pdf
pdf
JAX-RS 2.1 Specification