Java Magazine Logo
Originally published in the January/February 2014 issue of Java Magazine. Subscribe today.

New to Java, Part 2: Three Hundred Sixty–Degree Exploration of Java EE 7

by Josh Juneau

Leverage the latest features in the Java API for RESTful Web Services and the JSON Processing API.

This article is the second in a three-part series demonstrating how to use Java EE 7 improvements and newer web standards, such as HTML5, WebSocket, and JavaScript Object Notation (JSON) processing, to build modern enterprise applications.

In this second part, we will improve upon the movieplex7 application, which we started in the first article, by adding the ability to view, delete, and add movies within the application database.

To review, the movieplex7 application is a complete three-tier application that utilizes the following technologies, which are built into Java EE 7:

  • Java Persistence API (JPA) 2.1 (JSR 338)

  • JavaServer Faces (JSF) 2.2 (JSR 344)

  • Contexts and Dependency Injection (CDI) 1.1 (JSR 346)

  • Java API for Batch Processing (JSR 352)

  • Java API for RESTful Web Services (JAX-RS; JSR 339)

Note: The complete source code for the application can be downloaded here

Overview of the Demo Application

In Part 1, we learned how to download, install, and configure NetBeans 7.3.x and GlassFish 4, which will be used for building and deploying the application in this article as well.

Note: NetBeans 7.4 RC1 has been available for use since summer 2013; you can use that IDE to work with the application in this article, but some features will differ from those described here since this article uses version 7.3.1.

We configured the movieplex7 application within NetBeans, and generated the database schema within Apache Derby via schema generation configured within persistence.xml. We then built the JSF 2.2–based user interface for booking a movie, including binding to the back end by generating managed beans and making them injectable by adding the @Named CDI annotation. We also encapsulated a series of related views/pages with application-defined entry and exit points using the new Faces Flow.

In this article, we will utilize JAX-RS to perform the view and delete operations, and we will make use of the Java API for JSON Processing (JSON-P) for adding movies.

For the remainder of the article, please follow along using the Maven-based project that you created in NetBeans IDE for Part 1 of this series.

Creating the Web Pages and Logic for Viewing and Deleting Movies

The movieplex7 application utilizes the JAX-RS API for viewing and deleting movies. In this section, we will walk through the steps for adding views and business logic that allow movieplex7 users to view all movies, view movie details, and delete existing movies using JAX-RS.

The JAX-RS 2 specification adds the following new features to the API:

  • Client API

  • Asynchronous processing capability

  • Filters, interceptors, and well-defined extension points

  • Bean validation, which enables you to easily validate data by applying annotations to bean fields

Create a RESTful client. Let’s begin with adding to the application a bean that will act as a client, invoking the REST endpoint. To do so, follow these steps:

  1. Right-click Source Packages, and then select New and then Java Class. Name the class MovieClientBean, and set the package to org.glassfish.movieplex7.client. Lastly, click Finish to create the bean. Once the bean has been generated, it will open in the editor.

  2. Add the @Named and @SessionScoped class-level annotations above the class definition. 

    By adding @Named, we are enabling CDI for this class, which allows it to be injected into an Expression Language (EL) expression. The @SessionScoped annotation signifies that the bean is to be automatically activated and passivated with a session.

  3. Make the class implement java.io.Serializable because it is in session scope.

  4. Resolve imports, as needed. Any unresolved imports will show as errors within NetBeans (see Figure 1).

    new-to-java-pt2-f1

    Figure 1

NetBeans makes it easy to resolve the imports by either clicking the yellow lightbulb or right-clicking within the editor and selecting the Fix Imports option (Shift + Cmd + I keys on Mac OS X). 

Each of the annotations can resolve against a couple of different imports, and NetBeans chooses the imports that best suit the situation. Note that for @SessionScoped, both the javax.enterprise.context.SessionScoped and javax.faces.bean.SessionScoped classes may be imported. If you are using CDI, along with importing @Named, you should be sure to import @SessionScoped. And if you are working with JSF and @ManagedBean, you should import @SessionScoped.

It should also be noted that @ManagedBean is deprecated as of JSF 2.2, so @Named (CDI managed beans) should be used unless your application requires @ManagedBean for backward support.

