Weighing in at 1485 lines, with dozens of methods, UIData is a complex and
confusing behemoth of a component. It exhibits subtle problems in certain
conditions (see issue 153) relating to state management, because it maintains
child state in a manner inconsistent with all other components. UIData can also
be inefficient, in that it must save and restore child state many times during
rendering, decoding, etc.; this is to swap the current state of rows to trick
other JSF components into believing that multiple instances of its child
It also represents the only viable way of implementing a component that contains
a variable number of instances of the tags it contains. The reason for this is
that the logic behind implementing this component is so complex that it is not
an effective use of time to duplicate it for most people, and there is no
alternative approach available within the JSF RI, which may lead people to
believe that this is the only approach possible.
I propose that this component be retired in favor of a new methodology for these
types of collection-oriented components. The new methodology would work as follows.
When a tag is encountered (JSP, or, in the case of Facelets, XML) that
corresponds to a dataTable (or any other such component), the handler for the
tag should construct a component for the tag, and a child component for every
active collection entry (that is, every member of the data model starting from
the first row, whose number may for example be overridden by the "first"
attribute of h:dataTable, through the last row, whose number may be overridden
using the "rows" attribute).
Each of these children will contain the complete component tree represented by
the tags that are nested within h:dataTable. The children themselves would be a
standard component type (say, UICollectionEntry), which would have a null
renderer type by default (so that rendering falls through to the children).
The UICollectionEntry components have special handling for IDs; each one has an
integer ID. getId() (and getClientId()) will return the string representation
of this ID; setId(String) becomes a no-op. A new getRowId()/setRowId(int)
method pair is introduced.
By making the collection component and each UICollectionEntry implement
NamingContainer, the ID nesting will work exactly as UIData's pretends to work
today - except that the collection entry components (rows in the dataTable case)
will be real. This means that no state saving magic is needed and no context
switching to select rows during rendering and other lifecycle phases. Problems
with state maintenance evaporate.
I have developed a Facelets implementation of this idea. My collection
component class (equivalent to UIData) is 174 lines long. The collection entry
component class is 140 lines. The Facelets tag handler for collection
components is 143 lines. And that's including a 19-line copyright notice and
additional comments for each file. All the code is simple and straightforward,
and more importantly can be easily leveraged by an entry-level component
developer. I do not yet have a JSP version, but I plan to develop one as soon
as soon as I can.
I am willing to work offline with someone to review the code and demonstrate the
idea. I think that this would be a good move for JSF 2.0... please consider
|Field||Original Value||New Value|
|Fix Version/s||unscheduled [ 10405 ]|
|Status||Resolved [ 5 ]||Closed [ 6 ]|