By Rahman Usta

The new JSR 371 MVC 1.0 specification is coming. This specification will bring us an alternative way to apply MVC to the Java EE ecosystem in action-based manner.

The MVC 1.0 specification has grown up under the Java EE 8 umbrella and it’s RI (Reference Implementation) is Ozark.

In this blog, I want to introduce to you current state of MVC 1.0 and Ozark, and to give you some examples.

There is currently a conversation about MVC 1.0 on the lines of whether it will be based on Servletm or JAX-RS. There are advantages and disadvantages for both. If you follow up Servlet, you may develop and shape the spec and RI APIs in detail. If you follow up with JAX-RS, you may build everything top of it. For now, it seems the JAX-RS way will win, but it’s not certain.

If you already have experience with any action-based MVC frameworks (e.g. Spring MVC), you can easily adapt on MVC 1.0 and Ozark. I think the following picture clears how MVC 1.0 and Ozark works

ozark-mvc
Figure 1. How MVC 1.0 Works
View
View side can be any template kind. For example, JSP, Facelets, Freemarker, Handlerbars, Thymeleaf and so on. MVC 1.0 supports two view type: JSP and Facelts by default. But, you can use any View technology by developing your own ViewEngine.
Models
Models is basically a HashMap. You put your programming data to it. After that, ViewEngine will merge it with View.
MVC 1.0 Models Interface
public interface Models extends Map<String, Object>, Iterable<String> {

}
ViewEngine
Now, you have a View technology and Models data object. View document has some placeholder to demonstrate Model data. For example;
JSP placeholder
 <div>${person.name}</div>
Facelets placeholder
 <h:outputLabel value="#{person.name}"/>
Handlebars placeholder
<div>{{person.name}}</div>
Thymeleaf placeholder
<div th:text="${person.name}"></div>

These basically all do same thing. If you provide a Person object has a name property to those views, you can have a rendered view.

ViewEngine’s task is to merge Data and View. By default, Ozark contains two ViewEngine classes. JspViewEngine and FaceletsViewEngine. For example we can look at inside of ViewEngine and JSPViewEngine.

ViewEngine Interface
public interface ViewEngine {

 boolean supports(String view); 

 void processView(ViewEngineContext context) throws ViewEngineException; 

}
  • ViewEngine will support or not.
  • Render phase.
@Priority(1000)

public class JspViewEngine implements ViewEngine {

 private static final String VIEW_BASE = "/WEB-INF/"; 

 @Inject

 private ServletContext servletContext;

 public boolean supports(String view) {

 return view.endsWith("jsp") || view.endsWith("jspx"); 

 }

 public void processView(ViewEngineContext context) throws ViewEngineException {

 Models models = context.getModels(); 

 HttpServletRequest request = context.getRequest();

 HttpServletResponse response = context.getResponse();

 Iterator rd = models.iterator();

 while(rd.hasNext()) {

 String e = (String)rd.next();

 request.setAttribute(e, models.get(e)); 

 }

 RequestDispatcher rd1 = this.servletContext.getRequestDispatcher("/WEB-INF/"

 + context.getView());

 try {

 rd1.forward(request, response); 

 } catch (IOException | ServletException var7) {

 throw new ViewEngineException(var7);

 }

 }

}
  • JSP files location
  • This views supports files has jsp or jspx extension
  • Access Models object
  • Set each model values to current Request attribute list
  • Forward JSP view with their model attributes.

Developing a ViewEngine is as easy as you see above.

Controller
We can then combine View, Models and ViewEngine parts with JAX-RS Controller. There is a new @javax.mvc.Controller annotation that marks a JAX-RS resource class/method to produce a view document.
@Path("/")

@Controller

public class HomeController {

 @Inject

 private Models models;

 @GET

 @Path("/home1")

 public String home1() {

 return "/index.jsp"; 

 }

 @GET

 @Path("/home2")

 @View("/index.xhtml")

 public void home2() {}

 @GET

 @Path("/home3")

 public Viewable home3() {

 return new Viewable("index.hbs"); 

 }

 @GET

 @Path("/home4")

 public Viewable home4() {

 return new Viewable("index.html",HandlebarsViewEngine.class); 

 }

 @GET

4

 @Path("/home5")

 public Response home5() {

 return Response

 .ok()

 .entity(new Viewable("index.thyme"))

 .build(); 

 }

}
  • Marks this class as a MVC 1.0 Controller. All under methods will render a View document.
  • We can access a RequestScoped Models implementation via CDI (Context and Dependency Injection)
  • Renders index.jsp with current Models object.
  • Renders index.xhtml with current Models object.
  • Renders index.hbs with current Models object.
  • Renders index.html with current Models object and provided HandlebarsViewEngine class.
  • Renders index.thyme with current Models object.

As you see above, there are many ways to declare which view document will be rendered. We didn’t put any model value to View yet. Let’s do it now.

Imagine we have a Person class like below.

public class Person {

 private String name;

 private String surname;

 private Integer age;

 // getters, setters and constructors.

}

We can visualize these kind of objects with the following Handlebars View.

<!DOCTYPE html>

<html>

<head lang="en">

 <meta charset="UTF-8">

 <title>Person View</title>

</head>

<body>

 <div>{{person.name}}</div>

 <div>{{person.surname}}</div>

 <div>{{person.age}}</div>

</body>

</html>

And we need to combine them;

@GET

@Path("/")

public class PersonController {

 @Inject

 private Models models;

 @Path("/person")

 @Controller

 public String person() {

 Person person =new Person(); 

 person.setName("Hüseyin");

 person.setSurname("Akdoğan");

 person.setAge(35);

 models.put("person",person); 

 return "person.hbs"; 

 }

}
  • Create a new model object
  • Put it to global Models Map
  • Return view document name

Now, project structure of this project seems like below.

project-structure
Figure 2. Project Structure

You can deploy this app to Glassfish v4.1 to test. After deployment follow the http://localhost:8080/mvc/app/person URL to see the rendered Handlebars view.

result

You can download the source code here.

 

First Look at JSR 371, MVC 1.0 Specification and Ozark RI

About The Author
-

5 Comments

  • Jordi Llach
    Reply

    Is the controller’s model object request scoped? I guess it is.

    Maybe another example mixing different scoped models will be welcomed

    Thanks

  • Gustavo
    Reply

    Hi, i don’t understand something. In your github repo, the POJO “Person” doesn’t extends from “Models”. So, in JspViewEngine when get the models:

    context.getModels();

    how it is possible if the model is a single POJO without extends Models?

    And in ProductController, how is possible to inject “models” if Person doesn’t extends from Models?

    Thanks.

    • Leonardo Wolter
      Reply

      Probably `Models` is just a class that represents all the objects that will be available at your view, it doesn’t represent a Person as you suggested.

      Is similar to the Model from SpringMVC or the include part of Result from VRaptor

  • Leonardo Cesar Wolter
    Reply

    Will the spec use CoC? It would be nice 🙂

    I don’t want to write @View(“methodName”) public void methodName(){} for every time I need a new action since the view name will generaly be the same as the name of the method.

    The same apply for organizing views within folders for each controller, it would be nice if every views from HomeController were got from /WEB-INF/jsp/home

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>