Help

I'm the creator of Hibernate, a popular object/relational persistence solution for Java, and Seam, an application framework for enterprise Java. I've also contributed to the Java Community Process standards as Red Hat representative for the EJB, JPA, JSF specifications and as spec lead of the CDI specification. At Red Hat, I'm currently working on Ceylon, a new programming language for the JVM.

I also post stuff on G+.

Location: Guanajuato, Mexico, cabrones!
Occupation: Fellow at JBoss, a Division of Red Hat
Archive 'Web Frameworks'
My Books
Java Persistence with Hibernate
with Christian Bauer
November 2006
Manning Publications
841 pages (English), PDF ebook
Hibernate in Action
with Christian Bauer
August 2004
Manning Publications
408 pages (English), PDF ebook
14. Nov 2007, 04:52 CET, by Gavin King

Matt Raible lists his picks of the top web frameworks for deploying on the JVM:

  • GWT-Ext
  • Wicket
  • Grails
  • Flex/OpenLaszlo
  • Seam
  • Struts 2

What I think is most interesting about this list is simply how /different/ each of these frameworks is from each other. A couple of years ago, any list of the top web frameworks would have featured a bunch of metoo-ish action-style-MVC frameworks, with maybe one or two component-style-MVC frameworks thrown in. I /could/ summarize this list by saying that the balance seems to be shifting in favor of component-oriented approaches, but I don't actually think that this is the real story here.

You see, the component frameworks listed actually have much more that is /different/ about them than they have in common. And the same is true of the two action-style frameworks.

So the real story is that there has been a whole lot of creative thinking going on in the web framework space in the last couple of years (if I recall correct, four of these six frameworks did not even exist three years ago).

For the record, I believe that /any/ of these frameworks is a good foundation for web development, and a big improvement upon what people were using a few years ago.

Now, what I'm really interested to see is what happens next. Will certain projects (for example, Seam and Grails) decide to focus their energies on problems like orchestration, state management, data access and integration, while supporting /multiple view technologies/, and leaving other projects (for example, Wicket, JSF, GWT and Flex) to focus their energy upon the view? Or will each of these projects need to grow independently into a full stack solution?

Clearly, the example of Rails shows that a single project can deliver a full stack solution and that this is attractive to many users. However, it's not clear to me that this approach is as natural in the Java world, where we are more comfortable with choice and with heterogeneous technology environments, and where we are somewhat less inclined toward hero-worship.

The strategy we want to follow with Seam is to support multiple view technologies. We don't yet have a definitive list, but the ones I'm thinking of are JSF, GWT, Flex and potentially Wicket. But we're not kidding ourselves that this is a simple task. Developing and maintaining the level of /deep integration/ that Seam has for JSF is extremely expensive.

This post summarizes a complaint about JSF that I hear from time to time:

... traditional page design workflow isn't as straight-forward with JSF. With action-based web frameworks, it was rather easy for a HTML designer with some technical acumen to directly edit JSPs to implement a look and feel. Not so with JSF -- you're farther away from the final HTML. Its the components you include on the page that generate DIV tags and so forth. Having accrued 10+ years experience working with HTML, I find this the most frustrating aspect of JSF. We've been given a series of HTML Mockups from a design firm, and integrating has proved to be very challenging. I wonder if JSF merely shifts work efforts from HTML editing to Component customization.

Well, it may be frustrating at first, but on balance I would argue that it is a /good thing/ that your web designer is not editing HTML directly.

The reason is that you should not be implementing look and feel by directly editing HTML. If you're doing that, then you're working around the whole architecture of HTML. What you should be doing instead is adding CSS selectors to your semantic HTML content, and applying your layout, look and feel using CSS. The architecturally correct separation of responsibilities is:

  • Developers produce /semantic content/
  • Designers produce /stylesheets/

Now, most JSF component libraries (and most Ajax libraries in general) kinda muddy the water here by providing widgets that look pretty out of the box, and can be skinned according to some built-in theme facility. Well, this is an important marketing feature for something like RichFaces - users have an expectation that widgets will look pretty without customization - but for serious development I think it tends to lead people down the wrong path. That's why one of my first feature requests for RichFaces was a plain theme that looks /intentionally/ ugly, and is easy to style using CSS.

