The Hidden Gem of Web Frameworks

Tutorial – Stripes: a lean, mean Java web framework

FredDaoud
stripes

Fred Daoud introduces us to the Java Stripes Web Framework. Low-key but packs a punch.

Stripes
is a real hidden gem of a web framework. It is relatively low-key
but those who use it, swear by it. And for good reason–it is
simple, effective, and tightly focused on doing a few things and
doing them really, really well. This gives you a framework that
does a lot more for you than you have to do for it, while staying
out of your way and letting you do things the way you want to do
them. It also lets you pick your favorite tools for the other
layers involved in developing a complete web application, such as
persistence, security, and a jazzy user interface.

If you’ve never heard of Stripes,
you might wonder if it is being used in real-world applications. It
certainly is. Just one example is Modernizing
Medicine
 where my colleagues and I use Stripes to develop
a powerful Electronic Medical Assistant for Dermatologists. Daniel
Cane, President and CEO of Modernizing Medicine, states: “HOW I
heard about Stripes, I have no idea. But, once I did, I was
immediately hooked: the ease of binding and validation, and
elegance of manipulation of forms, the power of localization, and a
solid community of people willing to help. When looking at the
Stripes book, the tag line “…and Java Web Development is Fun
Again” sold me on the platform. I have been so happy with this
framework, and each week I learn something new.”

Show me some code

Intrigued yet? Let’s look at some
code. Say you are showing a list of products from your inventory
and you want to create a link that goes to the detail page for each
product. The code in your page might look something like this:
 

 

 <%-- sample01.jsp --%>
  <ul>
    <c:forEach var="${products}" item="product">
      <li>
       <stripes:link beanclass="com.example.ProductActionBean" event="showDetail">
          <stripes:param name="productId" value="${product.id}"/>
          ${product.name}
       </stripes:link>
      </li>
    </c:forEach>
  </ul>

 

Things to take away from this
example:

  •  Stripes uses JSP for templating. It is easy to use, has
    great support in your IDE, has an enormous user base, copious
    amounts of third-party libraries and support, and is documented by
    a ton of reference pages, articles, books, and blog posts.
  • Stripes does not reinvent anything that is already available in
    standard JSP, such as the forEach tag.
  • Stripes tags are straightforward. The link clearly shows that
    it targets the
    com.jaxenter.stripes.action.ProductActionBean class and
    the showDetail event. You know exactly where to look next.
    Also, if you rename ProductActionBean or change its
    package, it’s a plain search to find where it is referenced in
    JSPs. Finally, adding a productId parameter to the link is
    easily (and cleanly) done as well.

Let’s take a peek at the Java side
of things:

 

  /* ProductActionBean.java */
  package com.jaxenter.stripes.action;
  
  import net.sourceforge.stripes.action.ForwardResolution;
  import net.sourceforge.stripes.action.Resolution;
  import com.jaxenter.stripes.model.Product;
  
  public class ProductActionBean extends BaseActionBean {
    private Integer productId;
    private Product product;
  
    public Resolution showDetail() {
      product = loadProduct(productId);
      return new ForwardResolution("/WEB-INF/jsp/productDetails.jsp");
    }
  
    public Product getProduct() {
      return product;
    }
  
    public Integer getProductId() {
      return productId;
    }
    public void setProductId(Integer productId) {
      this.productId = productId;
    }
  }

 

Now we have a few more
takeaways:

  • The class includes a method named showDetail, which
    matches the value of the event=”showDetail” attribute in
    the JSP. This method will automatically be called when the user
    clicks on the link.
  • The class also includes a productId property. Its
    value will be set to the product ID associated with the link,
    because we have <stripes:param name=”productId”> tag
    in the body of the link.
  • Although all parameter values arriving over HTTP are
    Strings, we can use Integer for our
    productId property. Stripes will automatically do the type
    conversion, and also supports Date, BigDecimal,
    BigInteger, and all primitive and wrapper types,
    out-of-the-box. It’s easy to write type conversions for your own
    types, as well.
  • The result returned by the showDetail method is a
    Resolution, which defines what happens next. Here, we are
    using ForwardResolution which clearly shows that we are
    forwarding to productDetail.jsp. The information is all
    there, no need to search in a separate file to figure out what the
    “success” string means!
  • Stripes uses Action Beans, which are so named because
    they combine actions with JavaBean properties. Here, the
    action is showDetail, and the bean is
    the inclusion of the productId and product
    properties.

