Почему я могу привязать <f: actionListener> к произвольному методу, если он не поддерживается JSF?

Я использую Glassfish 3.1.2.2 и JSF Mojarra 2.1.6.

У меня есть следующая страница Facelets:

<h:form>
  <h:commandLink value="link">
    <f:actionListener binding="#{backingBean.someMethod(1)}"/>
  </h:commandLink>
</h:form>

И следующая поддержка < bean:

@RequestScoped
@ManagedBean
public class BackingBean {
  public void someMethod(int i) {
    System.out.println("It was called: " + i);
  }
}

Когда я нажимаю ссылку, на консоли появляется "Info: It called: 1".

Документация для binding гласит:

Библиотека: http://xmlns.jcp.org/jsf/core, http://java.sun.com/jsf/core (Jsf Core)

Тег: actionListener

связывания

Выражение привязки значений, которое оценивается объектом, реализующим javax.faces.event.ActionListener. [акцент мой]

Кроме того, в принятом ответе на этот вопрос указано, что для f:actionListener невозможно вызвать произвольный метод.

Почему вызван метод поддержки bean, если это не поддерживается?

Ответы

Ответ 1

Это является следствием новой функции EL 2.2 вызова метода в выражении значения через синтаксис #{bean.method()} вместо ссылки на свойство с помощью синтаксиса #{bean.property} (который действительно должен быть точного типа ActionListener). Он не работал бы с EL 2.1 или старше, и он также не работал бы, когда вы удаляете аргументы и круглые скобки. Этот документ был написан, когда EL 2.2 не существовал (он фактически не был изменен по сравнению с версия JSF 1.2 с мая 2006 года, был введен EL 2.2 Декабрь 2009 г.). Однако я согласен с тем, что для этого требуется обновление этой части, поскольку это путает начинающих.

Ответ, который вы нашли, сделал его точки на основе документа, но ответчик, похоже, не понял, основываясь на вопросе о том, что в то время как binding="#{testController.nodeListener}" не удалось, binding="#{testController.nodeListener(event)}" на самом деле работал. Это не дает вам возможности передать ActionEvent. Ответ был лучше, если он предложил просто использовать binding="#{testController.nodeListener()}" вместо этого и получить информацию о событиях другим способом, например, вызывая UIComponent#getCurrentComponent() или даже передав #{component} в качестве аргумента. Конечно, если вам действительно нужна его рука.

<h:commandLink value="link">
    <f:actionListener binding="#{bean.someMethod(component)}"/>
</h:commandLink>
public void someMethod(UIComponent component) {
    System.out.println("It was called on: " + component); // HtmlCommandLink
}

См. также: