mscharhag, Programming and Stuff;

A blog about programming and software development topics, mostly focused on Java technologies including Java EE, Spring and Grails.

Sunday, 4 October, 2015

Java EE 8 MVC: A detailed look at Controllers

Java EE MVC is a new action based MVC framework planned for Java EE 8 and specified in JSR-371. This is the second post of my Java EE 8 MVC tutorial. The first post covered the basics and shows how to get started with Ozark, the Java EE 8 MVC reference implementation.

In this post we will have a more detailed look at MVC Controllers.

MVC Controllers

A controller is responsible for processing incoming requests. It invokes business logic, updates the model and returns the view that should be rendered. An MVC Controller is a JAX-RS resource method annotated with @Controller. If a class is annotated with @Controller, then all resource methods of this class are regarded as controllers.

The following example shows a simple Controller that renders a product details page for a given product id:

@Path("product")
@Controller
public class ProductController {

  @Inject
  private Models models;

  @Inject
  private ProductService productService;

  @GET
  public String getProductDetailPage(@QueryParam("id") long productId) {
    Product product = this.productService.getProduct(productId);
    models.put("product", product);
    return "/WEB-INF/jsp/productDetailPage.jsp";
  }
}

This Controller resolves a product id (passed as id request parameter) to a product using a ProductService. The obtained product is added to the model and a path to a view is returned. The view is then rendered with the information stored in the model.

Like in JAX-RS, the @Path annotation is used to define the URL path. This Controller is accessible via a URL that looks like this:

/<application-path>/product?id=42

The following example shows a hybrid class with one MVC controller method and one traditional JAX-RS resource method:

@Path("hybrid")
public class HybridController {

  @GET
  @Path("jaxrs")
  public Response jaxrs() {
    return Response.status(200).build();
  }

  @Path("mvc")
  @GET
  @Controller
  public String mvc() {
    return "/WEB-INF/jsp/hello.jsp";
  }
}

Controller methods work very similar to JAX-RS resource methods. However, there are two small differences:

  • A return type of String on Controller methods is interpreted as a view path. With JAX-RS resource methods the returned String is interpreted as text content.
  • The default response media type for Controller methods is text/html. Like in JAX-RS the media type can be changed using the @Produces annotation.

MVC Controller classes and hybrid classes with MVC Controller methods need to be CDI-managed beans. Like JAX-RS resource classes, MVC controller classes are instantiated per request. For every request, a new Controller class instance is created.

Like in JAX-RS the supported HTTP verb is defined by annotations. If a controller method should listen for HTTP POST requests, it needs to be annotated with @POST instead of @Get.

For example:

@Controller
@Path("http")
public class PostController {

  @POST
  @Path("post")
  public String post() {
    return "/WEB-INF/jsp/hello.jsp";
  }
}

Controller return types

Four different return types are supported on MVC controller methods:

  • String - The returned string value is interpreted as view path.
  • void - In this case the view need to be defined using the @View annotation
  • Viewable - An abstraction that includes information about a view, the model and the used view engine.
  • Response - A JAX-RS response. The entity type of the response needs to be String, void or Viewable.

The following class defines four controller methods using different return types. All methods return the same response:

@Controller
@Path("return-types")
public class ReturnTypesController {

  @GET
  @View("/WEB-INF/jsp/hello.jsp")
  @Path("return-void")
  public void returnVoid() {
  }

  @GET
  @Path("return-string")
  public String returnString() {
    return "/WEB-INF/jsp/hello.jsp";
  }

  @GET
  @Path("return-string")
  public Viewable returnViewable() {
    return new Viewable("/WEB-INF/jsp/hello.jsp");
  }

  @GET
  @Path("return-response")
  public Response returnResponse() {
    return Response.status(Response.Status.OK)
        .entity("/WEB-INF/jsp/hello.jsp")
        .build();
  }
}

Returning a JAX-RS Response is the most flexible way. This way the JAX-RS Response builder can be used to modify the HTTP status code, response headers and more.

If void is used as return type, the view needs to be defined using the @View annotation. @View can be applied to methods (like in the previous example) and classes. If a class is annotated with @View, the view is applied to all controller methods in this class. A class level @View annotation can be overridden by a more specific view definition on method level, like shown in the following example:

@Controller
@Path("views")
@View("/WEB-INF/jsp/foo.jsp")
public class ViewController {

  @GET
  @Path("first")
  public void first() {
    // renders foo.jsp
  }

  @GET
  @Path("second")
  @View("/WEB-INF/jsp/bar.jsp")
  public void second() {
    // renders bar.jsp
  }

  @GET
  @Path("third")
  public String third() {
    // renders baz.jsp
    return "/WEB-INF/jsp/baz.jsp";
  }
}

Summary

The @Controller annotation can be used on methods and classes. When used on classes, all methods of the class are considered as controllers. Controller methods invoke business logic and determine the view that should be rendered. Classes with Controller methods are CDI managed beans. For every request, a new class instance will be created. Traditional JAX-RS resource methods can be combined with MVC Controller methods in the same class.

In the next posts about Java EE 8 MVC we will have a look at parameter binding and validation.

You can find the example source code on GitHub.

Comments

  • miki - Friday, 9 October, 2015

    soo its basically spring mvc but worse

Leave a reply