In my opinion, there is third, under-appreciated, attribute of the HTML architecture:

  • Both content and style are expressed /declaratively/

And, in my view, this is essential for understandability of the code.

Let's consider good 'ol <h:dataTable>:

<h:dataTable value="#{products}" var="prod">
   <h:column>
      <f:facet name="header">SKU</f:facet>
      #{prod.sku}
   </h:column>
   ...
</h:dataTable>

This code fits the semantic content description perfectly. It's a highly declarative specification that:

  1. there is a table, where each row is a product
  2. with a column that has a header and some content in each cell

I can't really imagine a nicer way to express this. Consider the traditional JSP/JSTL type approach:

<table>
   <tr>
      <th>SKU</th>
      ...
   </tr>
   <c:forEach items="${products}" var="prod">
      <tr>
         <td>
            <c:out value="${prod.sku}"/>
         </td>
         ...
      </tr>
   </c:forEach>
</table>

This is a significantly more complex implementation:

  • there are 5 levels of nesting, compared to 3
  • it's difficult to correlate the column header name with the content, except by counting <th>s and <td>s

Even worse, it features an /iterator/, thus mixing two completely different language paradigms (declarative vs. procedural) in a totally unsatisfying way.

On the other hand, it doesn't hide the bare HTML tags from us. If we wanted to edit the JSP template to add presentational concerns, it's easy enough. Unfortunately, once we start adding presentation concerns to our HTML, the HTML code becomes /much/ less reusable. What we should be doing instead is adding CSS selectors.

And, of course, all well-written JSF components make this super-easy:

<h:dataTable value="#{products}" 
                var="prod" 
         rowClasses="oddrow,evenrow"
        headerClass="header"
          syleClass="table products">
   <h:column>
      <f:facet name="header">SKU</f:facet>
      #{prod.sku}
   </h:column>
   ...
</h:dataTable>

Now our designer can concentrate upon developing declarative CSS stylesheets to target the selectors we have provided, and we will be free to make all kinds of changes to the semantic HTML without affecting the design (for example, we could use some fancy table control such as <rich:table> that provides lazy fetching of data from the server when the scrollbar is dragged, along with sortable, resizable columns and row selection. All without a line of JavaScript.

The declarative, semantic style of user interface development really starts to show its potential when we consider databinding. In a traditional UI library, tree views are a pain. We need to write messy Java code to adapt our application's model to something that the tree widget can comprehend. In RichFaces, we simply declare how the tree structure maps to the /structure/ of our object model. No Java code required:

<rich:tree>

    <rich:recursiveTreeNodesAdaptor roots="#{root}" 
                                    nodes="#{dir.children}"
                                      var="dir">
                                    
        <rich:treeNode>#{dir.name}/</rich:treeNode>
        
        <rich:treeNodesAdaptor nodes="#{dir.files}" 
                                 var="file">
                               
            <rich:treeNode>#{file.name}</rich:treeNode>
            
        </rich:treeNodesAdaptor>
        
    </rich:recursiveTreeNodesAdaptor>
    
</rich:tree>

Now just try to do that in some other Web framework! :-)

Probably, you can now guess why I'm going against the grain by sticking up for JSF when some folks are jumping on bandwagons like GWT or Wicket. These technologies attempt to specify a naturally hierarchical artefact using sequential code. Personally, I just don't get that. I'm deeply interested in technologies like Hibernate, JPA, Seam, Web Beans, EJB3, jBPM which reformulate what used to be programmatic concerns in a declarative mode. That there should be a movement /away/ from declarative programming in the one field where it is /most/ natural (user interface) is counter-intuitive to me.

Actually, the pure-declarative nature of JSF templates is a pretty unique feature of JSF. Facelets is the first templating language I've ever seen that doesn't need iterators and conditionals. JSP, Velocity, FreeMarker, RHTML, etc, all encourage the mixing of logic and content. Facelets/JSF let you express dynamic content every bit as declaratively as HTML or DocBook express static content. (Jacob Hookom is one of the smartest guys in Java, in case you missed it.)

