The value of attribute "method-signature" associated with an element type "cc:attribute" must not contain the '<' character - jsf

I got the error
The value of attribute "method-signature" associated with an element type "cc:attribute" must not contain the '<' character.
javax.faces.view.facelets.FaceletException: Error Parsing /resources/custom.xhtml: Error Traced[line: 6]
custom.xhtml
<f:view xmlns="http://www.w3.org/1999/xhtml"
xmlns:composite="http://java.sun.com/jsf/composite"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://java.sun.com/jsf/core">
<composite:interface>
<composite:attribute method-signature="List<String> function(String param)" name="function"/>
</composite:interface>
<composite:implementation>
<p:ajax event="change" update="#{cc.attrs.function}"/>
</composite:implementation>
</f:view>
The error comes from <String> because it's not allowed in XML to use angle brackets inside of tags. So what is the correct way to declare the method signature for the composite attribute? It's JSF 2 and Primefaces 7.0. What is the correct syntax for MethodExpression in JSF? Is generic method supported in EL? Should I escape the angle brackets using < and > or maybe remove the generic type and EL will parse List function(String param) correctly?

Generic methods are not supported by EL. Also, you have to provide full qualified class names as types. So the signature you need is
java.util.List function(java.lang.String param)

Related

How to use composite component attrs in targets

