How to display different values from different object types in a single dataTable?
I have an object (Ticket), which has a list of other objects (Message). Message is abstract, and has several subclasses - like EditMessage, CreationMessage, and so on. So that Ticket object contai开发者_Python百科ns a mix of that messages, and they are ordered by their creation time.
Now I want to display all those messages in a Facelets page, and I need to output values of fields, specific for that message type: i.e., editedField in EditMessage, userName in CreationMessage, ...
The most obvious way seems to use h:dataTable:
<h:dataTable value="#{ticketController.ticket.messages}" var="msg" >
// determine type of message, cast, and use <c:if> to output needed values
</h:dataTable>
The problem is that Facelets expression language does not have "instanceof" and casts. As far as I can see, this can be solved using some ugly round-tripping to managed bean, determining type of message in standard Java, return message of needed type, ... and so on.
Is there a better, more understandable and concise way of doing this?
Solution
My main problem was with <c:if> tag. It turned out that it is a JSTL tag, so it has slightly different rendering life cycle. Instead of it, I now use <h:panelGroup> and its "rendered" attribute.
Some code:
<h:dataTable value="#{ticketController.ticket.messages}" var="msg" >
<h:column>
<h:panelGroup rendered="#{msg.class.name == 'org.rogach.tsnt.TextMessage'}" >
<h:outputText value="msg.text" />
</h:panelGroup>
<h:outputText value="#{msg.creationTime}" />
</h:column>
</h:dataTable>
And no cast is ever needed.
Instead of instanceof, compare the name of the object's class.
Say:
<c:if test="${xxx.class.name == 'CreationMessage'}">
or c:choose
And you won't need any cast with EL. If the object doesn't have some property you specified it will give an exception, if it does have it's OK.
精彩评论