Saturday, December 15, 2007

NetBeans 6.0 and Rails

I have been looking for a good Rails IDE and think I have found one. I was using TextMate which has lots of great quick templating commands for Rails concepts for migrations, rhtml, and navigating between files and methods. However, I enjoy working with IDEs and tried some Eclipse based versions but felt that they were inadequate. My paying job at the time is mostly Java based and I use IntelliJ which makes my development more productive for that type of development.

I had not looked at NetBeans in some time because most Java developers were using Eclipse and that was fine for me at the time. So when I saw that NetBeans had a Rails related version of their IDE I was willing to give it another look. I can only say that for me this is a very nice IDE that has full functionality around the way I develop with Rails. Here are some of the features I find handy:

  • A simple IDE layout for components that is similar to IntelliJ. There are no unnecessary perspectives that Eclipse users have.
  • Support for auto-completion of methods with rdoc helpers.
  • Debugging capabilites that are simple to use.
  • Integration with version control repositories like Subversion.
  • Tools to manage your Gems and Plugins from the Tools menu
  • Easy navigation between Rails controllers and views as well as opening files via keystrokes.
  • Decent refactoring built in
  • Generators for creating Rails components.
  • Menus to run Rake and Migration scripts
  • Built in functionality to start a Rails console from your project
  • It works great on my Mac and much more than I expected...


  • Just to whet your appetite to get you more excited about this IDE here are a couple of screenshots from how I use this IDE:
    Here is what it looks like when editing files with code completion and quick docs:



    And here is a shot of what debugging looks like in NetBeans:



    If you are working on a Mac make sure you look at this link for setting up the fast debugger gem. You will also need to have XCode installed for compilation.
    I think you will agree that this is the best IDE for Rails at this time.

    Monday, March 5, 2007

    Java Through Ruby Through Java

    Java => Ruby

    Now that JRuby has matured I thought I would see what it would take to inject Java objects into Ruby objects via a Spring context. Here is how this works:

    First, create a Ruby class that will receive your Java objects:

    ruby_messenger.rb:

    require 'java'

    include_class 'com.meagle.common.spring.jruby.JRubySpring'
    include_class 'com.meagle.common.service.UserService'
    include_class 'com.meagle.common.service.impl.BaseUserServiceImpl'

    class RubyMessenger < JRubySpring

    def printMe
    p @@message
    p @@userService.to_s
    user = @@userService.findUser('admin')
    p "User first name: #{user.firstName}"
    #p user.to_xml
    end

    def setMessage(message)
    @@message = message
    end

    def getMessage
    @@message
    end

    def setUserService(userService)
    @@userService = userService
    end

    end

    RubyMessenger.new # this last line is not essential (but see below)
    This class will receive a user service object that allows us to make calls to a transactional Spring bean to a DAO defined in the main Spring configuration.

    Furthermore, I am injecting a simple String into the Ruby class from the Spring context called 'message'. Notice that the class extends an interface in Java called JRubySpring. This interface is used to expose methods on the Ruby object to our Java application. Here is what this Java interface looks like:

    JRubySpring.java:

    public interface JRubySpring {
    void printMe();

    void setUserService(UserService service);

    String getMessage();

    void setMessage(String message);
    }
    Now we have to tell Spring about our Ruby class and the properties to inject into the class. This can be wired up in a Spring 2.0 context configuration file like this:

    applicationContext-jruby.xml

    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:lang="http://www.springframework.org/schema/lang"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
    http://www.springframework.org/schema/lang
    http://www.springframework.org/schema/lang/spring-lang-2.0.xsd">

    <?xml version="1.0" encoding="UTF-8"?>

    <lang:jruby id="jrubyService"
    script-interfaces="com.meagle.common.spring.jruby.JRubySpring"
    script-source="classpath:ruby_messenger.rb">

    <lang:property name="message" value="Hello from Ruby!"/>

    <lang:property name="userService">
    <ref bean="userService"/>
    </lang:property>

    </lang:jruby>

    </beans>

    This instructs Spring to use the ruby_messenger.rb class from the classpath and allow Java classes to use the JRubySpring interface to invoke methods on the Ruby class. Furthermore, you can see the properties that are being injected into the Ruby class here.

    Finally, we need a way to test this out. Again, Spring can help us test this using the AbstractSpringIntegrationTestBase class to help with initializing a Spring context and running test scenarios. Here is the test class:

    JRubySpringTest.java

    public class JRubySpringTest extends AbstractSpringIntegrationTestBase {
    private UserService userService;

    public JRubySpringTest() {
    setDefaultRollback(true);
    }

    protected String[] getConfigLocations() {
    return new String[]{
    "applicationContext-core.xml",
    "applicationContext-jruby.xml"
    };
    }

    JRubySpring jrubyService;

    public void testGetUser() {
    System.out.println("Printing messages from plain old Java Spring context...");
    System.out.println(jrubyService.getMessage());
    User user = userService.findUser("admin");
    System.out.println("user = " + user.getFirstName());
    System.out.println("Printing messages from a Spring context injected
    into a Ruby object...");
    jrubyService.printMe();
    }

    public JRubySpring getJrubyService() {
    return jrubyService;
    }

    public void setJrubyService(JRubySpring jrubyService) {
    this.jrubyService = jrubyService;
    }

    public void setUserService(UserService userService) {
    this.userService = userService;
    }
    }
    This test class will initialize Spring and autowire the Ruby class into the test class with the Java/JRuby properties injected into the Ruby class as singletons.




    Here is some sample output when running this test class:

    03.05.2007 13:30:40,062 INFO dao.hibernate.JRubySpringTest.startNewTransaction:318 ->
    Began transaction (1): transaction manager [org.springframework.orm.hibernate3.HibernateTransactionManager@1284f8e]; default rollback = true

    Printing messages from plain old Java Spring context...

    Hello from Ruby!

    user = System

    Printing messages from a Spring context injected into a Ruby object...

    "Hello from Ruby!"


    "com.meagle.common.service.impl.BaseUserServiceImpl@595bcd"

    "User first name: System"

    03.05.2007 13:30:40,312 INFO dao.hibernate.JRubySpringTest.endTransaction:284 ->
    Rolled back transaction after test execution
    03.05.2007 13:30:40,328 INFO context.support.ClassPathXmlApplicationContext.doClose:599 ->
    Closing application context [org.springframework.context.support.ClassPathXmlApplicationContext;hashCode=6504030]

    Ruby => Java

    So what if you want to have an irb session and communicate with your Java objects. For this you just need your existing Spring context and a bootstrapping file for Ruby to initialize a JRuby console. It goes like this:

    jruby_console.rb

    # To use JRuby and Java Spring contexts together do the following:
    #
    # 1. Download the JRuby irb jar file from:
    # http://jruby.codehaus.org/Running+the+JRuby+Console+(graphical+IRB)
    #
    # 2. Add the jruby-console-0.9.2.jar file to your Java project classpath
    #
    # 3. Create a new configuration to run a Java application and set the main class to
    # org.jruby.demo.IRBConsole
    #
    # 4. Of course make sure your classpath is set correctly for your Spring config and
    # other classes/jars you need to test.
    #
    # 5. Run the application which will load the JRuby irb console
    #
    # 6. In the irb window type > load 'jruby_console.rb' to initialize this script.
    #
    # 7. This will load your Spring configuration. Access your Spring beans as
    # instance variables like this @beanName.
    #
    # 8. That was easy

    require 'java'

    # require this file if you want to include your domain objects instead of
    # including them one at a time.
    require 'domain_core.rb'

    # include this line to include all of your specific Java domain objects
    include Domain::Core

    include_class('org.springframework.context.support.ClassPathXmlApplicationContext')

    springConfigs = ["applicationContext-core.xml"]
    @context = ClassPathXmlApplicationContext.new(springConfigs.join(","))

    if @context.nil?
    p "*********Could Not initialize Spring context*********"

    return
    else
    p "*********Spring context initialized as @context*********"
    end

    p "(#{@context.beanDefinitionNames.length}) beans initialized in this context:"
    beans = ""

    # Assign non-abstract beans are initialized to instance variables.
    # Example: The 'userService' bean name will be accessible via the
    # instance variable '@userService'
    @context.beanDefinitionNames.sort.each do |bean|
    unless bean =~ /^abstract/
    instance_variable_set("@#{bean}", @context.getBean("#{bean}"))
    beans << bean + ", "
    end
    end

    p beans
    p "=========================================================================="
    p "Hey you - access your beans as instance variable like this @springBeanName"
    p "=========================================================================="

    Now you can do sadistic stuff like this:

     Welcome to the JRuby IRB Console

    irb(main):001:0> load 'jruby_console.rb'
    "*********Spring context initialized as @context*********"
    "(4) beans initialized in this context:"
    dataSource, sessionFactory, userDAO, userService"
    "=========================================================================="
    "Hey you - access your beans as instance variable like this @springBeanName"
    "=========================================================================="
    => true

    irb(main):002:0> user = @userService.find(33, User.new.class)
    => #

    irb(main):003:0> p user.firstName
    "Mark"
    => nil
    irb(main):004:0>

    Tuesday, December 5, 2006

    Autocompleting with Stripes and Scriptaculous

    I recently had to implement autocompletion AJAX functionality with script.aculous.us and Stripes. Once again this AJAX functionality was simple to integrate with Stripes. This code will return a list of users to select from after the user types more than two characters.

    Here is an example Stripes action that will be responsible for looking up the users and returning a partial page with the unorder list of users. In this example code the autoCompleteText will capture the text that will be autocompleted. A Spring bean will be used to call out to service which will use a Hibernate DAO to query for the user list.

     public class UserLookupAction implements ActionBean {

    String autoCompleteText;

    UserService userService;
    private List users;

    public Resolution findUsers(){
    this.users = userService.findUsersByAutocompletion(autoCompleteText);
    return new ForwardResolution("/pages/useradmin/FindUsers.jsp");
    }

    @SpringBean
    public void setUserService(UserService userService) {
    this.userService = userService;
    }

    public String getAutoCompleteText() {return autoCompleteText;}

    public void setAutoCompleteText(String autoCompleteText) {
    this.autoCompleteText = autoCompleteText;
    }

    public List getUsers() {
    return users;
    }

    public void setActionBeanContext(ActionBeanContext actionBeanContext);
    public ActionBeanContext getActionBeanContext() {return this.actionBeanContext;}
    }

    This JSP is responsible for making the AJAX calls to the Stripes action above. The AJAX.Autocompleter code from Scriptaculous does the work when more than two characters are present in the text field named autocomplete. If there are results they are returned in a partial page as an unordered list (more later). An animated gif indicator is used to signal the user that the AJAX call is being made and searching for results. Also, there is a callback method called getSelectionId that is called afterUpdateElement. This will be used to set the selected user id in a hidden field named autocompleteUserId. This will be used when editing the user through another Stripes action (UserEditAction).

     <style type="text/css">
    div.autocomplete {
    position:absolute;
    background-color:white;
    border:1px solid #888;
    margin:0px;
    padding:0px;
    }

    div.autocomplete ul {
    list-style-type:none;
    margin:0px;
    padding:0px;
    }

    div.autocomplete ul li.selected { background-color: #ffb;}

    div.autocomplete ul li {
    list-style-type:none;
    display:block;
    margin:0;
    padding:5px;
    cursor:pointer;
    border-bottom: 1px solid #cbcbcb;
    }
    </style>


    <%@ taglib prefix="stripes" uri="http://stripes.sourceforge.net/stripes.tld" %>

    <stripes:form beanclass="com.meagle.web.stripes.action.useradmin.UserEditAction">
    User Name:
    <stripes:text size="30" id="autocomplete" name="autoCompleteText"/>

    <div id="autocomplete_choices" class="autocomplete"></div>
    <script type="text/javascript">

    new Ajax.Autocompleter ("autocomplete",
    "autocomplete_choices",
    "${pageContext.request.contextPath}/useradmin/UserLookup.action?findUsers=",
    {minChars: 2, afterUpdateElement : getSelectionId, indicator: 'indicator1'});

    function getSelectionId(text, li) {
    $('autocompleteUserId').value = li.id;
    }
    </script>

    <stripes:hidden name="userId" id="autocompleteUserId"/>
    <stripes:submit name="editUser" class=class="code-quote">"textBox" value="Edit"/>

    <span id="indicator1" style="display: none">
    <img width=
    "14" height="14"
    src="${pageContext.request.contextPath}/images/indicator_circle_ball.gif"
    alt="Working..." />

    </stripes:form>
    Finally, this is the partial page that is returned by the UserLookupAction when results are returned. This simply iterates over the User objects from the Stripes action and creates an unorder list that is stylized with the CSS above.

     <%@ taglib prefix="c" uri=<http://java.sun.com/jsp/jstl/core> %>

    <ul>
    <c:forEach var="user" items="${ actionBean.users}">
    <li id="${user.id}">${user.firstName} ${user.lastName}</li>
    </c:forEach>

    </ul>

    Thursday, November 23, 2006

    AJUG Stripes Presentation

    Phil Barnes and I presented the Stripes framework at AJUG last night. We wanted to spread the word about Stripes and how it simplifies Java Web development. Most of the people who attended the presentation were using Struts as their presentation framework (no surprise here). We came prepared with many examples about how Stripes compared to Struts.

    I think that the presentation was well received and hopefully it will make people take another look at Stripes. We have researched many Java Web frameworks and this is probably the best one out there as far as simplicity while allowing the developer to focus on application development. Stripes uses convention over configuration for resolving URLs to action classes, has excellent databinding, and integrated well with other POJO based frameworks.

    Please contact me at meagle@gmail.com if you want a copy of the slides.

    Friday, April 28, 2006

    Stripes: I think we have a winner!

    For some time now I have been evaluating Java web frameworks. This was mostly driven by my frustration with existing frameworks I have been using. The amount of effort it takes to feed these frameworks to produce anything meaningful is usually painful and not fun to maintain. My baseline framework for Java Web development has been Struts. Struts is just outdated and requires way too many configuration files, extra classes outside the controller/action, and a separate ActionForm class that requires crude object binding. Enough said. From Struts I investigated a slew of frameworks such as Tapestry, Wicket, Spring MVC, and some JSF. These frameworks were definitely better than Struts (not too hard to achieve) but never felt much more productive and varied in learning curves. Then I started to investigate WebWork. This was definitely a step in the right direction. WebWork is an action based framework that is the basis for the Struts Action 2.0 Framework. WebWork does offer simpler actions, less configuration, some AJAX support, different view resolvers, interceptor stacks, and much more. We even decided to use WebWork for our new project after we felt that it addressed most of our concerns and there was nothing better to work with. We did experience more than a 40%+ reduction in the number lines of code and configuration files we had to write. This was great until...

    The Stripes project recently released version 1.3 of their web framework. This framework relies heavily on Java 5 capabilities to deliver a much simpler web framework. The configuration is done up front in the web.xml file where a filter and a Servlet dispatcher is configured. The only thing that you need to be aware of is to configure the root package of your Stripes action classes. This allows Stripes to inspect your action classes when your servlet container starts up. Stripes uses a convention based approach to determine which classes in this defined package will be Stripes actions. Therefore, action classes do not have to be configured in an XML file. That's right - no more struts-config, xwork.xml, JSF config nonsense, etc.

    From this point on you are ready to code. The action classes that you build contain concise annotations that handle interception, validation, Spring integration, and more. With your classes annotated you do not have to flip back and forth between external files and your action classes. This saves you a ton of time and reduces lines of code. In fact we migrated our WebWork code to Stripes equivalents and experienced another 20%+ reduction in the lines of code (and removing configuration files) while maintaining full functionality. Not too bad. The migration only took about 2 days to complete for about 8 complex actions and 12 JSPs. As you can see will be using this on all of our projects.

    The only con I can think of for Stripes is that you have to use JSP and the Stripes taglibs. However, the taglib is pretty good and very close to HTML in regards to the naming used. I am hoping that a Velocity view resolver is on the horizon in the not too distant future. However, I did not experience too many problems with JSTL and the Stripes taglib.

    If this sounds good take a look at the Stripes Quick Start Guide to quickly get up and running. Stripes is a great step forward for Java web development. It offers Java developers an simple way to program Java web applications with minimal configuration, high productivity, and a fun development framework that is addictive. This might be as close to the Ruby on Rails Action Pack for MVC development as we will see in a while from the Java community.

    Tuesday, March 28, 2006

    Comparing Web Frameworks: WebWork

    Lately there have been Java Web framework comparisons on theServerSide.com. These comparisons revolve around requirements on Simon Brown's Blog. I am not sure that the application is very relevant and has limited functionality. However, I decided I would try this with WebWork. I have been using WebWork for about 5 months now and have been very productive with the framework's capabilities and ease of use. I took the requirements for the read only blog and reproduced it with WebWork. There is really very little that needed to be coded to make this happen and I did this on a plane trip from Atlanta to Las Vegas where I am attending TSSS with only one battery in my notebook.

    To save time I copied some of the components from other people's implementations that were not framework specific.This included the domain objects Blog, BlogEntry, and BlogService. Theseare straightforward and I could have generated them in IntelliJ in about 2 minutes so no big deal. I also copied the stylesheet and image that was used to pretty up the blog look and feel. Again, no big deal and not really relevant to the framework comparison. So let me take a moment to preface some of my gripes with this little project. First, I do not consider someof the methods I used to code this application to be ideal. Since this is a read only blog application I did not use a persistence mechanism for the blog entries.

    Nevertheless, I coded the application to the specifications required using only the WebWork web tier components no more. The main WebWork component that needed to be designed was the action class. This is fairly lean and should be
    easy to interpret. Here is the code:

    public class BlogAction implements Preparable {

    private Blog blog;
    private BlogEntry blogEntry;
    private String blogEntryId;
    private BlogService blogService;

    public void prepare() throws Exception {
    blog = getBlogService().getBlog();
    }

    public String execute() {
    // simply display the default page -- the data was setup in prepare()
    return "success";
    }

    public String viewBlogEntry() {
    this.blogEntry = blog.getBlogEntry(this.blogEntryId);

    return "entry";
    }

    public void setBlogEntryId(String blogEntryId) {
    this.blogEntryId = blogEntryId;
    }

    public Blog getBlog() { return blog; }

    public BlogEntry getBlogEntry() { return blogEntry; }

    protected BlogService getBlogService() {
    if (blogService == null) {
    blogService = new BlogService();
    }
    return blogService;
    }

    public void setBlogService(BlogService blogService) {
    this.blogService = blogService;
    }

    }

    This is about 40 lines of code and most of that is comments, fields, and accessors. Really there are only about 5 lines of code of any logic. The prepare method is called before the action executes to setup the action. This gets called because the action implements the Preparable interface. The Prepare interceptor is invoked as one of the interceptors in the default interceptor stack. The service should really be injected into the action by an IoC container such as Spring (WebWork has good integration support with Spring). Also notice that other than implementing the Preparable interface this action is just a POJO.

    Here is the action configuration in the xwork.xml file:
       <action name="Blog" class="com.meagle.wwblog.web.webwork.actions.BlogAction">
    <result name="success">/pages/index.vm</result>
    <result name="blogentry">/pages/entry.vm</result>
    </action>
    As for the views there were two files. The first one shows the blog and associated entries. I used SiteMesh todecorate the common elements and JSP as the view resolver to display the stack elements. WebWork can also use Freemarker, Velocity, and other view resolvers as well. Here is what the Sitemesh decorator looks like:
         <%@ page pageEncoding="UTF-8"%>
    <%@ page contentType="text/html; charset=utf-8"%>

    <%@ taglib uri="http://www.opensymphony.com/sitemesh/decorator" prefix="decorator" %>
    <%@ taglib prefix="ww" uri="/webwork" %>
    <?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"
    xml:lang="en"
    lang="en">

    <head>

    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <title><decorator:title default="Welcome!" /></title>
    <meta http-equiv="Content-Style-Type" content="text/css">
    <link rel="stylesheet" href="/css/screen.css" type="text/css"/>
    </head>

    <body>
    <div id="container">
    <h1><decorator:title default="Welcome!" /></h1>

    <h2><ww:property value="%{blog.description}"/></h2>

    <decorator:body />
    </div>
    </body>

    </html>

    So this takes care of the blog title, name, and description that appears on each page. This also leaves a placeholder for the content of each page. Here is what was required to display the entries in the blog:

         <%@ page pageEncoding="UTF-8"%>
    <%@ page contentType="text/html; charset=utf-8"%>
    <%@ taglib uri="/webwork" prefix="ww" %>
    <html>

    <head>
    <title><ww:property value="%{blog.name}"/></title>
    </head>
    <body>
    <table>

    <ww:iterator value="blog.blogEntries" id="blogEntry">
    <tr>
    <td>
    <div class="blogEntry">
    <h3><ww:property value="title"/></h3>

    <div>
    <ww:if test="excerpt != null">
    <ww:property value="excerpt" escape="false"/>
    </ww:if>
    <ww:else>
    <ww:property value="body" escape="false"/>

    </ww:else>
    </div>

    <p>
    <ww:if test="excerpt != null">
    <ww:url id="readMoreUrl" action="Blog!viewBlogEntry">
    <ww:param name="blogEntryId" value="id"/>

    </ww:url>
    <a href="<ww:property value="readMoreUrl" escape="false"/>">Read More</a>
    </ww:if>
    </p>

    <p>
    Posted on <ww:date name="%{date}" format="dd MMMM yyyy hh:mm:ss z"/>
    </p>
    </div>
    </td>
    </tr>

    </ww:iterator>
    </table>
    </body>
    </html>

    Again, this is straightforward and captures the requirements of the application. The only interesting lines here that allows the user to conditionally view more of a blog entry is this:

          <ww:url id="readMoreUrl" action="Blog!viewBlogEntry">
    <ww:param name="blogEntryId" value="id"/>
    </ww:url>
    <a href="<ww:property value="readMoreUrl" escape="false"/>">Read More</a>

    These lines create a link that calls the viewBlogEntry method of the Blog action by using a WebWorkconvention. The blog entry ID is appended as a parameter so that we can display the correct blog entry. You may notice the "action" in the tag references our Action class method viewBlogEntry(); it's in this method that we pull the specific entry and expose it (via a class variable) so that the view layer can render the entry. Here is the code for the view for displaying the entry.

         <%@ page pageEncoding="UTF-8"%>

    <%@ page contentType="text/html; charset=utf-8"%>
    <%@ taglib prefix="ww" uri="/webwork" %>
    <html>
    <body>
    <ww:if test="blogEntry != null">
    <div class="blogEntry">

    <h3><ww:property value="blogEntry.title" escape="false"/></h3>

    <div><ww:property value="blogEntry.body" escape="false"/></div>

    <p>
    Posted on <ww:date name="%{blogEntry.date}" format="dd MMMM yyyy hh:mm:ss z"/>

    </p>
    </div>
    </ww:if>
    <ww:else>
    <div class="blogEntry">
    <h3>Sorry we could not locate that blog entry...</h3>

    </div>
    </ww:else>
    <div><a href="JavaScript:void(0)" onclick="history.go(-1)">Back</a></div>
    </body>
    </html>

    That is really all there was to coding the requirements of the application. The rest of the components were skeleton elements from a base WebWork configuration.

    Conclusion

    While this is a very simplistic web application with little functionality it does show how little coding is required by WebWork to make it happen. There is so much more that I would have like to have shown such as some of the data binding capabilities inside WebWork when submitting form information with complex object graph information.

    This trivial application really does not show WebWork's full capabilities. If you think there is value in this example then you should give WebWork a try on more complex applications.
    WebWork makes coding web development with Java simple and very productive with the framework's capabilities and ease of use.

    Tuesday, October 25, 2005

    Java Web Framework Changes...

    For some time now I have been having major frustrations deciding on a Java Web framework to replace Struts. In the past I have evaluated some alternatives such as some component based Web frameworks such as Tapestry and a little at JSF. Both of these solutions are powerful but can be quite complex. While I understand the benefits of component based frameworks I am not sure that either of these frameworks are absolutely necessary for our environment. So in between Tapestry and Struts there are over 50 other web frameworks that are slight derivatives of Struts, promising frameworks like Wicket with little doco, or strangely named frameworks with little substance. So of these frameworks only two came into consideration - Spring MVC and WebWork. Both of these frameworks are not component based but address the shortcomings of Struts. One of my biggest grips with Struts is having to implement ActionForm objects and dealing with the Action class with it's hard to unit test methods. Just binding Strings to ActionForms and translating those String to my model objects is a huge coding overhead. Spring MVC and WebWork allieviate this problem and add much more value. Both have support for continuations, AJAX, good documentation, Spring integration for actions, Velocity/Freemarker support, and community support. We currently use Spring in our middle tier and Hibernate for our persistence layer. However, we chose WebWork because of the simple configuration, easy to configure interceptors, pluggable view handlers, programmable continuations, and support for other popular frameworks like Spring. Choosing a Java web framework is very difficult and you have to accept that there is no single best choice. That is probably why there are too many already available and more will keep coming until someone gets it right. So our web tier for the forseeable future will now consist of WebWork 2.2 + Freemarker + SiteMesh.