Which EL context to use?
December 06, 2011 19:03:25 Last update: December 07, 2011 08:54:11
Our custom tag, as implemented in the previous note, is broken when a template is used.
Create a template file (
and a test page that uses it (
Then request the page with URL:
You'll find that our hello tag works inside
This is the corrected implementation:
Create a template file (
home-template.xhtml):
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets"> <h:head> <title>Facelets Template Demo</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> </h:head> <h:body> <div id="header"><h2>Facelets Taglib Demo</h2></div> <div id="content"> <ui:insert name="content">Default Content</ui:insert> </div> </h:body> </html>
and a test page that uses it (
home.xhtml):
<?xml version="1.0" encoding="UTF-8"?> <ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:my="http://www.example.com/ns/facelettags" template="home-template.xhtml"> <ui:define name="content"> <!-- using ui:param --> <ui:param name="paramName" value="#{param['name']}"/> <my:hello src="#{paramName}"/> <!-- using ui:repeat --> <ui:repeat var="repeatName" value="#{paramValues['name']}"> <p><my:hello src="#{repeatName}"/></p> </ui:repeat> </ui:define> </ui:composition>
Then request the page with URL:
http://localhost:8080/facelet-demo/home.jsf?name=Jack.
You'll find that our hello tag works inside
ui:repeat but fails to get the value defined by ui:param! What's the problem? Our hello tag implementation evaluated the EL with the wrong EL context!
This is the corrected implementation:
package com.example; import java.io.IOException; import java.lang.reflect.Method; import javax.el.ValueExpression; import javax.faces.component.UIComponent; import javax.faces.component.UIComponentBase; import javax.faces.context.FacesContext; import javax.faces.context.ResponseWriter; import javax.faces.view.facelets.FaceletContext; import javax.faces.view.facelets.TagAttribute; import javax.faces.view.facelets.TagHandler; import javax.faces.view.facelets.TagConfig; /** * Custom facelet tag that says hello. */ public class HelloTagHandler extends TagHandler { public HelloTagHandler(TagConfig config) { super(config); } public void apply(final FaceletContext context, final UIComponent parent) throws IOException { final ValueExpression ve = getRequiredAttribute("name").getValueExpression(context, Object.class); UIComponentBase c = new UIComponentBase() { public void encodeEnd(FacesContext ctx) throws IOException { ResponseWriter w = ctx.getResponseWriter(); w.write(String.format("Hello %s!", ve.getValue(ctx.getELContext()))); } // abstract method in base, must override public String getFamily() { return "com.example.facelettag.test"; } }; parent.getChildren().add(c); } }