O Renderer é o componente responsável por escrever o HTML do um componente do JSF na página.
package test2;
import java.io.IOException;
import java.util.Map.Entry;
import java.util.Set;
import javax.faces.component.UIComponent;
import javax.faces.component.UIInput;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.render.FacesRenderer;
import javax.faces.render.Renderer;
@FacesRenderer(componentFamily = "javax.faces.Input",
rendererType = "mypatterns.InputText")
public class MyInputTextRenderer extends Renderer {
@Override
public void encodeEnd(FacesContext context, UIComponent component)
throws IOException {
ResponseWriter writer = context.getResponseWriter();
writer.startElement("input", component);
writer.writeAttribute("id", component.getClientId(), "id");
writer.writeAttribute("type", "text", null);
writer.writeAttribute("name", component.getClientId(), null);
encodeAttribute(context, component);
writer.endElement("input");
}
private void encodeAttribute(FacesContext context, UIComponent component)
throws IOException {
ResponseWriter writer = context.getResponseWriter();
Set<Entry<String, Object>> attrs = component.getAttributes().entrySet();
for (Entry<String, Object> attr : attrs) {
writer.writeAttribute(attr.getKey(), attr.getValue(), null);
}
}
@Override
public void decode(FacesContext context, UIComponent component) {
String value = context.getExternalContext().getRequestParameterMap()
.get(component.getClientId());
((UIInput) component).setSubmittedValue(value);
}
}
Este é o código completo do meu custom Renderer para um h:inputText. Os métodos mais importantes aqui são o encodeEnd() e decode().
O primeiro, “encodeEnd(FacesContext, UIComponent)”, é o método que vai escrever o HTML. Esse método, provavelmente, precisará ser mais elaborado pois você provalvmente vai querer renderizar o valor de atributos como styleClass, style e outros.
O segundo método, “decode(FacesContext, UIComponent)”, é o método que vai ler o valor desse inputText da requisição. Depois de obter esse valor ele chama o método
setSubmitedValue(Object) do componente para “informar” ao JSF qual é o valor real desse Input. Esse método só é usado por componente do tipo Input.
A anotação @FacesRenderer serve para declarar o Renderer no framework. O atributo componentFamily precisa ter o mesmo valor da família do componente pelo quel esse Renderer é responsável, nesse caso “javax.faces.Input”. E o atributo rendererType é usado para identificar esse renderer nos arquivos de configuração.
<?xml version="1.0" encoding="UTF-8"?>
<facelet-taglib version="2.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facelettaglibrary_2_0.xsd">
<namespace>http://mypatterns.com/comp</namespace>
<tag>
<tag-name>inputText</tag-name>
<attribute>
<name>value</name>
<type>java.lang.String</type>
</attribute>
<component>
<component-type>javax.faces.HtmlInputText</component-type>
<renderer-type>mypatterns.InputText</renderer-type>
</component>
</tag>
</facelet-taglib>
Esse é o arquivo de declaração de tags do Facelets. A tag namespace no início é usado para declarar o nome da sua “biblioteca” de tags.
A tag “tag” declara o nome tag que você vai criar para usar o seu inputText com o seu custom Renderer. component-type e renderer-type informa qual é o componente (no seu caso “javax.faces.HtmlInputText” é a classe do h:inputText) e mypatterns.InputText é o valor do atributo rendererType da anotação @FacesRenderer do custom Renderer que foi criado.
Esse arquivo precisa ser declarado no seu web.xml da seguinte maneira:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<welcome-file-list>
<welcome-file>index.xhtml</welcome-file>
</welcome-file-list>
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
<context-param>
<param-name>javax.faces.FACELETS_SKIP_COMMENTS</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>javax.faces.FACELETS_LIBRARIES</param-name>
<param-value>/WEB-INF/custom-taglib.xml</param-value>
</context-param>
<!-- JavaServer Faces -->
<servlet>
<servlet-name>FacesServlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>FacesServlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
</web-app>
Onde, nesse caso a parte que diz:
<context-param>
<param-name>javax.faces.FACELETS_LIBRARIES</param-name>
<param-value>/WEB-INF/custom-taglib.xml</param-value>
</context-param>
é que declara a sua biblioteca de tags.
Agora a sua nova tag pode ser usada da seguinte maneira:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:my="http://mypatterns.com/comp">
<h:head>
<title>Facelet Title</title>
</h:head>
<h:body>
<h:form>
<h:outputLabel for="myInput" value="Input:" />
<my:inputText id="myInput" value="#{testBean.text}">
<f:attribute name="greatestSongEver" value="Fear Of The Dark" />
</my:inputText>
<h:commandButton value="Test" action="#{testBean.foo}" />
</h:form>
</h:body>
</html>
E o HTML gerado será o seguinte:
<input id="j_idt7:myInput" type="text" name="j_idt7:myInput" javax.faces.component.VIEW_LOCATION_KEY="/index.xhtml @13,65" com.sun.faces.facelets.MARK_ID="2059540600_7ac2180d" greatestSongEver="Fear Of The Dark" />
É isso, espero ter ajudado.