Skip to content

Search expression handler should check for empty expressions #5604

@djmj

Description

@djmj

Describe the bug

When you call SearchExpressionHandlerImpl.resolveClientIds(...) with an expression like "@this," that ends with the delimiter the function will call handler.invokeOnComponent(searchExpressionContext, expression, internalCallback); with an empty string leading to a IllegalArgumentException

java.lang.IllegalArgumentException: ""
	at jakarta.faces.component.UIComponentBase.findComponent(UIComponentBase.java:371)
	at com.sun.faces.component.search.SearchExpressionHandlerImpl.invokeOnComponent(SearchExpressionHandlerImpl.java:294)
	at jakarta.faces.component.search.SearchExpressionHandler.invokeOnComponent(SearchExpressionHandler.java:180)
	at com.sun.faces.component.search.SearchExpressionHandlerImpl.resolveClientIds(SearchExpressionHandlerImpl.java:109)

The problem lies in function splitExpressions(...) which does not remove trailing separators.

But it does remove leading separators since ",@this" will work as expression, making it inconsistent.

This leads to problems with composite components having optional expressions like <p:commandButton update="@form, #{cc.attrs.update}"/>

To Reproduce

Call the function with expression "@this," or "@this, " (optional space at end)

or using PrimeFaces with below example since PF 14 delegates the ajax client-id resolving to the faces implementation `SearchExpressionHandlerImpl. primefaces/primefaces#14114

<!-- not working - separator at end -->
<p:commandButton update="@this,"/>`  

<!-- working - separator at start -->
<p:commandButton update=",@this"/>`  

Solution

Fix splitExpression to ignore trailing separators (or empty sub expressions) in the expression argument

or

check the splitted expression inside the loop of resolveClientIds(...) to not be empty, consistent with checking the whole expression before splitting to not be empty.

for (String expression : handler.splitExpressions(facesContext, expressions)) {

       // "@this," will split to 
       if (!expressions.isEmpty()) {
            // ["@this", ""] - splitExpressions should only return ["@this"]
            for (String expression : handler.splitExpressions(facesContext, expressions)) {
                // check single expression to not be empty
                if (!expression.trim().isEmpty()) {
                    if (handler.isPassthroughExpression(searchExpressionContext, expression)) {
                        internalCallback.addClientId(expression);
                    } else {
                        handler.invokeOnComponent(searchExpressionContext, expression, internalCallback);
                    }
                }
            }
        }

Expected behavior

Ignore empty expressions.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions