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.0</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.0</version> </dependency>
<dependency> <groupId>org.glassfish.jersey.ext</groupId> <artifactId>jersey-mvc-freemarker</artifactId> <version>2.0</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.