In
productDetail.jsp, we can easily show the details of the selected product by
taking advantage of the automatic presence of the action bean
within the JSP, under
actionBean, courtesy of
Stripes: 

 <%-- productDetails.jsp --%>
  <h1>Product details</h1>
  <ul>
    <li>Name: ${actionBean.product.name}</li>
    <li>Description: ${actionBean.product.description}</li>
    <li>Price: ${actionBean.product.price}</li>
  </ul>

 

Knowing that the current action
bean is always available in the JSP under {actionBean}
makes it easy to transfer data to the view: just add a getter
method in the action bean class for the information that you want
to access.

More about action beans

Action beans are the workhorses of
a Stripes application. These classes are where you receive input
and handle events triggered by the user clicking on links or
submitting forms. One feature that makes things
easy for you, the developer, is, that action beans are
thread-safe.
A fresh instance is created to handle each
request, so you are free to use instance variables without worry.
The next thing to know about action beans is
that you handle events with methods of the following
signature:

 

 public Resolution eventName()

 

The method name
determines the name of the event that it handles.
We already
saw how to indicate the action bean class and event name in a link:
 

 

 <stripes:link beanclass="..." event="...">

 

We can do the same for a form just
as easily:  

 

 <stripes:form beanclass="...">
    <stripes:submit name="save" value="Save Data"/>
    <stripes:submit name="cancel" value="Cancel everything"/>
  </stripes:form>

 

The
name in each
<stripes:submit> tag indicates
which event handler method to call in the action bean (the

value is the button label to show in
the browser).
This makes it really easy to handle multiple
submit buttons in a form! Just write an event handler method for
each button:  

 

 public Resolution save() {
    // ... 
  }
  public Resolution cancel() {
    // ... 
  }

 

 

You can have
a
default event handler in an
action bean in two ways: first, if it is the only event handler
method in the action bean, it is automatically the default.

Second, you can designate an event handler method as the default by
annotating it:  

 

@DefaultHandler
  public Resolution view() {
    // ... 
  }
  public Resolution cancel() {
    // ... 
  }

 

 

After you have
handled an event, you need to tell Stripes where to go next.

You do this with a Resolution. Let’s talk about those
now.

Where to next? Resolutions

In Stripes, Resolution is
a simple interface to tell Stripes how to respond to the browser
after handling a request. The interface has just one method:
 

 

void execute(HttpServletRequest request, HttpServletResponse response);

 

As you can see,
it is simple and lets you do just about anything in order to send a
response to the browser.
Of course, Stripes has some
built-in implementations for common responses:

  • ForwardResolution forwards to a
    template, typically a JSP
  • RedirectResolution sends a redirect
    to the browser, typically to another action bean
  • StreamingResolution makes it easy
    to send a binary file as a response, such as a PDF
  • JavaScriptResolution sends a Java
    object in JavaScript, which is very useful when using
    Ajax
  • ErrorResolution sends an HTTP
    error, with error code and descriptive message

One of these
will suit your needs most of the time, but you can extend them or
write your own from scratch to get any customized behavior that you
require. The two most commonly used resolutions are

ForwardResolution and RedirectResolution:

 

  // Forwards to a JSP
  return new ForwardResolution("/WEB-INF/jsp/productDetails.jsp");
  
  // Redirects to another action bean and its default event handler
  return new RedirectResolution(AnotherActionBean.class);
  
  // Redirects to another action bean and a specific event handler
  return new RedirectResolution(AnotherActionBean.class, "showDetails");
  
  // Redirects to another action bean and a specific event handler, 
  // with request parameters
  return new RedirectResolution(AnotherActionBean.class, "showDetails")
    .addParameter("productId", 42).addParameter("showDescription", true);

 

Resolutions are expressive and let
you know right then and there, exactly what the next step is in
responding to the browser.

 
 

Binding: the superfeature

Many a Stripes user, including
myself, feel that the most powerful feature in Stripes is its
binding of request parameters to action bean properties. We’ve
looked at that feature briefly; now let’s dig deeper. Suppose you have a model object that has properties which
are, in turn, other model objects, such as a
Person with an
Address

 

  /* Person.java */ 
  package com.jaxenter.stripes.model;
  
  public class Person {
    private String firstName;
    private Address address;
  
    public String getFirstName() {
      return firstName;
    }
    public void setFirstName(String firstName) {
      this.firstName = firstName;
    }
    public Address getAddress() {
      return address;
    }
    public void setAddress(Address address) {
      this.address = address;
    }
  }
  /* Address.java */
  package com.jaxenter.stripes.model;
  
  public class Address {
    private String streetName;
  
    public String getStreetName() {
      return streetName;
    }
    public void setStreetName(String streetName) {
      this.streetName = streetName;
    }
  }

 

