JSF MethodExpression javax.el.PropertyNotFoundExce

2019-02-25 21:49发布

问题:

I'm trying to develop a custom component that will need to call a method from the backingbean to get some data from the bb (this will be called in the decode phase after a certain Ajax call) with one parameter (it will come in the ajax call).

The problem I'm having is that I define the attribute as a MethodExpression (in the taglibrary and the component), I get the Ajax post, decode the parameter and when I try to get the Method binding from the component I get the following error:

javax.el.PropertyNotFoundException: /easyFaces.xhtml @19,151 dataSource="#{theBean.loadDataFromSource}": The class 'ar.com.easytech.faces.test.homeBean' does not have the property 'loadDataFromBean'.

Here is the relevant code.. (and please let me know if this is not the correct way to do this..)

taglib:

<attribute>
    <display-name>Data Source</display-name>
    <name>dataSource</name>
    <required>true</required>
    <type>javax.el.MethodExpression</type>
    <method-signature>java.util.List theDataSource(java.lang.String)</method-signature>
</attribute>

Component definition:

public class Autocomplete extends HtmlInputText implements ClientBehaviorHolder 
...
    public MethodExpression getDataSource() {
        return (MethodExpression) getStateHelper().eval(PropertyKeys.dataSource);
    }

    public void setDataSource(MethodExpression dataSource) {
        getStateHelper().put(PropertyKeys.dataSource, dataSource);
    }

and finally the rendered method that generates the error:

private List<Object> getData(FacesContext context, Autocomplete autocomplete, String data) {

    Object dataObject = null;
    MethodExpression dataSource = autocomplete.getDataSource();

    if (dataSource != null) {
        try {
            dataObject = dataSource.invoke(context.getELContext(), new Object[] {data});
            return convertToList(dataObject);
        } catch (MethodNotFoundException e) {
            logger.log(Level.INFO,"Method not found: {0}", dataSource.getExpressionString() );

        }
    }
    return null;

}

Here is the method from the BB

public List<String> autcompleteFromSource(String param) {

    List<String> tmpData = new ArrayList<String>();
    tmpData.add("XXA_TABLE_A");
    tmpData.add("XXA_TABLE_B");
    tmpData.add("XXA_TABLE_C");

    return tmpData;
}

And the .xhtml with the component

<et:autocomplete id="autoc" minLength="3" delay="500" value="#{easyfacesBean.selectedValue}" dataSource="#{easyfacesBean.autcompleteFromSource}" />

The thing is if I define a method getAutocompleteFromSource() it recognised the method and the error changes to can't convert list to MethodExpression, so evidently it is simply interpreting the autocompleteFromSource as a simple property and not a method definition, is this even the correct way to call method from BB? (giving that it's not an actual action nor validation )

回答1:

I found the solution for this, as it turns out you also need to define a "Handler"to define the Method Signature, so I created the handler and added to the taglib and everything started to work fine..just for reference.. here is the handler..

Regards

public class AutocompleteHandler extends ComponentHandler {

    public AutocompleteHandler(ComponentConfig config) {
        super(config);
    }

    protected MetaRuleset createMetaRuleset(Class type) {
        MetaRuleset metaRuleset = super.createMetaRuleset(type);
        metaRuleset.addRule(new MethodRule("dataSource", List.class, new Class[] { String.class }));
        return metaRuleset;
    }

}