Custom taglib results in MethodNotFoundException - jsf-2

What I want to do is declare a common datatable header as a composite component. But this answer set me straight since it was not rendered:
How to create a composite component for a datatable column?
Basically it instructed me to try my own taglib and this works really well except my header has a link in it that does reRender. When this link is pressed MethodNotFoundException is thrown.
This is my custom taglib:
<?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://stackoverflowdummy.com/dumb/components</namespace>
<tag>
<tag-name>tableHeader</tag-name>
<source>tags/tableHeader.xhtml</source>
<attribute>
<description></description>
<name>value</name>
</attribute>
<attribute>
<description>The listener that handles sorting</description>
<name>sortAction</name>
<method-signature>java.lang.String action()</method-signature>
</attribute>
<attribute>
<description>The property that holds the current id to sort on
</description>
<name>sortValue</name>
</attribute>
<attribute>
<description>The component that needs to be updated after changes
</description>
<name>reRender</name>
</attribute>
</tag>
</facelet-taglib>
I tried without method-signature and I also tried removing "action". My web.xml does include the taglib like this:
<context-param>
<param-name>javax.faces.FACELETS_LIBRARIES</param-name>
<param-value>/WEB-INF/cc.taglib.xml</param-value>
</context-param>
I also tried with "facelets.LIBRARIES" but it made no difference.
<h:commandLink value="#{o.label}" action="#{sortAction}" immediate="true" reRender="#{reRender}">
<f:setPropertyActionListener target="#{sortValue}" value="#{o.column.sortId}" />
</h:commandLink>
End usage is defined like this:
sortAction="#{myBean.sort}"
That bean has a method called with signature String sort(); and it works really well if I just define it and skip using my own tag. However everything works with the tag except the action method...

The JavaBean Specification gives multiple ways on how to call a method. In fact, you can call a action the normal way #{actionBean.actionMethod}, but also the way #{actionBean['actionMethod']}.
The sorting Action you are giving is transferred as a MethodExpression, which compared to ValueExpressions gave me problems in some JSF Environments.
What I'd like you to try testwise is, to give the action as two separate (value) parameters:
sortActionBean="#{myBean}"
sortActionMethod="sort"
and call those in the template as #{sortActionBean['sortActionMethod']}. A good article on this topic is Passing action methods facelets tags.
Hope it helps...

Related

How do I get IDE code completion to work with JSF 2.2 non-composite component attributes?

