Why Another MVC?
by Ed Burns
Published August 2014
Take a look at two kinds of MVC and understand their complementary usages.
The recent filing of a new JSR for an MVC 1.0 framework in Java EE 8 [1] calls for some clarification on how that JSR relates to JSF. This document aims to reassure the JSF user community about our continued commitment to evolving JSF and to clarify the complementary usages of these two view technologies. Joshua Wilson beat me to the punch with a similar blog entry, which is also well worth reading.
First, let’s get one thing straight. Java EE already has an MVC framework: JSF. Why do we need another one? Isn’t this overkill? The answer lies in a subtle distinction between different kinds of MVC. For the purposes of this article, we consider two kinds of MVC: UI component oriented MVC and action oriented MVC. There are other kinds of MV* concepts out there, but let’s stick with just these two. After looking at these two different styles of MVC, the article explains the rationale for filing a separate JSR for MVC 1.0 and explains how this new specification will relate to the next version of JSF.
UI Component Oriented MVC == JSF
Figure 1: UI Component Oriented MVC as Exposed in JSF
With JSF, the model is CDI, the View is your Facelet pages, and the controller is the JSF lifecycle, as shown in Figure 1. One hallmark of UI component oriented MVC is the emphasis it places on the concept of “inversion of control (IoC)”. JSF takes this concept into the view tier, allowing you to define little bits of code for your view related concerns (conversion, validation, events). This, along with the existing IoC provided by CDI, means that JSF is much more about setting up the pieces and letting the framework do the rest (including managing the view state) than it is about managing the request/response flow of the underlying HTTP.
The following stock symbol lookup code example illustrates the extreme IoC in component oriented MVC by emphasizing the “little bits of code for your view related concerns” concept. First the view: index.xhtml
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:jsf="http://xmlns.jcp.org/jsf">
<head jsf:id="head">
<title>Symbol lookup</title>
</head>
<body jsf:id="body">
<form jsf:id="form">
<p>Enter symbol:
<input name="textField" type="text" jsf:value="#{bean.symbol}" />
<input type="submit" jsf:id="submitButton" value="submit" jsf:actionListener="#
{bean.actionListener}">
<f:ajax execute="@form" render="@form" />
</input>
</p>
<div jsf:rendered="#{not empty bean.info}">
<p>Info for #{bean.symbol}: #{bean.info}.</p>
</div>
</form>
</body>
</html>
This is a simple HTML page instrumented with JSF components. The symbol to lookup is entered into the text field with name='textField'. The button to submit the input with type='submit'. It references an actionListener
method. This is where you put your code that looks up the info for symbol. This could interface with a database, a web service, or whatever you like. Note the <f:ajax />
component inside the form’s button. This causes the button to be ajaxified, allowing the form submission and page update to automatically happen over XmlHttpRequest. Finally, there is a conditionally rendered div that displays the result of the lookup.
The other portion of code is in the Java class referenced by the #{bean}
EL expressions. This is class Bean.java.
import java.io.Serializable;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
@Named
@RequestScoped
public class Bean implements Serializable
private String symbol;
public String getSymbol() {
return symbol;
}
public void setSymbol(String symbol) {
this.symbol = symbol;
}
public void actionListener() {
// Poll stock ticker service and get the data for the requested symbol.
this.info= "" + System.currentTimeMillis();
}
private String info;
public String getInfo() {
return info;
}
}
This really is just a simple Java object with a read/write JavaBeans property called symbol
, a read only JavaBeans property called info
and a method called actionListener()
.JSF handles all the boilerplate mechanics of the controller. The app will deploy easily to any Java EE 7 container, such as GlassFish 4.0. The default URL after deployment is <http://localhost:8080/symbol/faces/index.xhtml
> This simple example is hosted at <https://bitbucket.org/edburns/jsf-symbol>. The example includes two additional files not shown here, one of them the zero-byte marker file: faces-config.xml
, the other the Maven pom.xml.
UI component oriented MVC is useful when you are ok with hiding the HTML/CSS/JS and HTTP from the page author. The page author is more about composing UIs from pre-built components and putting in little bits of code here and there to integrate it with the model tier. With this approach, you are indeed placing a lot of trust in the container, but you get a very simple and rapid development model in return.
The benefits of this approach start to diminish when requirements dictate the need to access the lower level HTTP request/response cycle and when more control is desired over the rendering and behavior of the HTML/CSS/JS comprising the UI. The HTML5 Friendly Markup feature of JSF 2.2 mitigates this particular concern somewhat, but there is no getting around the fact that component frameworks look at the world through component colored glasses. These problems have lead to some to label JSF as “too sticky”, but it must be said that this stickiness is a side effect of IoC and dependency injection in general. This stickiness also gets in the way when trying to combine JSF with other technologies without regard for how JSF operates. Finally, for one who is already used to the request/response style of programming, such as those coming from a PHP or Struts background, the learning curve for JSF requires changing the way one thinks about web app development. Such a mindshift is often perceived as not worth the effort. (Your author humbly disagrees.)
Action Oriented MVC == MVC 1.0
In contrast to UI component oriented MVC, the kind of MVC being advocated in MVC 1.0 can be called “action oriented MVC”. This style is shown in Figure 2 and was popularized in frameworks such as Apache Struts and Spring MVC.
Figure 2: Action Oriented MVC
The controller dispatches to a specific action, based on information in the request. Each action does a specific thing to transform the request and take action on it, possibly updating the model tier. This approach does not try to hide the request/response model of the underlying HTTP, and it also says absolutely nothing about the specifics of the HTML/CSS/JS comprising the UI.
Though the API for MVC 1.0 is wide open, one piece of prior art that will certainly influence its design is the Jersey MVC system. The Jersey source code includes numerous examples, including the Bookstore Webap, which is excerpted here. Again, we start with the view, this time a simple JSP page.
<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<style type="text/css" media="screen">
@import url(<c:url value="/css/style.css"/> );
</style>
<title>REST Bookstore Sample</title>
</head>
<body>
<h1>${it.name}</h1>
<h2>Item List</h2>
<ul>
<c:forEach var="i" items="${it.items}">
<li><a href="items/${i.key}/">${i.value.title}</a>
</c:forEach>
</ul>
<h2>Others</h2>
<p>
<a href="count">count inventory</a>
<p>
<a href="time">get the system time</a>
<p>
<a href="jsp/help.jsp">regular resources</a>
</p>
</body>
</html>
In this approach, the style reference must be manually inserted with the @import statement in the <head> section. If the page used JavaScript, a reference to it must also be inserted. With JSF, these resources would automatically be included by virtue of using a component that required them in the page. In the symbol
example above, the usage of <f:ajax />
causes a JavaScript reference to be included in the page. The Bookstore Webapp uses several EL expressions, first in the <h1> element. This bean is placed in scope by the Jersey MVC framework. JSTL iterates over the collection of books exposed by ${it}
, in the <c:forEach> element.
The index.jsp
is rendered implicitly when a GET request to the root URL of the deployed web app is rendered. This happens due to the JAX-RS @Path("/")
annotation on the following code
@Path("/")
@Singleton
@Template
@Produces("text/html;qs=5")
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Bookstore {
private final Map<String, Item> items = new TreeMap<String, Item>();
private String name;
public Bookstore() {
setName("Czech Bookstore");
getItems().put("1", new Book("Svejk", "Jaroslav Hasek"));
getItems().put("2", new Book("Krakatit", "Karel Capek"));
getItems().put("3", new CD("Ma Vlast 1", "Bedrich Smetana", new Track[]{
new Track("Vysehrad",180),
new Track("Vltava",172),
new Track("Sarka",32)}));
}
@Path("items/{itemid}/")
public Item getItem(@PathParam("itemid") String itemid) {
Item i = getItems().get(itemid);
if (i == null) {
throw new NotFoundException(Response
.status(Response.Status.NOT_FOUND)
.entity("Item, " + itemid + ", is not found")
.build());
}
return i;
}
@GET
@Produces({MediaType.APPLICATION_XML, MediaType.TEXT_XML, MediaType.APPLICATION_JSON})
public Bookstore getXml() {
return this;
}
public long getSystemTime() {
return System.currentTimeMillis();
}
public Map<String, Item> getItems() {
return items;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Note the manual rendering of HTML anchors in index.jsp. The href of those anchors refers to a RESTful URL that is backed by the getItem( )
method in the Bookstore.java class. This illustrates the characteristic of action oriented MVC of having to manually deal with the “what happens when the user clicks something in the UI” machinery. With component oriented MVC, all of that is handled by the framework.
The Bookstore Webapp runs on GlassFish 4.0 and the source code is available in the Jersey repo on GitHub: <https://github.com/jersey/jersey.git>.
This approach is preferred to a component oriented MVC approach when a greater degree of control over the request/response is required. Web designers may favor this approach because they view the abstraction provided by a component oriented MVC as just getting in the way when what they really want to do is control the HTML/CSS/JS themselves. Finally, this approach is a great fit for REST because of its tight association with the semantics of HTTP.
Conclusion
The decision to include MVC 1.0 in Java EE 8, while continuing to enhance and support JSF, was taken based on community feedback from many sources, including the Java EE 8 Developer Survey [2]. Given the clear community preference to do MVC, the question became: in what part of Java EE should the work be done? Several options were considered before deciding on filing a separate JSR. The most obvious choice was to do the work in the JSF JSR. One approach would be to have an alternate Lifecycle
implementation. This would minimize developer confusion from the perspective of overall Java EE. On the other hand, this approach would scare away people who wouldn’t go anywhere near JSF due to its perceived complexity and steeper learning curve, even if the association was only organizational. Another choice was to do the work within the JAX-RS JSR. JAX-RS is a good fit for action oriented MVC because it is inherently is close to HTTP and therefore inherently action oriented. A downside for this option is that it’s impossible to do server side MVC, even the action oriented variety, without introducing some level of statefulness to the system. Pure RESTafarians abhor state, and thus would oppose polluting JAX-RS with statefulness. The last option, of having a separate JSR has the benefit of not scaring people away by association with JSF. The confusion of “which one should I use” is still a possibility, but hopefully this article and the work itself will clear that up.
Finally, don’t pay too much attention to which JSR is hosting the work. It’s better to look at Java EE as a cohesive full stack solution that has both styles built in. These two view technologies will share several key components:
- Use of CDI as the model tier
- Use of Bean Validation as the validation layer
- Use of Expression Language as the glue between the view and the model
- Use of Facelets and/or JSP as the required supported view declaration languages.
The MVC 1.0 JSR will also explore using Faces Flows and/or Flash scope and will likely share elements of JAX-RS.
On the JSF side, in addition to whatever changes are necessary to support MVC 1.0, JSF 2.3 is a community focused release. Topics to be addressed include ajax method invocation, numerous clean up and clarifications, and community requested features such as better support for Twitter Bootstrap, jQuery and Foundation.
About the Author
Ed Burns is currently the spec lead for JavaServer Faces, a topic on which Ed recently co-authored a book for McGraw Hill. Burns is a Consulting Member of the Technical Staff at Oracle. He has worked on a wide variety of client and server side web technologies since 1994, including NCSA Mosaic, Mozilla, the Sun Java Plugin, Jakarta Tomcat and, most recently JavaServer Faces. Ed is an experienced international conference speaker, with consistently high attendence numbers and ratings at JavaOne, JAOO, JAX, W-JAX, No Fluff Just Stuff, JA-SIG, The Ajax Experience, and Java and Linux User Groups.
References
[1]
https://jcp.org/en/jsr/detail?id=371
Follow us on Facebook, Twitter, and the Oracle Java Blog.