jsfcomponentsmyfacesbea

Getting ClassCastException with JSF 1.2 Custom Component and BEA 10.3


Im getting a ClassCastException if i use Attributes in my Custom Headline Tag. Without Attributes rendering works fine.

Calling <t:headline value="test" /> gives a ClassCastException even before a Method in my HeadlineComponent or HeadlineTag-Class is called. <t:headline /> works fine.

I'm using MyFaces-1.2, on BEA 10.3

default.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="f"  uri="http://java.sun.com/jsf/core"%>
<%@ taglib prefix="h"  uri="http://java.sun.com/jsf/html"%>
<%@ taglib prefix="t" uri="http://www.tobi.de/taglibrary" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Tobi Test</title>
</head>
<body>
<f:view>

 <t:headline value="test" />

</f:view>
</body>
</html>

HeadlineComponent.java

package tobi.web.component.headline;

import java.io.IOException;

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

public class HeadlineComponent extends UIOutput {

  private String value;
  private Integer size;

  @Override
  public Object saveState(FacesContext context) {
    Object values[] = new Object[3];
    values[0] = super.saveState(context);
    values[1] = value;
    values[2] = size;
    return ((Object)(values));
  }

  @Override
  public void restoreState(FacesContext context, Object state) {
    Object values[] = (Object[])state;
    super.restoreState(context, values[0]);
    value = (String)values[1];
    size = (Integer)values[2];
  }


  @Override
  public void encodeBegin(FacesContext context) throws IOException {
    // Wenn keine Groesse angegeben wurde default 3
    String htmlTag = (size == null) ? "h3" : "h"+getSize().toString();
    ResponseWriter writer = context.getResponseWriter();
    writer.startElement(htmlTag, this);
    if(value == null) {
      writer.write("");
    } else {
      writer.write(value);
    }
    writer.endElement(htmlTag);
    writer.flush();
  }


  public String getValue() {
    if(value != null) {
      return value;
    }
    ValueExpression ve = getValueExpression("value");
    if(ve != null) {
      return (String)ve.getValue(getFacesContext().getELContext());
    }
    return null;
  }
  public void setValue(String value) {
    this.value = value;
  }
  public Integer getSize() {
    if(size != null) {
      return size;
    }
    ValueExpression ve = getValueExpression("size");
    if(ve != null) {
      return (Integer)ve.getValue(getFacesContext().getELContext());
    }
    return null;
  }
  public void setSize(Integer size) {
    if(size>6) size = 6;
    if(size<1) size = 1;
    this.size = size;
  }

}

HeadlineTag.java

package tobi.web.component.headline;

import javax.el.ValueExpression;
import javax.faces.component.UIComponent;
import javax.faces.webapp.UIComponentELTag;

public class HeadlineTag extends UIComponentELTag {

  private ValueExpression value;
  private ValueExpression size;

  @Override
  public String getComponentType() {
    return "tobi.headline";
  }

  @Override
  public String getRendererType() {
    // null, da wir hier keinen eigenen Render benutzen
    return null;
  }

  protected void setProperties(UIComponent component) {
    super.setProperties(component);
    HeadlineComponent headline = (HeadlineComponent)component;

    if(value != null) {
      if(value.isLiteralText()) {
        headline.getAttributes().put("value", value.getExpressionString());
      } else {
        headline.setValueExpression("value", value);
      }
    }
    if(size != null) {
      if(size.isLiteralText()) {
        headline.getAttributes().put("size", size.getExpressionString());
      } else {
        headline.setValueExpression("size", size);
      }
    }
  }


  @Override
  public void release() {
    super.release();
    this.value = null;
    this.size = null;
  }

  public ValueExpression getValue() {
    return value;
  }
  public void setValue(ValueExpression value) {
    this.value = value;
  }
  public ValueExpression getSize() {
    return size;
  }
  public void setSize(ValueExpression size) {
    this.size = size;
  }
}

taglibrary.tld

<?xml version="1.0" encoding="UTF-8" ?>
<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-jsptaglibrary_2_1.xsd"
 version="2.1">
 <description>Tobi Webclient Taglibrary</description>
 <tlib-version>1.0</tlib-version>
 <short-name>tobi-taglibrary</short-name>
 <uri>http://www.tobi.de/taglibrary</uri>
 <tag>
  <description>Eine Überschrift im HTML-Stil</description>
  <name>headline</name>
  <tag-class>tobi.web.component.headline.HeadlineTag</tag-class>
  <body-content>empty</body-content>
  <attribute>
   <description>Der Text der Überschrift</description>
   <name>value</name>
   <required>false</required>
   <rtexprvalue>true</rtexprvalue>
  </attribute>
  <attribute>
   <description>Die Größe der Überschrift nach HTML (h1 - h6)</description>
   <name>size</name>
   <required>false</required>
   <rtexprvalue>true</rtexprvalue>
  </attribute>
 </tag>

