Составной компонент JSF, поддерживающий выражение EL bean-компонента по умолчанию при сбое обязательного атрибута, методы неизвестны

У меня есть составной компонент JSF util_primefaces:inplace_name, для которого требуется вспомогательный компонент «менеджер», который выполняет постоянные обновления при редактировании поля «имя» объекта (с использованием p: inplace):

<cc:interface>
  <cc:attribute name="manager" type="com.example.web.AbstractManager" required="false" default="#{blockManager}"/>
  <cc:attribute name="element" type="com.example.entity.Element" required="true"/>
  <cc:attribute name="elid" required="true"/>
  <cc:attribute name="update" required="false" default="@parent"/>
 ..
</cc:interface>

<cc:implementation>
 ..
 <p:inplace id="#{cc.attrs.elid}" editor="true" emptyLabel="UNDEF" >
  <p:ajax 
   event="save" 
   listener="#{cc.attrs.manager.onInplaceNameSaveEvent}"
   process="@this #{cc.attrs.elid}-name"
   update="#{cc.attrs.update}"
  />
 <h:inputText id="#{cc.attrs.elid}-name" value="#{cc.attrs.element.name}"/>
 ..

Где, например, @ViewScoped @ManagedBean BlockManager в конечном итоге расширяет AbstractManager, у которого есть метод слушателя:

public void onInplaceNameSaveEvent(AjaxBehaviorEvent ae).

[ПОДДЕРЖКА: здесь описана причина необычного атрибута "elid", он больше не играет роли в этом вопросе: Primefaces p:inplace: Как более элегантно распространять выражение EL для объединения объектов ]

Когда я вызываю составной компонент, передающий явный #{blockManager} (или другой подкласс AbstractManager), он работает нормально:

<util_primefaces:inplace_name 
 element="#{tenancy}" 
 elid="tenancy"
 manager="#{blockManager}"
/>

Но если я не передам #{blockManager}, при выполнении редактирования и сохранения на месте я получаю сообщение об ошибке, что метод onInplaceNameSaveEvent(AjaxBehaviorEvent) неизвестен:

<util_primefaces:inplace_name 
 element="#{tenancy}" 
 elid="tenancy"
/>

Ошибка:

WARNING: Method not found: [email protected](javax.faces.event.AjaxBehaviorEvent)
javax.el.MethodNotFoundException: Method not found: [email protected](javax.faces.event.AjaxBehaviorEvent)
at com.sun.el.util.ReflectionUtil.getMethod(ReflectionUtil.java:155) 

В: Почему вспомогательный компонент не принимается правильно, используя default="#{blockManager}" в атрибуте составного компонента?


person Webel IT Australia - upvoter    schedule 21.07.2012    source источник


Ответы (1)


Согласно документации для тега cc:attribute , значение default должно оцениваться как java.lang.String.

Вот почему выражение #{blockManager} не работает так, как вы ожидаете, вы можете установить значения по умолчанию только для атрибутов String.

Чтобы увидеть, что произойдет, вы можете протестировать регистрацию следующей функции в taglib (как показано здесь):

public static String typeOf(Object o) {
    return o == null ? null : o.getClass().toString();
}

и используйте его в составном компоненте следующим образом:

<ui:composition>
    <cc:interface>
        <cc:attribute name="param" type="java.lang.Integer" required="true"
            default="1" />
    </cc:interface>
    <cc:implementation>
        <h:outputText value="#{fnc:typeOf(cc.attrs.param)}" />
    </cc:implementation>
</ui:composition>

Теперь, если вы используете компонент без указания param, вот так:

<my:comp />

... он выведет class java.lang.String, потому что он использует результат выражения ValueExpression для атрибута default, который является строкой "1".

И когда вы указываете параметр:

<my:comp param="1" />

... он выводит class java.lang.Integer, потому что теперь это значение, полученное в результате приведения к типу, указанному для cc:attribute.

person Elias Dorneles    schedule 22.07.2012
comment
огромное спасибо. Кстати, я провел пару связанных экспериментов с любопытными результатами, например, если определить атрибут name=testInteger type=java.lang.Integer default=1a (обратите внимание на преднамеренный альфа-символ в строке по умолчанию) и h:outputText value=#{ cc.attrs.testInteger} он выводит нормально как 1a (не Integer), когда я вызываю компонент без явного testInteger, однако, если я вызываю составной компонент с testInteger=1b, он не работает, как и ожидалось, с NumberFormatException . - person Webel IT Australia - upvoter; 23.07.2012
comment
интересно... тоже собираюсь провести несколько тестов! Благодарность! :) - person Elias Dorneles; 23.07.2012