Category Archives: struts

Unit Testing Struts 2 Actions wired with Spring using JUnit

Hopefully this entry serves as some search engine friendly documentation on how one might unit test Struts 2 actions configured using Spring, something I would think many, many people want to do. This used to be done using StrutsTestCase in the Struts 1.x days but Webwork/Struts provides enough flexibility in its architecture to accommodate unit testing fairly easily. I’m not going to go over how the Spring configuration is setup. I’m assuming you have a struts.xml file which has actions configured like this:

<struts>
 <package namespace="/site" extends="struts-default">
  <action name="deletePerson" class="personAction"
                  method="deletePerson">
   <result name="success">/WEB-INF/pages/person.jsp</result>
  </action>
 </package>
 ...
</struts>

You also might have an applicationContext.xml file where you might define your Spring beans like this.

<beans>
 <bean id="personAction"
  class="com.arsenalist.action.PersonAction"/>
 ...
</beans>

Then of course you also need to have an action which you want to test which might look something like:

public class PersonAction extend ActionSupport {

  private int id;

  public int getId() {
    return id;
  }
  public void setId(int id) {
    this.id = id;
  }
  public String deletePerson() {
    ....
    return SUCCESS;
  }
}

Remember than in Struts 2, an action is usually called before and after various other interceptors are invoked. Interceptor configuration is usually specified in the struts.xml file. At this point we need to cover three different methods of how you might want to call your actions.

  1. Specify request parameters which are translated and mapped to the actions domain objects (id in the PersonAction class) and then execute the action while also executing all configured interceptors.
  2. Instead of specifying request parameters, directly specify the values of the domain objects and then execute the action while also executing all configured interceptors.
  3. Finally, you just might want to execute the action and not worry about executing the interceptors. Here you’ll specify the values of the actions domain objects and then execute the action.

Depending on what you’re testing and what scenario you want to reproduce, you should pick the one that suits the case. There’s an example of all three cases below. The best way I find to test all your action classes is to have one base class which sets up the Struts 2 environment and then your action test classes can extend it. Here’s a class that could be used as one of those base classes.

See the comments for a little more detail about whats going on. One point to note is that the class being extended here is junit.framework.TestCase and not org.apache.struts2.StrutsTestCase as one might expect. The reason for this is that StrutsTestCase is not really a well written class and does not provide enough flexibility in how we want the very core Dispatcher object to be created. Also, the interceptor example shown in the Struts documentation does not compile as there seems to have been some sort of API change. It’s been fixed in this example.

import com.opensymphony.xwork2.ActionProxy;
import com.opensymphony.xwork2.ActionProxyFactory;
import junit.framework.TestCase;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.dispatcher.Dispatcher;
import org.apache.struts2.views.JspSupportServlet;
import org.springframework.context.ApplicationContext;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockServletConfig;
import org.springframework.mock.web.MockServletContext;
import org.springframework.web.context.ContextLoader;

import java.util.HashMap;

/**
 * @author Zarar Siddiqi
 */
public abstract class BaseStrutsTestCase extends TestCase {
    private static final String CONFIG_LOCATIONS = "META-INF/applicationContext-app.xml," +
                "META-INF/applicationContext-security.xml";
    private static ApplicationContext applicationContext;
    private Dispatcher dispatcher;
    protected ActionProxy proxy;
    protected static MockServletContext servletContext;
    protected static MockServletConfig servletConfig;
    protected MockHttpServletRequest request;
    protected MockHttpServletResponse response;

    public BaseStrutsTestCase(String name) {
        super(name);
    }

    /**
     * Created action class based on namespace and name
     * @param clazz Class for which to create Action
     * @param namespace Namespace of action
     * @param name Action name
     * @return Action class
     * @throws Exception Catch-all exception
     */
    @SuppressWarnings("unchecked")
    protected <t> T createAction(Class<t> clazz, String namespace, String name)
            throws Exception {

        // create a proxy class which is just a wrapper around the action call.
        // The proxy is created by checking the namespace and name against the
        // struts.xml configuration
        proxy = dispatcher.getContainer().getInstance(ActionProxyFactory.class).
                createActionProxy(
                namespace, name, null, true, false);

        // by default, don't pass in any request parameters
        proxy.getInvocation().getInvocationContext().
                setParameters(new HashMap());

        // do not execute the result after executing the action
        proxy.setExecuteResult(true);

        // set the actions context to the one which the proxy is using
        ServletActionContext.setContext(
                proxy.getInvocation().getInvocationContext());
        request = new MockHttpServletRequest();
        response = new MockHttpServletResponse();
        ServletActionContext.setRequest(request);
        ServletActionContext.setResponse(response);
        ServletActionContext.setServletContext(servletContext);
        return (T) proxy.getAction();
    }

