I'm writing a simple custom function in Facelets with a sample method. The problem is that the JSF 2 application fails to locate that function. The error message is:
/test.xhtml #15,73 rendered="#{test:isGranted('ONE_ROLE')}" Function 'test:isGranted' not found.
I've been checking and rechecking and can't find the problem. Any comment here would be really appreciated as it's clear that I'm missing something (but it seems that the steps involved are really simple).
Do you know if there are other requisites?
Thanks in advance.
The relevant code:
In the web.xml the tag XML descriptor is declared
<context-param>
<param-name>javax.faces.FACELETS_LIBRARIES</param-name>
<param-value>/WEB-INF/test.taglib.xml</param-value>
</context-param>
The file test.taglib.xml:
<?xml version="1.0"?>
<!DOCTYPE facelet-taglib PUBLIC
"-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN"
"http://java.sun.com/dtd/facelet-taglib_1_0.dtd">
<facelet-taglib>
<namespace>http://www.test.com/security/tags</namespace>
<function>
<function-name>isGranted</function-name>
<function-class>com.test.security.taglibs.IsGranted</function-class>
<function-signature>boolean isGranted(java.lang.String role)</function-signature>
</function>
</facelet-taglib>
The tag class:
public class IsGranted extends TagHandler {
public static boolean isGranted(String role) {
// Do nothing. Just a test.
return false;
}
}
And the test file:
<?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:h="http://java.sun.com/jsf/html"
xmlns:test="http://www.test.com/security/tags">
<body>
<h:outputText value="You should NOT see this." rendered="#{test:isGranted('ONE_ROLE')}"/>
</body>
</html>
In your example you are declaring the sec namespace prefix but use the test prefix in your function call. But maybe that was just a copying mistake.
Another possible cause would be the header of your taglib file, which uses the facelets 1.0 DTD instead of the JSF 2.0 version. This might be problematic depending on your JSF implementation, for example for MyFaces see this bug report and discussion thread. The header for a JSF 2.0 taglib would be:
<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">
Related
I'm trying to make a simple JSF hello world, with JSF 2.0, JBoss AS 7.0
Here's my xhml file :
<!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:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<h:head>
<title>Page 1</title>
</h:head>
<body>
<f:view>
<h:outputLabel value="Hello Stock Manager Hello JSF again" />
<br/>
<h:outputLabel value="Tester Bean : #{testerBean.message}" />
</f:view>
</body>
</html>
and here's the managed bean class :
package prv.stockmanager.web.beans;
public class TesterBean {
private String message = "This is a message";
public TesterBean() {
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
And here's the faces-config (which is in the web-inf) :
<?xml version="1.0" encoding="UTF-8"?>
<faces-config version="2.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xi="http://www.w3.org/2001/XInclude"
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">
<managed-bean>
<managed-bean-name>testerBean</managed-bean-name>
<managed-bean-class>prv.stockmanager.web.beans.TesterBean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property> <property-name>message</property-name>
<property-class>java.lang.String</property-class>
<value/>
</managed-property>
</managed-bean>
</faces-config>
The page works fine without exception if I remove the call to the managed bean. But when I call the managed bean I get this :
Bean or property class prv.stockmanager.web.beans.TesterBean for managed bean testerBean cannot be found.
at com.sun.faces.mgbean.BeanManager.create(BeanManager.java:265) [jsf-impl-2.1.3-b02-jbossorg-2.jar:2.1.3-SNAPSHOT]
at com.sun.faces.el.ManagedBeanELResolver.resolveBean(ManagedBeanELResolver.java:244) [jsf-impl-2.1.3-b02-jbossorg-2.jar:2.1.3-SNAPSHOT]
Is it because JBoss AS 7.0 is using JSF 2.1 jar file or something? Should I use JSF 2.1 then? How to change that?
Problem resolved, I figured out that Eclipse is not generating the class. I disabled the automatic build and it worked fine. There should be a problem with JBoss Studio that I am using.
I have some problems with the default URL that jsf shows:
The url is displayed like this:
www.URL.com/PROYECT_NAME/
And I want something like this
www.URL.com/PROYECT_NAME/home
I sent up the welcome file like this.
<welcome-file-list>
<welcome-file >faces/views/home.xhtml</welcome-file>
</welcome-file-list>
So what I really want is that when jsf shows the welcome file show and url like this www.URL.com/PROYECT_NAME/home or the complete route faces/views/home.xhtml.
I know is a dumb question but Im stock in it
It is possible to achieve that using a filter-based servlet extension like PrettyFaces.
It is simple to use, has good documentation and examples, but to illustrate your case you could do something like this:
Download prettyfaces.jar and add to your classpath. Usually /WEB-INF/lib folder.
Add a pretty-config.xml file containing the URL mappings to the /WEB-INF folder.
Example of pretty-config.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<pretty-config xmlns="http://ocpsoft.com/prettyfaces/3.3.3" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://ocpsoft.com/prettyfaces/3.3.3 http://ocpsoft.com/xml/ns/prettyfaces/ocpsoft-pretty-faces-3.3.3.xsd">
<url-mapping id="home">
<pattern value="/home" />
<view-id value="/home.xhtml" />
</url-mapping>
</pretty-config>
To redirect to this mapping from a controller you should use a string like pretty: + url-mapping-id.
Example of controller bean:
#ManagedBean
#ViewScoped
public class HomeBean
{
public String goHome()
{
return "pretty:home";
}
}
That's it. Whenever you fire a request, if PrettyFaces filter finds the url mapping pattern /home it will display the view id home.xhtml but keep the URL as /home. Pretty.
Also, as a suggestion, for your welcome-file-list you could add only index.html.
Example of web.xml welcome-file-list tag:
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
And add an index.html file like this to your application root folder.
Example of index.html file:
<!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">
<head>
<title>My Application</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta http-equiv="refresh" content="0;url=/myapplication/home" />
</head>
<body>
<h3>Loading...</h3>
</body>
</html>
By doing this, whenever someone requests your application it will get a fast loading page and will be redirected to /home.
I hope it helps.
There are important parts of my JSF 2.0 application:
functions.taglib.xml:
<?xml version="1.0"?>
<!DOCTYPE facelet-taglib PUBLIC "-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN" "http://java.sun.com/dtd/facelet-taglib_1_0.dtd">
<facelet-taglib xmlns="http://java.sun.com/JSF/Facelet">
<namespace>http://marius/components</namespace>
<function>
<function-name>empty</function-name>
<function-class>com.test.ui.function.JsfFunctions</function-class>
<function-signature>java.util.Boolean empty(java.lang.Object)</function-signature>
</function>
</facelet-taglib>
JsfFunctions class:
package com.test.ui.function.function;
public class JsfFunctions {
public static boolean empty(Object obj) {
return obj == null;
}
}
web.xml:
<context-param>
<param-name>org.apache.myfaces.EXPRESSION_FACTORY</param-name>
<param-value>com.sun.el.ExpressionFactoryImpl</param-value>
</context-param>
<context-param>
<param-name>com.sun.faces.expressionFactory</param-name>
<param-value>com.sun.el.ExpressionFactoryImpl</param-value>
</context-param>
<context-param>
<param-name>facelets.LIBRARIES</param-name>
<param-value>/META-INF/functions.taglib.xml</param-value>
</context-param>
pom.xml:
<dependency>
<groupId>javax.el</groupId>
<artifactId>el-api</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>el-impl</artifactId>
<version>2.2</version>
</dependency>
XHTML file:
<?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">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:t="http://myfaces.apache.org/tomahawk"
xmlns:func="http://marius/components"
xmlns:composite="http://java.sun.com/jsf/composite">
<composite:interface>
<composite:attribute name="rendered" default="#{true}" />
</composite:interface>
<composite:implementation>
<t:dataScroller id="#{cc.attrs.tableId}Scroller"
for="#{cc.attrs.tableId}"
rendered="#{cc.attrs.rendered and !func:empty(cc.attrs.dataModel)}">
....
I get this error:
javax.el.ELException: Error Parsing: #{cc.attrs.rendered and !cl:empty(cc.attrs.dataModel)}
com.sun.el.lang.ExpressionBuilder.createNodeInternal(ExpressionBuilder.java:171)
com.sun.el.lang.ExpressionBuilder.build(ExpressionBuilder.java:188)
com.sun.el.parser.ParseException: Encountered ":" at line 1, column 28.
Was expecting one of:
"}" ...
"." ...
"[" ...
When I disable EL 2.2 integration everything works OK. Does it mean that EL 2.2 doesn't work with custom EL functions?
Look here,
xmlns:func="http://marius/components"
...
rendered="#{cc.attrs.rendered and !cl:empty(cc.attrs.dataModel)}"
You declared it on XML namespace func, but you're calling it on cl: namespace. Either rename XML namespace to cl or change the cl: prefix to func:.
Unrelated to the concrete problem, there are several other issues:
You declared a Facelets 1.x taglib. As you're already on JSF/Facelets 2.x, you should prefer a Facelets 2.x taglib declaration.
You used a Facelets 1.x specific context param facelets.LIBRARIES which only exist in JSF/Facelets 2.x for backwards compatibility. But it will be removed sooner or later. You should use java.faces.FACELETS_LIBRARIES instead.
Why don't you just use the EL standard empty keyword?
rendered="#{cc.attrs.rendered and not empty cc.attrs.dataModel}">
The empty keyword will check if it is null and if it's an array or a collection also if it has a length/size of 0.
If you just want to check for null, you could also just do
rendered="#{cc.attrs.rendered and cc.attrs.dataModel != null}">
See also:
How to create a custom EL function to invoke a static method?
I think I found the reason of the error. It seems as error was thrown because my function had name "empty". Probably it is a reserved keyword. Everything works after renaming function.
I'm using GlassFish 3.1, and trying to pass parameter to commandButton action. Following is my code:
beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans 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/beans_1_0.xsd" />
faces-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<faces-config 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-facesconfig_2_0.xsd" />
ManagedBean class
package actionParam;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
#Named("bean")
#RequestScoped
public class ActionParam {
public ActionParam() {
super();
}
public String submit(int param) {
System.out.println("Submit using value " + param);
return null;
}
}
and finally,
View
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!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:f="http://java.sun.com/jsf/core">
<h:head>
<meta http-equiv="Content-Type"
content="text/html; charset=ISO-8859-1" />
<title>Test Action Param</title>
</h:head>
<h:body>
<h:form id="actionForm">
<h:commandButton id="actionButton" value="Submit"
action="#{bean.submit}">
<f:param name="param" value="123"></f:param>
</h:commandButton>
</h:form>
</h:body>
</html>
When I click submit button, I get javax.el.MethodNotFoundException.
If I remove <f:param ... /> and pass parameter as follows,
.
:
<h:commandButton id="actionButton" value="Submit"
action="#{bean.submit(123)}">
</h:commandButton>
:
.
it works OK.
But I was thinking first way (using f:param) is correct one.
Which is the correct way to pass parameter?
Thanks in advance.
The <f:param> sets a HTTP request parameter, not an action method parameter. To get it, you would need to use <f:viewParam> or #ManagedProperty. In this particular case, the latter is more suitable. You only have to replace CDI annotations by JSF annotations in order to get #ManagedProperty to work:
#ManagedBean(name="bean")
#RequestScoped
public class ActionParam {
#ManagedProperty("#{param.param}")
private Integer param;
public String submit() {
System.out.println("Submit using value " + param);
return null;
}
}
When you're targeting a Servlet 3.0 container (Tomcat 7, Glassfish 3, JBoss AS 6, etc) with a web.xml whose <web-app> root declaration definies Servlet 3.0, then you should be able to just pass the parameter straight into the action method by EL as that's supported by EL 2.2 (which is part of Servlet 3.0):
<h:commandButton id="actionButton" value="Submit"
action="#{bean.submit(123)}">
</h:commandButton>
with
public String submit(Integer param) {
System.out.println("Submit using value " + param);
return null;
}
If you target an old Servlet 2.5 container, then you should still be able to do this using JBoss EL. See also this answer for installation and configuration details: Invoke direct methods or methods with arguments / variables / parameters in EL
I'm trying to create a custom composite component taglib in my office but i get a strange issue with EL. It seems expressions as #{cc.attrs.[var] } are already resolve as empty.
I try to create my taglib in a jar. In my jar i have my files ordered as following:
|_ /
.....|_ META-INF
..........|_ compo.taglib.xml
..........|_ resources
...............|_ components
....................|_ hello.xhtml
compo.taglib.xml contains:
<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://www.example.com/jsf/compo</namespace>
<composite-library-name>compo</composite-library-name>
<tag>
<tag-name>hello</tag-name>
<source>./components/hello.xhtml</source>
</tag>
</facelet-taglib>
hello.xhtml contains:
<?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:composite="http://java.sun.com/jsf/composite">
<composite:interface name="hello" displayName="hello">
<composite:attribute name="name" required="true" type="String"/>
</composite:interface>
<composite:implementation >
hello #{cc.attrs.name}!
</composite:implementation>
</html>
My web project contains in WEB-INF lib my taglib as a jar, jsf-impl.jar and jsf-api.jar (from Mojarra) my page is simply that:
<?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:comp="http://www.example.com/jsf/compo" >
<body>
<comp:hello name="John"></comp:hello>
</body>
</html>
At rendering i see "hello !" but not "hello John!". Attributes values seems be lost somewhere. I try this sample on tomcat 6.0.29 and Websphere 7.
I made something wrong?
Have you tested your control in web application rather than from taglib (jar file)?
I can only guess but I think your attribute is not showing because you named it name. In some cases "name" attribute is beeing used by JSF (for example in f:attribute or f:param or even ui:param uses attribute name). Try to replace attribute name with oder word.
You need to look here and check if attribute name is available.
Yes this case appears also with other attributes.
I tried with the component in web application and issue doesn't appear.
I also tried with the component in a jar with default namespace: issue doesn't appear. I think there is bug when using composite component in a jar with custom namespace.