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