</taglib>

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_1_2.xsd"
    version="1.2">

 <component>
  <description>Erzeugt eine Überschrift nach HTML-Stil</description>
  <display-name>headline</display-name>
  <component-type>tobi.headline</component-type>
  <component-class>tobi.web.component.headline.HeadlineComponent</component-class>
  <attribute>
   <attribute-name>value</attribute-name>
   <attribute-class>java.lang.String</attribute-class>
  </attribute>
  <attribute>
   <attribute-name>size</attribute-name>
   <attribute-class>java.lang.Integer</attribute-class>
   <default-value>3</default-value>
  </attribute>
 </component>

</faces-config>

exception

Root cause of ServletException.
java.lang.ClassCastException: java.lang.String
    at jsp_servlet._jsf.__default._jsp__tag1(__default.java:194)
    at jsp_servlet._jsf.__default._jsp__tag0(__default.java:145)
    at jsp_servlet._jsf.__default._jspService(__default.java:104)
    at weblogic.servlet.jsp.JspBase.service(JspBase.java:34)
    at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:227)
    at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:125)
    at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:292)
    at weblogic.servlet.internal.ServletStubImpl.onAddToMapException(ServletStubImpl.java:408)
    at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:318)
    at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:175)
    at weblogic.servlet.internal.RequestDispatcherImpl.invokeServlet(RequestDispatcherImpl.java:505)
    at weblogic.servlet.internal.RequestDispatcherImpl.forward(RequestDispatcherImpl.java:251)
    at org.apache.myfaces.context.servlet.ServletExternalContextImpl.dispatch(ServletExternalContextImpl.java:341)
    at org.apache.myfaces.application.jsp.JspViewHandlerImpl.buildView(JspViewHandlerImpl.java:486)
    at org.apache.myfaces.application.jsp.JspViewHandlerImpl.renderView(JspViewHandlerImpl.java:337)
    at org.apache.myfaces.lifecycle.RenderResponseExecutor.execute(RenderResponseExecutor.java:41)
    at org.apache.myfaces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:140)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:182)
    at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:227)
    at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:125)
    at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:292)
    at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:175)
    at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3498)
    at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
    at weblogic.security.service.SecurityManager.runAs(Unknown Source)
    at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2180)
    at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2086)
    at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1406)
    at weblogic.work.ExecuteThread.execute(ExecuteThread.java:201)
    at weblogic.work.ExecuteThread.run(ExecuteThread.java:173)

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_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>tobi.web</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>

  <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>

  <context-param>
    <param-name>javax.servlet.jsp.jstl.fmt.localizationContext</param-name>
    <param-value>resources.application</param-value>
  </context-param>

  <context-param>
    <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
    <param-value>client</param-value>
  </context-param>
  <context-param>
    <param-name>org.apache.myfaces.ALLOW_JAVASCRIPT</param-name>
    <param-value>true</param-value>
  </context-param>

  <context-param>
    <param-name>org.apache.myfaces.PRETTY_HTML</param-name>
    <param-value>true</param-value>
  </context-param>

  <context-param>
    <param-name>org.apache.myfaces.DETECT_JAVASCRIPT</param-name>
    <param-value>false</param-value>
  </context-param>

  <context-param>
    <param-name>org.apache.myfaces.AUTO_SCROLL</param-name>
    <param-value>true</param-value>
  </context-param>

  <servlet>
    <servlet-name>faces</servlet-name>
    <servlet-class>org.apache.myfaces.webapp.MyFacesServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>faces</servlet-name>
    <url-pattern>*.jsf</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>faces</servlet-name>
    <url-pattern>*.faces</url-pattern>
  </servlet-mapping>

  <listener>
    <listener-class>org.apache.myfaces.webapp.StartupServletContextListener</listener-class>
  </listener>

</web-app>

Solution

  • I see, the <rtexprvalue> in taglibrary.tld should be replaced by <deferred-value> for JSF 1.2 on JSP 2.1 when you use UIComponentELTag.

      <attribute>
       <description>Der Text der Überschrift</description>
       <name>value</name>
       <required>false</required>
       <deferred-value>
        <type>java.lang.String</type>
       </deferred-value>
      </attribute>
      <attribute>
       <description>Die Größe der Überschrift nach HTML (h1 - h6)</description>
       <name>size</name>
       <required>false</required>
       <deferred-value>
        <type>java.lang.Integer</type>
       </deferred-value>
      </attribute>
    

    Give it a try. Also see the JSF 1.2 release notes.