JAX-RS Providers Part III

In this lesson, we are going to explore

  • Exception Mappers: how to transform low application level exceptions to logical HTTP reponses

  • Context Providers: provides context (of other classes) to resources and providers

Exception Mapper

The javax.ws.rs.core.Response object allows developers to wrap HTTP error state and return it to caller. A javax.ws.rs.WebApplicationException (unchecked exception) can be used as a bridge between the native business/domain specific exceptions and an equivalent HTTP error response. A javax.ws.rs.ext.ExceptionMapper represents a contract (interface) for a provider that maps Java exceptions to Response objects.

It's benefits are obvious

  • helps embrace “don’t repeat yourself” (DRY) principle. your exception detection and transformation logic is not repeated across all of your service methods

  • allows flexible mappings between business logic exceptions and the desired HTTP response

  • in addition to returning HTTP status codes, you can choose to return HTTP payload in the message body as well

Let's look at an example

//Custom exception mapper
public class BookNotFoundMapper implements
ExceptionMapper<BookNotFoundException>{
@Override
Response toResponse(
BookNotFoundException bnfe){
return Response.status(404).build();
}
}

In the above example, thanks to the exception mapper, a BookNotFoundException is converted to a HTTP 404 response to the caller

New exception hierarchy

JAX-RS 2.0 has been supplemented with unchecked exceptions that inherit from javax.ws.rs.WebApplicationException. This design relieves the developer from having to build and throw a WebApplicationException with explicit HTTP error information.

JAX-RS exception hierarchy

The new set of exceptions are intuitively named and each of them maps to a specific HTTP error scenario (by default) – this means that, throwing any of these exceptions from your resource classes would result in a pre-defined (as per mapping) HTTP error response being sent to the client e.g. the client would receive a HTTP 403 in case you throw a NotAuthorizedException. The exceptions’ behavior can also be modified at runtime by using the ExceptionMapper to return a different Response object.

Exception

HTTP Error code

BadRequestException

400

ForbiddenException

403

InternalServerErrorException

500

NotAcceptableException

406

NotAllowedException

405

NotAuthorizedException

401

NotFoundException

404

NotSupportedException

415

ServiceUnavailableException

503

Context Provider

Context services are provided by the implementation of ContextResolver interface (which has just one method).

  • Think of context as configuration metadata which can help with various aspects (instance creation etc.) and

  • the Context Provider as a factory for these contexts

//Simple Context Provider/Resolver
@Provider
@Produces("application/json")
public class MyCustomContextProvider implements ContextResolver<MyCustomContext> {
public MyCustomContext getContext(){
return new MyCustomContext();
}
}
//Leveraging the Context Provider
public class Resource{
@Context ctx
Providers providers;
@GET
@Produces("application/json")
public Response get(){
//fetch it
MyCustomContext customCtx = providers.
getContextResolver(MyCustomContext.class
,MediaType.APPLICATION_JSON);
//use it
MyCustomClass clazz = customCtx.create();
}
}