Which EL context to use? 

Joined:
08/13/2009
Posts:
164

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 (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);
    }
}
Share |
| Comment  | Tags