    protected void setUp() throws Exception {
        if( applicationContext == null ) {
            // this is the first time so initialize Spring context
            servletContext = new MockServletContext();
            servletContext.addInitParameter(ContextLoader.CONFIG_LOCATION_PARAM,
                    CONFIG_LOCATIONS);
            applicationContext = (new ContextLoader()).initWebApplicationContext(servletContext);

            // Struts JSP support servlet (for Freemarker)
            new JspSupportServlet().init(new MockServletConfig(servletContext));
        }
        // Dispatcher is the guy that actually handles all requests.  Pass in
        // an empty. Map as the parameters but if you want to change stuff like
        // what config files to read, you need to specify them here.  Here's how to
        // scan packages for actions (thanks to Hardy Ferentschik - Comment 66)
        // (see Dispatcher's source code)
        HashMap params = new HashMap();
        params.put("actionPackages", "com.arsenalist.action");
        dispatcher = new Dispatcher(servletContext, params);
        dispatcher.init();
        Dispatcher.setInstance(dispatcher);
    }
}

By extending the above class for our action test classes we can easily simulate any of the three scenarios listed above. I’ve added three methods to PersonActionTest which illustrate how to test the above three cases: testInterceptorsBySettingRequestParameters, testInterceptorsBySettingDomainObjects() and testActionAndSkipInterceptors(), respectively.

public class PersonActionTest extends BaseStrutsTestCase {

 /**
  * Invoke all interceptors and specify value of the action
  * class' domain objects directly.
  * @throws Exception Exception
  */
 public void testInterceptorsBySettingDomainObjects()
         throws Exception {
  PersonAction action = createAction(PersonAction.class,
                "/site", "deletePerson");
  action.setId(123);
  String result = proxy.execute();
  assertEquals(result, "success");
 }

 /**
  * Invoke all interceptors and specify value of action class'
  * domain objects through request parameters.
  * @throws Exception Exception
  */
 public void testInterceptorsBySettingRequestParameters()
                     throws Exception {
  createAction(PersonAction.class, "/site", "deletePerson");
  request.addParameter("id", "123");
  String result = proxy.execute();
  assertEquals(result, "success");
 }

 /**
  * Skip interceptors and specify value of action class'
  * domain objects by setting them directly.
  * @throws Exception Exception
  */
 public void testActionAndSkipInterceptors() throws Exception {
  PersonAction action = createAction(PersonAction.class,
                  "/site", "deletePerson");
  action.setId(123);
  String result = action.deletePerson();
  assertEquals(result, "success");
 }
}

The source code for Dispatcher is probably a good thing to look at if you want to configure your actions more specifically. There are options to specify zero-configuration, alternate XML files and others. Ideally the StrutsTestCaseHelper should be doing a lot more than what it does right now (creating a badly configured Dispatcher) and should allow creation of custom dispatchers and object factories. That’s the reason why I’m not using StrutsTestCase since all that does is make a couple calls using StrutsTestCaseHelper.

If you want to test your validation, its pretty easy. Here’s a snippet of code that might do that:

 public void testValidation() throws Exception {
  SomeAction action = createAction(SomeAction.class,
                  "/site", "someAction");
  // lets forget to set a required field: action.setId(123);
  String result = proxy.execute();
  assertEquals(result, "input");
  assertTrue("Must have one field error",
                  action.getFieldErrors().size() == 1);
 }
 

This example uses Struts 2.0.11 and Spring 2.0.6. That about sums things up.

Updated on November 4th, 2007 to make it a little simpler and compatible for newer versions of Struts and Spring. Thanks to Haroon Rafique.

Struts 2 Validation using Annotations

In a week where the Raptors bowed out of the playoffs there was some good news: I was pleasantly surprised how easy it was to get fairly complex server side validation working with Struts 2 by just using annotations. No XML whatsoever. Going into this task I was pretty sure annotations would let me down by having a shortcoming which could only be compensated for by writing validation files, but unlike my attempt at using all annotations for action configuration, this endeavor was successful.

I had written a java.net article about WebWork Validation and everything said there applies here too with the major add-on that we can now use annotations.  So let’s get to an example of visitor field validation where we annotate the properties of a Java bean and have it’s validation rules apply to a form written using <s:form>.  Note that in the same manner we annotate the bean, we an also annotate the actual action class, the concept is similar.

The form has three fields:

  • name: text input
  • gender: select box
  • favoriteTeams: checkbox

