Теперь я могу частично ответить на этот вопрос.Теперь я могу видеть, что происходит, и описывать это, но я все еще не до конца понимаю - с точки зрения фаз JSF и объема запроса - почему это происходит так, как есть.Это тонкая и хитрая проблема.
Чтобы объяснить это, я переписал контрольный пример, чтобы упростить его.Тестовая страница view.xhtml, которая принимает параметр запроса id:
<f:view>
<f:metadata>
<f:viewParam name="id" value="#{elementController.id}"/>
</f:metadata>
</f:view>
<h:body>
<h:form>
<h:panelGroup rendered="#{empty elementController.selected}">
<div style="color:orange;">
No Element found for id(#{elementController.id}) or page called without id query param.
</div>
</h:panelGroup>
<h:panelGroup rendered="#{not empty elementController.selected}">
[<h:outputText value="#{elementController.selected.id}"/>]
<h:outputText value="#{elementController.selected.name}"/>
</h:panelGroup>
<br/><br/>
<h:commandButton value="Apply" action="#{elementController.action}" />
</h:form>
</h:body>
Где ElementController расширяет RequestController.При загрузке view.xhtml параметр запроса id устанавливается как viewParam с использованием setId, который загружает соответствующий объект Element по id (из базы данных) и устанавливает его как «текущий» (он же «выбранный») элемент, доступный как getSelected (), который также выполнял тест на нулевой ток, и это было причиной проблемы:
public void setId(Long id) {
log_debug("setId","id",id);
if (id != null) {
this.id = id;
T found = (T) getAbstractFacade().find(id);
if (found == null) {
String $error = "No object with id(" + id + ") found for class " + getManagedClass().getSimpleName();
log_error($error);
}
setCurrent(found);
}
}
public T getSelected() {
log_debug("getSelected","current",current);
if (current == null) {
//current = newElement(); //THIS WAS CAUSING PROBLEMS
log_warn("getSelected","null current Element");
}
return current;
}
Проблема заключалась в том, что при отправке формы getSelected () вызывался дважды для каждого экземпляратест '# {not empty elementController.selected}' или '# {empty elementController.selected}' до вызова действия и с полем 'current' null .
В @RequestScoped @ManagedBean ElementController метод getSelected () проверил, является ли текущий (или выбранный) Элемент нулевым, и выполнял действие, приводящее к ошибке, и это было коротким замыканием вызовадействие в commandButton, когда был вызван «не пустой elementController.selected»:
(проблема, которую я вижу,Не имеет никакого отношения к тому, является ли «выбранный» Элемент, подвергнутый тесту «не пустой» или «пустой», @Entity или нет, я ошибочно полагал, что, поскольку проблема заключается в ElementController, который обрабатывает сущности Element, иКонечно, этот вывод в любом случае звучит неправильно.)
Если я избавлюсь от назначения newElement (), которое вызывало ошибку, и было там для ловли случаев, когда страница просмотра вызывается без параметра id(это запускает загрузку «текущей» сущности по идентификатору), и вместо того, чтобы записать предупреждение, я вижу, что для каждого экземпляра теста «не пустой elementController.selected» или «empty elementController.selected» это предупреждение регистрируется дваждыДО того, как действие commandButton вызывается при отправке формы.
Каким-то образом - и это часть, которую я не до конца понимаю - в @RequestScoped, элемент, который был назначен переменной 'current' (он же "selected")) теряется, и тест "not empty elementController.selected" на странице просмотра(и, следовательно, getSelected ()) вызывается дважды с current = null (с побочными эффектами).
Если я изменю область действия ElementController на @SessionScoped, проблема исчезнет;текущее состояние элемента поддерживается, и getSelected () никогда не вызывается с 'current' null.
Буду признателен за любые комментарии-ответы, которые объясняют в терминах фаз JSF и запрашивают область действия, почему моя переменная 'current' внезапноnull и почему '# {not empty elementController.selected}' выполняется дважды до , когда вызывается действие.Я проверил, что setId вообще не вызывается между ними (только при начальной загрузке страницы представления), что-то еще сбрасывает текущий до нуля, или bean-объект области видимости воссоздается между отправкой формы и вызовом действия.