Table of Contents
Jersey provides an extension to support the Model-View-Controller (MVC) design pattern. In the context of Jersey components, the Controller from the MVC pattern corresponds to a resource class or method, the View to a template bound to the resource class or method, and the Model to a Java object (or a Java bean) returned from a resource method.
Jersey MVC templating support is provided by Jersey as a set of (three) extension modules:
The base module that provides API and extension SPI for MVC templating support in Jersey. This module is required by any particular MVC templating engine integration module that implements the exposed SPI.
An integration module with Freemarker-based templating engine. The module provides a custom
TemplateProcessor for Freemarker templates and a set of related engine-specific
configuration properties.
An integration module for JSP-based templating engine. The module provides a custom
TemplateProcessor for JSP templates, custom tag implementation and a set of
related engine-specific configuration properties.
In a typical set-up projects using the Jersey MVC templating support would depend on the base module that
provides the API and SPI and a single templating engine module for the templating engine of your choice.
These modules need to be mentioned explicitly in your pom.xml file.
If you want to use just templating API infrastructure provided by Jersey for the MVC templating support in order to implement your custom support for a templating engine other than the ones provided by Jersey (JSP/Freemarker), you will need to add the base jersey-mvc module into the list of your dependencies:
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-mvc</artifactId>
<version>2.1</version>
</dependency>
To use one of the templating engines for which Jersey provides the integration implementation (JSP/Freemarker)
in your project, you need to add the jersey-mvc-jsp or jersey-mvc-freemarker module to your pom.xml
respectively:
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-mvc-jsp</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-mvc-freemarker</artifactId>
<version>2.1</version>
</dependency>
Both of these modules transitively depend on the base jersey-mvc, so it is not necessary to add
the base jersey-mvc module explicitly into your dependency list, however it is a recommended
Maven practice to do so.
If you are not using Maven you need to make sure to have all required transitive dependencies (see jersey-mvc/jersey-mvc-freemarker/jersey-mvc-jsp) on the classpath.
To use capabilities of Jersey MVC templating support in your JAX-RS/Jersey application you need to register
Features provided by the modules mentioned above. For jersey-mvc it is
MvcFeature, for jersey-mvc-jsp it's JspMvcFeature and
for jersey-mvc-freemarker it is FreemarkerMvcFeature.
Both JspMvcFeature and FreemarkerMvcFeature also register
MvcFeature so you don't need to register it explicitly when using these
JSP/Freemarker modules.
Example 17.1. Registering MvcFeature
new ResourceConfig()
.register(org.glassfish.jersey.server.mvc.MvcFeature.class)
// Further configuration of ResourceConfig.
.register( ... );
Example 17.2. Registering JspMvcFeature
new ResourceConfig()
.register(org.glassfish.jersey.server.mvc.jsp.JspMvcFeature.class)
// Further configuration of ResourceConfig.
.register( ... );
Jersey web applications that want to use MVC templating support feature should be registered as Servlet
filters rather than Servlets in the application's web.xml. The
web.xml-less deployment style introduced in Servlet 3.0 is not supported at the moment
for web applications that require use of Jersey MVC templating support.
Each of the three MVC modules contains a *Properties
(e.g. FreemarkerMvcProperties) file which defines a set of properties that could be
set in a JAX-RS Application / ResourceConfig in order to take effect,
see the Example 17.3, “Setting MvcProperties.TEMPLATE_BASE_PATH value in ResourceConfig” and Example 17.4, “Setting FreemarkerMvcProperties.TEMPLATE_BASE_PATH value in web.xml”.
Following list contains description of the available properties:
MvcProperties.TEMPLATE_BASE_PATH - "jersey.config.server.mvc.templateBasepath"
The base path where templates are located.
FreemarkerMvcProperties.TEMPLATE_BASE_PATH - "jersey.config.server.mvc.templateBasepath.freemarker"
The base path where Freemarker templates are located.
JspMvcProperties.TEMPLATE_BASE_PATH - "jersey.config.server.mvc.templateBasepath.jsp"
The base path where JSP templates are located.
Example 17.3. Setting MvcProperties.TEMPLATE_BASE_PATH value in ResourceConfig
new ResourceConfig()
.property(MvcProperties.TEMPLATE_BASE_PATH, "templates")
.register(MvcFeature.class)
// Further configuration of ResourceConfig.
.register( ... );
Example 17.4. Setting FreemarkerMvcProperties.TEMPLATE_BASE_PATH value in web.xml
<servlet>
<servlet-name>org.glassfish.jersey.examples.freemarker.MyApplication</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>org.glassfish.jersey.examples.freemarker.MyApplication</param-value>
</init-param>
<init-param>
<param-name>jersey.config.server.mvc.templateBasePath.freemarker</param-name>
<param-value>freemarker</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
Some of the passages/examples from this and the next section was taken from MVCJ blog article written by Paul Sandoz earlier.
In Jersey 2.0, the base MVC API (excluding the SPI part) consists of two classes (in the
org.glassfish.jersey.server.mvc package in base MVC module) that we will explore in more detail
now, namely Viewable and @Template.
These classes determines which approach (explicit/implicit) you would be taking when working with Jersey MVC
templating support.
In this approach a resource method explicitly returns a reference to a view template and the data model to be
used. For this purpose the Viewable class has been introduced in Jersey 1 and is also
present (under a different package) in Jersey 2. A simple example of usage can be seen in
Example 17.5, “Using Viewable in a resource class”.
Example 17.5. Using Viewable in a resource class
package com.foo;
@Path("foo")
public class Foo {
@GET
public Viewable get() {
return new Viewable("index", "FOO");
}
}
In this example, the Foo JAX-RS resource class is the controller and the
Viewable instance encapsulates the provided data model ("FOO" string)
and a named reference to the associated view template ("index").
The template name reference "index" is a relative value that Jersey will resolve to its
absolute template reference using the fully qualified class name of Foo (more on resolving
relative template name to the absolute one can be found in the JavaDoc of Viewable class),
which, in our case, is:
"/com/foo/Foo/index"
Jersey will then search all the registered template processors (see Section 17.5, “Custom Templating Engines”) to find a template processor that can resolve the absolute template reference further to a "processable" template reference. If a template processor is found then the "processable" template is processed using the supplied data model.
Let's change the resource GET method in our Foo resource a little:
Example 17.6. Using absolute path to template in Viewable
@GET
public Viewable get() {
return new Viewable("/index", "FOO");
}
In this case, since the template reference begins with "/", Jersey will consider the reference
to be absolute already and will not attempt to absolutize it again. The reference will be used "as is" when
resolving it to a "processable" template reference as described earlier.
All HTTP methods may return Viewable instances. Thus a POST method may
return a template reference to a template that produces a view that is the result of processing an
HTML Form.
A resource class can have templates implicitly associated with it via @Template annotation.
For example, take a look at the resource class listing in Example 17.7, “Using @Template on a resource class”.
Example 17.7. Using @Template on a resource class
@Path("foo")
@Template
public class Foo {
public String getFoo() {
return "FOO";
}
}
The example above uses a lot of conventions and requires some more explanation. First of all, you may have
noticed that there is no resource method defined in this JAX-RS resource. Also, there is no template
reference defined.
In this case, since the @Template annotation placed on the resource class does not
contain any information, the default relative template reference "index" will be used. Later
it will get resolved to an absolute "/com/foo/Foo/index" template reference.
As for the missing resource methods, a default @GET method will be implicitly generated by Jersey
for the Foo resource (our MVC Controller). The implementation of the implicitly added
resource method performs the equivalent of the following explicit resource method:
@GET
public Viewable get() {
return new Viewable("index", this);
}
As you can see, the resource class serves in this case also as a model. Producible media types are determined
based on the @Produces annotation declared on the resource class, if any.
In case of a resource class-based implicit MVC view template, the controller is also the model. In this
case the template reference "index" is special, it is the template reference
associated with the controller itself.
Implicit sub-resource templates are also supported, for example, for a template reference
"bar" that resolves to an absolute template reference "/com/foo/Foo/bar"
that in turn resolves to a processable template reference. Following @GET method is also implicitly
added to the Foo controller that performs the equivalent of the following explicit
sub-resource method:
@GET
@Path("{implicit-view-path-parameter}")
public Viewable get(@PathParameter("{implicit-view-path-parameter}") String template) {
return new Viewable(template, this);
}
In other words, a HTTP GET request to a "/foo/bar" would be handled by this
auto-generated method in the Foo resource and would delegate the request to a registered
template processor supports processing of the absolute template reference
"/com/foo/Foo/bar", while the model is still an instance of the JAX-RS resource class
Foo.
In case a resource method is annotated with @Template annotation then the return
value of the method defines the MVC model part. The processing of such a method is then essentially the same
as if the return type of the method was an instance of the Viewable class.
If a method is annotated with @Template and is also returning a
Viewable instance then the values (resolvingClass) from the
Viewable instance take precedence over those defined in the annotation. Producible
media types are determined from the method's @Produces annotation.
Implicit view templates support works dynamically (as is the case for explicit MVC) so it is possible (if the deployment system is configured correctly) to add or modify templates while the application is running.
As stated earlier, Jersey provides support for JSP templates in jersey-mvc-jsp extension module. There is a JSP template processor that resolves absolute template references to processable template references represented as JSP pages as follows:
Procedure 17.1. Resolving JSP processable template reference
if the absolute template reference does not end in ".jsp" append this suffix to the
reference; and
if Servlet.getResource returns a non-null value for the appended reference then
return the appended reference as the processable template reference otherwise return null
(to indicate the absolute reference has not been resolved by the JSP template processor).
Thus the absolute template reference "/com/foo/Foo/index" would be resolved to
"/com/foo/Foo/index.jsp", provided there exists a "/com/foo/Foo/index.jsp"
JSP page in the web application.
Jersey will assign the model instance to the attribute named "it". So in the case of the implicit
example it is possible to referece the foo property on the Foo resource
from the JSP template as follows:
<h1>${it.foo}</h1>
To add support for other (custom) templating engines into Jersey MVC Templating facility, you need to implement the TemplateProcessor and register this class into your application.
When writing template processors it is recommend that you use an appropriate unique suffix for the processable template references. In such case it is then possible to easily support mixing of multiple templating engines in a single application without any conflicts.
Example 17.8. Custom TemplateProcessor
@Provider
class MyTemplateProcessor implements TemplateProcessor<String> {
@Override
public String resolve(String path, final MediaType mediaType) {
final String extension = ".testp";
if (!path.endsWith(extension)) {
path = path + extension;
}
final URL u = this.getClass().getResource(path);
return u == null ? null : path;
}
@Override
public void writeTo(String templateReference,
Viewable viewable,
MediaType mediaType,
OutputStream out) throws IOException {
final PrintStream ps = new PrintStream(out);
ps.print("path=");
ps.print(templateReference);
ps.println();
ps.print("model=");
ps.print(viewable.getModel().toString());
ps.println();
}
}
Example 17.9. Registering custom TemplateProcessor
new ResourceConfig()
.register(MyTemplateProcessor.class)
// Further configuration of ResourceConfig.
.register( ... );
To see an example of MVC (JSP) templating support in Jersey refer to the MVC (Bookstore) example.