我在primefaces 5.1 datatable周围创建了一个复合组件:
没有AJAX的组件(selectorServicio2.xhtml
)
<ui:component
xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:cc="http://java.sun.com/jsf/composite"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:p="http://primefaces.org/ui"
xmlns:pe="http://primefaces.org/ui/extensions">
<cc:interface componentType="selectorServicio2">
<cc:attribute name="servicios" required="true" type="java.util.Collection"
shortDescription="Colección de servicios entre los que se buscarán los datos"/>
<cc:attribute name="seleccionSimpleAttr" type="es.imasmallorca.selene.model.prestacion.Servicio"/>
<cc:attribute name="seleccionMultipleAttr" type="java.util.List"/>
<cc:attribute name="seleccionMultiple" required="false" type="java.lang.Boolean" default="false"/>
<cc:attribute name="scrollHeight" required="false" type="java.lang.Integer"/>
</cc:interface>
<cc:implementation>
<p:dataTable id="selectorServicio" widgetVar="#{cc.widgetId}"
value="#{cc.attrs.servicios}" var="_servicio"
scrollable="#{not empty cc.attrs.scrollHeight}" scrollHeight="#{cc.attrs.scrollHeight}"
selectionMode="#{cc.attrs.seleccionMultiple ? 'multiple' : 'single'}"
selection="#{cc.attrs.seleccionMultiple ? cc.attrs.seleccionMultipleAttr : cc.attrs.seleccionSimpleAttr}" rowKey="#{_servicio.codigo}">
<p:column>
<h:outputText value="#{_servicio.entidad.nombre}"/>
</p:column>
<p:column>
<h:outputText value="#{_servicio.tipoServicio.nombre}"/>
</p:column>
</p:dataTable>
</cc:implementation>
</ui:component>
它有一个支持类(SelectorServicio2.java
):
@FacesComponent("selectorServicio2")
public class SelectorServicio2 extends UIInput implements NamingContainer {
private static final Logger log = Logger.getLogger(SelectorServicio2.class.getName());
private static final String ID_SERVICIOS_SELECCIONADOS = "ServiciosSeleccionados";
@Override
public String getFamily() {
return UINamingContainer.COMPONENT_FAMILY;
}
public void encodeBegin(FacesContext facesContext) throws IOException {
@SuppressWarnings("unchecked")
List<Servicio> servicios = (List<Servicio>) this.getAttributes().get("servicios");
if (servicios == null) {
servicios = new ArrayList<>();
}
Collections.sort(servicios, new ServicioPorNombreEntidadTipoServicio(Criterio.ENTIDAD_TIPOSERVICIO));
getStateHelper().put("servicios", servicios);
getStateHelper().put(ID_SERVICIOS_SELECCIONADOS, new ArrayList<Servicio>());
super.encodeBegin(facesContext);
}
@Override
public Object getValue() {
ArrayList<Servicio> servicios = new ArrayList<>();
Servicio servicio = (Servicio) this.getStateHelper().get("servicio");
if (servicio != null) {
servicios.add(servicio);
}
return servicios;
}
public String getWidgetId() {
return "wdgSelectorServicio2_" + this.getClientId().replace(":", "_");
}
public void setServicioSeleccionado(Servicio servicioSeleccionado) {
if (servicioSeleccionado == null) {
this.getStateHelper().remove("servicio");
} else {
this.getStateHelper().put("servicio", servicioSeleccionado);
}
}
public Servicio getServicioSeleccionado() {
return (Servicio) this.getStateHelper().get("servicio");
}
}
这可以按预期工作(text.xhtml
):
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:p="http://primefaces.org/ui"
xmlns:imas="http://java.sun.com/jsf/composite/components">
<h:head></h:head>
<h:body>
<h:form>
<imas:selectorServicio2 id="serviceSelector"
servicios="#{testBean.services}"
seleccionSimpleAttr="#{testBean.selectedService}"
scrollHeight="110">
</imas:selectorServicio2>
</h:form>
</h:body>
</html>
现在,为了添加Ajax支持,我做了:
<cc:clientBehavior name="servicioSeleccionado" event="rowSelect" targets="selectorServicio"/>
添加到cc:interface
的{{1}}。selectorServicio2.xhtml
实现SelectorServicio2
(奇怪的是,我不需要实现任何方法,但在编译类时没有任何问题。)将ajax标记添加到ClientBehaviorHolder
:
test.xhtml
将<imas:selectorServicio2 id="serviceSelector"
servicios="#{testBean.services}"
seleccionSimpleAttr="#{testBean.selectedService}"
scrollHeight="110">
<f:ajax event="servicioSeleccionado" listener="#{testBean.selectService}"/>
</imas:selectorServicio2>
方法添加到selectService()
:
TestBean.java
在这些更改之后,我得到一个NullPointerException:
java.lang.NullPointerException at com.sun.faces.facelets.tag.jsf.core.AjaxHandler.applyAttachedObject(AjaxHandler.java:333) 在 com.sun.faces.facelets.tag.jsf.core.AjaxHandler.applyNested(AjaxHandler.java:258) 在 com.sun.faces.facelets.tag.jsf.core.AjaxHandler.apply(AjaxHandler.java:182) 在 javax.faces.view.facelets.DelegatingMetaTagHandler.applyNextHandler(DelegatingMetaTagHandler.java:137) 在 com.sun.faces.facelets.tag.jsf.CompositeComponentTagHandler.applyNextHandler(CompositeComponentTagHandler.java:183) 在 com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:203) 在 javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:120) 在 javax.faces.view.facelets.DelegatingMetaTagHandler.applyNextHandler(DelegatingMetaTagHandler.java:137) 在 com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:203) 在 javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:120) 在 javax.faces.view.facelets.DelegatingMetaTagHandler.applyNextHandler(DelegatingMetaTagHandler.java:137) 在 com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:203) 在 javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:120) 在 javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:95) 在 com.sun.faces.facelets.compiler.NamespaceHandler.apply(NamespaceHandler.java:93) 在 com.sun.faces.facelets.compiler.EncodingHandler.apply(EncodingHandler.java:87) 在 com.sun.faces.facelets.impl.DefaultFacelet.apply(DefaultFacelet.java:161) 在 com.sun.faces.application.view.FaceletViewHandlingStrategy.buildView(FaceletViewHandlingStrategy.java:995) 在 com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:99) 在com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:219)
我做错了什么?
我在Java 7上使用带有标准配置(JSF 2.2)的Wildfly 8.1
答案 0 :(得分:1)
java.lang.NullPointerException
at com.sun.faces.facelets.tag.jsf.core.AjaxHandler.applyAttachedObject(AjaxHandler.java:333)
让我们检查source of AjaxHandler#applyAttachedObject():
332 Collection<String> eventNames = bHolder.getEventNames();
333 if (!eventNames.contains(eventName)) {
334 throw new TagException(this.tag,
335 getUnsupportedEventMessage(eventName, eventNames, parent));
336 }
啊哈,getEventNames()
返回null
。该方法已在UIComponentBase
上实施,其javadoc说明如下:
这是
ClientBehaviorHolder.getEventNames()
的默认实现。UIComponent
未实现ClientBehaviorHolder
接口,但为ClientBehaviorHolder
定义的方法提供了默认实现,以简化子类实现。希望支持ClientBehaviorHolder
契约的子类必须声明子类实现ClientBehaviorHolder
,,并且必须覆盖此方法以返回客户端事件名称的非空Collection
组件支持。
从技术上讲,您应该在组件中覆盖getEventNames()
,返回一组受支持的事件名称。
然而,你实际上并不需要它。 <cc:clientBehavior>
已经在嵌套在复合中的<p:dataTable>
组件上重新定位它,该组件已经正确实现了该接口和方法。因此,您应该从支持组件中删除 ClientBehaviorHolder
接口。
此外,<f:ajax>
不适用于PrimeFaces特定事件,您应该使用<p:ajax>
。它将呈现一个脚本,该脚本又调用PrimeFaces特定的ajax客户端API。