Nearby lessons
19 of 30JSP - Simple Tags (SimpleTag Model)
- Understand the SimpleTag interface and its 5 methods
- Learn the SimpleTag Handler lifecycle
- Use SimpleTagSupport for easy tag development
- Process tag body content with JspFragment
- Implement dynamic attributes
- Compare Simple Tags vs Classic Tags
The Simple Tag Model (JSP 2.0) simplifies custom tag development by replacing the complex classic tag lifecycle with a single doTag() method. This lesson covers the SimpleTag interface, SimpleTagSupport class, body processing with JspFragment, dynamic attributes, and a comparison with classic tags.
SimpleTag Interface
SimpleTag is a child interface of JspTag and contains 5 methods:
public void setJspContext(JspContext c)
public void setParent(JspTag t)
public void setJspBody(JspFragment f)
public void doTag() throws JspException, IOException
public JspTag getParent()
| Method | Description |
|---|---|
setJspContext() | Provides the JspContext object (equivalent to PageContext in classic model) |
setParent() | Sets the parent tag (for nested tags) |
setJspBody() | Provides the tag body as a JspFragment (if tag has a body) |
doTag() | Main method — contains all tag logic. Equivalent to doStartTag + doEndTag + doAfterBody. |
getParent() | Returns the parent tag, or null |
SimpleTag Handler Lifecycle
The lifecycle of a SimpleTag handler is much simpler than the classic model:
- Identify — JSP engine finds the tag handler via taglib directive and TLD
- Create — Web container creates a new instance (public no-arg constructor). Simple tag objects are never reused — a new instance is created for each invocation.
- setJspContext() — Makes JspContext available
- setParent() — Sets parent tag (for nested tags)
- Set Attributes — Setter methods called for each attribute
- setJspBody() — If tag has a body, provides the JspFragment
- doTag() — Executes the tag logic. This is the only method you must implement.
- Destroy — Tag handler object is destroyed after doTag() completes
SkipPageException behavior:
- If
doTag()throwsSkipPageException→ rest of the JSP is NOT executed - If
doTag()does NOT throw it → rest of the JSP executes normally
SimpleTagSupport — Convenience Class
SimpleTagSupport implements SimpleTag and provides default implementations for all methods. It also adds helper methods:
public JspContext getJspContext() // Get the JspContext
public JspFragment getJspBody() // Get the tag body fragment
public JspTag findAncestorWithClass(JspTag t, Class c) // Find ancestor
Demo — Basic Simple Tag
Project structure:
cust10/
├── test.jsp
├── WEB-INF/
│ ├── MyTld.tld
│ └── classes/tags/
│ └── MyCustomTag.class
test.jsp:
<%@ taglib prefix="mine" uri="/WEB-INF/MyTld.tld" %>
<h1>This is Simple Tag Demo</h1>
<mine:mytag />
<h1>This is rest of the JSP</h1>
MyCustomTag.java:
package tags;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
import java.io.*;
public class MyCustomTag extends SimpleTagSupport {
public void doTag() throws JspException, IOException {
JspWriter out = getJspContext().getOut();
out.println("<h1>Hello this is from simple tag handler</h1>");
// throw new SkipPageException(); // Uncomment to stop rest of JSP
}
}
Output (without SkipPageException):
This is Simple Tag Demo
Hello this is from simple tag handler
This is rest of the JSP
Output (with SkipPageException):
This is Simple Tag Demo
Hello this is from simple tag handler
Body-content Differences: Simple vs Classic
The allowed values for <body-content> differ between the two models:
| Value | Classic Tags | Simple Tags |
|---|---|---|
empty | ✓ | ✓ |
tagdependent | ✓ | ✓ |
scriptless | ✓ | ✓ |
jsp | ✓ (default) | ✗ Not allowed |
Key rule: In the Simple Tag Model, scripting elements are not allowed in tag body. Default value is scriptless.
Processing Body Content with JspFragment
To access and process the tag body in a Simple Tag Handler, use getJspBody():
public JspFragment getJspBody()
The returned JspFragment object represents the tag body. It provides these methods:
| Method | Description |
|---|---|
getJspContext() | Returns the JspContext |
invoke(Writer w) | Evaluates the tag body and writes to the supplied Writer. Pass null to write directly to the JspOutputStream. |
Demo — Process tag body:
<%@ taglib prefix="mine" uri="/WEB-INF/MyTld.tld" %>
<h1>This is Before tag invocation</h1>
<mine:mytag>
<h1>This is Tag Body</h1>
</mine:mytag>
<h1>This is After tag invocation</h1>
MyCustomTag.java:
package tags;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
import java.io.*;
public class MyCustomTag extends SimpleTagSupport {
public void doTag() throws JspException, IOException {
JspWriter out = getJspContext().getOut();
out.println("<h1>Hello this is from simple tag handler</h1>");
getJspBody().invoke(null); // Evaluate and output the tag body
}
}
Key Differences: Simple Tags vs Classic Tags
| Property | Simple Tags | Classic Tags |
|---|---|---|
| Tag Interfaces | SimpleTag | Tag, IterationTag, BodyTag |
| Implementation Class | SimpleTagSupport | TagSupport, BodyTagSupport |
| Key Method | doTag() | doStartTag(), doEndTag(), doAfterBody() |
| Object Reuse | Never reused — new instance per invocation | Reused by web container |
| Output | getJspContext().getOut().println() | pageContext.getOut().println() |
| IOException | No try-catch needed (declared in throws) | Must enclose in try-catch |
| Body Processing | getJspBody().invoke(null) | Returns EVAL_BODY_INCLUDE or EVAL_BODY_BUFFERED |
| Page Stop | Throw SkipPageException | Return SKIP_PAGE from doEndTag() |
| Implicit Objects | Via JspContext | Via PageContext |
| Tag Body Content | JspFragment | BodyContent buffer |
| Scripting in Body | Not allowed (scriptless) | Allowed (jsp) |
Dynamic Attributes
In general, tag attributes must be declared in the TLD file. Dynamic attributes allow you to use attributes without pre-declaring them — introduced in JSP 2.0.
To support dynamic attributes:
- In the TLD, add
<dynamic-attributes>true</dynamic-attributes> - The tag handler must implement the
DynamicAttributesinterface - Implement
setDynamicAttribute(String namespace, String name, Object value)
The web container calls setDynamicAttribute() for each dynamic attribute at runtime.
Demo — Math operations with dynamic attributes:
<%@ taglib prefix="mine" uri="/WEB-INF/MyTld.tld" %>
<h1>Hello this is Sample JSP</h1>
<mine:mytag num="2" min="10" max="20" pow="2" />
MyCustomTag.java:
package tags;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
import java.io.*;
public class MyCustomTag extends SimpleTagSupport implements DynamicAttributes {
double num;
String output = "";
public void setNum(double num) { this.num = num; }
public void setDynamicAttribute(String ns, String name, Object value) {
double d = Double.parseDouble((String) value);
if (name.equals("min"))
output += "The Minimum value is: " + Math.min(num, d) + "<br>";
else if (name.equals("max"))
output += "The Maximum value is: " + Math.max(num, d) + "<br>";
else if (name.equals("pow"))
output += "The Power value is: " + Math.pow(num, d) + "<br>";
}
public void doTag() throws JspException, IOException {
JspWriter out = getJspContext().getOut();
out.println("<h1>" + output + "</h1>");
}
}
Dynamic Attributes with Static Attributes
You can combine declared (static) attributes with dynamic attributes:
MyTld.tld:
<taglib version="2.1">
<tlib-version>1.2</tlib-version>
<tag>
<name>mytag</name>
<tag-class>tags.MyCustomTag</tag-class>
<attribute>
<name>num</name>
<required>true</required>
</attribute>
<dynamic-attributes>true</dynamic-attributes>
<body-content>empty</body-content>
</tag>
</taglib>
- SimpleTag uses one doTag() method instead of doStartTag/doEndTag/doAfterBody
- SimpleTag objects are never reused — a new instance per invocation
- SimpleTagSupport provides convenient defaults for all methods