This article is sponsored by the Java Community Process.
JSF and JSP: What's New in Java EE 5

A Conversation with Ed Burns and Jan Luehe

by Frank Sommers
May 17, 2006

Summary
Ed Burns is co-specification lead for JSR 252, JavaServer Faces 1.2, and Jan Luehe leads JSR 245, Java Server Pages 2.1. Artima interviewed the two spec leads on April 14, 2006, and then in a subsequent email exchange, about new JSF and JSP features included in Java EE 5. Burns and Luehe discuss the JSP and JSF common expression language, AJAX, and the role annotations play in dependency injection.

Frank Sommers: What are the new features in the latest JSP and JSF specifications?

Ed Burns: The main theme of Java EE 5 is ease of development, and the key new JSP and JSF features echo this desire. Both technologies evolved over many years, and what you see now in the current specification versions is the result of that evolution.

Before delving into the details of new JSP and JSF features, it might help your readers if I explained a bit the history of these specs. JSP [together with the Servlet API] was one of the earlier specifications, starting sometime around the year 2000, but the technology predated that initial JSR. At that time, the specs were defining Servlet 2.3 and JSP 1.2, and would then become part of J2EE 1.3.

JSF 1.0 came out around February of 2004 as an independent technology [of J2EE], and it relied on Servlet 2.3 and JSP 1.2. JSF defined a standard UI model for the Web. Many people confuse it with an application framework, but it's really a component framework. Components have properties, methods, and events, and that's what JSF brings to Web programming.

JSF 1.0 had important innovations to deliver on its own schedule. JSF 1.1 was mainly a bug- fix release [Editor's note: also developed as JSR 127] and worked with the same version of the Servlet API as JSF 1.0 did. The first version of the JSF spec to be included in Java EE is the current version, JSF 1.2, and it works with Servlet 2.5 and JSP 2.1, which are also part of Java EE 5.

While it may be confusing at first to look at these version changes, it helps in understanding how JSP and JSF technologies evolved relatively independently until recently. The main thrust of the current JSF and JSP specs has been the desire the align these technologies. That's in keeping with the Java EE 5 theme of ease of development, and the JSF and JSP expert groups worked very hard together to ensure that the resulting specs make it easier to work with JSF and JSP together.

At the heart of the JSP-JSF alignment is a unified expression language. JSP included an expression language since the 1.2 version, but because these technologies have different purposes—for instance, JSP and JSF component life cycles are different—their respective expression languages did not align well with each other. Although part of the JSP 2.1 release, the unified expression language now has its own specification, and we can imagine uses of this expression language outside of JSF as well.

Jan Luehe: We also added features to align these specs with other parts of Java EE 5. Again, here the chief goal was to provide greater development ease. We now have annotations that can potentially reduce the amount of code a developer has to write. For instance, you can use annotations to specify dependency injection in servlets now. JSPs can take advantage of the entire Java EE 5 persistence model as well.

Unified Expression Language

Frank Sommers: You mentioned that the unified expression language now lives in its own specification document. What was the reason for that separation?

Ed Burns: JSF 1.1 delivered many innovations for Web developers, and we wanted to expose some of those outside of JSF, mainly so that JSP can take advantage of them. The result is that the expression language is now independent of its hosting technology. In time, we might expose this expression language even outside of Java EE, and at some point it may even occupy its own JSR.

For example, one of the things we are considering is for this expression language to provide data binding in Java SE applications. It would probably be a sub-language for data binding, similar to how the expression language is used to obtain values from a JSF component. In [Java] SE, it might be a Swing expression language.

Frank Sommers: What differentiates an expression language from a scripting language?

Ed Burns: An expression language, or EL, is not a full-fledged programming language—you can't write programs in an expression language. Instead, an expression language is used mainly as a short-hand for accessing values. It makes it easy for page authors to access variables within different scopes, for instance, and to access properties of values. In addition, expression languages provide the notion of having some model data, and can help in navigating that model data.

An expression language often comes with some predefined values with a scope, such as a page context. The expressions are resolved within that scope. And you can specify what that context is. In the unified JSF/JSP expression language, whenever you evaluate an expression, you provide the context for that evaluation. In other words, you specify the context in which a variable can be defined. In the JSP context, for instance, the variable scopes are page, session, or application.

The application developer provides an EL context factory. Of course, we provide some base classes for those context factories. But the interesting part is that the whole notion of these contexts are general, and we didn't include any Web concepts in the EL core. All those [Web- specific concepts] are brought into the EL by the application. The independence of the unified EL from Web technologies is reflected in that we promoted the EL-related classes into their own package, javax.el.

The context you specify is then taken into account as a model object name is evaluated into an object reference, and as object properties are resolved. This is done by one or more EL resolvers, defined by an ELResolver implementation. A resolver takes a part of an expression, a name-to-value reference, and resolves that to an object reference. There can be a chain of resolvers. Each element of the chain might be able to resolve a part of the expression within a context the resolver knows about.

You can decide what kind of resolvers to add into this resolver chain. In JSF, for instance, you have a managed bean resolver that knows how to resolve references in the context of managed beans. Or you have a JavaBean EL resolver: Given a POJO, it looks for naming conventions to resolve a value. For instance, if you say, user.address.street in the EL, the bean resolver would be used to resolve that expression to an object value given the bean naming patterns.

Within the context of the resolvers, expressions act as a means to get a value, and also as a means to set a value. For example, when rendering an input field, the initial render of the field may or may not have a default value. If it does, the default value will be obtained by performing a "get" operation. However, when the value of the field is filled in by the user and submitted to the server, the expression receives that value by performing a "set" operation on the server.

This is an important point, because it provides for plugability in the architecture. If a value cannot be resolved within the context of one resolver, resolution attempts will [bubble up] the chain of resolvers. So to support, say, the Spring Framework, you would plug in resolvers specific to Spring, and then the system can manipulate Spring beans.

The EL itself defines no [technology-specific] resolvers. The core EL package defined in javax.el provides only basic resolvers, such as those capable of operating on maps, arrays, or beans. Apart from these abstract resolvers, each technology, such as JSP and JSF, and possibly others taking advantage of javax.el, defines technology-specific resolvers.

Jan Luehe: There is also a concept of delayed evaluation of an expression. In the old-style notation, with $ and curly braces surrounding the expression, the expression is compiled when the JSP is compiled, and is evaluated once, when the JSP executes. We also have another way to specify eval-expressions in the JSP and JSF contexts, and that is to use # instead of $. [Editor's note: Eval-expressions are expressions that require evaluation, as opposed to literal expressions.] Such a deferred-evaluation expression is not evaluated until its value is needed. This is especially useful in JSF, where the component life cycle is not tied to page execution. While the latest JSP and JSF specs are backwards compatible with earlier versions, if you want to take advantage of the delayed-evaluation feature, then you must upgrade.

AJAX and Annotations

Frank Sommers: What AJAX-related features were added to JSF and JSP?

Ed Burns: While a lot could be done with JSF and AJAX beyond what we provide now, the JSF and JSP spec leads had to work within the constraints of time in terms of what we could do. We did make some key changes in the JSF API to help AJAX-style applications. These build on JSF's strength in state management—JSF components maintain their own state. With AJAX, you can transfer that state back and forth between server and component. There are many ways of doing that, and we don't specify one particular way in the JSF specs.

JSF's ability to maintain state within the component comes in handy in many AJAX use-cases. For instance, in a drop-down list, when the user selects a list item, that selection can cause another part of the page to show. To enable that state transfer [of the component's serialized state], the JSF state model included a hidden field that contained the component's full serialized state. We now standardized the name of that hidden field, and you can access that field from within AJAX.

