0

I have an application with a risk matrix. The headings are 5 severities (from the severitiesBean in my example) and 5 likelihoods (from the likelihoodsBean in my example). (The headings go by different names in literature, such as exposure or probability or consequences.) In each cell there is a risk rating (enumerated from the riskRatingsBean). To give you an idea of what this looks like visually, there is an example here.

I am able to display the matrix just fine, which seems all people asking related questions on SO cared about. However, I want to display and allow the administrator of the system to edit the risk for each cell in the grid. A selectOneMenu dropdown in either h: or p: (PrimeFaces) seems like a good way of allowing the selection.

Here's the JSF:

<h:panelGroup id="editArea">
<table border="1" style="border-collapse:collapse;" class="riskMatrix">
    <tr>
        <td rowspan="2" colspan="2"></td>
        <th colspan="5">Severity</th>
    </tr>
    <tr>
        <!-- Severities going across the top -->
        <ui:repeat var="severity" value="#{severitiesBean.severities}">
            <th style="text-align: center;">
                <h:outputText value="#{severity.name}"/>
            </th>
        </ui:repeat>
    </tr>
    <ui:repeat id="likelihoodLoop" var="likelihood" value="#{likelihoodsBean.likelihoods}" varStatus="lkhdvar">
        <tr>
            <ui:fragment rendered="#{lkhdvar.index == 0}">
                <th rowspan="5">Likelihood</th>
            </ui:fragment>
            <!-- Likelihoods going down the side -->
            <th>
                <h:outputText value="#{likelihood.name}"/>
            </th>
            <!-- The rating for each cell going across -->
            <ui:repeat id="severitiesLoop" var="severity" value="#{severitiesBean.severities}">
                <td class="#{riskRatingsBean.riskRatings.get(riskMatrixBean.riskMatrix[severity.id-1][likelihood.id-1]-1).cssClass}" style="text-align: center;">
                    <p:selectOneMenu
                            id="RiskRatingDropDown" effect="none"
                            value="#{riskMatrixBean.riskMatrix[severity.id-1][likelihood.id-1]}">
                        <f:selectItems value="#{riskRatingsBean.riskRatings}" var="rating" itemLabel="#{rating.name}" itemValue="#{rating.id}"/>
                    </p:selectOneMenu>
                </td>
            </ui:repeat>
        </tr>
    </ui:repeat>
</table>
</h:panelGroup>
<h:messages id="riskMatrixErrorMessages"/>
<p:commandButton id="SaveButton" value="Update" actionListener="#{riskMatrixBean.saveRiskMatrix}"
    update="editArea"/>

In the riskMatrixBean, the matrix is defined like this:

public int[][] getRiskMatrix()
{
    return riskMatrix;
}

This all displays perfectly. However, I want to be able to update the values. When I click on the submit button, I get an exception:

javax.faces.component.UpdateModelException: java.lang.ClassCastException: Unable to add an object of type [java.lang.Integer] to an array of objects of type [int]
  at javax.faces.component.UIInput.updateModel(UIInput.java:866)
  at javax.faces.component.UIInput.processUpdates(UIInput.java:749)
  at com.sun.faces.facelets.component.UIRepeat.process(UIRepeat.java:633)
  at com.sun.faces.facelets.component.UIRepeat.processUpdates(UIRepeat.java:880)
  at com.sun.faces.facelets.component.UIRepeat.process(UIRepeat.java:633)
  at com.sun.faces.facelets.component.UIRepeat.processUpdates(UIRepeat.java:880)
  at javax.faces.component.UIComponentBase.processUpdates(UIComponentBase.java:1291)
  at javax.faces.component.UIComponentBase.processUpdates(UIComponentBase.java:1291)
  at javax.faces.component.UIForm.processUpdates(UIForm.java:281)
  at javax.faces.component.UIComponentBase.processUpdates(UIComponentBase.java:1291)
  at javax.faces.component.UIViewRoot.processUpdates(UIViewRoot.java:1254)
  at com.sun.faces.lifecycle.UpdateModelValuesPhase.execute(UpdateModelValuesPhase.java:78)
  at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
  at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:198)
  at javax.faces.webapp.FacesServlet.service(FacesServlet.java:650)
  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
  at org.apache.myfaces.webapp.filter.ExtensionsFilter.doFilter(ExtensionsFilter.java:357)
  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
  at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
  at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
  at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:581)
  at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
  at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
  at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:931)
  at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
  at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
  at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
  at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
  at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
  at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.ClassCastException: Unable to add an object of type [java.lang.Integer] to an array of objects of type [int]
  at javax.el.ArrayELResolver.setValue(ArrayELResolver.java:96)
  at com.sun.faces.el.DemuxCompositeELResolver._setValue(DemuxCompositeELResolver.java:255)
  at com.sun.faces.el.DemuxCompositeELResolver.setValue(DemuxCompositeELResolver.java:281)
  at org.apache.el.parser.AstValue.setValue(AstValue.java:218)
  at org.apache.el.ValueExpressionImpl.setValue(ValueExpressionImpl.java:253)
  at com.sun.faces.facelets.el.TagValueExpression.setValue(TagValueExpression.java:131)
  at javax.faces.component.UIInput.updateModel(UIInput.java:832)
... 33 more

I'm at a loss as to what I'm doing wrong. Obviously the updateModel during the updateModelValuesPhase doesn't know how to deal with the int[][] and how I've specified the selectOneMenu value attribute. I suspect there is something wrong with the approach, but I'm not sure what. Maybe it's something to do with the nested ui:repeats? I tried to change to using Integer[][] and to List<List<Integer>>, and still no luck, although I probably did something else wrong along the way. I'm open to changing my data type as necessary.

Thanks in advance!

Pixelstix
  • 702
  • 6
  • 21
  • How exactly does `Integer[][]` fail? (or did you really use `Integer[]` in some way?) The `List>` will fail for reasons explained here: http://stackoverflow.com/q/19872633 – BalusC Jan 06 '16 at 08:00
  • Yes, it was `Integer[][]`, I've updated the question. I changed my code back to Integer[][] so I'd be able to describe what went wrong, and it's now working! I have no idea what I'm doing differently today than I did yesterday, maybe I just needed to sleep on it? I probably wouldn't have gone back to try `Integer[][]` again if you hadn't asked about it. Dank je wel, @BalusC, for once again pointing us all in the right direction. You are so appreciated! – Pixelstix Jan 06 '16 at 14:36
  • Perhaps a dirty build/deploy. You're welcome. – BalusC Jan 06 '16 at 17:32

0 Answers0