Lecture 3: REST Web Service (with Jersey) - Jyväskylän...

25
UNIVERSITY OF JYVÄSKYLÄ Lecture 3: REST Web Service (with Jersey) TIES4560 SOA and Cloud Computing Autumn 2018 University of Jyväskylä Khriyenko Oleksiy

Transcript of Lecture 3: REST Web Service (with Jersey) - Jyväskylän...

UNIVERSITY OF JYVÄSKYLÄ

Lecture 3: REST Web Service (with Jersey)

TIES4560 SOA and Cloud ComputingAutumn 2018

University of Jyväskylä Khriyenko Oleksiy

UNIVERSITY OF JYVÄSKYLÄ

Related tutorials:• http://docs.oracle.com/javaee/6/tutorial/doc/giepu.html• http://www.tutorialspoint.com/restful/restful_jax_rs.htm• http://www.mkyong.com/tutorials/jax-rs-tutorials/• http://crunchify.com/how-to-build-restful-service-with-java-using-jax-rs-and-jersey/

19/09/2018 TIES4560 - Lecture 3 2

REST Web Services

JAX-RSJAX-RS is an API for RESTful Web Services. JAX-RS contains Interfaces, therefore, to build an App weneed actual implementation of them.

There are many implementation libraries of the API (e.g. Rest Jersey , Restlet , RESTEasy , etc.).

REST API Application

App code

Jersey

JAX-RSInterface annotation

Implementation classes

… Jersey is developed by people who wrote specification for JAX-RS (javax.ws.rs.*)

… learn one implementation and you will almost know all of them!!!

Application Server

UNIVERSITY OF JYVÄSKYLÄ

REST API Client is the webdevelopers helper program to createand test custom HTTP requests.

3

REST Web Services

API Client

HTTP request

HTTP response

RESTful Web Service API

ChromePostman: https://chrome.google.com/webstore/detail/postman/fhbjgbiflinjbdggehcddcbncdddomop?hl=en

Advanced REST client: https://chrome.google.com/webstore/detail/advanced-rest-client/hgmloofddffdnphfgcellkdfbfbjeloo

DHC: https://chrome.google.com/webstore/detail/dhc-rest-client/aejoelaoggembcahagimdiliamlcdmfm?hl=en

FirefoxFirefox add-on: https://addons.mozilla.org/en-US/firefox/addon/restclient/

