Model-View-Controller (MVC 1.0) in JavaEE 8

May 22, 2015-5 min read

JavaEE 8 is scheduled to ship with a new model-view-controller API, named MVC 1.0. It offers a way to build action-based web frameworks on the Java EE platform. The MVC API is built on top of JAX-RS and integrates seamlessly with CDI and Bean Validation. This post serves as a brief overview to this new Java MVC API.

MVC 1.0 is described in JSR 371. Its reference implementation is called ozark, a version of which is already available at:

<dependency>
<groupId>com.oracle.ozark</groupId>
<artifactId>ozark</artifactId>
<version>1.0.0-m01</version>
<scope>compile</scope>
</dependency>

You will need a relatively new version of glassfish to see ozark in action (version 4.1 build 13 worked fine for me). Also, the dependency scope must be set to compile, since ozark is not yet part of glassfish server.

A sample application with source code can be found at [https://github.com/gedim21/jee-mvc-app](Model-View-Controller (MVC 1.0) in JavaEE 8 ). Run mvn package embedded-glassfish:run and point your browser at localhost:8888 to see the application running.

As you can probably imagine, the MVC APIs main components are Controllers, Models and Views.

Controllers

An MVC controller is simply a JAX-RS resource, annotated with the @javax.mvc.Controller annotation. For example, a very simple controller can be defined as:

import javax.mvc.Controller;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
@Path("hello")
public class HelloBean {
@GET
@Controller
public String hello() {
return "/hello.jsp";
}
}

The @javax.mvc.Controller annotation can also be applied to the class, in which case all resource methods are treated as controllers.

Return Types

A Controller method can have one of four return types:

String

As in the example above, when a String is returned by a controller, it is interpreted by the API as a path to the view.

Void

If the controller’s return type is void, then it must be decorated with the@javax.mvc.View annotation, which contains the path to a view:

@Path("hello")
public class HelloBean {
@GET
@Controller
@View("/hello.jsp")
public void hello() {
}
}

Viewable

A javax.mvc.Viewable objects contains information about a view and about how it will be processed. You can optionally include a reference to a Models instance (see the Models section below) if you want to overwrite the one provided by the implementation. Also, you can specify the ViewEngine class that will process the view in case you want to override the default engine selection mechanism.

@Path("hello")
public class HelloBean {
@GET
@Controller
public Viewable hello() {
return new Viewable("/hello.jsp");
}
}

Response

A typical javax.ws.rs.core.Response object, gives the Controller full access to a response, including setting content types, character encodings and performing HTTP redirects:

@Path("hello")
public class HelloBean {
@GET
@Controller
public Response hello() {
return Response.status(Response.Status.OK).entity("/hello.jsp").build();
}
}

Models

A model is used by the ViewEngine to process a view. The MVC API can potentially support two ways of providing models to a view. The first way, which must always be supported by an implementation, is the javax.mvc.Models interface. The second way is through CDI enabled beans. The support for the latter is optional and may not always be provided by the implementing library. The ozark implementation supports both ways. The Models interface

The javax.mvc.Models is essentially a Map of names to model instances. Specifically in the ozark library, the concrete implementation of javax.mvc.Models is a RequestScoped CDI bean that delegates all method calls to a HashMap<String, Object> instance.

For an example, suppose we have the following User model that we want to make available to a view:

public class User {
private String name;
public String getName() {return name;}
public void setName(String name) {this.name = name;}
}

Then the Controller would use an injected instance of javax.mvc.Models and add the User model under the name "user". In a JSP view, the User would be available as ${user}.

@Path("hello")
public class HelloBean {
@Inject
Models models;
@GET
@Controller
public String hello(@QueryParam("name") String name) {
User user = new User();
user.setName(name);
models.put("user", user);
return "/hello.jsp";
}
}

CDI models

When CDI support is available, the Models interface is skipped altogether:

import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
@Named(value = "user")
@RequestScoped
public class User {
private String name;
public String getName() {return name;}
public void setName(String name) {this.name = name;}
}
@Path("hello")
public class HelloBean {
@Inject
User user;
@GET
@Controller
public String hello(@QueryParam("name") String name) {
user.setName(name);
return "/hello.jsp";
}
}

When both the MVC API implementation library and the ViewEngine that will process the view support CDI beans, their usage is recommended over the Models interface.

Views

In the view below, the user model is automatically resolved either from the CDI bean named “user” or from the entry with name “user” from the Models interface

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Hello</title>
</head>
<body>
<h1>Hello ${user.name}</h1>
</body>
</html>

View Engines

A View Engine is used to process a view. The implementing MVC-API libraries must provide built-in support for at least the JSP and Facelets engines. Unless specified explicitly in the Viewable object, the ViewEngine that will be used to process the view will be selected automatically.

Ozark chooses the ViewEngine based on the view's extension; JspViewEngine for .jsp and .jpsx entensions, and FaceletsViewEngine for .xhtml. Both of these engines just forward the request to the container.

Conclusion

In addition to all the above, the MVC API also includes lifecycle events and a mechanism for exception handling. All in all, the MVC API is a nice addition to the JavaEE ecosystem. It manages to integrate well with existing technologies and provide an standard API to a very commonly used pattern.