Stripes vs. Struts

Stripes was born out of my ongoing frustration with the lack of a high quality, easy to use web framework. Sure, Struts has its good points, but there are a lot of small things that really add up. A lot of small things that you learn to work around, and live with, without realizing how unproductive it's making you.

Up until recently it would have been difficult to create a framework that was better-enough to warrant competing with Struts. And with JSF on the horizon (perpetually?), and other web frameworks in play (WebWork, Tapestry, Wicket) some might question the rationale behind yet another framework. But with Java 1.5 and Servlet 2.4 I think the time has come. The rationale is plain and simple - I wanted a web framework that made it easy, no, fun, to write web applications in Java. The best way to demonstrate is perhaps by a comparison with Struts.

Number of artifacts

One of my prime frustrations with Struts is the fact that just to implement a single page/form, I have to write or edit so many files. And I have to keep them in sync, or else things start going horribly wrong. With Struts I have to write my JSP, my Action, my Form, a form-bean stanza in the struts-config.xml, an action stanza in the struts-config.xml, and if I'm going to do it the Struts way, a bunch of forward stanzas. And let's not go into the fact that since this is all stored in one xml file I'm continually facing merge conflicts with my team mates. Yes, there are annotations for Struts, but they are just literal translations of what's in the XML file, and they don't feel natural to me.

Compare this with Stripes. I write my JSP. I write my ActionBean and annotate it with a @UrlBinding to specify the URL it should respond to, and one or more @HandlesEvent annotations to map events to methods. I'm done. All the information about the form and the action is in the same place.

Incremental development

Write a JSP with a Struts <html:form> tag on it and try to preview it in your container before you write your form-bean. Boom! You can't. Exception! Could not find form bean! Now write your form bean. Wait - that's still not good enough. Since everything is hooked together through the action stanza in the XML you better have an action, and edit that too.

Maybe it's just me, but I like to be able to write my JSP, see if it looks ok, then go and write the back end components to go with it. It's not brain surgery, and Stripes lets you do it.

Property binding

Struts lets you use nested properties, and that's great. But say you have a property on your Form 'person.address.line1'. Struts will try and set it for you, but if person or address is null, you'll be very sad indeed. So you have to pre-instantiate any objects on which you want to use nested properties. This just seems like too much work.

Stripes will instantiate just about anything for you. Just so long as 'person' and 'address' have no-arg constructors Stripes will build them, join them together, set them on your ActionBean and then set the 'line1' property. It'll even instantiate implementations for any of the Collections interfaces, which leads us to...

Indexed Properties

The JavaBean specification is great for the most part, but it is clearly a child of the Java GUI side of the house. Struts' implementation of indexed properties matches the JavaBean specification. But in a disconnected web model, your Action won't know (and shouldn't have to know) how many indexed properties are coming back. To make it work you end up coding "smart" indexed getter and setter methods that extend lists and insert objects just to keep Struts happy.

Stripes does it all for you. You provide a getter and setter that use a List or Map type, using generics to inform Stripes what type of thing should be in the List or Map. Stripes will instantiate the List or Map for you if necessary, extend it when needed, manufacture new objects and put them in the list and, you know, set properties of objects in the list.

Validation

Other frameworks take shots at Struts for Validation. It's just fundamentally in the wrong place. Forget that the Struts Validator requires yet another XML file with yet more information about your Form that has to be kept in sync. Validation in Struts is divorced from Type Conversion. This is just plain wrong. Why validate that something is a well formed date, then spend a whole bunch more effort converting it to one? Well Struts almost does that. It expends a lot of effort validating it, tosses it all away and then performs some pretty weak type conversion. It's inefficient, and a pain to use. Which is why most of the Struts projects I've seen steer clear of Struts Validator.

In Stripes validation is tied closely to type conversion. A number of commonly used validations can be applied pre-conversion using a simple annotation. This includes things like required field checks, length checks, regex checking etc. Then type conversion happens, or tries to. If it fails, type converters produce validation errors that can be displayed to the user. So you can put your effort into creating good type converters (if the built in ones don't cover your needs) and be done.

Null mean Null (or does it)

Ask yourself this. You have an int property in your form bean and the user doesn't enter a value in a text box. What should your property be set to? Zero sounds like a sensible default right? Now, what if you have an Integer property? If the user doesn't submit anything I'd say that means null wouldn't you? Apparently Struts thinks it means zero again. And if there are validation errors, the form will even repopulate with the value zero! The only way to get around this is to declare your number properties as Strings and do your own conversion (which is a lot of effort if your dealing with multiple Locales).

Stripes takes the position that the HTML specification is a little inconsistent, and does what it can to make it more consistent for application developers. As a result, empty strings are treated the same as if the field didn't get submitted. The user didn't enter a value, so why should your ActionBean receive one and have to figure out what it means?

Formatting

The Struts FAQ says this (among other things) in answer to why the Struts tags provide so little formatting:

Struts on why formatting in tags doesn't exist

First, work started on the JSTL and we didn't want to duplicate the effort.

Second, work started on Java Server Faces, and we didn't want to duplicate that effort either.

Third, in a Model 2 application, most of the formatting can be handled in the ActionForms (or in the business tier), so all the tag has to do is spit out a string. This leads to better reuse since the same "how to format" code does not need to be repeated in every instance. You can "say it once" in a JavaBean and be done with it.

Great. JSTL doesn't have form tags, so while JSTL is great, it doesn't really help here. JSF and Struts don't mix so well even now, and that's a reason to leave people without formatting for years? And the last is just a cop-out. I want to be able to format data in the right way for each page. And it needs to be localizable etc.

Stripes provides high quality formatting support using the same java.text APIs that the JSTL formatting is built on. It's as similar to JSTL formatting as it can be, while being constrained to living on form tags (i.e. we can't have a separate tag for formatting a date vs. a number and so on).

Multi-Event Actions

If you want to have a form that submits multiple different events in Struts you have to either extend the DispatchAction or write your own support for it. And since the DispatchAction requires all buttons to have the same name, and uses the value to determine the method to invoke, it's a huge pain if you're using localized or even just externalized values for your buttons.

Stripes uses the name of the button itself, and has built in support for multi-event Actions. You can localize to your heart's content, and Stripes will detect which button was pressed and invoke the right method for you.

JSP / View Helpers

Struts doesn't really provide a good pattern for providing dynamic data to JSPs that are not the result of another Action. This leaves you with the options of writing a pre-action for the page or doing something outside of Struts. Then, what if another Action wants to forward to your page after it's completed processing. Do you chain the actions? Do you make the second action meet the dependencies of the page also?

Stripes has a neat way of handling this. A custom tag allows the use of ActionBeans as view helpers. It works similarly to the jsp:useBean tag in that if the ActionBean already exists it just gives you a reference to it. If it doesn't exist, the tag will bring it into existence, bind data out of the request on to it, and get it ready for use.

"HTML" Tags

Maybe it's just me who could never get used to it, but why do the Struts form input tags use 'property' instead of 'name'? And why is it 'styleClass' instead of 'class'? It also makes it hard to change a tag back and forth from a plain HTML tag to a Struts tag.

Stripes takes pains to make all the form input tags as close to (if not identical to) their HTML counterparts as possible.