RESTful Java with JAX-RS 2.0 (2013)
Part II. JAX-RS Workbook
Chapter 26. Examples for Chapter 12
In Chapter 12, you learned how filters and interceptors can be used to augment your JAX-RS service classes. In this chapter, we through how to build and run some of the examples shown in that chapter. Specifically, we’ll go write a ContainerResponseFilter, a DynamicFeature, and an implementation of a WriterInterceptor. If you want to see examples of a ClientRequestFilter and a ContainerRequestFilter bound via a @NameBinding, check out Chapter 29.
Example ex12_1 : ContainerResponseFilter and DynamicFeature
ex12_1 implements the @MaxAge and CacheControlFilter example in the section DynamicFeature.
The Server Code
The @MaxAge, CacheControlFilter, and MaxAgeFeature classes were explained pretty well in DynamicFeature, so I’m not going to go into them again here. We applied the @MaxAge annotation to the CustomerResource.getCustomer() method:
src/main/java/com/restfully/shop/services/CustomerResource
@GET
@Path("{id}")
@Produces("application/xml")
@MaxAge(500)
publicCustomergetCustomer(@PathParam("id")intid)
{
Customercustomer=customerDB.get(id);
if(customer==null)
{
thrownewWebApplicationException(Response.Status.NOT_FOUND);
}
returncustomer;
}
Applying this annotation to this method will cause the CacheControlFilter to be bound to this method when it is executed. The filter will cause a Cache-Control header to be added to the HTTP response with a max age of 500 seconds. Let’s also take a look at how these classes are registered:
src/main/java/com/restfully/shop/services/ShoppingApplication.java
@ApplicationPath("/services")
publicclassShoppingApplicationextendsApplication
{
privateSet<Object>singletons=newHashSet<Object>();
privateSet<Class<?>>classes=newHashSet<Class<?>>();
publicShoppingApplication()
{
singletons.add(newCustomerResource());
classes.add(MaxAgeFeature.class);
}
@Override
publicSet<Class<?>>getClasses()
{
returnclasses;
}
@Override
publicSet<Object>getSingletons()
{
returnsingletons;
}
}
Notice that we only register the MaxAgeFeature class. This class handles the registration of the CacheControlFilter if the JAX-RS method is annotated with @MaxAge.
The Client Code
The client code hasn’t changed much from other examples. We first start off by creating a Customer on the server. We then do a GET request to get the customer, checking for the Cache-Control header generated by the CacheControlFilter on the server side:
src/test/java/com/restfully/shop/test/CustomerResourceTest.java
...
System.out.println("*** GET Created Customer **");
response=client.target(location).request().get();
CacheControlcc=CacheControl.valueOf(
response.getHeaderString(HttpHeaders.CACHE_CONTROL));
System.out.println("Max age: "+cc.getMaxAge());
There is nothing really special about this code other than it shows you how to create a CacheControl object from a header string.
Build and Run the Example Program
Perform the following steps:
1. Open a command prompt or shell terminal and change to the ex12_1 directory of the workbook example code.
2. Make sure your PATH is set up to include both the JDK and Maven, as described in Chapter 17.
3. Perform the build and run the example by typing maven install.
Example ex12_2: Implementing a WriterInterceptor
In this example, we implement support for generating the Content-MD5 header. This header is defined in the HTTP 1.1 specification. Its purpose is to provide an additional end-to-end message integrity check of the HTTP message body. While not proof against malicious attacks, it’s a good way to detect accidental modification of the message body in transit just in case it was transformed by a proxy, cache, or some other intermediary. Well, OK, I admit it’s a pretty lame header, but let’s show how we can implement support for it using a WriterInterceptor:
publicclassContentMD5WriterimplementsWriterInterceptor
{
@Override
publicvoidaroundWriteTo(WriterInterceptorContextcontext)
throwsIOException,WebApplicationException
{
MessageDigestdigest=null;
try
{
digest=MessageDigest.getInstance("MD5");
}
catch(NoSuchAlgorithmExceptione)
{
thrownewIllegalArgumentException(e);
}
To implement a WriterInterceptor, we must define an aroundWriteTo() method. We start off in this method by creating a java.security.MessageDigest. We’ll use this class to create an MD5 hash of the entity we’re marshalling.
ByteArrayOutputStreambuffer=newByteArrayOutputStream();
DigestOutputStreamdigestStream=newDigestOutputStream(buffer,digest);
OutputStreamold=context.getOutputStream();
context.setOutputStream(digestStream);
Next we create a java.io.ByteArrayOutputStream and wrap it with a java.security.DigestOutputStream. The MD5 hash is created from the marshalled bytes of the entity. We need to buffer this marshalling in memory, as we need to set the Content-MD5 before the entity is sent across the wire. We override the OutputStream of the ContainerRequestContext so that the MessageBodyWriter that performs the marshalling uses the DigestOutputStream.
try
{
context.proceed();
byte[]hash=digest.digest();
StringencodedHash=Base64.encodeBytes(hash);
context.getHeaders().putSingle("Content-MD5",encodedHash);
Next, context.proceed() is invoked. This continues with the interceptor chain and until the underlying MessageBodyWriter is invoked. After proceed() finishes, we obtain the hash from the MessageDigest and Base-64–encode it using a RESTEasy utility class. We then set theContent-MD5 header value with this encoded string.
byte[]content=buffer.toByteArray();
old.write(content);
}
After the header is set, we write the buffered content to the real OutputStream.
finally
{
context.setOutputStream(old);
}
}
}
Finally, if you override the context’s OutputStream it is always best practice to revert it after you finish intercepting. We do this in the finally block.
We enable this interceptor for all requests that return an entity by registering it within our Application class. I won’t go over this code, as you should be familiar with how to do this by now.
The Client Code
The client code is basically the same as ex12_1 except we are viewing the returned Content-MD5 header:
src/test/java/com/restfully/shop/test/CustomerResourceTest.java
@Test
publicvoidtestCustomerResource()throwsException
{
...
System.out.println("*** GET Created Customer **");
response=client.target(location).request().get();
Stringmd5=response.getHeaderString("Content-MD5");
System.out.println("Content-MD5: "+md5);
}
Build and Run the Example Program
Perform the following steps:
1. Open a command prompt or shell terminal and change to the ex12_2 directory of the workbook example code.
2. Make sure your PATH is set up to include both the JDK and Maven, as described in Chapter 17.
3. Perform the build and run the example by typing maven install.
All materials on the site are licensed Creative Commons Attribution-Sharealike 3.0 Unported CC BY-SA 3.0 & GNU Free Documentation License (GFDL)
If you are the copyright holder of any material contained on our site and intend to remove it, please contact our site administrator for approval.
© 2016-2026 All site design rights belong to S.Y.A.