I have this piece of code:
<composite:interface componentType="nestedGridCellEditor">
<composite:attribute name="componentName" required="false" shortDescription="Name of the attribute to display in the id"/>
<composite:attribute name="action" required="false" targets="#{cc.attrs.componentName}button" shortDescription="A method expression or a string outcome to process when command is executed"/>
</composite:interface>
<composite:implementation>
<span id="#{cc.clientId}" style="display: flex;">
<p:commandButton id="#{cc.attrs.componentName}button"/>
</composite:implementation>
</span>
And I use it that way (I'm using it several of times, with a different componentName):
<sm:nestedGridCellEditor id="DateNGCE" componentName="Foo2101"
action="#{contractTermsBudgetController.updateRow('Date', budget)}"/>
What I want it to do is to use componentName inside the id of the component, and to put it inside the targets as well.
Right now it giving me an error about the targets and about the action method.
(i.e - "Unable to re-target MethodExpression as inner component referenced by target id 'button' cannot be found")
How can I do this?
EDIT
The purpose of this is because I'm using this composite inside several tables and I want to identify each button by its table's ID which should include the table name and not the clientId.
That's why I need to pass the name through the componentName.

JSF h:commandLink with hml entity characters, superscript etc

What is the best way of using special characters and formatting in a dynamically generated h:commandLink?
I am rendering an equation (e.g. A=π*r2) as a list of h:commandLink items, so that each symbol in the equation can be separately clicked:
JSF:
<ui:repeat value="#{eqBean.eqSymbolDisplays}" var="eqSym">
<h:commandLink value="#{eqSym.text}" styleClass="#{eqSym.styleClass}" action="#{eqBean.eqSymbolClick(eqSym)}" />
</ui:repeat>
Bean:
public String getText(){
// Return the text for a given symbol
}
The question is what the getText method should do when the symbol needs a special character, special mathematical symbol, and/or needs to be a super-script or sub-script?
Here are some specific problems/questions:
(1) How do I use the greek letter π symbol in a CommandLink? If I return π then that is what gets displayed, not the greek symbol
(2) What is the best way to do a superscript in a CommandLink? I could use a CSS style but some people say that is a bad idea, especially when the superscript implies meaning, rather than just presentation, as it does for a number raised to a power.
See :
Beware CSS for Superscript/Subcript
The answer was obvious in the end: Just replace the value attribute of the h:commandLink with a child h:outputText element that has escape="false" :
JSF:
<ui:repeat value="#{eqBean.eqSymbolDisplays}" var="eqSym">
<h:commandLink styleClass="#{eqSym.styleClass}" action="#{eqBean.eqSymbolClick(eqSym)}" >
<h:outputText value="#{eqSym.htmlText}" escape="false"/>
</h:commandLink>
</ui:repeat>

JSF composite:attribute with f:attribute conversion error

I'm implementing a JSF component and need to conditionally add some attributes. This question is similar to a previous JSF: p:dataTable with f:attribute results in "argument type mismatch" error, but with a completely different error message, so I raised a new question.
<composite:interface>
<composite:attribute name="filter" required="false" default="false"
type="java.lang.Boolean"/>
<composite:attribute name="rows" required="false" default="15"
type="java.lang.Integer"/>
...
</composite:interface>
<composite:implementation>
<p:dataTable ivar="p" value="#{cc.attrs.dm}">
<c:if test="#{cc.attrs.filter}">
<f:attribute name="paginator" value="#{true}"/>
<f:attribute name="rows" value="#{cc.attrs.rows}"/>
</c:if>
...
<p:dataTable>
</composite:implementation>
This results in an error java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer. Even if I manually set this, I get errors:
<f:attribute name="rows" value="15"/> ... argument type mismatch
<f:attribute name="rows" value="#{15}"/> ... java.lang.Long cannot be cast
to java.lang.Integer
If I add the attribute directly, there is no exception and the correct number of rows is diplayed:
<p:dataTable var="p" value="#{cc.attrs.dm}" rows="#{cc.attrs.rows}">
This is indeed an unfortunate corner case with numbers in EL and composite component attributes. There's no solution for this. The type information is not available in #{cc.attrs} when used in <f:attribute> and thus treated as String. The #{15} cannot be represented as an integer in EL either, all numbers are always implicitly treated as Long when the type information is absent. The ClassCastException can be prevented by using a tag file instead of a composite component.
Your best bet is doing the check in the actual rows attribute itself.
<p:dataTable ... rows="#{cc.attrs.filter ? cc.attrs.rows : null}">

Facelets: ui:param default value

How can one define a default value for a facelet template parameter?
Consider the following element using a template parameter:
<h:outputText value="#{templParam}"></h:outputText>
The above line will print the the template parameter templParam which is passed by a ui:param tag in a ui:composition using the template:
<ui:param name="templParam" value="Hello world"></ui:param>
But if ui:param tag is missing nothing will be printed. Although, how can one print e.g "Default value" in this case?
Could use this:
<h:outputText value="#{empty templParam ? 'Default value' : templParam}" />
I hope it helps.
A default value can be defined by using a ternary operator checking for null value.
<h:outputText value="#{templParam != null ? templParam : 'Default value'}"></h:outputText>
This will print "Default value" if the parameter was not passed by a ui:param tag.
After the composition tag to define the start of the template, the template parameter can be set to its default value (if it is empty) so that all following uses of it don't require checking for a null each time (and its default value is in one place in the code).
<html xmlns:c="http://java.sun.com/jsp/jstl/core" >
<ui:composition>
<c:set var="templParam" value="#{empty templParam ? 'Default value' : templParam}"
scope="request" />
<h:outputText value="Use 1: #{templParam}" />
<h:outputText value="Use 2: #{templParam}" />

Enum values in Composite Component attribute

My issue is quite simple : I want to create a composite component with a String attribute, Type.
<cc:attribute name="type" />
This attribute will have 3 acceptable values, [TYPE1, TYPE2, TYPE3]
Is it possible to say my component will accept only these values ?
Unfortunately no, you cannot put a compile/buildtime restriction on a composite component attribute value in the cc interface. You can however put a runtime restriction by checking the value in the cc implementation.
<ui:param name="type" value="#{cc.attrs.type}" />
<ui:fragment rendered="#{type == 'TYPE1' or type == 'TYPE2' or type == 'TYPE3'}">
<p>The type is TYPE1, TYPE2 or TYPE3.</p>
<p>Write your component's body here.</p>
</ui:fragment>
That'll be your best bet.

Resources