Comment procéder pour créer ses propres TagLibs acceptant des attributs dynamiques ?

C’est à cette question que cet article tente de répondre par un simple exemple. Les TagLibs permettent aux développeurs de pages JSP d’implémenter leurs propres tags JSP qui exécutent du code Java plus ou moins complexe. Pour rendre ce code paramétrable, il est possible d’utiliser les attributs du tag.

Exemple simple

Voici un exemple d’implémentation de taglib avec la classe com/company/project/HelloTag.java :

package com.company.project;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;
public class HelloTag extends TagSupport {
	private String from = null;
	private String to = null;
	public void setFrom(String from) {
		this.from = from;
	}
	public void setTo(String to) {
		this.to = to;
	}
	public int doStartTag() throws JspException {
		try {
			pageContext.getOut().println	("Hello <blink>"+to+"</blink>"+(from!=null?", I'm "+from:"")+".");
		} catch (IOException e) {
			throw new JspException ("I/O Error", e);
		}
		return SKIP_BODY;
	}
}

Sa défintion dans WEB-INF/ht.tld :

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!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>1.0</tlib-version>
	<jsp-version>1.2</jsp-version>
	<short-name>ht</short-name>
	<uri>ht</uri>
	<display-name>Hello tag</display-name>
	<description>Hello tag</description> 	<tag>
		<name>hello</name>
		<tag-class>com.company.project.HelloTag</tag-class>
		<body-content>empty</body-content>
		<attribute>
			<name>from</name>
			<required>false</required>
		</attribute>
		<attribute>
			<name>to</name>
			<required>true</required>
		</attribute>
	</tag>
</taglib>

Et la page JSP l’utilisant index.jsp :

<?xml version="1.0" encoding="ISO-8859-1" ?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0" xmlns:ht="/WEB-INF/ht.tld">
<html xmlns="http://www.w3.org/1999/xhtml"> <head>
	<title>Hello tag</title>
</head>
<body>
	<ht:hello to="you" from="me" /><br />
	<ht:hello to="you" />
</body>
</html>
</jsp:root>

Cet exemple fonctionne assez bien et affiche le texte suivant :

Hello you, I'm me. Hello you.

Cependant, les attributs to et from sont souvent amenés à être dynamiques. C’est à dire, qu’ils peuvent être le résultat d’un scriptlet ou d’expressions languages. Malheureusement le code ci-dessus ne fonctionne pas avec des attributs dynamiques.

Les scriptlets

Si la page JSP est modifiée pour utiliser un scriptlet ainsi :

	<ht:hello to="<%=request.getParameter("name")%>" from="me" />

Le résultat de l’exécution de la page en passant la valeur pipo au paramètre name est :

Hello <%=request.getParameter("name")%>, I'm me.

Pour que le scriptlet soit évalué, il est nécessaire de modifier la définition du taglib de manière à préciser que les attributs du tags peuvent être le résultat de scriptlets :

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!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>1.0</tlib-version>
	<jsp-version>1.2</jsp-version>
	<short-name>ht</short-name>
	<uri>ht</uri>
	<display-name>Hello tag</display-name>
	<description>Hello tag</description> 	<tag>
		<name>hello</name>
		<tag-class>com.company.project.HelloTag</tag-class>
		<body-content>empty</body-content>
		<attribute>
			<name>from</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>to</name>
			<required>true</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
	</tag>
</taglib>

Avec cette modification, le taglib fonctionne mieux et donne le résultat suivant :

Hello pipo, I'm me. Hello you.

Les expressions languages

Les scripltets sont très bien. Mais depuis JSP 2.0 et aujourd’hui avec JSP 2.1, il est préférable d’utiliser les expressions languages. La page JSP utilisant ces expressions est la suivante :

<?xml version="1.0" encoding="ISO-8859-1" ?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0" xmlns:ht="/WEB-INF/ht.tld">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<title>Hello tag</title>
</head>
<body>
	<ht:hello to="${param.name}" from="me" />
</body>
</html>
</jsp:root>

A l’exécution de cette page, le résultat obtenu est le suivant :

Hello ${param.name}, I'm me.

L’expression language n’est pas interprétée. Pour résoudre ce problème, il est nécessaire de modifier le code du taglib. Voici la version améliorée et supportant les expressions languages :

package com.company.project;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;
import org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager;
public class HelloTag extends TagSupport {
	private String from = null;
	private String to = null;
	public void setFrom(String from) {
		this.from = from;
	}
	public void setTo(String to) {
		this.to = to;
	}
	public int doStartTag() throws JspException {
		try {
			String fromEL = (String)ExpressionEvaluatorManager.evaluate("from", this.from, String.class, this, super.pageContext );
			String toEL= (String)ExpressionEvaluatorManager.evaluate("to", this.to, String.class, this, super.pageContext );
			pageContext.getOut().println	("Hello <blink>"+toEL+"</blink>"+(fromEL!=null?", I'm "+fromEL:"")+".");
		} catch (IOException e) {
			throw new JspException ("I/O Error", e);
		}
		return SKIP_BODY;
	}
}

Cette fois, la page affiche correctement le message :

Hello pipo, I'm me. Hello you.

Maintenant ce taglib paramétrable accepte les attributs dynamiques. Ainsi le code HTML généré pourra dépendre du contexte de l’utilisateur.