Now that the class has been created, it is time to add code to implement the client. 

  1. First, declare Client and WebTarget class variables, and then create the lifecycle callback methods: init() and destroy(). Annotate the init() method with @PostConstruct and annotate the destroy() method with @PreDestroy

    Annotating these methods will prompt the application server container to invoke the init() method before the bean is constructed and, similarly, to invoke the destroy() method before it is destroyed.

  2. In the init() method, obtain a new client using ClientBuilder and, in turn, set the endpoint URI of the web service target by calling the client.target method. 

    Take care when creating Client instances, because they are resource-intensive objects that are used to manage the client-side communication infrastructure. Be sure to create only the required number, and close them when you are finished. The end result should resemble the code in Listing 1

     Client client;
        WebTarget target;
    
        @PostConstruct
        public void init() {
            client = ClientBuilder.newClient();
            target = client
                    .target("http://localhost:8080/movieplex7/webresources/movie/");
        }
    
        @PreDestroy
        public void destroy() {
            client.close();
        }
    

     

    Listing 1

  3. Implement the method that will return the movies to the caller by adding the code shown in Listing 2. To return the movies, the target.request method is invoked, which in turn invokes the HTTP GET method, returning a value of type Movie[]

      public Movie[] getMovies() {
            return target.request().get(Movie[].class);
        }
    

     

    Listing 2

  4. Lastly, resolve imports.

Create a view to invoke the client. Now that the client has been created, it is time to write the view that will invoke the client. 

  1. Within the NetBeans project, right-click Web Pages, select New -> Folder, and specify the name client for the folder. Click Finish.

  2. Right-click the newly created client folder, and choose New, Other, JavaServer Faces, and Faces Template Client, and then click Next >. Name the new file movies.xhtml, click Browse (next to Template), expand Web Pages and WEB-INF, select template.xhtml, and click Select File. Click Finish. Remove the <ui:define> sections with “top” and “left” as names, because these are inherited from the template.

  3. Once the file is opened in the editor, replace the content within the <ui:define> area with the code fragment shown in Listing 3

    <h:form prependId="false">
      <h:selectOneRadio value="#{movieBackingBean.movieId}"
                         layout="pageDirection">
           <c:forEach items="#{movieClientBean.movies}" var="m">
           <f:selectItem itemValue="#{m.id}" itemLabel="#{m.name}"/> 
           </c:forEach>
      </h:selectOneRadio>
      <h:commandButton value="Details" action="movie" />
    </h:form>
    

     

    Listing 3

The code within the movies .xhtml view obtains all the movies by invoking the getMovies method within the MovieClientBean. It does so by binding the items attribute within the c:forEach element to the getMovies method, which returns an object of type Movie[] and iterates over each element. 

Each movie within the array is then displayed as a separate item via the <f:selectItem> element, which utilizes the var attribute of the c:forEach as a handle to expose the itemValue and itemLabel values for each object within the Movie[]. Note that the view also contains a commandButton element that is labeled "Details", which contains a movie action. When clicked, this button will look for a view named movie.xhtml, because the action matches the name of the view to invoke.

After adding the code, use the NetBeans auto-importer to resolve the namespace prefix-to-URI resolution by clicking the yellow lightbulb on the left.

Next, create the backing bean for the view: 

  1. Right-click the org.glassfish .movieplex7.client package, select New->Java Class, specify MovieBackingBean for the name, and click Finish.

  2. Add the following field to the class: 

        int movieId;
     
    
  3. Create getters/setters for the new field by right-clicking the editor pane and selecting Insert Code, which will open a contextual menu. Select Getter and Setter within the menu, as shown in Figure 2. Select the checkbox next to the field when the Generate Getters and Setters window opens, and then click Generate.

    new-to-java-pt2-f2

    Figure 2

  4. Add @Named and @SessionScoped class- level annotations, along with implementing java .io.Serializable, and resolve imports.