Another interesting JSF feature that helps with AJAX development is life-cycle listeners. JSF provides listeners on the component life-cycle. But you can provide custom life-cycle listeners on a per servlet basis. You can have life-cycle listeners that process AJAX-based events, and events occurring in the view. Suppose you want to use Faces validation, and set a specific database validation listener on a component. With a per-view listener, you can attach a listener to the view, and use that listener to take action for validation [when some aspect of the view changes]. The benefit of the per-View phase listener is that it doesn't affect all requests, just ones to that view.

It's worth noting that there is now a growing library of AJAX-enabled JSF components. We're just now going public with a set of nine components that you can run in Java Studio Creator. The components include an AJAX file-upload component, an AJAX progress bar, a pop-up bubble. Another interesting component in this library is an AJAX validator, and this goes back to life-cycle processing. When doing client-side validation you can't take advantage of the JSF-provided life-cycle elements. Yet you often want validation to be part of a component's life-cycle. For instance, before updating the model data, you may always want to ensure that the data matches [validation requirements]. This component wraps validation into a JSF life cycle.

The validator component is handy for those cases when mere syntactic validation, as often practiced in pure client side validation, is not sufficient. For example, a credit card number can be syntactically validated to ensure that it contains sixteen digits. This can and should be done entirely on the client. However, to verify that the account is active and in good stead requires a server transaction. Requiring the user to do a full page refresh just to get this data would be a hassle. The Ajax validator component enables wrapping any JSF component with any JSF validator, and running just the validation part of the lifecycle on that specific component instance.

Frank Sommers: You mentioned dependency injection and annotations. How do annotations help a JSF and JSP developer?

Jan Luehe: You can now inject dependencies, such as resources, into JSF. An example is a managed bean. All other Web tier technologies have taken advantage of dependency injection as well: In JSP, you can inject a tag handler, in servlets, a servlet or a servlet filter. You also inject these into custom JSP tags as well.

An interesting example of how this helps is in conjunction with the new Java persistence API in Java EE 5. You can inject a persistence context or a JDNI resource into a JSP or servlet by sticking an annotation into a custom tag. This avoids having to write a lot of boiler-plate code.

Consider a servlet that increments and persists in a database the number of times the person identified by the request parameter "name" has been greeted. If the servlet was mapped to /HelloServlet in samples.war, an invocation of it might look as follows:

http://<host>:<port>/samples/HelloServlet?name=tom