This translates to the following HTML form written using Struts tags:

<s:form>
<s:textfield name="person.name" label="'Name'"/>
<s:select name="person.gender" label="'Gender'"
      list="#{'M':'Male', 'F':'Female'}" />
<s:checkboxlist name="person.favoriteTeams"
      list="#{'RAP':'Raptors', 'ARS':'Arsenal'}"
      label="'Teams'"/>
<s:submit cssClass="submit"
      value="'Submit'"/>
</s:form>

In the action class PersonAction, just the following is needed:

@Validation
public class PersonAction extends ActionSupport {

  private Person person;

  // don't provide message, it is supplied by
  // annotations in Person class
  @VisitorFieldValidator(message="")
  public Person getPerson() {
    return person;
  }
  public void setPerson(Person person) {
    this.person = person;
  }

  public String execute() {
    // do processing
    return SUCCESS;
  }
}

Two annotations are needed, the @Validation annotation is needed to tell Struts that actions in this class might need to be validated. The @VisitorFieldValidator is telling Struts that the person object properties need validation. If you had multiple actions mapped to the same action class, all actions would be validated. Now this might not be desirable because if you had say two actions called viewForm and submitForm, you would only want to validate the latter. To get around this problem while still using annotations all we have to do is add the @SkipValidation annotation on the action method:

@SkipValidation
public String viewForm() {
  return SUCCESS;
}

As the name suggests @SkipValidation will bypass validation for calls to this method.

Now we must specify the actual rules for the properties to be validated. This must be done in the Java bean:

@Validation
public class Person {
  private String name;
  private String gender;
  private String[] favoriteTeams;

  @RequiredStringValidator(message="Supply name")
  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  @RequiredStringValidator(message="Supply gender")
  public String getGender() {
    return gender;
  }

  public void setGender(String gender) {
    this.gender = gender;
  }

  @RequiredFieldValidator(message="Supply a team")
  public String[] getFavoriteTeams() {
    return favoriteTeams;
  }

  public void setFavoriteTeams(String[] favoriteTeams) {
    this.favoriteTeams = favoriteTeams;
  }

}

It’s a fairly straightforward class where @RequiredStringValidator is used for both the text input and the select box since they can only hold a singular value. The interesting part of this bean is how favoriteTeams is validated. We specify a String[] instead of a String as multiple checkboxes can be selected, Struts is smart enough to populate it properly. The other difference is that @RequiredFieldValidator is specified which enforces at least one checkbox to be selected. As a side-note, when using a radio button you would still use @RequiredStringValidator since only a single value is passed through. A multiple select box would require the use of an array and @RequiredFieldValidator.

A small quirk that I noticed is that even though the @*Validator annotations have a message and a key attribute to specify a message or a resource key, the message attribute is mandatory. So even if you’re specifying a resource key for your validation message, you still have to specify message=””.
The benefit of using visitor field validation is that the same properties can be validated in different actions without writing any new rules. Since the rules (annotations) reside in the Java bean, the Java bean can be specified as a property in different action classes to the same effect.

If you’re looking to perform client-side validation, check out Really easy field validation by Dexagogo, a powerful JavaScript library that’s based on Prototype and happens to be super-easy to use.

Struts 2 Form Control Templates

This, like many other areas of Struts 2 has remained virtually unchanged after it’s port from Webwork. The idea is that you can template the look of your controls in a fine-grained or application-wide level. Suppose you have a fetish for good practice and want to precede every occurrence of an input tag with a label tag like so:

<label for="firstName">First Name</label>
   <input type="text" name="firstName"
          id="firstName"/>

Although you can write a label tag for every input tag manually to achieve this effect, you can also specify a template to render your <s:textfield> tags to reduce the actual code you write in your JSP or Freemarker page.

Create a template called text.ftl in the folder template/mySimpleTheme and make sure template is in your classpath. Include the following in text.ftl:

<label
<#if parameters.id?exists>
for="${parameters.id?html}" <#t/>
</#if>
>${parameters.label?html}</label>

<#include "/${parameters.templateDir}/simple/text.ftl" />

The include file is pointing to a bare-bones template packaged with Struts which renders a simple <input type=”text”/> with all its attributes. All we’re doing in the additional code is doing a check for the existence of an id being passed in via the textfield tag and printing it in a label tag along with the value of label that is being passed in. Now that we’ve got a template to work with, all that’s left to do is use it. Here’s a way you can apply it to a single textfield:

<s:textfield id="firstName" name="firstName"
                theme="mySimpleTheme"
                label="First Name"/>

The above would render:

<label for="firstName">First Name</label>
   <input type="text" name="firstName"
          id="firstName"/>

The theme=”mySimpleTheme” declaration is telling Struts to look for a template in the mySimpleTheme directory under template (the default template directory). If you want this template to render all textfield elements instead of you specifying theme=”mySimpleTheme” every time, you can modify the struts.ui.theme and struts.ui.templateDir properties in struts.properties which have the default values of xhtml and template, respectively. To take a peek at the built-in templates that Struts provides, you’ll need to dig open struts2-core-2.0.6.jar and look at the template folder. This is probably a good exercise for anybody trying to develop a custom UI using Struts 2.

As mentioned the default theme is xhtml which renders <td>’s, <tr>’s and every thing else that is undesirable in markup. If you want to disable the rendering of anything but the attributes of the tag, you can use the provided “simple” theme as such:

<s:textfield id="firstName" name="firstName"
                theme="simple"
                label="First Name"/>

Alternately you could just set the struts.ui.theme to simple in struts.properties. You can also set the template attribute of each control to point to a different templates directory.

The overall mechanism for controlling appearance is completely different than Struts 1.x and somewhat more complex than it might need to be for many cases. It’s probably abstracted by erring on the side of caution and allowing you the freedom to tweak your templates any which way. Some might argue that there is an extremely tight binding between the display of controls and their functionality (both being controlled by Struts tags) and they would be true.

This is a fairly low-level method of controlling the look of a control and CSS is your best bet when trying to render them properly. Struts does use CSS classes when rendering their built-in themes of xhtml and xhtml_css although the naming might not be to your liking. For example, if you use their xhtml_css theme and use <s:textfield>, you’ll end up having to write CSS classes called wwgrp and wwlbl to control the display of labels and input elements.

One quick note, the xhtml_css theme also generates a very worthless <br/> tag between a label and the control which can throw of your entire look, do get rid of this you’ll have to do a .wwgrp br { display: none; } in your CSS stylesheeet.

Struts 2 and Zero Configuration for Actions and Results

Struts 2 (WebWork on drugs?) comes equipped with some pretty nice features, one of them being Zero Configuration where you don’t have to write any XML configuration or muck around with property files to get your application up and running. You simply specify a path to your action packages and Struts will read the classes, create actions based on the class name and register it with XWork. Once you combine this with the annotation support for action classes which enables you to define results and namespaces, the struts.xml (or should I say xwork.xml) goes out the window.

To start with, you must specify the path your action packages reside in, this can be a comma separated list:

<filter>
  <filter-name>action2</filter-name>
  <filter-class>
  org.apache.struts2.dispatcher.FilterDispatcher
  </filter-class>
  <init-param>
  <param-name>actionPackages</param-name>
  <param-value>
  com.arsenalist.action,com.arsenalist.otheractions
  </param-value>
  </init-param>
</filter>

Here’s an example of how the classes in com.arsenalist.action that extend ActionSupport (or implement Action) get mapped to a URL:

  • LoginAction: Gets mapped to login. Since this class ends with the word Action, Sturts strips Action out of the name and converts it to lowercase. If you don’t want the action to be converted to lowercase, you must set the forceLowerCase to false for the ClasspathConfigurationProvider.
  • SubmitOrder: This gets innocently mapped to submitorder.
  • SubmitActionClass: Since the action is in the middle of the class name and not at the end, this gets mapped to submitactionclass.

So the URL to call the execute() method of the LoginAction class becomes:

http://<hostname&gt;:<port>/login.action

Remember you can call different methods in the action class provided you set the struts.enable.DynamicMethodInvocation property to true in struts.properties. The usual syntax for invoking dynamic methods applies here too, so to call the attemptLogin() method in the LoginAction class the URL will be:

http://<hostname>:<port>/login!attemptLogin.action

Now lets talk about specifying results in the action class via annotations instead of XML.

@Result(name=Action.SUCCESS,
  value="/WEB-INF/pages/login.ftl",
  type=FreemarkerResult.class)
public class LoginAction extends ActionSupport {

  public String execute() {
    return SUCCESS;
  }
  public String attemptLogin() {
    return SUCCESS;
  }
}

You can specify multiple Results using the @Results annotation. You may also specify namespaces for your actions classes using the @Namespace annotation, for example if we had declared @Namespace(“/security”) at the class level in addition to the @Result annotation, the URL to execute LoginAction.execute() would be:

http://<hostname>:<port>/security/login.action

Now if this is too much work for you and you would rather use default results instead of specifying them through annotations, fear not, there is something for you. It’s called the struts2-codebehind-plugin and instead of you specifying paths to results, it will implicitly assume the path to your result in the format of:

pathPrefix/actionName-resultCode.ext

where pathPrefix is specified in struts.xml. So an example path to a result would be /WEB-INF/pages/login-success.ftl. To use this, simply add this JAR to your classpath. Or alternately add the following to your Maven pom.xml:

<dependency>
  <groupId>org.apache.struts</groupId>
  <artifactId>struts2-codebehind-plugin</artifactId>
  <version>2.0.6</version>
</dependency>

You’ll also need to specify the pathPrefix in struts.xml or alternately declare a property in struts.properties.

<constant name="struts.codebehind.pathPrefix"
          value="/WEB-INF/pages/"/>

I don’t really like this method as its too too restrictive in its nature and sometimes the same result can be returned for different actions which would introduce a redundancy in the convention.

Important Note

The one thing struts.xml buys you is having multiple actions map to the same action class. For example, if you wanted to have /doThis.action and /doThat.action map to different methods in the same class, you wouldn’t be able to do it using annotations since they force you to have one action URL per class. In most of the development I’ve done, having one class per action URL added way too many action classes to the application. If I want to process CRUD operations for a user, it would make sense to have only one UserAction class with different action paths (/user/update, /user/delete etc.) which correspond to different methods in UserAction. Of course, you can always use the /actionName!methodName.action syntax to get around this restriction of annotations but once you start integrating something like Sitemesh into your app and want your paths nicely mapped to views, you might end up wishing you had used struts.xml.

Struts and Webwork: A Tale of Two Tools

It wasn’t too many years ago that the people at Apache realized that you could probably come up with an organized way to use JSP’s and Servlets without making a huge mess. They called it Struts and it was a good, maybe even a great product when it came out. As the years went on and incremental releases of Struts started coming out, the product never really got better. Things were fixed here and there, maybe a feature was added but nothing worthy of a major release ever happened to it. Developers, even the slower ones, realized that an MVC framework offers a way to sanely manage the various scenarios in a web application, and even streamline some of the behavior common to their applications. Struts opened the door to a new wave of web development and served as the flagship product leading the way for J2EE.

However, Struts never got past the 1.x range of things because it never got significantly better. It always stayed the same and it’s committers decided that there’s no need to fix something when it’s not drastically broken. Then it was left to other people to come up with add-ons and plugins to Struts to make up for the lacking framework. Products like Struts Spring Plugin and Struts AjaxTags which had no business existing, were created. What should have been part of the framework, was now an add-on. It was left to Michael McGrady to figure out how to properly use buttons in a Struts application. All in all, Struts slowed down to a crawl until nothing but bug fixes highlighted the releases.

In the corner sat Patrick Lightbody and Jason Carreira who saw what Struts was lacking and started on Webwork, a framework that was based on common sense. OpenSymphony’s Webwork was a simple alternative to Struts that lacked the community support, but had all the features to make web development a whole lot easier. What the initial releases of Webwork lacked were more than made up for the groundbreaking Webwork2, which blew Struts out of the water in every way. Webwork2 had Spring integration, pluggable view rendering, an intuitive validation framework, dynamic action invocation, action classes that were simple and powerful and a tag library that supported them perfectly. Later releases of Webwork2 had Ajax capabilities and even made use of Java 5.0 generics and annotations. In short, if you had to start a new project, you’d be a fool not to go with Webwork.

I was a Webwork user and despised using Struts because it felt clumsy, redundant and boring. Then one day I was reading Patrick Lightbody’s blog and he mentioned that Struts and Webwork were merging for the betterment of the Java development community. I was shocked to see the pretty girl actually agree to a date with an 80 year old dying patient. There was no reason for it. In my shock I asked people why on earth Webwork would even want to be associated with a product like Struts that was good five years ago and was now reduced to being used by developers who refused to use anything except what they’re comfortable with. They told me that Webwork lacked the marketing power of Struts and nobody was going to use it because they were already using Struts. That to me wasn’t a reasonable explanation since I believed that people would soon see just how much better Webwork was than Struts and would naturally switch over. But my theory will never get a chance to be proved correct since the two have now merged.

So what convinced the Webwork folks to join forces with Struts? I don’t know. I’m not privy to that information but I’m sure it was a convincing argument. Now that the two have actually become one, I hope Struts2, now in beta, adapts a progressive and exciting approach to changing web trends and technologies much like Webwork did. I would hate to see Struts2 fall behind like its predecessor, especially when it’s got the great start it needs, thanks to Webwork.

Even though the body is Struts, I hope the soul is still Webwork.