You’d like to
enable the user to create a person with an address using an HTML
form.
With Stripes, it would look something like this –
first, you’d have an action bean with a Person property:
 

 

  /* PersonActionBean.java */
  package com.jaxenter.stripes.action;
  
  import net.sourceforge.stripes.action.DefaultHandler;
  import net.sourceforge.stripes.action.ForwardResolution;
  import net.sourceforge.stripes.action.Resolution;
  import com.jaxenter.stripes.model.Person;
  
  public class PersonActionBean extends BaseActionBean {
    private Person person;
  
    @DefaultHandler
    public Resolution view() {
      return new ForwardResolution("/WEB-INF/jsp/personForm.jsp");
    }
  
    public Person getPerson() {
      return person;
    }
    public void setPerson(Person person) {
      this.person = person;
    }
  }

Notice that we
also have a default event handler that forwards to

personForm.jsp; this is where we create the HTML form: 

 <%-- personForm.jsp --%>
  <stripes:form beanclass="com.jaxenter.stripes.action.PersonActionBean">
    <div>
      First name:
      <stripes:text name="person.firstName"/>
    </div>
    <div>
      Street name:
      <stripes:text name="person.address.streetName"/>
    </div>
    <div>
      <stripes:submit name="save" value="Save"/>
    </div>
  </stripes:form>

See how simple
and straightforward that is?
We use the
<stripes:form> tag and indicate the target action
bean class name. Then we create text inputs with the name attribute
that corresponds to the target property: person.firstName
and person.address.streetName. When the user submits the
form, Stripes will automatically call
getPerson().setFirstName(<value>) and
getPerson().getAddress().setStreetName(<value>) on
the action bean to populate the person object and its
nested properties.

It gets better: you might think
that you’ll get a NullPointerException because we never
created a new Person() object. Never fear! Stripes does it
for you, even on nested properties. When it gets null from
a getter when binding request parameters to properties, Stripes
creates a new object and sets it. So you can just add properties
and let Stripes take care of the housekeeping. Finally, we just need an event handler for the submit
button, which is named
save:

 

 public Resolution save() {
    // save the person object... 
  }

 

By the time
the
save() method is called by
Stripes, the parameters have been bound to the action bean
properties, so we can count on the
person
object to be created, populated, and ready to be
saved. Well, that is not
entirely true: for that to work, the user has to fill in the form,
rather than submit a blank form.
We can easily address this
with validation.

Validation: easy and awesome

Stripes offers a simple way to
perform validation on user input: annotations on action bean
properties, and custom validation methods. Continuing our Person form example; say we
want to make sure that the user enters values in both the

person.firstName and person.address.streetName fields. We use annotations on the person
property in the action bean:  

 

 /* PersonValidatedActionBean.java */
  package com.jaxenter.stripes.action;
  
  import net.sourceforge.stripes.action.DefaultHandler;
  import net.sourceforge.stripes.action.DontValidate;
  import net.sourceforge.stripes.action.ForwardResolution;
  import net.sourceforge.stripes.action.Resolution;
  import net.sourceforge.stripes.validation.Validate;
  import net.sourceforge.stripes.validation.ValidateNestedProperties;
  import com.jaxenter.stripes.model.Person;
  
  public class PersonValidatedActionBean extends BaseActionBean {
    @ValidateNestedProperties({
      @Validate(field="firstName", required=true),
      @Validate(field="address.streetName", required=true)
    })
    private Person person;
  
    @DefaultHandler
    @DontValidate
    public Resolution view() {
      return new ForwardResolution("/WEB-INF/jsp/personValidatedForm.jsp");
    }
  
    public Resolution save() {
      // save the person object... 
      return new ForwardResolution("/WEB-INF/jsp/personSaved.jsp");
    }
  
    public Person getPerson() {
      return person;
    }
    public void setPerson(Person person) {
      this.person = person;
    }
  }

 