Prior to dependency injection, the servlet would look up and update a JNDI resource, like this:

 
InitialContext initCtx = new InitialContext();  
DataSource ds = (DataSource)  
    initCtx.lookup("java:comp/env/jdbc/PersonDB");  
Connection conn = ds.getConnection();  
PreparedStatement pst = conn.prepareStatement(  
    "update Person set hellocount=hellocount+1 where name = ?");  
pst.setString(1, name);  
pst.executeUpdate();  

With resource injection, the requested data source can be made available to the servlet right after the servlet has been instantiated:

 

@Resource private DataSource ds;  
 
Connection conn = ds.getConnection();  
PreparedStatement pst = conn.prepareStatement(  
    "update Person set hellocount=hellocount+1 where name = ?");  
pst.setString(1, name);  
pst.executeUpdate();  
To simplify things further, a person's record could be implemented as an Entity bean, as follows:
 
@Entity  
public class Person {  
    
    @Id protected String name;  
    
    protected int hellocount;  
 
    protected Person() {  
    }  
 
    public Person(String name) {  
        this.name = name;  
    }  
 
    public void incrementHelloCount() {  
        hellocount++;  
     }  
}  

and accessed and updated using the new Persistence framework in Java EE 5, like this:

@PersistenceUnit private EntityManagerFactory emf;  
@Resource private UserTransaction utx;  
 
utx.begin();  
EntityManager em = emf.createEntityManager();  
Person p = em.find(Person.class, name);  
if (p != null) {  
    p.incrementHelloCount();  
}  
utx.commit();  

APPENDIX

The following code examples show three versions of the same servlet. Listing 1 shows how a data source is obtained via a JNDI lookup. Listing 2 injects the data source as a dependency into the servlet, alleviating the need to use JNDI. Listing 3 shows how the same servlet can use EJB 3 persistence to further simplify what a developer has to write.

Listing 1. HelloServlet.java

import java.io.*;
import java.sql.*;
import javax.naming.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.sql.*;

public class HelloServlet extends HttpServlet {

    public void service(HttpServletRequest req, HttpServletResponse res)
            throws IOException, ServletException {

        String name = req.getParameter("name");
        if (null == name) {
            return;
        }

        Connection conn = null;
        try {
            InitialContext initCtx = new InitialContext();
            DataSource ds = (DataSource)
                initCtx.lookup("java:comp/env/jdbc/PersonDB"); 
            conn = ds.getConnection();
            PreparedStatement pst = conn.prepareStatement(
                "update Person set hellocount=hellocount+1 where name = ?");
            pst.setString(1, name);
            pst.executeUpdate();
        } catch (NamingException namingEx) {
            throw new ServletException(namingEx);
        } catch (SQLException sqlEx) {
            throw new ServletException(sqlEx);
        } finally {
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException ex) {
                    // ignore
                }
            }
        }
    }
}

Listing 2. HelloServletResourceInjection.java

import java.io.*;
import java.sql.*;
import javax.annotation.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.sql.*;

public class HelloServletResourceInjection extends HttpServlet {

    @Resource private DataSource ds;
    
    public void service(HttpServletRequest req, HttpServletResponse res)
            throws IOException, ServletException {

        String name = req.getParameter("name");
        if (null == name) {
            return;
        }

        Connection conn = null;
        try {
            conn = ds.getConnection();
            PreparedStatement pst = conn.prepareStatement(
                "update Person set hellocount=hellocount+1 where name = ?");
            pst.setString(1, name);
            pst.executeUpdate();
        } catch (SQLException ex) {
            throw new ServletException(ex);
        } finally {
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException ex) {} // ignore
            }
        }
    }
}

Listing 3. HelloServletPersistence.java

import java.io.*;
import javax.annotation.*;
import javax.persistence.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.transaction.*;

public class HelloServletPersistence extends HttpServlet {

    @PersistenceUnit private EntityManagerFactory emf;
    @Resource private UserTransaction utx;

    public void service(HttpServletRequest req, HttpServletResponse res)
            throws IOException, ServletException {

        String name = req.getParameter("name");
        if (null == name) {
            return;
        }

        try {
            utx.begin();
        } catch (Exception e) {
            throw new ServletException(e);
        }

        EntityManager em = emf.createEntityManager();
        try {
            Person p = em.find(Person.class, name);
            if (p != null) {
                p.incrementHelloCount();
            }
            utx.commit();
        } catch (Exception e) {
            try {
                utx.rollback();
            } catch (Exception ee) {} // log exception
            throw new ServletException(e);
        } finally {
            em.close();
        }
    }
}

Listing 4. Person.java

import javax.persistence.*;

@Entity
public class Person {
    @Id protected String name;
    protected int hellocount;

    protected Person() {
    }

    public Person(String name) {
        this.name = name;
    }

    public void incrementHelloCount() {
        hellocount++;
    }
}

Resources

Talk back!

Have an opinion? Readers have already posted 2 comments about this article. Why not add yours?

About the author

Frank Sommers is a Senior Editor with Artima Developer. Prior to joining Artima, Frank wrote the Jiniology and Web services columns for JavaWorld. He is an elected member of the Jini Community's Technical Advisory Committee.