1

I wrote a simple custom component with JSF1 and it works fine. But when I use it in JSF2, it doesn't work. Here is how I use it:

<?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:d="http://jsftutorials.com/"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core">
    <h:body>
        <f:view>
          <d:ticker>Hello World!</d:ticker>
        </f:view>
    </h:body>
</html>

Here is how the component is created for JSF1:

faces-config.xml

<?xml version="1.0" encoding="UTF-8"?>

<faces-config 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-facesconfig_2_0.xsd"
    version="2.0">
    <component>
        <component-type>ticker</component-type>
        <component-class>ticker.UITicker</component-class>
    </component>
</faces-config>

ticker.tld

<?xml version="1.0" encoding="UTF-8"?>
<!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>d</short-name>
    <uri>http://jsftutorials.com/</uri>
    <tag>
        <name>ticker</name>
        <tag-class>ticker.TickerTag</tag-class>
        <body-content>JSP</body-content>
    </tag>
</taglib>

TickerTag.java

package ticker;

import javax.faces.component.UIComponent;
import javax.faces.webapp.UIComponentTag;

@SuppressWarnings("deprecation")
public class TickerTag extends UIComponentTag {

    public void release() {
        super.release();
    }

    protected void setProperties(UIComponent component) {
        super.setProperties(component);

    }

    public String getComponentType() {
        return "ticker";
    }

    public String getRendererType() {
        return null;
    }
}

UITicker.java

package ticker;

import java.io.IOException;

import javax.faces.component.UIOutput;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;

public class UITicker extends UIOutput {

    public void encodeBegin(FacesContext context) throws IOException {
        ResponseWriter writer = context.getResponseWriter();
        writer.startElement("div", this);
    }

    public void encodeEnd(FacesContext context) throws IOException {
        ResponseWriter writer = context.getResponseWriter();
        writer.endElement("div");
    }
}

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    version="3.0">
    <display-name></display-name>

    <welcome-file-list>
        <welcome-file>index.xhtml</welcome-file>
    </welcome-file-list>

    <context-param>
        <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
        <param-value>server</param-value>
    </context-param>

    <context-param>
        <param-name>javax.faces.CONFIG_FILES</param-name>
        <param-value>/WEB-INF/faces-config.xml</param-value>
    </context-param>

    <listener>
        <listener-class>com.sun.faces.config.ConfigureListener</listener-class>
    </listener>

    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.faces</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.xhtml</url-pattern>
    </servlet-mapping>
</web-app>

What should I change to get it to work in JSF2?

Amin Oruji
  • 74
  • 1
  • 1
  • 11

1 Answers1

1

That's a JSP tag. JSP is deprecated in JSF 2.0 and succeeded by Facelets (XHTML). You're indeed using Facelets instead of JSP. Your component would only work when you're using JSF2 with legacy JSP instead of Facelets. You need to change the old JSP tag to be a Facelets tag.

Here are the changes you need to make:

  • faces-config.xml: remove the <component> altogether.

  • ticker.tld: rename it to ticker.taglib.xml and replace the content by:

    <?xml version="1.0" encoding="UTF-8"?>
    <facelet-taglib 
        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"
        version="2.0">
        <namespace>http://jsftutorials.com</namespace>
        <tag>
            <tag-name>ticker</tag-name>
            <component>
                <component-type>ticker</component-type>
            </component>
        </tag>
    </facelet-taglib>
    
  • TickerTag.java: remove it altogher. You don't need it for Facelets.

  • UITicker.java: add the following annotation on the class (this replaces the <component> entry in faces-config.xml)

    @FacesComponent("ticker")
    public class UITicker extends UIOutput {
    

    (note: the annotation value must match <component-type> in the taglib XML file, not <tag-name>)

    As UIOutput does by default not allow text children, it's basically the wrong choice to represent a <div> component. You'd better extend UIPanel instead.

    @FacesComponent("ticker")
    public class UITicker extends UIPanel {
    

    (note that the standard <h:panelGroup layout="block"> component already renders a <div> like that; I understand that you're just learning JSF, but just to be sure for the case you are really looking for a JSF component which renders a div)

  • web.xml: add the following context param:

    <context-param>
        <param-name>javax.faces.FACELETS_LIBRARIES</param-name>
        <param-value>/WEB-INF/ticker.taglib.xml</param-value>
    </context-param>
    

    (note: this is unnecessary when you provide the taglib as JAR file in /WEB-INF/lib and have the .taglib.xml file in /META-INF of the JAR)

When reading/learning something about JSF, assure that you're reading the right tutorials/resources targeted at JSF2 and not the ones targeted at JSF1. Many, many things are done differently.

See also:

Community
  • 1
  • 1
BalusC
  • 992,635
  • 352
  • 3,478
  • 3,452
  • thanks a lot, I changed my project as you said. but it doesn't work again :(. should I define d:ticker? I removed TickerTag.java, I added @FacesComponent and I removed faces-config.xml config, I added context-param config in web.xml but it doesn't work! – Amin Oruji Jan 02 '13 at 17:22
  • Ah, that is in turn a specific problem related to extending `UIOutput`. It does by default not allow text children (the `
    ` is definitely in the generated HTML output, but the text "Hello World" simply not). You'd better extend `UIPanel` instead. I'll edit the answer.
    – BalusC Jan 02 '13 at 18:45
  • thanks, I changed UIOutput to UIPanel but it doesn' work again, I think my problem isn't that. this is my page source after runing -> http://dpaste.com/861112/. d:ticker and namespace isn't converted to html! – Amin Oruji Jan 02 '13 at 19:03
  • Well, have you followed the `ticker.tld` modification step? You didn't tell anything about that in your first comment. Not having the proper taglib.xml file will result in exactly this problem. – BalusC Jan 02 '13 at 19:05
  • I have ticker.taglib.xml in WEB-INF with this source -> http://dpaste.com/861113/ – Amin Oruji Jan 02 '13 at 19:08
  • Right, you have a trailing slash in your XML namespace declaration in the page. Remove it: `xmlns:d="http://jsftutorials.com"` – BalusC Jan 02 '13 at 19:10
  • Let me +1 this as it looks bad on you @BalusC. – Buhake Sindi Apr 22 '13 at 20:41