The
@Validate(required=true) annotation
marks a property as a required field.
We can place this
annotation directly on an action bean property if we are submitting
a value directly to that property. In our example, we’re not doing
that; we’re submitting values to nested properties of the
person property. In that case, we need to place our
@Validate annotations inside a
@ValidateNestedProperties annotation, and use the
field attribute to indicate which nested property we are
validating. Notice that we also added
@DontValidate to the view()
method so that the validations are not enforced
when the user first arrives to the action bean–they haven’t had a
chance to fill in the form at that point.

Now, with these validations, a
blank form will not cause our save event handler to be
called. Instead, Stripes will catch the validation errors and
redisplay the form instead, with error messages at the location
where we add the <stripes:errors/> tag:

 

  <%-- personValidatedForm.jsp --%>
  <stripes:form beanclass="com.jaxenter.stripes.action.PersonValidatedActionBean">
    <stripes:errors/>
    <div>
      First name:
      <stripes:text name="person.firstName"/>
    </div>
    <div>
      Street name:
      <stripes:text name="person.address.streetName"/>
    </div>
    <div>
      <stripes:submit name="save" value="Save"/>
    </div>
  </stripes:form>

 

Submitting a blank form will result
in a page as shown in the figure below (Fig. 1).

 

What’s really nice is that if the
user fills in one of the fields, but not the other, the page will
be redisplayed with the error message concerning the required field
that was left blank, but the field that was filled in will
automatically be repopulated. Notice that we don’t have to
do anything in the <stripes:text> tag for that to
happen. This keeps your JSP code clean and tight. Stripes comes
with the following built-in validations:  

 

  • required field
  • minimum and maximum length
  • minimum and maximum value, for numerical input
  • matching a regular expression mask
  • evaluation of a JSP expression

Writing a custom
validation method is a breeze, too.
Just write a method
annotated with @ValidationMethod. For example:

 

@ValidationMethod
  public void validateSomething(ValidationErrors errors) {
    if (!password.equals(confirmPassword)) {
      errors.add(new SimpleError("The passwords do not match."));
    }
  }

 

By adding an error to the
errors list, we cause Stripes to return to the form
instead of calling the event handler, just like when a built-in
validation fails.

Finally, note that Stripes only
calls the validation method if the built-in validations have
passed. Again, this keeps your code clean and tight, because for
example you don’t have to do null checks on the password
and confirmPassword if you made them required fields. If the
required validation fails, the custom validation method will not be
called. The error messages concerning the fields being required
will be shown instead.

 
 

More about forms and binding

I said that parameter binding was
one of Stripes’ strongest features. Combined with Stripes’ form
tags, it’s a powerful one-two punch. So let’s explore that further.
Suppose you have an enum, Gender, as follows:

 

package com.jaxenter.stripes.model;
  
  public enum Gender {
    FEMALE("Female"),
    MALE("Male");
  
    private String description;
  
    private Gender(String description) {
      this.description = description;
    }
  
    public String getDescription() {
      return description;
    }
  }

 

 

Here is how you could create a form
to select one gender with radio buttons, any number of genders with
checkboxes, and one gender with a select box:  

 

  <%-- formControls.jsp --%>
  <stripes:form beanclass="com.jaxenter.stripes.action.FormControlsActionBean">
    <div>
      Radio buttons:
      <c:forEach var="gender"
        items="<%= com.jaxenter.stripes.model.Gender.values() %>">
        <stripes:radio name="radioChoice" value="${gender}"/>${gender.description}
      </c:forEach>
    </div>
    <div>
      Checkboxes:
      <c:forEach var="gender"
        items="<%= com.jaxenter.stripes.model.Gender.values() %>">
        <stripes:checkbox name="checkboxChoices" value="${gender}"/>
        ${gender.description}
      </c:forEach>
    </div>
    <div>
      Select box:
      <stripes:select name="selectChoice">
        <stripes:option value="">Select...</stripes:option>
        <stripes:options-enumeration enum="com.jaxenter.stripes.model.Gender"
          label="description"/>
      </stripes:select>
    </div>
    <div><stripes:submit name="view" value="Send"/></div>
  </stripes:form>

 

As you can see,
the Stripes tag library makes it easy to create forms and use form
controls.
Remember that the form controls automatically
repopulate from previous values. Also, Stripes will automatically
handle the conversion between String and our
Gender enum type. Finally, notice the
<stripes:options-enumeration> tag that takes the
class name of an enum and automatically creates a list of
options from its values. It renders the enumeration’s constant by
default, but we can also use another property as we have done here
by specifying the label attribute. Stripes also has a
<stripes:options-collection> and a
<stripes:options-map> tag to render a list of
options from any Collection or Map,
respectively.