Insomnia is a cross-platform application for organizing, running, and debugging HTTP requests (https://insomnia.rest/).

TIES4560 - Lecture 319/09/2018

UNIVERSITY OF JYVÄSKYLÄ

Jersey RESTful Web Services framework is opensource, production quality, framework for developing RESTful Web Services in Java that providessupport for JAX-RS APIs and serves as a JAX-RS (JSR 311 & JSR 339) Reference Implementation.Jersey provides it’s own API that extend the JAX-RS toolkit with additional features and utilities tofurther simplify RESTful service and client development. (https://jersey.github.io/)

Jersey is distributed mainly via Maven

4

REST Web Services

Archetype Group Id: org.glassfish.jersey.archetypes

Archetype Artifact Id: jersey-quickstart-webapp

Archetype Version: 2.27

Related tutorials:• https://jersey.github.io/documentation/latest/index.html

…<servlet-mapping>

<servlet-name>Jersey Web Application</servlet-name><url-pattern> /webapi/* </url-pattern>

</servlet-mapping>…

Modify web.xml file to map the Servlet thatis provided by Jersey package withcorresponding URL pattern.So, all the REST API requests will bepreconfigure to go to the URL

<port>/<artifactId> /webapi/

… from now, just start to create resources by providing corresponding annotations to the classes!!!

TIES4560 - Lecture 319/09/2018

UNIVERSITY OF JYVÄSKYLÄ

Application class in Jersey…This is another way to configure REST API Application as an alternative to Servlet configuration inweb.xml file.

o Use @ApplicationPath annotation to specify the URL your API is mapped to (e.g. webapi )

o By default, Jersey checks all the resources with @Path annotation in your application and add them to the list tobe managed. Alternatively, you may directly specify classes that have to be considered by Jersey viaimplementation (overwriting a default implementation) of the getClasses() method. In this way you may excludesome classes from the consideration…

5

REST Web Services

…@ApplicationPath(" webapi ")public class MyRESTApp extends Application {

public Set<Class<?>> getClasses(){return new HashSet<Class<?>>(); //this returns empty set of classes (add there ...)

}

Related tutorials:• https://jersey.github.io/documentation/latest/index.html

… from now, just start to create resources by providing corresponding annotations to the classes!!!

TIES4560 - Lecture 319/09/2018

UNIVERSITY OF JYVÄSKYLÄ

@Path annotation's value is a relative URI path.

@GET, @PUT, @POST, @DELETE and @HEAD are resource methoddesignator annotations defined by JAX-RS and which correspond to the HTTP methods.

@Produces annotation is used to specify the MIME media types of representations a resourcecan produce and send back to the client (text/plain, application/xml, application/json).

6

REST Web Services

…@Path("/publications")public class PublicationResource {

@GET@Produces("text/plain")

// @Produces({"application/xml", "applicati on/json"})// @Produces(value={MediaType.APPLICATION_J SON, MediaType.TEXT_XML})

public String getPublications(){return "Publications...";

}}

To return JSON Response we need corresponding convertor to JSON format. For this purpose youmay uncomment corresponding dependency reserved in pom.xml file.

<!-- uncomment this to get JSON support --><dependency>

<groupId>org.glassfish.jersey.media</groupId><artifactId>jersey-media-json-binding</artifactId>

</dependency>

TIES4560 - Lecture 319/09/2018

UNIVERSITY OF JYVÄSKYLÄ

@XmlRootElement annotation specifies a root element for JAXB, which is used by Jerseyto generate XML schema from Java objects.Java Architecture for XML Binding (JAXB) provides a fast and convenient way to bind XML schemas and Javarepresentations, making it easy for Java developers to incorporate XML data and processing functions in Javaapplications. As part of this process, JAXB provides methods for reading XML instance documents into Java contenttrees, and then writing Java content trees back into XML instance documents. (https://docs.oracle.com/javase/tutorial/jaxb/intro/)

7

REST Web Services

…@Path("/publications")public class PublicationResource {

PublicationService publicationService = new PublicationService();

@GET@Produces(MediaType.APPLICATION_XML)public List<Publication> getPublications(){

return publicationService.getAllPublications();}

}

…@XmlRootElementpublic class Publication {

private long id;private String title;private Date published;private String mainAuthor;

public Publication(){}…}

TIES4560 - Lecture 3

Be sure that you have allgetters and setters for classvariables to generate properXML(JSON) output…

19/09/2018

UNIVERSITY OF JYVÄSKYLÄ

� since we cannot hardcode the path of a resource accessed by Id, we use {variable name} insteadof concrete part of the URL.

� to get an access to the variable use @PathParam( “variable name” ) annotation for method’sargument.

� the variable in @Path annotation may be customized by specifying a different regular expressionafter the variable name (default regular expression is [^/]+?). For example, if a user name must begin withone uppercase or lowercase letter and zero or more alphanumeric characters and the underscore character. If a user namedoes not match that template, a 404 (Not Found) response will be sent to the client.

@Path("users/{username: [a-zA-Z][a-zA-Z_0-9]* }")

- to get nested URI (nested path) use the same @Pathannotation for a class method.

8

REST Web Services/publications/{publicationId}/

…@Path("/publications")public class PublicationResource {

PublicationService publicationService = new Publicati onService();@GET@Produces(MediaType.APPLICATION_XML)public List<Publication> getPublications(){

return publicationService.getAllPublications();}@GET@Path("/{publicationId}")@Produces(MediaType.APPLICATION_JSON)public Publication getPublication( @PathParam( “publicationId" ) long id){

Publication publication = publicationService.getPubl ication(id); return publication;

}}

TIES4560 - Lecture 319/09/2018

UNIVERSITY OF JYVÄSKYLÄ

Use @POST annotation to identify method that consumes HTTP POST request and createsnew resource based on resource sent within the request body.

@Consumes annotation is used to specify the MIME media types of representations aresource can consume from the client (text/plain, application/xml, application/json).

9

REST Web Services

…@Path("/publications")@Produces(MediaType.APPLICATION_JSON)public class PublicationResource {

PublicationService publicationService = new Publicati onService();@GET@Produces(MediaType.APPLICATION_XML)public List<Publication> getPublications(){

return publicationService.getAllPublications();}@GET@Path("/{publicationId}")public Publication getPublication(@PathParam(“publi cationId") long id){

Publication publication = publicationService.getPubl ication(id); return publication;

}@POST@Consumes(MediaType.APPLICATION_JSON)public Publication addPublication (Publication publi cation){

return publicationService.addPublication(publication );}

}

TIES4560 - Lecture 319/09/2018

UNIVERSITY OF JYVÄSKYLÄ

Use @PUT annotation to identify method that consumes HTTP PUT request and updatesspecified resource with resource sent within the request body.

Use @DELETE annotation to identify method that consumes HTTP DELETE request anddeletes specified resource.

10

REST Web Services

…@Path("/publications")@Produces(MediaType.APPLICATION_JSON)public class PublicationResource {

PublicationService publicationService = new Publicati onService();…@PUT@Path("/{publicationId}")@Consumes(MediaType.APPLICATION_JSON)public Publication updatePublication( @PathParam( "publicationId" ) long id, Publication

publication){publication.setId(id);return publicationService.updatePublication(publica tion);

}@DELETE@Path("/{publicationId}")public void deletePublication ( @PathParam( "publicationId" ) long id){

publicationService.removePublication (id);}

}

TIES4560 - Lecture 319/09/2018

UNIVERSITY OF JYVÄSKYLÄ

Filtering and Pagination require use of query parameters of the request.

Use @QueryParam (“parameter name” ) annotation for method’s argument to get avalue of the parameter .

11

REST Web Services

public List<Publication> getAllPublicationsForYear(int year){List<Publication> publicationsForYear = new ArrayList<>();Calendar cal = Calendar.getInstance();for (Publication publication : publications.values()){

cal.setTime(publication.getPublished());if (cal.get(Calendar.YEAR)== year){ publicationsForYear.add(publication); }

}return publicationsForYear;

}public List<Publication> getAllPublicationsPaginated(int start, int size){

ArrayList<Publication> list = new ArrayList<Publication>(publications.values());if (start + size > list.size()) return new ArrayList<Publication>();return list.subList(start,start+size) ;

}…

/publications?year=2018

/publications?start=5&size=10

and

…@GETpublic List<Publication> getPublications( @QueryParam( “year” ) int year,

@QueryParam( “start” ) int start,@QueryParam( “size” ) int size){

if(year > 0){ return publicationService.getAllPubli cationsForYear(year); }if(start >= 0 && size > 0){

return publicationService.getAllPublicationsPaginat ed(start, size);}return publicationService.getAllPublications();

}…

TIES4560 - Lecture 319/09/2018

UNIVERSITY OF JYVÄSKYLÄ

Param annotations:

� @MatrixParam( “parameter name” ) annotation is similar to @QueryParam and used for the cases whenparameters are separated by (;) in the request.

� @HeaderParam( “parameter name” ) annotation is used to access an extra metadata in a form of customheader values of the request.

� @CookieParam( “parameter name” ) annotation to access values of the cookie’s names.

� @FormParam( “parameter name” ) annotation to access “key:value” pairs in HTML Form submissions.

12

REST Web Services

/publications;year=2016;size=5

In the mentioned cases you suppose to know parameter names in advance. If you do not have suchopportunity, you are able to get them and other useful metadata from the Context of the request using@Context annotation and corresponding components:

� UriInfo provides both static and dynamic, per-request information, about the components of a request URI (e.g.absolute path .getAbsolutePath(), base URI .getBaseUri(), query parameters .getQueryParameters(), etc.).

� HttpHeaders provides access to request header information either in map form or via strongly typedconvenience methods. (e.g. names of all the headers .getRequestHeaders(), cookies .getCookies(), date.getDate(), accepted Media Types .getAcceptedMediaTypes(), etc.).

There are also other components as: SecurityContext, ResourceContext, Request, Configurati on, Application, Providers .

public String getParamsUsingContext( @Context UriInfo uriInfo,@Context HttpHeaders headers){

String path = uriInfo.getAbsolutePath().toString();String cookies = headers.getCookies().toString();return "Path: "+path+"; Cookies - "+cookies;

}

TIES4560 - Lecture 319/09/2018

UNIVERSITY OF JYVÄSKYLÄ

@BeanParam annotation that may be used to inject custom JAX-RS "parameter aggregator"value object into a resource class field, property or resource method parameter.

13

REST Web Services

You may aggregate variousannotations under one class that willcontain them. It will definitely makeyour code more readable.

Also, use this approach especially incase you are not sure which concreteparameter is used.

public class PublicationFilterBean {

private @QueryParam( "year" ) int year;private @QueryParam( "start" ) int start;private @QueryParam( "size" ) int size;

public int getYear() {return year;}public void setYear(int year) {this.year = year;}public int getStart() {return start;}public void setStart(int start) {this.start = start;}public int getSize() {return size;}public void setSize(int size) {this.size = size;}

}

…@GETpublic List<Publication> getPublications( @BeanParam PublicationFilterBean fBean){

if(fBean.getYear() > 0){return publicationService.getAllPublicationsForYear (fBean.getYear());

}if(fBean.getStart() >= 0 && fBean.getSize() > 0){

return publicationService.getAllPublicationsPaginat ed(fBean.getStart(), fBean.getSize());}return publicationService.getAllPublications();

}…

TIES4560 - Lecture 319/09/2018

UNIVERSITY OF JYVÄSKYLÄ

@...Param annotations on the level of a class variables vs. class method‘s attributes…

It allows you to use …Param values in all the methods of the class.

14

REST Web Services

…@Path("/publications")@Produces(MediaType.APPLICATION_JSON)public class PublicationResource {

@PathParam( "publicationId" ) private long pubId ;@QueryParam( “year” ) private int pubYear ;@QueryParam( “start” ) private int pubStart ;@QueryParam( “size” ) private int pubSize ;

PublicationService publicationService = new Publicati onService();…@GETpublic List<Publication> getPublications( @QueryParam( “year” ) int year ,

@QueryParam( “start” ) int start ,@QueryParam( “size” ) int size ){

if(year > 0){ return publicationService.getAllPubli cationsForYear(year); }if(start >= 0 && size > 0){

return publicationService.getAllPublicationsPaginat ed(start, size);}return publicationService.getAllPublications();

}@DELETE@Path("/{publicationId}")public void deletePublication ( @PathParam( "publicationId" ) long id ){

publicationService.removePublication (id);}

}

TIES4560 - Lecture 319/09/2018

UNIVERSITY OF JYVÄSKYLÄ

� Jersey has a set of default ParamConvertor s to deal with basic types to convert from a String.� To manage conversion to custom type we need to implement ParamConvertor interface as well as

ParamConvertorProvider that will be registered to Jersey.

You may use such conversion when you do not want to implement the same conversion logic in different places of your application.

Param Converter for a custom type conversion.

15

REST Web Services

@Provider // the annotation preregisters our Provider for JAX- RS to be usedpublic class MyDateConverterProvider implements ParamConverterProvider {

@Overridepublic <T> ParamConverter<T> getConverter (final Class<T> rawType, Type genericType, Annotation []

annotations) {if(rawType.getName().equals( MyDate .class.getName())){

return new ParamConverter <T>(){@Overridepublic T fromString (String value){

MyDate myDate = null;if(" submission ".equalsIgnoreCase(value)){ myDate = new MyDate(31,1 0,2018); }if(" notification ".equalsIgnoreCase(value)){ myDate = new MyDate(30,1 1,2018); }if(” cameraReady ".equalsIgnoreCase(value)){ myDate = new MyDate(31,1 2,2018); }return rawType.cast( myDate );

}@Overridepublic String toString (T bean) { if(bean == null){return null;} return bean.t oString(); }

};}return null;

}}

@Path("call/ {deadline} ")public class CallForPaperResource {

@GET@Produces(MediaType.TEXT_PLAIN)public String getRequestedCall( @PathParam(" deadline ") MyDate date){return "Date:”+date.toString();}

}

TIES4560 - Lecture 319/09/2018

UNIVERSITY OF JYVÄSKYLÄ

per-Request and Singleton Resources in JAX-RS

16

REST Web Services

� By default, a class that represents a resource is initialized (new instance is created) every timewhen resource is requested (per-Request ).

� If you need to keep some data, keep the data in a separate object (instance of other class) ormake the resource Singleton with corresponding annotation.

� It is not allowed to use …Param annotation on a level of class variables (only on a level ofclass method’s attributes).

…@Path("secured")@Produces(value={MediaType.TEXT_PLAIN, MediaType.AP PLICATION_JSON})@Singletonpublic class SecuredResource {

private int counter;

@GET@Path("degrees")public String securedMethod() {

counter++;return "This secured API is called “ + counter + " time(s)...";

}}

TIES4560 - Lecture 319/09/2018

UNIVERSITY OF JYVÄSKYLÄ

When we implement API for nested resources , we may do it in the same class of the rootresource (but it might not be so convenient).

17

REST Web Services

@Path("/{publicationId}/comments")public CommentResource getCommentResource(){

return new CommentResource(); }

/publications/{publicationId}/comments /publications/{publicationId}/comments/{commentId}

@GET@Path(" /{publicationId}/comments ")public List<Comment> getComments(@PathParam("public ationId") long publicationId){

return commentService.getAllComments(publicationId) ;}

So, it is much more reasonable to do this for new (nested)resource in a separate class and make a “reference”(delegate further actions) to it from the class of our root(parent) resource…@Path("/")@Consumes(MediaType.APPLICATION_JSON)@Produces(MediaType.APPLICATION_JSON)public class CommentResource {

private CommentService commentService = new CommentSer vice();@GETpublic List<Comment> getComments( @PathParam( "publicationId" ) long publicationId){

return commentService.getAllComments(publicationId); }@GET@Path("/{commnetId}")public Comment getComment( @PathParam( "publicationId" ) long publicationId,

@PathParam( "commentId" ) long commentId){return commentService.getComment(publicationId, comm entId); }

…}

TIES4560 - Lecture 319/09/2018

UNIVERSITY OF JYVÄSKYLÄ

Response might return not only a content in the body. Additionally, service may return extrametadata (status codes and various headers).

18

REST Web Services

- returns only Publicationresource in JSON formatinside a response body.

@POST@Consumes(MediaType.APPLICATION_JSON)public Publication addPublication (Publication publi cation){

return publicationService.addPublication(publication );}

@POST@Consumes(MediaType.APPLICATION_JSON)public Response addPublication (Publication publication){

Publication newPub = publicationService.addPublicatio n(publication);return Response . status(Status. CREATED)

.header (”Location", … )

.entity (newPub)

.build(); }

Use a response builder to enrich response with metadata.- returns status code201-Created and URI ofnewly created resourcein the location header inaddition to Publicationresource in JSON formatinside a response body.

(Similarly, you can addcookie, encoding andvarious headers as well).

You may use quick shortcut to specify both “created” status code and location of created resource… Use @ContextUriInfo and URI builder to simplify construction of resource URI .

public Response addPublication (Publication publicati on, @Context UriInfo uriInfo){Publication newPub = publicationService.addPublicatio n(publication);String newId = String. valueOf(newPub.getId());URI uri = uriInfo .getAbsolutePathBuilder().path(newId).build();return Response . created(uri)

.entity(newPub).build(); }

TIES4560 - Lecture 319/09/2018

UNIVERSITY OF JYVÄSKYLÄ

HATEOAS (Hypermedia As The Engine Of Application State)

19

REST Web Services

To make Response navigable we need to add links to related resources into Response.

We have to extend a model of ourPublication object with new variable Linkthat contains href and rel variables inside.

{ “id” : “10”,

“title” : “Publication 123”,

“mainAuthor” : “me”,

“published” : “…”,

“co-Authors” : […],

“links” : [ { “href” : “/publications/10”,

“rel” : “self” },

{ “href” : “/publications/10/comments”,

“rel” : “comments” },

{ “href” : “/profiles/3”,

“rel” : “mainAuthorProfile” }

]

}

…@XmlRootElementpublic class Publication {

private long id;private String title;private Date published;private String mainAuthor;private List<Author> coAuthors = new ArrayList<>();private List<Link> links = new ArrayList<>();

public Publication(){}public void addLink (String url, String rel){

Link link = new Link();link.setLink(url);link.setRel(rel);links.add(link);

}…}

…public class Link {

private String link;private String rel;

// below generate getters and setters for all the variable of the class…

}

TIES4560 - Lecture 319/09/2018

UNIVERSITY OF JYVÄSKYLÄ

HATEOAS …

20

REST Web Services

Add the links to Publication resource……@POST@Consumes(MediaType.APPLICATION_JSON)public Response addPublication(Publication publication , @Context UriInfo uriInfo){

Publication newPublication = publicationService.addPu blication(publication);String uri = uriInfo .getBaseUriBuilder() http://localhost:8080/MyRESTws/webapi/

.path( PublicationResource.class ) /publications

.path(Long.toString(publication.getId())) /{publicationId}

.build()

.toString();newPublication .addLink (uri," self ");…

// do similarly for ”profile” link…uri = uriInfo .getBaseUriBuilder() http://localhost:8080/MyRESTws/webapi/

.path(PublicationResource.class) /publications

.path( PublicationResource.class , "getCommentResource" ) /{publicationId}/comments

.resolveTemplate ("publicationId", publication.getId())

.build()

.toString();newPublication .addLink (uri,” comments ");String newId = String.valueOf(newPublication.getId()) ; URI uri = uriInfo.getAbsolutePathBuilder().path(newI d).build();return Response.created(uri)

.entity(newPublication)

.build();}

nested resource

TIES4560 - Lecture 319/09/2018

UNIVERSITY OF JYVÄSKYLÄ

Handle Exceptions …

21

REST Web Services

- constructor simplytakes a message andpass it to the parent.

public class DataNotFoundException extends RuntimeException{private static final long serialVersionUID = -6672553 621676928689L;public DataNotFoundException(String message){

super(message);}

}

- method throws anexception in case thereis no publication withrequested Id.

Create own classes for exceptions (e.g. DataNotFoundException) that extend RuntimeException.(add generated serialVersionUID since it is required by any RuntimeException)

public Publication getPublication(long id){Publication publication = publications.get(id);if(publication == null){ throw new DataNotFoundException ("Publication

with id "+id+" not found"); }return publication;

}

The service throws our exception to the resource handler, resource handler throws it further to theframework. To actually handle an exception thrown by above method, we have to make frameworkable to catch it and return a JSON response:o Create a JSON Response

o Map an exception to the JSON Response

TIES4560 - Lecture 319/09/2018

UNIVERSITY OF JYVÄSKYLÄ

Handle Exceptions …

22

REST Web Services

@Provider // the annotation preregisters our Mapper for JAX-R S to be usedpublic class DataNotFoundExceptionMapper implements ExceptionMapper <DataNotFoundException >{

@Overridepublic Response toResponse (DataNotFoundException ex) {

ErrorMessage errorMessage = new ErrorMessage(ex.getMe ssage(),404,"http://myDocs.org");return Response. status(Status. NOT_FOUND)

.entity(errorMessage)

.build();}

}

Create JSON Response by creating a new class ErrorMessage that will represent a JSON object…

@XmlRootElementpublic class ErrorMessage {

private String errorMessage;private int errorCode; //own custom error code private String documentation; //link to documentation regarding a error and it’s resolving public ErrorMessage(){}public ErrorMessage(String errorMessage, int errorCo de, String documentation) {

super();this.errorMessage = errorMessage;this.errorCode = errorCode;this.documentation = documentation;

}// below generate getters and setters for all the v ariable of the class…}

Map the exception to our Response using ExceptionMapper class.

TIES4560 - Lecture 319/09/2018

UNIVERSITY OF JYVÄSKYLÄ

Handle Exceptions …

23

REST Web Services

You may create a bunch of other Mappers for different Exceptions you would like to handle.Only thing you need is to decide which status code you would like to use for that case…

@Providerpublic class GenericExceptionMapper implements ExceptionMapper <Throwable >{

@Overridepublic Response toResponse ( Throwable ex) {

ErrorMessage errorMessage = new ErrorMessage(ex.getMe ssage(),500,"http://myDocs.org");return Response. status(Status. INTERNAL_SERVER_ERROR)

.entity(errorMessage)

.build();}

}

It is always good to have a Generic Exception Mapper that will handle whatever is thrown if there isno explicit mapper for it (using Throwable as a synonym to Catch All).

TIES4560 - Lecture 319/09/2018

UNIVERSITY OF JYVÄSKYLÄ

Handle Exceptions …

24

REST Web Services

JAX-RS has its own set of exceptions that are mapped to a status of a response. The parent class ofthose exceptions is WebApplicationException.

Do not forget to disable a Generic Exception Mapper since it will interfere with WebApplicationException handler

public Comment getComment(long publicationId, long commentId){Publication publication = publications.get(publicati onId);ErrorMessage errorMessage = new ErrorMessage("Not fou nd...", 404, "http://myDocs.org");Response response = Response. status(Status. NOT_FOUND)

.entity(errorMessage)

.build();if(publication == null){

throw new WebApplicationException (response);}Map<Long, Comment> comments = publications.get(publ icationId).getComments();Comment comment = comments.get(commentId);if(comment == null){

throw new NotFoundException (response);}return comment;

}

Since WebApplicationException is a parent class, there are a lot of classes that are inherited from itand provide custom responses and statuses (e.g. NotFoundException, InternalServerErrorException , etc.).

Check JAX-RS javadoc for more detailed descriptions of those subclasses

TIES4560 - Lecture 319/09/2018

UNIVERSITY OF JYVÄSKYLÄ

some HINTs …

25

REST Web Services

� Hide some of resource properties from XML or JSON conversion (useful for nested resources)…

� Use content negotiation feature… Playing around with various combinations of @Consumesand @Produces annotations for the methods, you may provide different implementations andlogics for service consumers who specify content type of sent request body and type ofacceptable response using corresponding values in the request header (Content-Type headerand Accept header respectively).

…@XmlRootElementpublic class Publication {

private long id;private String title;private Date published;private String mainAuthor;private List<Author> coAuthors = new ArrayList<>();private Map<Long, Comment> comments = new HashMap<>();private List<Link> links = new ArrayList<>();

public Publication(){}

@XmlTransientpublic Map<Long, Comment> getComments() {

return comments ;}

…}

Annotate fields that we do not want to be included in XML or JSON output with @XMLTransient.

TIES4560 - Lecture 319/09/2018