На самом деле мне нужны два ПраймФейс <p:pickList>
, которые проверяются с помощью компонента OmniFaces' <o:validateAll>
. Обратите внимание, что при проверке списка выбора с помощью <o:validateAll>
есть проблема, которую можно решить с помощью описано в выпуске 488 в системе отслеживания проблем OmniFaces.
Итак, очень простой пример моего требования выглядит так:
<h:form id = "form1">
<p:messages id = "messages">
<p:autoUpdate/>
</p:messages>
<p:pickList id = "pick1" value = "#{dummy.dualListModel}"
var = "item" itemLabel = "#{item}" itemValue = "#{item}">
<p:ajax event = "transfer"/>
</p:pickList>
<p:pickList id = "pick2" value = "#{dummy.dualListModel2}"
var = "item" itemLabel = "#{item}" itemValue = "#{item}">
<p:ajax event = "transfer"/>
</p:pickList>
<o:validateAll id = "validPicks" components = "pick1 pick2"
message = "all values required!" />
<h:commandButton id = "done" value = "Done" action = "#{dummy.action1}"/>
</h:form>
<h:form id = "theOtherForm">
<h:commandButton id = "otherFormAction" value = "Action in other form"
action = "#{dummy.action2}"/>
</h:form>
Компонент поддержки дурачок просто предоставляет геттеры/сеттеры для двух свойств dualListModel
и методов действий, которые ничего не делают.
Когда я запускаю этот код и оставляю хотя бы один список выбора пустым, отправка кнопки Done
приводит к ошибке проверки, как исключение. Однако нажатие кнопки в другой форме после неудачной проверки приводит к NullPointerException
в PickListRenderer
. Вот трассировка стека:
Caused by:java.lang.NullPointerException
at org.primefaces.component.picklist.PickListRenderer.encodeMarkup(PickListRenderer.java:92)
at org.primefaces.component.picklist.PickListRenderer.encodeEnd(PickListRenderer.java:59)
at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:920)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1863)
at javax.faces.render.Renderer.encodeChildren(Renderer.java:176)
at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:890)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1856)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1859)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1859)
at com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:456)
at com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:134)
at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:337)
at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:337)
at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:337)
at org.omnifaces.viewhandler.OmniViewHandler.renderView(OmniViewHandler.java:119)
at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:120)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:219)
[...]
Я использую OmniFaces 2.7 и PrimeFaces 6.2.
Пожалуйста, обрати внимание, что я использую пользовательский рендерер для PickList, который переопределяет getConvertedValue()
, как описано в связанной проблеме выше. Однако это никоим образом не меняет поведение средства визуализации, которое должно повлиять на эту ошибку. Это просто заставляет <o:validateAll>
признать, что список выбора пуст.
Мне это кажется ошибкой, но я не уверен, ошибка ли это в OmniFaces или в PrimeFaces. У кого-нибудь есть идеи?
В качестве обходного пути можно добавить атрибут required = "true"
ко всем спискам выбора.
Та же проблема существует и с PrimeFaces 7.0 (только номера строк немного отличаются).
Кроме того, я создал еще один NPE с приведенным выше кодом и PrimeFaces 7.0, когда подсчитывал пустые списки выбора через «готово», а затем переносил элемент в один из списков выбора в целевой список.
Другое исключение возникает здесь:
Caused by:java.lang.NullPointerException
at org.primefaces.component.picklist.PickList.validateValue(PickList.java:140)
at javax.faces.component.UIInput.validate(UIInput.java:982)
at org.primefaces.component.picklist.PickList.validate(PickList.java:181)
at javax.faces.component.UIInput.executeValidate(UIInput.java:1248)
at javax.faces.component.UIInput.processValidators(UIInput.java:712)
at com.sun.faces.context.PartialViewContextImpl$PhaseAwareVisitCallback.visit(PartialViewContextImpl.java:575)
at com.sun.faces.component.visit.PartialVisitContext.invokeVisitCallback(PartialVisitContext.java:183)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1689)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1700)
at javax.faces.component.UIForm.visitTree(UIForm.java:371)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1700)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1700)
at com.sun.faces.context.PartialViewContextImpl.processComponents(PartialViewContextImpl.java:403)
at com.sun.faces.context.PartialViewContextImpl.processPartial(PartialViewContextImpl.java:266)
at org.primefaces.context.PrimePartialViewContext.processPartial(PrimePartialViewContext.java:63)
at javax.faces.context.PartialViewContextWrapper.processPartial(PartialViewContextWrapper.java:219)
at org.omnifaces.context.OmniPartialViewContext.processPartial(OmniPartialViewContext.java:124)
at javax.faces.component.UIViewRoot.processValidators(UIViewRoot.java:1193)
at com.sun.faces.lifecycle.ProcessValidationsPhase.execute(ProcessValidationsPhase.java:76)
В соответствующий код значение oldModel
, которое инициализируется через getValue()
, равно null
.
Я бы добавил код, в котором вы переопределяете рендерер, поскольку он играет роль мог бы...
Код пользовательского средства визуализации доступен в связанной проблеме OmniFaces. Как уже упоминалось, он просто переопределяет getConvertedValue()
и изменяет только одну строку, которая создает экземпляр DualListModel
.
Проблема подтверждена и опубликована на GitHub: https://github.com/primefaces/primefaces/issues/4756.
Я отправил исправление, которое, надеюсь, будет включено в PF 7.0.2 и PF 7.1.
https://github.com/primefaces/primefaces/pull/4759
текущее исправление ИМХО только маскирует настоящую причину, которая до сих пор неясна. NPE в PickListRenderer
(из исходного вопроса) все еще существует. Воспроизведение было обновлено, и проблема на github была вновь открыта.
Как писал Меллоуэр, о проблеме сообщили как Выпуск PrimeFaces #4756. Оказалось, что проблема существует только с Mojarra (проверено с 2.2.17, 2.2.18, 2.2.19 и 2.3.9), а не с MyFaces. Итак, была создана еще одна проблема: Мохарра #4398.
Если в вашем списке выбора используется FacesConverter, обратите внимание, что входное значение не должно быть экранировано при сравнении для извлечения исходного объекта. На самом деле, если входная строка похожа на «Курица и яйцо», конвертер получает 'Chicken&Egg'
Пример:
@Override
public YourObject getAsObject(FacesContext facesContext, UIComponent uiComponent, String name)
{
PickList pickList = (PickList) uiComponent;
DualListModel<YourObject> dualListModel = (DualListModel<YourObject>) pickList.getValue();
List<YourObject> all = dualListModel.getSource();
all.addAll(dualListModel.getTarget());
return all.stream().filter(element ->
String.valueOf(element.getName()).equals(HtmlUtils.htmlUnescape(name)))
.findFirst().get();
}
Я подожду, пока @balusC не вмешается, поскольку он обычно знает, где на самом деле находится эта ошибка. У меня есть ощущение, что это может быть связано с тем, как работает PickList.