Add menu-item navigation and movie details. Provide a way for the user to access the movie listing, and code the Details button for the user interface:

  1. In template.xhtml, add the code shown in Listing 4 to the <ui:insert> with the name="left" attribute within the <form> element.  

    <p/><h:outputLink value="${
    facesContext.externalContext.requestContextPath
    }/faces/client/movies.xhtml">Movies</h:outputLink>
    

     

    Listing 4

    This will generate the menu item for navigation to the movies.xhtml view.

  2. To enable the functionality for selecting a movie and clicking the Details button, provide the ability for the MovieClientBean class to access the MovieBackingBean by injecting MovieBackingBean into the class. To do this, add the following code to MovieClientBean:

    @Inject
    MovieBackingBean bean;
    

     

  3. After adding the @Inject annotation, select the yellow lightbulb to import javax .inject.Inject.

  4. Make use of the Client and WebTarget instances to obtain the currently selected Movie object. To do so, add a variable named movie, which represents the currently selected object, to the REST endpoint URI by placing {movie} at the end of the path. It can then be bound to a concrete value using the resolveTemplate method, passing "movie" as the binding string and bean .getMovieId() as the binding value, which is populated from the currently selected movie. To enable this functionality, add to MovieClientBean the code shown in Listing 5

    public Movie getMovie() {
            Movie m = target
               .path("{movie}")
               .resolveTemplate("movie", bean.getMovieId()).request()
               .get(Movie.class);
            return m;
        }
    

     

    Listing 5

  5. Create the movie.xhtml view in the client folder of your project. To do so, copy the code shown in Listing 6 and paste it into the <ui:define> element of that view. Click the yellow lightbulb to resolve any namespace prefix-URI mappings. 

    <h1>Movie Details</h1>
    <h:form>
        <table cellpadding="5" cellspacing="5">
             <tr>
                  <th align="left">Movie Id:</th>
                  <td>#{movieClientBean.movie.id}</td> 
            </tr>
            <tr>
                  <th align="left">Movie Name:</th>
                  <td>#{movieClientBean.movie.name}</td>
            </tr>
              <tr>
                  <th align="left">Movie Actors:</th>
                  <td>#{movieClientBean.movie.actors}</td> </tr>
        </table>
        <h:commandButton value="Back" action="movies" />
    </h:form>
    

     

    Listing 6

Run the project. Run the project by right-clicking the project name and then selecting Run from the contextual menu (Fn + F6 keys on Mac OS X). Click the Movies option in the left navigation bar to show the output shown in Figure 3.

new-to-java-pt2-f3

Figure 3

Every movie in the array is listed within the view, with a button next to each. The output is generated from a REST endpoint, as opposed to the traditional Enterprise JavaBeans (EJB)/JPA–backed endpoint.

Choose a movie by selecting the button next to it and clicking on the Details button. Once clicked, the details of the movie will be shown (see Figure 4). Click the Back button to return to the list of movies.

new-to-java-pt2-f4

Figure 4

Providing Delete Capability

Enhance the application by providing the ability to delete a movie. 

  1. Use a commandButton to invoke a method within the backing bean named delete Movie(), which will delete the selected movie. To do so, add the code in Listing 7 to the movies.xhtml view. The button should be added after the code for the Details button.  

    <h:commandButton
        value="Delete"
        action="movies"
        actionListener="#{movieClientBean.deleteMovie()}"/>
    

     

    Listing 7

    Note: To format your code nicely within the view, right-click within the editor and choose the Format option.

  2. Add the deleteMovie() method to MovieClientBean by pasting into the Java class the code shown in Listing 8. The method is annotated with @Transactional, which is new in JTA 2.1 (released as part of Java EE 7).  

     @Transactional
        public void deleteMovie() {
            target
                    .path("{movieId}")
                    .resolveTemplate("movieId", bean.getMovieId())
                    .request()
                    .delete();
        }
    

     

    Listing 8

    This annotation provides the ability to control the transactional boundaries on CDI managed beans.

  3. Resolve imports and run the application.

Running the project now displays the Delete button at the bottom of the movie listing, as shown in Figure 5. If you select a movie and then you click the Delete button, the movie is removed from the database and the view is refreshed.

new-to-java-pt2-f5

Figure 5

Providing the Ability to Add Movies

Now that we’ve enhanced the application by providing the ability to view and delete movies, it is time to provide the capability to add movies to the database. To do so, we will make use of the JSON Processing 1.0 (JSON-P) API, which provides a standard API for parsing and generating JSON for use by applications. We will also be using the JAX-RS API for reading and writing JSON.

Before delving into the application examples for adding a movie, let’s briefly explore the functionality that the JSON-P and JAX-RS APIs bring to the table. For those who are unfamiliar, JSON is a data exchange format that is widely used via web services and other connected applications. JSON is composed of objects and arrays of data that can be used as a common format for working with data in internet applications. The JSON-P API provides a standard for parsing, transforming, and querying JSON data using the object model (tree-based) or the streaming model (event-based parser). The JSON-P API is composed of the following packages: 

  • javax.json: Contains interfaces, utility classes, and Java types for JSON objects

  • javax.json.stream: Contains parser and generator interfaces for the streaming model 