20. Mar 2006, 20:00 CET, by Gavin King

Recently, Simon Brown put together a set of requirements for a very simple blogger application that could be used to compare Java web frameworks. I have my reservations about the actual requirememts he put together (in particular, there is no form submission!) but since some other framework authors have bitten, I've gone ahead and ported the example to Seam. I want to put a massive caveat around this post: Seam is absolutely not designed for applications like blogs or web forums; these kind of problems are very easy to solve using something like PHP or Ruby on Rails and there is no really good reason to use Java for a problem like this (unless Java is all you know). We have a set of requirements here with /no conversations/ and /no business processes/, so all the sophisticated state management machinery of Seam is redundant. Nevertheless, frameworks need to make simple things easy, and you'll see how little Java code we need to write to solve this simple problem using Seam.

To begin, I copied the standard Seam web.xml, faces-config.xml, application.xml and build.xml files from the Seam booking demo, changing names in a couple of places, and removing all the JSF navigation rules from faces-config.xml. None of this stuff is interesting, and it is always almost identical in every Seam application. I also copied Simon's screen.css stylesheet.

Simon started out with a domain model with Blog and BlogEntry classes that in a real application would be mapped to the database via Hibernate or EJB3, along with a BlogService class, which implements a static singleton containing some test data. The static variable and static initializer is an incredibly ugly way to implement a singleton in Seam, so I took the liberty of rewriting this class as an application-scope Seam component.

@Name("blog")
@Startup
@Scope(APPLICATION)
public class BlogService 
{

   private Blog blog;