Problem: I get code completion on the tags but not the attributes.
I am working on a new web application using
Java 8
JSF 2.2.14
PrimeFaces 6.1
Netbeans 8.2
We are using a library that is provided to us in JavaScript (generated from Typescript sources). I have written a non-composite component to wrap this library and keep all that JavaScript code hidden and in one place. It initializes the the library and provides attributes to pass JavaScript callback functions to the library (so we still have to write some JavaScript).
snippet from the JSF .xhtml file
<script type="text/javascript">
function jscallbackHandler() { alert("function called!");}
</script>
<myComponent:initialize callback1="jscallbackHandler" />
This tag invokes my class to write a lot of JavaScript into the page to setup and initialize the library.
I am using the #FacesComponent annotation to declare my classes as custom components.
snippet from 'InitMyComponent.java' file
#FacesComponent(createTag = true,
tagName = "initialize",
namespace = "https://com.my.project/myComponent",
value = InitMyComponent.FAMILY)
public class InitMyComponent extends UIComponentBase { ... }
This is working except for IDE code completion and I can't find documentation or examples for JSF 2.2 components that show how to declare attributes and hook them into the project. I have seen many examples of earlier JSF 2.x components that use a taglib.xml to define the attributes for code completion, but it seems to be 'at odds' with features of the JSF 2.2 style annotation. I have to remove most of the attributes of the annotation (basically revert to a JSF 2.0 style annotation) or I get "Expression Error: Named Object ... not found". I have also gotten Tag Library supports namespace, but no tag was defined for name. If I just provide a component name to the annotation that matches the one in the taglib file it works, but just no code completion.
I have a FACELETS_LIBRARIES name/value pair in a context-param tag in the web.xml to declare where my facelet-taglib file is located.
snippet from the 'web.xml' file
<!-- Enable IDE autocompletion on component attributes -->
<context-param>
<param-name>javax.faces.FACELETS_LIBRARIES</param-name>
<param-value>/WEB-INF/myComponent.taglib.xml</param-value>
</context-param>
I have a facelet-taglib file named 'myComponent.taglib.xml' in my WEB-INF directory (same place as faces-config.xml and web.xml).
UPDATE: Responding to the comment by Kukeltje, I updated my facelet-taglib file to version 2.2, but I still get "No Suggestions" from my IDE... also updated the namespaces in my .xhtml JSF source file (even though this site said the older versions were still supported
https://jsflive.wordpress.com/2013/05/16/jsf22-namespaces/)
snippet from the 'myComponent.taglib.xml' file
<?xml version="1.0"?>
<facelet-taglib version="2.2"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-facelettaglibrary_2_2.xsd">
<namespace>http://java.sun.com/jsf/composite/components</namespace>
<composite-library-name>myComposites</composite-library-name>
<namespace>https://com.my.project/myComponent</namespace>
<tag>
<tag-name>initialize</tag-name>
<component>
<component-type>InitMyComponent</component-type>
</component>
<attribute>
<name>callback1</name>
<required>false</required>
<type>java.lang.String</type>
</attribute>
</tag>
The faces-config.xml file - defines the javaee and schema namespaces, and version 2.2 but it is otherwise 'empty'.
<?xml version="1.0" encoding="UTF-8"?>
<faces-config
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd"
version="2.2">
</faces-config>
I am fine with having to type in all the attributes but I just can't seem to find the proper way to hook this feature into my project.
Note: I have experimented with using a composite component. The code completion for attributes worked, but then I lost code completion for the tags. I'm just writing out JavaScript to setup and call a JavaScript library's initialize function but also, I would really love to pass a JavaScript object back to a bean on the server when my callback function is invoked. I am currently using a BalusC provided solution that involves p:remoteCommand and updating hidden input fields. I would greatly prefer to provide reference to the bean using EL in an attribute of my custom component.

custom jsf ui component to replace <f:selectItems />

I've been trying to create a custom ui component for jsf to replace <f:selectItems />, which is wrapped in a selectOneMenu. So my facesComponent needs to generate all the options while the selectOneMenu provides the <select></select>.
Problem is that the options are not rendered inside the selectOneMenu, but rather just outside of it.
My facesComponent looks like this:
#FacesComponent(value = "be.mokuril.jsf.SelectItemsForEnum")
public class SelectItemsForEnum extends UISelectItems {
#Override
public void encodeAll(FacesContext facesContext) throws IOException {
ResponseWriter responseWriter = ResponsefacesContext.getResponseWriter();
responseWriter.startElement("option", null);
responseWriter.writeAttribute("value", 1, null);
responseWriter.write("option1");
responseWriter.endElement("option");
responseWriter.startElement("option", null);
responseWriter.writeAttribute("value", 2, null);
responseWriter.write("option2");
responseWriter.endElement("option");
}
And this is my taglib:
<facelet-taglib xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
version="2.0" id="mw"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facelettaglibrary_2_0.xsd"
>
<namespace>http://www.mokuril.be/jsf/mw</namespace>
<composite-library-name>mw</composite-library-name>
<tag>
<tag-name>selectItemsForEnum</tag-name>
<component>
<component-type>be.mokuril.jsf.SelectItemsForEnum</component-type>
</component>
</tag>
And the xhtml to reproduce the problem:
<h:form>
<h:selectOneMenu>
<mw:selectItemsForEnum />
</h:selectOneMenu>
</h:form>
I've also been looking at the component tree:
<HtmlSelectOneMenu disabled="false" id="j_idt7" immediate="false" inView="true" localValueSet="false" readonly="false" rendered="true" required="false" transient="false" valid="true">
<SelectItemsForEnum id="j_idt8" inView="true" rendered="true" transient="false"/>
</HtmlSelectOneMenu>
And if I use <f:selectItems /> instead of my component I get this:
<UISelectItems id="j_idt9" inView="true" rendered="true" transient="false"/>
Which is actually what I expected it to look like, but I clearly must be overlooking something important.
Your concrete problem is caused because UISelectOne/UISelectMany components will scan their direct children for UISelectItem(s) instences. When you use a composite component, its content is basically wrapped in an UIPanel component, which is not an instance of UISelectItem(s), so the selection components will ignore it. Technically, you should be using a custom component instead of a composite component. See also When to use <ui:include>, tag files, composite components and/or custom components?
However, you'll stumble upon the next problem: the UISelectOne/UISelectMany will continue to render the options all by themselves and ignore the output from your renderer. Basically, no one <f:xxx> component renders HTML by itselves. This responsibility is up to its <h:xxx> parent. Technically, you should be overriding the renderer of <h:selectOneMenu> instead if you want to manipulate the output of <f:selectItem(s)>.
It's unclear which problem you're trying to solve this way, but if I were to do educated guesses, those questions should most probably answer and solve your real problem the correct way: How to use enum values in f:selectItem(s) and/or How to add tooltip to f:selectItems.

parsing error while including taglib

I'm trying to use Apache Commons Lang 3 in my JSF 2 application, and I followed BalusC's example
But when I included this line in my .xhtml page :
<%#taglib prefix="f" uri="/WEB-INF/functions.tld" %>
I have an error while parsing the page code.
How can I fix the problem?
The answer was targeted on a question whose asker is known to use JSF 1.x on JSP. The syntax which you've there is specific to JSP, the legacy predecesor of Facelets which is deprecated since JSF 2.0.
Get rid of the functions.tld file altogether. The proper JSF 2.x Facelets way of declaring a custom function based on an existing static method is as follows:
First create a /WEB-INF/functions.taglib.xml:
<?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://example.com/functions</namespace>
<function>
<function-name>escapeJavaScript</function-name>
<function-class>org.apache.commons.lang.StringEscapeUtils</function-class>
<function-signature>java.lang.String escapeJavaScript(java.lang.String)</function-signature>
</function>
</facelet-taglib>
Then register it in /WEB-INF/web.xml:
<context-param>
<param-name>javax.faces.FACELETS_LIBRARIES</param-name>
<param-value>/WEB-INF/functions.taglib.xml</param-value>
</context-param>
(that step is unnecessary when it is placed in /META-INF of a JAR file which is in turn placed in /WEB-INF/lib)
Finally declare and use it as follows:
<html ... xmlns:func="http://example.com/functions">
...
<h:outputScript>var foo = '#{func:escapeJavaScript(bean.foo)}';</h:outputScript>
Note that I've updated the answer you found accordingly. Also note that this function is already provided out the box as #{of:escapeJS(bean.foo)} by JSF utility library OmniFaces, in case you're using it.

Primefaces outputLabel for composite component

I have an issue with using p:outputLabel when used with composite component. I have composite component with p:inputText field (I removed irrelevant parts from component):
<cc:interface>
<cc:editableValueHolder name="myInput" targets="myInput"/>
<cc:attribute name="required" required="true" type="java.lang.Boolean" default="false"/>
</cc:interface>
<cc:implementation>
<p:inputText id="myInput" required="#{cc.attrs.required}"/>
</cc:implementation>
Now, I wont to use this component with p:outputLabel:
<p:outputLabel for="myComponent:myInput" value="#{resources['myLabel']}:"/>
<my:myComponent id="myComponent" required="#{myBean.required}"/>
Everything works fine, required validation, message is displayed as well, but there is no * sign on label, as there is when I connect label directly to p:inputText component. If I, on the other hand, hardcode required="true" on p:inputText everything works fine.
I debugged through org.primefaces.component.outputlabel.OutputLabelRenderer and discovered that component is recognized as UIInput, but input.isRequired() returns false. Farther debugging discovered that required attribute isn't yet defined on component, so it returns false as default value i UIInput:
(Boolean) getStateHelper().eval(PropertyKeys.required, false);
Also, if I just move p:outputLabel inside composite component everything works fine. Like EL is evaluated later inside composite component?
I'm using Primefaces 3.5 with Mojarra 2.1.14
This is, unfortunately, "by design". The evaluation of the #{} expressions is deferred to the exact moment of the access-time. They're unlike "standard" EL ${} in JSP not evaluated at the exact moment they're been parsed by the tag handler and "cached" for future access during the same request/view. At the moment the <p:outputLabel> is rendered, and thus the #{cc.attrs.required} as referenced by UIInput#isRequired() needs to be evaluated, there's no means of any #{cc} in the EL context. So any of its attributes would not evaluate to anything. Only when you're sitting inside the <cc:implementation>, the #{cc} is available in the EL context and all of its attribues would thus successfully evaluate.
Technically, this is an unfortunate corner case oversight in the design of <p:outputLabel>. Standard JSF and EL are namely behaving as specified. Basically, the presentation of the label's asterisk depending on the input's required attribute should be evaluated the other way round: at the moment the <p:inputText> inside the composite is to be rendered or perhaps even already when it's to be built. Thus, the label component should not ask the input component if it's required, but the input component should somehow notify the label component that it's required. This is in turn hard and clumsy (and thus inefficient) to implement.
If moving the label to inside the composite is not an option, then your best bet is to create a tag file instead of a composite component around the input component. It only requires some additional XML boilerplate.
/WEB-INF/tags/input.xhtml:
<ui:composition
xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:p="http://primefaces.org/ui"
>
<c:set var="id" value="#{not empty id ? id : 'myInput'}" />
<c:set var="required" value="#{not empty required and required}" />
<p:inputText id="#{id}" required="#{required}"/>
</ui:composition>
/WEB-INF/my.taglib.xml:
<?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://example.com/my</namespace>
<tag>
<tag-name>input</tag-name>
<source>tags/input.xhtml</source>
</tag>
</facelet-taglib>
/WEB-INF/web.xml:
<context-param>
<param-name>javax.faces.FACELETS_LIBRARIES</param-name>
<param-value>/WEB-INF/my.taglib.xml</param-value>
</context-param>
Usage:
<html ... xmlns:my="http://example.com/my">
...
<p:outputLabel for="myInput" value="#{resources['myLabel']}:" />
<my:input id="myInput" required="#{myBean.required}" />
I just did a quick test and it works fine for me.
See also:
When to use <ui:include>, tag files, composite components and/or custom components?

Facelet Method call where property required

Is it possible to invoke a method where property is expected in JSF 2.0 Facelet EL. For example:
<h:outputText value="#{pojo.methodName}" />
where pojo is an instance of POJO and methodName is the name of method. An error would be thrown because JSF expects to find getMethodName method.
Before someone asks why one would need this, consider any value we want to display in text which is computed and we don't have required getter method and no source code.
Update after BalusC Answer:
No rename possible because no source code available. methodName() didn't work. The only difference is that in actual code its chained pojo.
<h:outputText value="#{pojo1.pojo2.methodName()}" />
Since other properties are working for pojo2, I assume that its methodName which can not be invoked. Server says "The class does not have the property methodName"
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
Empty faces-config
<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">
</faces-config>
P.S. environment JBoss 6 and JSF 2
Add parentheses:
<h:outputText value="#{pojo.methodName()}" />
(which only works in EL 2.2, which is part of Java EE 6, so it only works out box in Tomcat 7, Glassfish 3, etc, see also Invoke direct methods or methods with arguments / variables / parameters in EL)
Or just rename the method:
public String getMethodName() {
// ...
}

Resources