org.primefaces.component.datatable.feature.CellEditFeature.encode()中的java.lang.NullPointerException

时间:2014-09-03 18:03:53

标签: jsf-2 primefaces

我正在尝试使用动态生成的列创建可编辑的数据表。

表格按原样呈现,单击时单元格进入编辑模式,但是当按下输入或焦点离开单元格时,我在服务器上得到空指针异常。调用onCellEdit方法,但未在car对象中设置单元格值。

  • 我是否在valuep:inputText的{​​{1}}属性的EL表达式中做了一些奇怪的事情?我应该为p:outputTextvar上的p:dataTable属性使用其他一些属性吗?什么样的EL表达式在这里有效?
  • 我错过了其他什么吗?
  • 或者这可能是PrimeFaces中的错误?我可以看到错误发生在p:columns,当它期望获得CellEditFeature.encode但结果为空时。

我使用Primefaces 4.0和5.0尝试了相同的结果。我使用的是JSF 2.2,Glassfish 4.0和Java 1.8.0_20。

如果有人能帮助我找出问题的原因,我将非常感激。在Stack Overflow上有一个动态可编辑数据表的工作示例也很有用。

Bellow是一个最小的例子,它使用了我试图添加编辑的动态生成列的Primefaces展示示例,以及异常堆栈跟踪。

网页:

CellEditor

支持bean:

<p:dataTable id="cars" var="car" value="#{dtColumnsView.cars}" widgetVar="carsTable"
    editable="true" editMode="cell" >

  <p:ajax event="cellEdit" listener="#{dtColumnsView.onCellEdit}" update=":form:msgs" />

  <p:columns value="#{dtColumnsView.columns}" var="column" columnIndexVar="colIndex" 
    styleClass="ui-editable-column">

    <f:facet name="header">
      <h:outputText value="#{column.header}" />
    </f:facet>

    <p:cellEditor>
      <f:facet name="output"><h:outputText value="#{car[column.property]}" /></f:facet>
      <f:facet name="input"><p:inputText id="modelInput" value="#{car[column.property]}" /></f:facet>
    </p:cellEditor>

  </p:columns>
</p:dataTable>

异常堆栈跟踪:

@ManagedBean(name = "dtColumnsView")
@ViewScoped
public class ColumnsView implements Serializable {

  private static final long serialVersionUID = 1L;

  private List<ColumnModel> columns;
  private List<Car> cars;

  @ManagedProperty("#{carService}")
  private CarService service;

  @PostConstruct
  public void init() {
    cars = service.createCars(10);
    columns = Arrays.asList(
        new ColumnModel("Id", "id"), 
        new ColumnModel("Brand", "brand"), 
        new ColumnModel("Year", "year"));
  }

  public List<Car> getCars() {
    return cars;
  }

  public List<String> getBrands() {
    return service.getBrands();
  }

  public List<String> getColors() {
    return service.getColors();
  }

  public void setService(CarService service) {
    this.service = service;
  }

  public List<ColumnModel> getColumns() {
    return columns;
  }

  public void onCellEdit(CellEditEvent event) {
    Object oldValue = event.getOldValue();
    Object newValue = event.getNewValue();
    System.out.println("Cell Changed, Old: " + oldValue + ", New:" + newValue);
    if (newValue != null && !newValue.equals(oldValue)) {
      FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_INFO, "Cell Changed", "Old: " + oldValue + ", New:" + newValue);
      FacesContext.getCurrentInstance().addMessage(null, msg);
    }
  }

  public void dumpCars() {
    for (Car c : cars) System.out.println(c.brand);
  }

  static public class ColumnModel implements Serializable {

    private static final long serialVersionUID = 1L;

    private String header;
    private String property;

    public ColumnModel(String header, String property) {
      this.header = header;
      this.property = property;
    }

    public String getHeader() {
      return header;
    }

    public String getProperty() {
      return property;
    }
  }
}

1 个答案:

答案 0 :(得分:4)

org.primefaces.component.columns.Columns后面的<p:columns>类会在null方法上返回一个硬编码的getCellEditor()See source code

258    public CellEditor getCellEditor() {
259        return null;
260    }

至少在链条中进一步解释了NPE,但由于我不是PrimeFaces开发者,我无法解释为什么它有目的地返回硬编码null。您最好的选择是向PrimeFaces报告一个新问题。 It doesn't seem to be already reported before


同时,理论上你应该能够用<p:columns>取代<c:forEach><p:column>来解决这个棘手的问题。

<c:forEach items="#{dtColumnsView.columns}" var="column" varStatus="loop">
  <p:column>

    <f:facet name="header">
      <h:outputText value="#{column.header}" />
    </f:facet>

    <p:cellEditor>
      <f:facet name="output"><h:outputText value="#{car[column.property]}" /></f:facet>
      <f:facet name="input"><p:inputText id="modelInput_#{loop.index}" value="#{car[column.property]}" /></f:facet>
    </p:cellEditor>

  </p:column>
</c:forEach>

注意:确保手动将迭代索引分配给循环内的任何组件ID。

另见: