Scott
Leberknight
RESTful
Web Services with
Jersey
"Jersey RESTful Web Services framework is
[an] open source, production quality framework
for developing RESTful Web Services in Java..."
Jersey...
...produces & consumes
RESTful web services
(in Java, mostly pain-free)
...is the JAX-RS reference
implementation
(and extends JAX-RS with
additional features)
JAX-RS?
Java API for RESTful Services
It's about the
Resources,
stupid...
"A JAX-RS resource is an annotated
POJO that provides so-called resource
methods that are able to handle HTTP
requests for URI paths that the resource
is bound to."
@Path("/simple")	
public class SimpleResource {	
!
@GET	
@Produces("text/plain")	
public String get() {	
return "it's quite simple, you see?";	
}	
}
resource class
Root Resources
POJO (plain-old Java object)
Annotated with @Path and/or
method designator (e.g. @GET)
@Path
Specifies the URI at which a
resource is located
URI template capability
(via @PathParam)
URI path template
@Path("/users/{userid}")	
@GET	
@Produces("application/json")	
public User user(@PathParam("userid") String id) {	
return _userRepository.getUser(id);	
}
Method designators
Represent the HTTP method that
resource methods respond to
@GET	
@Produces("text/plain")	
public String get() {	
return "this is it!";	
}
HTTP method designator
@Produces
Specifies the MIME type of
representations that a resource
produces
Media Types
MediaType class contains constants
for common MIME types...
Media Types
MediaType.TEXT_PLAIN	
!
MediaType.APPLICATION_JSON	
!
MediaType.APPLICATION_XML	
!
MediaType.MULTIPART_FORM_DATA	
!
// and more...
@Consumes
Specifies the MIME type of
representations that a resource
can consume
@Consumes
@Path("/users")	
@POST	
@Consumes(MediaType.APPLICATION_JSON)	
public Response create(User user) {	
Long id = _userRepository.create(user);	
URI uri = URIBuilder.fromURI("/users")	
.path(id).build();	
return Response.created(uri).build();	
}
Sub-Resources & Paths
methods annotated with @Path in
root resource classes, or...
methods returning an (annotated)
resource class
@Path("/myapp")	
public class UserResource { // root resource	
@Path("users")	
@GET	
@Produces(MediaType.TEXT_HTML)	
public String getUsersAsHtml() { ... } 	
!
@Path("users.xml")	
@GET	
@Produces(MediaType.APPLICATION_XML)	
public String getUsersAsXml() { ... }	
!
@Path("users.json")	
@GET	
@Produces(MediaType.APPLICATION_JSON)	
public String getUsersAsXml() { ... }	
}
Sub-resource methods
Sub-resource URIs
/myapp/users
/myapp/users.xml
/myapp/users.json
Injection
Use annotations to specify data to
be injected...
Query & form parameters
Headers, cookies, etc.
Security context
...and more
@*Param
QueryParam
HeaderParam
MatrixParam
FormParam
CookieParam
BeanParam
@QueryParam
@Path("query-params")	
@GET	
public String colors (@QueryParam("red") int red,	
@QueryParam("green") int green,	
@QueryParam("blue") int blue) {	
return String.format("RGB(%d,%d,%d)", red, green, blue);	
}
@HeaderParam
@Path("header-params")	
@GET	
public String headers(@HeaderParam("Accept") String accept,	
@HeaderParam("X-Foo") String foo) {	
	
return String.format("Accept: %s, X-Foo: %s",	
accept, foo);	
}
@MatrixParam
@Path("matrix-params")	
@GET	
public String matrixParams(@MatrixParam("red") int red,	
@MatrixParam("green") int green,	
@MatrixParam("blue") int blue) {	
return String.format("RGB(%d,%d,%d)", red, green, blue);	
}
What's a "matrix param"?
http://www.w3.org/DesignIssues/MatrixURIs.html
Also, see Tim-Berners Lee on matrix param
design issues circa 1996...
acme.com/rest/samples/color;red=25;green=78;blue=192
Parameters separate by semi-colons, e.g.
Not widely used, supported (or known)
What if a parameter isn't
supplied???
@DefaultValue
@Path("defaults")	
@GET	
public String defaults(	
@DefaultValue("Orange") @QueryParam("color") String color,
@DefaultValue(MediaType.APPLICATION_JSON)	
@HeaderParam("Accept") String accept) {	
!
return String.format("color: %s, Accept: %s", color, accept);	
}
@FormParam
@Path("form-params")	
@POST	
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)	
public Response formParams(@FormParam("first") String firstName,	
@FormParam("last") String lastName) {	
!
String entity = String.format("%s %s", firstName, lastName);	
return Response.ok(entity).build();	
}
@BeanParam
@Path("bean-params")	
@POST	
public Response beanParams(@BeanParam User user) {	
!
String entity = String.format("User: %s %s",	
user.getFirstName(), user.getLastName());	
return Response.ok(entity).build();	
}
@BeanParam class
public class User {	
!
@QueryParam("first")	
@DefaultValue("John")	
private String _firstName;	
!
@QueryParam("last")	
@DefaultValue("Doe")	
private String _lastName;	
!
public String getFirstName() {	
return _firstName;	
}	
!
public String getLastName() {	
return _lastName;	
}	
}
@Context
Use to obtain information
related to request/response
UriInfo
@Path("context-uri-info/{thing}")	
@GET	
public String uriInfo(@Context UriInfo info) {	
URI baseUri = info.getBaseUri();	
MultivaluedMap<String, String> queryParams = info.getQueryParameters();	
MultivaluedMap<String, String> pathParams = info.getPathParameters();	
!
return String.format("base URI: %s, query params: %s, path params: %s",	
baseUri, queryParams.entrySet(), pathParams.entrySet());	
}
HttpHeaders
@Path("http-headers")	
@GET	
public String httpHeaders(@Context HttpHeaders headers) {	
List<MediaType> acceptableMediaTypes = 	
headers.getAcceptableMediaTypes();	
String xFoo = headers.getHeaderString("X-Foo");	
!
return String.format("acceptableMediaTypes: %s, X-Foo: %s",	
acceptableMediaTypes, xFoo);	
}
Raw form parameters
@Path("raw-form")	
@POST	
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)	
public Response rawForm(MultivaluedMap<String, String> formParams) {	
!
String entity = formParams.entrySet().toString();	
return Response.ok(entity).build();	
}
(Note: don't actually need @Context in above)
Resource Life Cycle
Scopes
Per-Request (default)
new instance created on each request
Per-lookup
new instance created on each lookup
(perhaps within same request)
Singleton
only one instance for entire app
JAX-RS Application
Model
Defines components of a JAX-RS
application, i.e. resources
Application class
Independent of deployment environment
JAX-RS apps provide concrete
implementation class
Simple Application
public class SampleApplication extends Application {	
!
@Override	
public Set<Class<?>> getClasses() {	
Set<Class<?>> classes = new HashSet<>();	
!
classes.add(SampleResource.class);	
classes.add(SimpleResource.class);	
classes.add(UserResource.class);	
!
return classes;	
}	
}
Jersey's implementation of Application
Jersey ResourceConfig
Extend or create programmatically
Provides additional features like
resource classpath scanning
Jersey ResourceConfig
public class SampleJerseyApp extends ResourceConfig {	
!
public SampleJerseyApp() {	
// scan classpath for resources	
packages("com.acme.rest", "com.foo.services");	
!
// register filters	
register(CsrfProtectionFilter.class);	
register(UriConnegFilter.class);	
register(HttpMethodOverrideFilter.class);	
!
// other configuration, etc.	
}	
}
Deployment Options
JavaSE
(e.g. Grizzly, Jetty, Simple, etc.)
Servlet container
(e.g. Tomcat, Jetty)
JavaEE
(e.g. JBoss, etc.)
OSGi
Using Grizzly
HTTP Server
(JavaSE deployment)
public class Server {	
public static final String BASE_URI = "http://localhost:8080/rest/";	
!
public static HttpServer startServer() {	
ResourceConfig config = new ResourceConfig()	
.packages("com.acme.rest")	
.register(CsrfProtectionFilter.class)	
.register(UriConnegFilter.class)	
.register(HttpMethodOverrideFilter.class);	
!
// create a new Grizzly HTTP server rooted at BASE_URI	
return GrizzlyHttpServerFactory	
.createHttpServer(URI.create(BASE_URI), config);	
}	
!
public static void main(String[] args) throws Exception {	
final HttpServer server = startServer();	
System.out.printf("Jersey app started with WADL available at "	
+ "%sapplication.wadlnHit enter to stop it...n", BASE_URI);	
System.in.read();	
server.shutdownNow();	
}	
}
Grizzly Server
Client API
Jersey provides a client API to consume
RESTful services
Written in fluent-style
(method chaining)
Supports URI templates, forms, etc.
Client client = ClientBuilder.newClient();	
WebTarget target = client.target("http://localhost:8080/rest")	
.path("sample/query-params");	
String response = target.queryParam("red", 0)	
.queryParam("green", 113)	
.queryParam("blue", 195)	
.request()	
.get(String.class);
Client API example
Representations
...supports common media types like
JSON, XML, etc.
...implementations provide ways to
convert to/from various media
representations
JAX-RS...
...supplies support out-of-box for XML,
JSON, etc.
...uses MOXy as the default provider for
JSON and XML conversion
Jersey...
@Path("/")	
public class UserResource {	
!
@Path("/users.json") @GET @Produces(MediaType.APPLICATION_JSON)	
public Collection<User> users() {	
return _userRepository.getAllUsers();	
}	
!
@Path("/users/{userid}.json") @GET	
@Produces(MediaType.APPLICATION_JSON)	
public User user(@PathParam("userid") Integer id) {	
return _userRepository.getUser(id);	
}	
!
@Path("/users.json") @POST @Consumes(MediaType.APPLICATION_JSON)	
public Response create(User user) throws Exception {	
Long id = _userRepository.save(user);	
URI uri = UriBuilder.fromUri("users").path(id).build();	
return Response.created(uri).build();	
}	
!
// more resource methods...	
}
Automatic JSON support
Building Responses
@POST	
@Consumes("application/xml")	
public Response post(String content) {	
  URI createdUri = buildUriFor(content);	
  String createdContent = create(content);	
  	
return Response.created(createdUri)	
.entity(Entity.text(createdContent)).build();	
}
& more to explore...
Security
JerseyTest
Asynchronous
API
Filters &
Interceptors
Bean Validation
MVC templates
...and more (see Jersey user guide)
References
https://jersey.java.net
Jersey web site
https://jersey.java.net/documentation/latest/index.html
Jersey user guide (latest)
https://grizzly.java.net/
Project Grizzly web site
https://jersey.java.net/apidocs/latest/jersey/index.html
Jersey API docs
https://jax-rs-spec.java.net
JAX-RS web site
My Info
twitter: sleberknight
www.sleberknight.com/blog
scott dot leberknight at gmail dot com

RESTful Web Services with Jersey