   @Create
   public void initBlog()
   {
      blog = new Blog();
      blog.setName("Webapp framework blog");
      blog.setDescription("Comparison of J2EE web application frameworks");
      blog.setLocale(new Locale("en", "AU"));
      blog.setTimeZone(TimeZone.getTimeZone("PST"));
      blog.addBlogEntry(new BlogEntry(...);
      blog.addBlogEntry(new BlogEntry(...);
      blog.addBlogEntry(new BlogEntry(...);
   }
  
  @Unwrap
  public Blog getBlog()
  {
     return blog;
  }

}

I left Blog and BlogEntry the way I found them and just copied them across.

That's all we need to start work on the first page of the web application.

There is some common header information on all pages of the application, so we'll use a facelets template, template.xhtml, to define the common stuff.

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
                      "[=>http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd]">
<html xmlns="[=>http://www.w3.org/1999/xhtml]"
      [=>xmlns:ui=]"=>http://java.sun.com/jsf/facelets"
      [=>xmlns:h=]"=>http://java.sun.com/jsf/html"
      [=>xmlns:f=]"=>http://java.sun.com/jsf/core"
      [=>xml:lang=]"en"  
      lang="en">
      
<f:view>
   <head>
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
      <title>#{blog.name}</title>
      <link href="screen.css" rel="stylesheet" type="text/css" />
   </head>
   
   <body>
      <div id="container">
         <h1>#{blog.name}</h1>
         <h2>#{blog.description}</h2>
         <[=>ui:insert] name="content"/>
      </div>
   </body>
</f:view>

</html>

Note that this is all plain XML with namespaces, no wierd tags.

The index page, index.xhtml, in the example application displays a list of the three latest blog entries.

<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
                             "[=>http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd]">
<[=>ui:composition] xmlns="=>http://www.w3.org/1999/xhtml"
    [=>xmlns:ui=]"=>http://java.sun.com/jsf/facelets"
    [=>xmlns:h=]"=>http://java.sun.com/jsf/html"
    [=>xmlns:f=]"=>http://java.sun.com/jsf/core"
    template="template.xhtml">

<[=>ui:define] name="content">
   <h:dataTable value="#{blog.recentBlogEntries}" var="blogEntry" rows="3">
      <h:column>
         <div class="blogEntry">
            <h3>#{blogEntry.title}</h3>
            <div>
               #{blogEntry.excerpt==null ? blogEntry.body : blogEntry.excerpt}
            </div>
            <p>
               <h:outputLink value="entry.seam" rendered="#{blogEntry.excerpt!=null}">
                  <f:param name="blogEntryId" value="#{blogEntry.id}"/>
                  Read more
               </h:outputLink>
            </p>
            <p>
               Posted on 
               <h:outputText value="#{blogEntry.date}">
                  <f:convertDateTime timeZone="#{blog.timeZone}" locale="#{blog.locale}" type="both"/>
               </h:outputText>
            </p>
         </div>
      </h:column>
   </h:dataTable>
</[=>ui:define]>

</[=>ui:composition]>

This is of course also plain XML.

(Usually I would not need to explicitly define locales in my templates. JSF and Seam use the request locale by default. But Simon's requirements say that I have to use the locale of the Blog.)

Now, if we hit http://localhost:8080/seam-blog/index.seam, this is the result:

http://hibernate.org/~gavin/blog_index.png

Now for the blog entry page (which we get to by clicking Read more). Assuming I've understood them correctly, Simon's requirements say that if a nonexistent entry is requested, we are supposed to send a 404 error and forward to an error page. Now, this is not the most natural thing to do in JSF or Seam. Usually, JSF applications use pull-style MVC when handling GET requests. Normally I would write the entry page to be able to handle the case of a nonexistent entry (this is easy). But Simon is the boss here, and his requirements call for a push-style design. We'll use a Seam /page action/.

@Name("entryAction")
public class EntryAction
{
   @In private Blog blog;
   @In private FacesContext facesContext;
 
   @RequestParameter
   private String blogEntryId;
   
   @Out(scope=EVENT, required=false)
   private BlogEntry blogEntry;

   public void getBlogEntry() throws IOException
   {
      blogEntry = blog.getBlogEntry(blogEntryId);
      if (blogEntry==null)
      {
         HttpServletResponse response = (HttpServletResponse) facesContext.getExternalContext().getResponse();
         response.sendError(HttpServletResponse.SC_NOT_FOUND);
         facesContext.responseComplete();
      }
   }

}

This action is meant to run before the entry page is rendered. It retrieves the requested BlogEntry from the singleton instance of Blog and outjects it to the event context. If no BlogEntry matches the request parameter, it sends a 404 error.

We need to list the page action in WEB-INF/pages.xml.

<pages>
   <page view-id="/entry.xhtml" action="#{entryAction.getBlogEntry}"/>
</pages>

Now we can write the entry page, entry.xhtml:

<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
                             "[=>http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd]">
<[=>ui:composition] xmlns="=>http://www.w3.org/1999/xhtml"
                [=>xmlns:ui=]"=>http://java.sun.com/jsf/facelets"
                [=>xmlns:h=]"=>http://java.sun.com/jsf/html"
                [=>xmlns:f=]"=>http://java.sun.com/jsf/core"
                template="template.xhtml">

<[=>ui:define] name="content">
   <div class="blogEntry">
      <h3>#{blogEntry.title}</h3>
      <div>#{blogEntry.body}</div>
      <p>
         Posted on 
         <h:outputText value="#{blogEntry.date}">
            <f:convertDateTime timezone="#{blog.timeZone}" locale="#{blog.locale}" type="both"/>
         </h:outputText>
      </p>
   </div>
</[=>ui:define]>

</[=>ui:composition]>

Along with the 404 error page, 404.xhtml:

<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
                             "[=>http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd]">
<[=>ui:composition] xmlns="=>http://www.w3.org/1999/xhtml"
                [=>xmlns:ui=]"=>http://java.sun.com/jsf/facelets"
                [=>xmlns:h=]"=>http://java.sun.com/jsf/html"
                [=>xmlns:f=]"=>http://java.sun.com/jsf/core"
                template="template.xhtml">

<[=>ui:define] name="content">
   <h3>Page not found</h3>
</[=>ui:define]>

</[=>ui:composition]>

This page needs to be listed in web.xml:

<error-page>
   <error-code>404</error-code>
   <location>/404.seam</location>
</error-page>

Now if I click the Read more link, I get to the URL http://localhost:8080/seam-blog/entry.seam?blogEntryId=3 and see the following:

http://hibernate.org/~gavin/blog_entry.png

If I edit the URL and change the id to 6, I'll get a 404:

http://hibernate.org/~gavin/blog_404.png

And so we're done :-)