JAX-RS annotations
The most important annotations in JAX-RS are listed in the following table:
Meaning
@PATH
Sets the path to base URL + /your_path. The base URL is based on your application name, the servlet, and the URL pattern from the web.xml configuration file.
@POST
Indicates that the following method will answer to an HTTP POST request.
@GET
Indicates that the following method will answer to an HTTP GET request.
@PUT
Indicates that the following method will answer to an HTTP PUT request.
@DELETE
Indicates that the following method will answer to an HTTP DELETE request.
@Produces
Defines which MIME type is delivered by a method annotated with @GET. It can be "text/plain", "application/xml", or "application/json" for example.
@Consumes
Defines which MIME type is consumed by this method.
@PathParam
Used to extract (inject) values from the URL into a method parameter. This way you inject, for example, the ID of a resource into the method to get the correct object.
@QueryParam
Used to extract (inject) the URI query parameter coming with the request. The Uniform Resource Identifier (URI) is a string of characters used to identify a name or a resource on the Internet.
@DefaultValue
Specifies a default value. Useful for optional parameters.
@CookieParam
Annotation that allows you to inject cookies sent by a client request into your JAX-RS resource methods.
@Provider
The @Provider annotation is used for anything that is of interest to the JAX-RS runtime, such as MessageBodyReader and MessageBodyWriter. For HTTP requests, MessageBodyReader is used to map an HTTP request entity body to method parameters. On the response side, a return value is mapped to an HTTP response entity body by using MessageBodyWriter. If the application needs to supply additional metadata, such as HTTP headers or a different status code, a method can return a response that wraps the entity and that can be built using Response.ResponseBuilder.
@ApplicationPath
The @ApplicationPath annotation is used to define the URL mapping for the application. The path specified by @ApplicationPath is the base URI for all resource URIs specified by @Path annotations in the resource class. You may only apply @ApplicationPath to a subclass of javax.ws.rs.core.Application.
The annotation names might not be clear or self-explanatory at first glance. Let's look at the sample REST endpoint implementation, and it will become a lot clearer. The application itself is marked with the @ApplicationPath annotation. By default, during start-up of the JEE compliant server, JAX-RS will scan all the resources in a Java application archive to find the exposed endpoints. We can override the getClasses() method to manually register the resource classes in the application with the JAX-RS runtime. You can see it in the following example:
package pl.finsys.jaxrs_example @ApplicationPath("/myApp") public class MyApplication extends Application { @Override public Set<Class<?>> getClasses() { final Set<Class<?>> classes = new HashSet<>(); classes.add(MyBeansExposure.class); return classes; } }
In the previous example, we just register a REST application, giving it the /myApp base URI path. There is only one REST method handler (endpoint), the MyBeansExposure class, which we register within the REST application. The simplified REST endpoint, implemented in the separate Java class can look same as this:
package pl.finsys.jaxrs_example import javax.annotation.PostConstruct; import javax.enterprise.context.ApplicationScoped; import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.container.ResourceContext; import javax.ws.rs.core.Context; import javax.ws.rs.core.Response; @ApplicationScoped @Path("beans") public class MyBeansExposure { @Context ResourceContext rc; private Map<String, Bean> myBeans; @GET @Produces("application/json") public Collection<Bean> allBeans() { return Response.status(200).entity(myBeans.values()).build(); } @GET @Produces("application/json") @Path("{id}") public Bean singleBean(@PathParam("id") String id) { return Response.status(200).entity(myBeans.get(id)).build(); } @POST @Consumes("application/json") public Response add(Bean bean) { if (bean != null) { myBeans.put(bean.getName(), bean); } final URI id = URI.create(bean.getName()); return Response.created(id).build(); } @DELETE @Path("{id}") public void remove(@PathParam("id") String id) { myBeans.remove(id); } }
As you can see in the previous example, we have class-level @Path annotation. Every method marked with @GET, @PUT, @DELETE, or @POST annotations will respond to a call to the URI starting with the base @Path. Additionally, we can use the @Path annotation on a method level; it will, kind of, extend the URI path that the specific method responds to. In our example, the HTTP GET executed with a URI path myApp/beans will call the allBeans() method, returning the collection of beans in JSON format. The GET method executed using the myApp/beans/12 URI path will call the singleBean() method, and the {id} parameter will be transferred to the method because of the @PathParam annotation. Calling the HTTP DELETE method on the myApp|beans|12 URI will execute the remove() method with an id parameter value 12. To give you almost infinite flexibility, the @Path annotation supports regular expressions. Consider the following example:
package pl.finsys.jaxrs_example import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.core.Response; @Stateless @Path("/books") public class BookResource { @GET @Path("{title : [a-zA-Z][a-zA-Z_0-9]}") public Response getBookByTitle(@PathParam("title") String title) { return Response.status(200).entity("getBookByTitle is called, title : " + title).build(); } @GET @Path("{isbn : \\d+}") public Response getBookByISBN(@PathParam("isbn") String isbn) { return Response.status(200).entity("getBookByISBN is called, isbn : " + isbn).build(); } }
In the previous example, we have two @GET mappings, each with the same /books/ path mapped. The first one, with the /{title : [a-zA-Z][a-zA-Z_0-9]} parameter, will react only to letters and numbers. The second one, with the /{isbn : \\d+} parameter, will be executed only if you provide a number when calling the URI. As you can see, we have mapped two identical paths, but each one will react to a different type of incoming path parameter.
Apart from using @PathParam, we can also use @QueryParams to supply parameters using the request parameters. Take a look at the following example:
package pl.finsys.jaxrs_example import java.util.List; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.core.Context; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; @Stateless @Path("/users") public class UserResource { @EJB private UserService userService; @GET @Path("/query") @Produces("application/json") public Response getUsers( @QueryParam("from") int from, @QueryParam("to") int to, @QueryParam("orderBy") List<String> orderBy)) { List<User> users = userService.getUsers(from, to, orderBy); return Response.status(200).entity(users).build(); } }
In the previous example, when calling HTTP GET on the /users/query?from=1&to=100&orderBy=name JAX-RS will pass the URI parameters into the getUsers() method parameter and call the injected userService to get the data (for example, from a database).
To package the JAX-RS application, we will need a Maven pom.xml file, of course. In its simplest form, it can look the same as the following:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>pl.finsys</groupId> <artifactId>jee7-rest</artifactId> <packaging>war</packaging> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>javax</groupId> <artifactId>javaee-api</artifactId> <version>7.0</version> <scope>provided</scope> </dependency> </dependencies> <build> <finalName>jee7-rest</finalName> </build> <properties> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <failOnMissingWebXml>false</failOnMissingWebXml> </properties> </project>
Creating JEE7 REST services is quite straightforward, isn't it? By building the project and deploying it to a JEE compliant application server, we have a couple of endpoints ready and waiting to be called over HTTP. But there's an even more simple and faster approach. In the era of microservices, we would want to create individual components faster with a minimal overhead, after all. Here comes Spring Boot. Let's look at it now.