Gerrit's Blog

Thoughts and ideas, mostly tech based. But I don't promise anything.

05.05.2015

Howdy MVC 1.0

Maybe one or two of you might noticed that there is something in the upcoming Java EE8 release worth to mention if you are doing web apps. The JSR 371 a.k.a. MVC 1.0 is an approach to establish a standardized Model-View-Controller framework.

If you -like me- have been working with frameworks like SpringMVC it comes clear at the first glance that you should be able to create an example app within minutes (after reading the specs). It will also be a plus if you -unlike me- are already familiar with JAX-RS because the current idea is to use an existing standard to expose your controllers / endpoints / <insert term you like>.

Is JSF dead yet?

Short answer: No.

Long answer: Still no. The MVC has no intention to replace JSF. It is a complete parallel development in the Java EE universe. In other words: Why should JSF be retired in favor of MVC? JSF is a component based framework and MVC is / will / should be a action based framework. There has been and will be a portion of use cases where someone should prefer JSF as the technical solution.1

Ready

For my first practical look I will leave application servers aside and work with an Apache Tomcat. This gives me (and you) the benefit that we have a listing of all needed APIs and their implementations in the project dependencies. If we don’t ship a needed implementation the application will fail at start. An application server might provide some implementations we depend on and the project will just run without them defined in our project out of the box and we do not know what we are using under the hood.

Set

To get a clean overview of our dependencies take a look at the gradle build file:

dependencies {
  compile group: 'com.oracle.ozark', name: 'ozark', version: '1.0.0-m01'
  compile group: 'javax.mvc', name: 'javax.mvc-api', version: '1.0-edr1'

  compile group: 'javax.enterprise', name: 'cdi-api', version: '1.2'
  compile group: 'org.jboss.weld.servlet', name: 'weld-servlet', version: '2.2.11.Final'

  compile group: 'org.glassfish.jersey.containers', name: 'jersey-container-servlet', version: '2.17'
  compile group: 'org.glassfish.jersey.ext.cdi', name: 'jersey-cdi1x', version: '2.17'

  compile group: 'javax.servlet', name: 'jstl', version: '1.2'
}

First of all we need the api and reference implementation of MVC 1.0. Since there is only one we include ozark. To get in the Java EE CDI game quickly I decided to use weld as my CDI implementation. As I said before MVC 1.0 is based on jax-rs so we need to make sure that jax-rs and its CDI support is in our classpath. Last but not least I included jstl because the first sample will use jsp with jstl.

Go

After setting things up we can start to create our first simple application. There are so much todo-list samples out there that I want to start with something different and more region based: The BeerApp.

First of all we create our application

@ApplicationPath("/beer")
public class BeerApplication extends Application {
}

And now we need a simple controller

@Path("/")
public class BeerController {

    @Inject
    Models models;

    @GET
    @Controller
    public String beerList() {
        models.put("beers", newArrayList("Beer1", "Beer2"));
        return "list.jsp";
    }

    @Path("{beerId}/")
    @GET
    @Controller
    public String beerDetails(@PathParam("beerId") String beerId) {
      models.put("name", "super beer");
        return "details.jsp";
    }
}

Just take some jsps to the menu and you have your first MVC 1.0 application. This is most basic one for the index.jsp:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title></title>
</head>
<body>
<c:forEach items="#{beers}" var="beer">
    <h3>${beer}</h3>
</c:forEach>
</body>
</html>

The controller will be mapped to the root of the application because we will just handle beers (sounds so tasty). The first method does not have a path but it’s explicit mapped to the path value of the controller. The second method takes a param and will return a detail view for one beer. Create a artifact and deploy it in your tomcat instance. You now have two endpoints http://.../beer/ and http://.../beer/<id>

Let’s play

Looking in the spec and the controller again there are multiple possibilities to return informations. You may also build a response including more details in the http layer:

@Path("{beerId}/")
@GET
@Controller
public Response beerDetails(@PathParam("beerId") String beerId) {
    models.put("name", "super beer");
    return Response.status(Response.Status.OK).entity("details.jsp").build();
}

where the Response builder helps you to create the matching response for the request. Another possible return type is a Viewable to take more control over how the view is meant to be processed.

@Path("{beerId}/")
@GET
@Controller
public Viewable beerDetails(@PathParam("beerId") String beerId) {
    models.put("name", "super beer");
    Viewable viewable = new Viewable("blubb.html", models);
    viewable.setViewEngine(MyCustomViewEngine.class);
    return viewable;
}

Ozark ships with JSP and Facelet ViewEngine. You can implement your own ViewEngine by implementing the ViewEngine interface. As an example you could provide a Thymeleaf or Tiles ViewEngines.

Last but not least you can provide JSON Data from the same controller. You need to include a json library. I choose genson because it registers itself as a JSON converter

compile group: 'com.owlike', name: 'genson', version: '1.3'

And we add another method to our controller that returns the pure object.

@Path("{beerId}/")
@GET
@Produces({MediaType.APPLICATION_JSON})
public Beer jsonDetails(@PathParam("beerId") String beerId) {
    return new Beer("super beer");
}

As you might notice we use the same path for html and json. Now we can fire up curl and test our app.

curl -i -H "Accept: application/json" 'http://localhost:8080/beer-app/beer/1' gives us {"name":"super beer"}

curl -i -H "Accept: application/html" 'http://localhost:8080/beer-app/beer/1' returns the html view <body> super beer </body>

We get the possiblity to extract the data generation into one single method and just do the view generating logic in the annotated methods. The little overhead of two one-to-three-liner methods is ignorable.

Summary

MVC 1.0 will be released with Java EE 8 which is scheduled for Q3/2016. There is still a lot of time to grow. My first impression is that there is much potential in this technology for the Java EE universe. It is the right choice to provide an additional web framework beside JSF. You have to give the user/developer the chance to choose the framework he needs to solve his problems.

You can check out the current status of my sample application at github.

For this introduction I completely ignored the post and validation process. This will be discussed in a follow up post.

  1. Still have not found any in my daily work but there should be some.