Joshua Java

Creating custom component in Struts 2

Posted by: Joshua on: December 27, 2008

On my previous Tapestry 5 article I mentioned how difficult it is to create a custom component with Struts 2 compared to Tapestry 5. Since in our legacy apps we used Struts 2 and I got a task that made me to create a custom component I might as well just document it here since it is not documented in Struts 2 documentation nor the Struts 2 book.

I will show you a very simple example on how to create custom component which is the renown “Hello World”. This component would have one property: name.

First of all you would create a Component object which is extended from Component class. This is a reusable UI Component in Struts 2 which can be reused for JSTL, Freemarker and Velocity. For this article I will show you how to reuse it in JSTL, but it shouldn’t be hard to reuse it in Freemarker and Velocity once you get the gist of how custom components works in Struts 2.

package lab.struts2.components;

import com.opensymphony.xwork2.util.ValueStack;
import org.apache.struts2.components.Component;

import java.io.IOException;
import java.io.Writer;
import java.util.Iterator;
import java.util.List;

public class Hello extends Component {
    protected String name;

    public Hello(ValueStack stack) {
        super(stack);
    }

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

    public boolean start(Writer writer) {
        try {
            writer.write("Hello " + name);
        } catch (IOException e) {
            e.printStackTrace();
        }

        return true;
    }

    public boolean end(Writer writer) {
        return true;
    }

    @Override
    public boolean usesBody() {
        return false;
    }
}

As you can see from the code above, the Writer is located in this Component class. If you have written a JSTL tag before then you would know that the Writer is in the Taglib class. That is because this component will be reused by other view like Freemarker or Velocity. Since the Writer that is responsible to send buffer to the view is located in this class, you have to write the start and end method in this class. These two methods will be responsible to process anything on the tag opener and tag closer. The last method is the usesBody which is responsible to indicated whether body should be used or not. Besides those methods you must also create the property that can be accepted by this Component including its setters. The last thing you must write in this class is a constructor which receives ValueStack as its parameter.

Now onward to the next step. As I have told you that this article intend to show how to reuse Struts 2 component in JSTL. So the next step would be creating a JSTL tag. In this article we will extend the Tag class from ComponentTagSupport which is a Struts 2 base class for JSTL view that supports Struts 2 component. Two methods that must exists in this class is the populateParams and getBean method which is responsible to propagate the values that is set to the Component object. Now in this class you must also again write the property that can be accepted along with its setters.

package lab.struts2.taglib;

import org.apache.struts2.views.jsp.ComponentTagSupport;
import org.apache.struts2.components.Component;
import com.opensymphony.xwork2.util.ValueStack;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import lab.struts2.components.Hello;

public class HelloTag extends ComponentTagSupport {
    protected String name;

    public Component getBean(ValueStack stack,
             HttpServletRequest req,
             HttpServletResponse res) {
        return new Hello(stack);
    }

    protected void populateParams() {
        super.populateParams();

        Hello hello = (Hello)component;
        hello.setName(name);
    }

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

Since we are reusing the component in JSTL, the last step would be registering this component in a .tld file which defines what properties that can be called from the JSP page. As for me I would save this .tld in META-INF/

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
        "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<taglib>
    <tlib-version>2.2.3</tlib-version>
    <jsp-version>1.2</jsp-version>
    <short-name>lab</short-name>
    <uri>/lab</uri>
    <display-name>"Lab Tags"</display-name>
    <description><![CDATA["lab"]]></description>
    <tag>
        <name>hello</name>
        <tag-class>lab.struts2.taglib.HelloTag</tag-class>
        <body-content>JSP</body-content>
        <description><![CDATA[Render a hello]]></description>
        <attribute>
            <name>id</name>
            <required>false</required>
            <rtexprvalue>false</rtexprvalue>
            <description>
                <![CDATA[id for referencing element]]></description>
        </attribute>
        <attribute>
            <name>name</name>
            <required>true</required>
            <rtexprvalue>false</rtexprvalue>
            <description><![CDATA[ Name]]></description>
        </attribute>
    </tag>
</taglib>

Now that we have created our component, we would call it from a JSP page as such:

<!DOCTYPE html PUBLIC
	"-//W3C//DTD XHTML 1.1 Transitional//EN"
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<%@taglib prefix="s" uri="/struts-tags" %>
<%@taglib prefix="lab" uri="/lab" %>

<html>
<head>
	<title>Hello World</title>
	<s:head />
</head>
<body>
    <lab:hello name="joshua"/>
</body>
</html>

If you open up your browser it would display: Hello joshua.

Well that shows you some effort you need to do for creating custom component in Struts 2. As you can see that this is only a very trivial example, but it shouldn’t be too difficult to get more advanced from here. Good luck.

11 Responses to "Creating custom component in Struts 2"

stop using struts and tapestry it is all dead. User more advanced ultra modern framework like Wicket.

Not everybody have the privilege to use whatever framework in their project :-)

Hi Joshua,

Thank you very much for this post, I really appreciate it. I am in the process of doing a conversion from Struts 1 on IBM Portal to Struts 2 on Tomcat and I think that this article will prove to be very helpful.

Take Care,
Cory Wheeler

Thanks for article. Very useful!

@pen ma

what do you mean about :
stop using struts and tapestry it is all dead. User more advanced ultra modern framework like Wicket.

is it the struts2 & tapestry project have been discountinued?..
i see many people is still learn and use Struts2 and tapestry for their solution..

CMIIW..
thx..

@Aji Dont Listen to the lame pen ma is an idiot and he does not know what he is talking about.

Tapestry, Wicket and Struts are alive and well projects that continue to improve.

Nice article to get started with.

Nice post. Could you put an example on how to manage, instead of a String for the “name” variable, a List for exemple ?

I want to have a inside Writer.write . However, it is not being rendered in the webbrowser…

Leave a Reply