Links: Table of Contents | Single HTML

Chapter 17. MVC Templates

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.

17.1. Dependencies

Jersey MVC templating support is provided by Jersey as a set of (three) extension modules:

  • jersey-mvc

    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.

  • jersey-mvc-freemarker

    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.

  • jersey-mvc-jsp

    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.

Note

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.

17.2. Registration and Configuration

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.

Note

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( ... );


Important

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>


17.3. Explicit vs. Implicit View Templates

Note

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.

17.3.1. Viewable - Explicit View Templates

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.

Tip

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.

17.3.2. @Template - Implicit View Templates

17.3.2.1. Resource classes

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.

Note

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.

17.3.2.2. Resource methods

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.

Note

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.

17.4. JSP

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

  1. if the absolute template reference does not end in ".jsp" append this suffix to the reference; and

  2. 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>

17.5. Custom Templating Engines

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.

Tip

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( ... );


17.6. Other Examples

To see an example of MVC (JSP) templating support in Jersey refer to the MVC (Bookstore) example.