The JAX-RS API is the Java API for building RESTful web services, which are lightweight web services. In this example, we will use JAX-RS Entity Providers, which supply mapping services between internet data representations and their associated Java types. There are several predefined type mappings, including String, byte[], and many others. If an application needs to define its own mapping to custom types, that can be done using the MessageBodyReader and MessageBodyWriter interfaces.

Create the MessageBodyReader. The following steps can be used to provide the ability to add a new movie to the application. Please note that for production applications, add, delete, and update functionality should be made available only after proper authentication. 

  1. Right-click Source Packages, select New and Java Package, and then specify the package name as org.glassfish.movieplex7.json and click Finish.

  2. Right-click the newly created package, and select New and then Java Class. Then specify the name as MovieReader and click Finish.

  3. Add the following class-level annotations to the new MovieReader class: 

    @Provider
    @Consumes
    (MediaType.APPLICATION_JSON) 

    The @Provider annotation allows the implementation to be discovered by the JAX-RS runtime during the provider scanning phase. It can be used for any class that is of interest to JAX-RS. The @Consumes annotation specifies the MIME media type of representations that were sent by the client and can be consumed by a resource. In this case, MediaType.APPLICATION_JSON indicates that a JSON resource will be consumed.

  4. Resolve imports by clicking the yellow lightbulb (Shift + Cmd + I keys on Mac OS X) to import the following classes: 

    javax.ws.rs.core.MediaType
    javax.ws.rs.Consumes
    javax.ws.rs.ext.Provider 
  5. Modify the class signature so that it implements MessageBodyReader<Movie>, resolve imports, and then click the yellow lightbulb hint in the left column and select Implement all abstract methods, as shown in Figure 6.

    new-to-java-pt2-f6

    Figure 6

  6. Replace the generated isReadable() method with the code shown in Listing 9, which will determine whether the MessageBodyReader can produce an instance of a particular type. 

    @Override
        public boolean isReadable(Class<?> type, Type type1, 
    Annotation[] antns, MediaType mt) {
            return Movie.class.isAssignableFrom(type);
        }
    

     

    Listing 9

  7. Replace the generated read From() method with the code shown in Listing 10, and resolve imports, as needed. 

    @Override
        public Movie readFrom(Class<Movie> type, Type type1, 
    Annotation[] antns, MediaType mt, MultivaluedMap<String, String>  
    mm, InputStream in) throws IOException, WebApplicationException {
            Movie movie = new Movie();
            JsonParser parser = Json.createParser(in);
            while (parser.hasNext()) {
                switch (parser.next()) {
                    case KEY_NAME:
                        String key = parser.getString();
                        parser.next();
                        switch (key) {
                            case "id":
                                movie.setId(parser.getInt());
                                break;
                            case "name":
                                movie.setName(parser.getString());
                                break;
                            case "actors":
                                movie.setActors(parser.getString());
                                break;
                            default:
                                break;
                        }
                        break;
                    default:
                        break;
                }
            }
            return movie;
        }
    

     

    Listing 10

This code first reads a type from the input stream named in, and then creates a JsonParser object from that stream by calling Json .createParser(in). Key values are then read from the parser, and they are used to populate a new Movie instance. The newly created Movie is then returned. 

Create the MessageBodyWriter.

  1. Right-click the newly created package, and select New and Java Class. Then specify the class name as MovieWriter and click Finish.

  2. Add the following class-level annotations:  

    @Provider
    @Produces
    (MediaType
         .APPLICATION_JSON)
    

     

    @Produces is used to specify the MIME media type of the resource being produced. In this case, JSON will be produced.

  3. Resolve imports by clicking the yellow lightbulb (Shift + Cmd + I keys on Mac OS X).

    Note: Be sure to import the javax.ws.rs.Produces class.

  4. Modify the class definition so that it implements MessageBodyWriter<Movie> and resolve imports. Then click the yellow lightbulb hint in the left column and select Implement all abstract methods.

  5. Overwrite the implementations for the isWriteable(), get Size(), and writeTo() methods with those shown in Listing 11. Resolve the imports.

    @Override
        public boolean isWriteable(Class<?> type, Type type1, 
    Annotation[] antns, MediaType mt) {
            return Movie.class.isAssignableFrom(type);
        }
    
        @Override
        public long getSize(Movie t, Class<?> type, Type type1, 
    Annotation[] antns, MediaType mt) {
            return -1;
        }
    
        @Override
        public void writeTo(Movie t, Class<?> type, Type type1, 
    Annotation[] antns, MediaType mt, MultivaluedMap<String, Object> 
    
    mm, OutputStream out) throws IOException, WebApplicationException {
            JsonGenerator gen = Json.createGenerator(out);
    
            gen.writeStartObject().write("id", t.getId())
                    .write("name", t.getName()).write("actors", t.getActors()).writeEnd();
            gen.flush();
        }
    

    Listing 11

The isWriteable() method determines whether the specified type can be written. getSize() returns the length in bytes of the serialized form of the object type, Movie. In JAX-RS 2.0, this method is deprecated, and all MessageBodyWriter implementations are advised to return -1. Lastly, the writeTo() method writes a given type to an HTTP message. A JsonGenerator is created by passing the OutputStream to Json.createGenerator, and the resulting JsonGenerator is then used to write the JSON data in a streaming manner. 

Create the Add Movie form and backing bean components.

  1. Create a new view within the client folder named addmovie .xhtml, and replace the content within <ui:define> with the code shown in Listing 12

    <h1>Add a New Movie</h1> <h:form>
                        <table cellpadding="5" cellspacing="5"> <tr>
                                <th align="left">Movie Id:</th>
                                <td><h:inputText 
    value="#{movieBackingBean.movieId}"/></td> </tr>
                            <tr>
                                <th align="left">Movie Name:</th>
                                <td><h:inputText 
    value="#{movieBackingBean.movieName}"/>
                                </td>
                            </tr>
                            <tr>
                                <th align="left">Movie Actors:</th>
                                <td><h:inputText 
    value="#{movieBackingBean.actors}"/></td>
                            </tr>
                        </table>
                        <h:commandButton value="Add" action="movies"
    
    actionListener="#{movieClientBean.addMovie()}"/>

    Listing 12

    The code in addmovie .xhtml creates a form for input of the id, name, and actors of a movie. The values are bound to fields within the MovieBackingBean managed bean controller. The action Listener attribute of the commandButton is bound to an action method in the controller, which is responsible for adding the field values to the database. The action attribute is set to movies, which is the view to which control will be returned.

    Note: Some of the field and method bindings within the view have yellow lines underneath them (see Figure 7). These lines signify that the fields and methods do not yet exist.

    new-to-java-pt2-f7

    Figure 7

  2. Open MovieBackingBean in the IDE, and add the following fields to the class. Then create the getters and setters: 

        String movieName;
        String actors;
    
  3. For navigation, add a commandButton to addmovie by adding to movies.xhtml the code shown in Listing 13.

        <h:commandButton value="New Movie" action="addmovie" />
        

    Listing 13

  4. Add the addMovie() method shown in Listing 14 to MovieClientBean. Resolve imports. 

       public void addMovie() {
        Movie m = new Movie();
        m.setId(bean.getMovieId());
         m.setName(bean.getMovieName()); 
              m.setActors(bean.getActors()); 
    target
    .register(MovieWriter.class)
    .request()
    .post(Entity.entity(m, MediaType.APPLICATION_JSON));
    }
        

    Listing 14

    The addMovie method generates a new Movie instance, and then populates it using the values that are current in the backing bean. Once completed, the bean is sent to the REST endpoint by invoking the target.register() method to register a MovieWriter, which then provides conversion from the Movie plain old Java object (POJO) into JSON format.

  5. Learn More


     Part 1 of this series

    Test the application by running it, selecting the Movies link in the left-hand menu, and then clicking the New Movie button at the bottom of the movie listing. Complete the “Add a New Movie” form by providing a value for the MovieID field, as shown in Figure 8. When you click Add, the new movie will be displayed within the movie listing.

    new-to-java-pt2-f8

    Figure 8

Conclusion

In this article, we modified the movieplex7 application that was started in Part 1, providing the ability to view, add, and delete movies. The article covered the following technologies:

  • JSF 2.2

  • JAX-RS 2.0

  • Java API for JSON-P 1.0

In the third and final article in this series, we will be adding the ability to process movie ticket sales, assign movie points, and chat with others. To add these capabilities, we will make use of Batch Applications for the Java Platform 1.0 (JSR 352), Java Message Service 2.0 (JSR 343), and Java API for WebSocket 1.0 (JSR 356), respectively. 


juneau-headshot

Josh Juneau is an IT professional with more than 11 years of experience. A senior consultant and trainer at Fujitsu Canada, he has worked with different technologies and programming languages, including Java and Java EE, Microsoft, Oracle, and open source.