One more very nice feature is that
we can include a “Select…” option as the first in the list to
prompt the user to select an option, instead of selecting one by
default. By doing this, we can make sure that the user makes a
selection. Indeed, because the value of the “Select…” option is a
blank string, the corresponding property on the action bean will be
null if the user does not make a selection. Using
@Validate(required=true), we can enforce the requirement
of selecting an option. This is much cleaner than using -1
or some other magic value and then manually checking for that value
as meaning “no selection was made”! We are ready to look at the
action bean:  

 

  package com.jaxenter.stripes.action;
  
  import java.util.List;
  import net.sourceforge.stripes.action.ForwardResolution;
  import net.sourceforge.stripes.action.Resolution;
  import com.jaxenter.stripes.model.Gender;
  
  public class FormControlsActionBean extends BaseActionBean {
    private Gender radioChoice;
    private List<Gender> checkboxChoices;
    private Gender selectChoice;
  
    public Resolution view() {
      return new ForwardResolution("/WEB-INF/jsp/formControls.jsp");
    }
  
    public Gender getRadioChoice() {
      return radioChoice;
    }
    public void setRadioChoice(Gender radioChoice) {
      this.radioChoice = radioChoice;
    }
    public List<Gender> getCheckboxChoices() {
      return checkboxChoices;
    }
    public void setCheckboxChoices(List<Gender> checkboxChoices) {
      this.checkboxChoices = checkboxChoices;
    }
    public Gender getSelectChoice() {
      return selectChoice;
    }
    public void setSelectChoice(Gender selectChoice) {
      this.selectChoice = selectChoice;
    }
  }

 

The properties
correspond to the
name
attributes that we have in the JSP. As I
mentioned, Stripes converts from the incoming String to
the corresponding Gender. What’s more, for the checkboxes,
we have a List<Gender> property. This list will
automatically contain the genders that the user has selected. We
don’t even have to create a new ArrayList; Stripes will do
that for us, too!

Feature-packed, but without
excess

Stripes offers many useful features
while staying focused on its raison d’être: it is a
server-side web framework, not a full-stack framework nor a
client-side graphical user interface. Its philosophy is that there
are many excellent solutions for those tiers of an application, so
it does not reinvent the wheel and does not prevent you from
choosing your favorite solution for things like
persistence, JavaScript widgets, and so on. Here
is a summary of more features offered by Stripes:

  • Automatic discovery of your action beans simply by mentioning,
    once and for all, the root package of your action beans. No need to
    adjust configuration every time you add, modify, or remove an
    action bean.
  • Similarly, automatic discovery of your extensions:
    these are custom type converters, formatters, and other Stripes
    artifacts that you extend or implement to suit your needs.
  • A layout system that is both simple and powerful. The
    recurring theme of not requiring configuration holds here as
    well.
  • Annotations to easily create wizards, forms that span
    multiple pages.
  • Interceptors, which allow you to tap into the Stripes
    lifecycle and do virtually anything to customize the framework to
    meet your requirements.
  • Exception handling to define, in one place, how to
    handle exceptions, from specific to general.
  • Testing facilities so that you can write automated
    tests for your Stripes web application.
  • Localization to easily make your application available
    in multiple languages.

Conclusion

Stripes strikes a perfect balance
of powerful features, simplicity, and tight focus to give you a
framework that does a lot for you without getting in your way nor
suffering from feature bloat. It is easy to learn and intuitive, so
you quickly become productive. It is customizable and extendable,
so you can tweak it to suit your more advanced or particular
requirements. Last but not least, it has one of
the friendliest communities in the open source framework space, so
if you need help, write a message to the mailing
list
.

Author Bio

Fred Daoud is the author of
Stripes and Java Web
Development is Fun Again
 and
currently uses Stripes at
Modernizing Medicine,
Inc
. He has been using Java
since 1997 and loves web frameworks. He also likes using other
JVM-based languages such as Clojure, JRuby, and Groovy.

 

This article previously appears
in Java Tech Journal – Java Web Frameworks. Find more articles on
web frameworks here.

Author
FredDaoud
Fred Daoud is the author of Stripes and Java Web Development is Fun Again and currently uses Stripes at Modernizing Medicine, Inc. He has been using Java since 1997 and loves web frameworks. He also likes using other JVM-based languages such as Clojure, JRuby, and Groovy.
Comments
comments powered by Disqus