RichFaces 3 to RichFaces 4 migration

TLDR: RichFaces reached a richly merited end of life in June 2016. It was a poorly managed catastrophe of a project that deserved no better.

Noting here that the official migration guide is no better than about 30% complete. As a metric on that, I wrote an XSLT stylesheet of 378 lines in 2011 based on the migration guide. I then left the project in abeyance until June 2015 and based on further investigations and getting it working it is already up to 1090 lines. Bearing in mind that any XSLT stylesheet has some overhead, 378/1090 = about 35%.

After you've done what it says in the Migration Guide:

  1. Open the TLD/VLD generated documentation for each component you use in adjacent browser tabs, one for each version, and compare them carefully. There are dozens of undocumented changes in attribute names and purposes, and some attributes have been moved from parent containers to child containers.

  2. There are also important things that have just been arbitrarily removed, such as rich:page and rich:layout.

    I'll provide a list of some of the extra things I have discovered at the end of this.

  3. You will then be confronted with the unpleasant realization that they have also changed large numbers of their own style class names, so if you've defined styles for any of those in your own style sheet you have yet more work to do.

  4. You will also discover that their claim that you can define your own style classes and specify them in the rich components to implement your own styles is simply untrue. Your style classes are applied at a containing level but in many cases such as table cells they have seen fit to define fonts etc at the table cell level, where the only way you can override them is by redefining their cells styles by name.

  5. You also have to ensure that your stylesheet is included after the Rich Faces ones. In 3.3 this was automatic, as theirs were included first. Theirs are now included last, so you have to use h:outputStylesheet and do so as late as possible, to ensure it is generated afterwards.

I used an XSLT transform to implement the Migration Guide and accomplish 1-2 above. It presently has over 1000 lines and I have by no means finished yet. Why they couldn't have provided such a thing themselves is a mystery to me.

Why it was deemed necessary to make such major changes between release 3 and 4 is another and deeper mystery. It is a very poorly managed product. I won't be migrating it again, or deploying it anew.

EDIT Undocumented changes I have found (using XPath syntax for brevity):

  • a4j:status

    1. The documentation is vague on the point, but the for= attribute has been removed: it now operates by default within the nearest parent a4j:region, unless there are tie-ups to specific widgets via the status= attributes. So if you have multiples within the same region they will now all fire.

    2. If you want it to apply to a specific widget via status= you have to change the corresponding a4j:status/@id to an @name attribute.

    3. After you fix all that, it still doesn't work:

      • An a4j:status with @for (removed) attribute won't stop
      • with an @name attribute and no @id won't do anything
      • and with both @name and @id won't stop.
  • rich:column/@breakBefore now breakRowBefore

  • rich:page removed.

  • rich:layout removed.

  • rich:column/@sortOrder now must be lowercase.

  • rich:dropDownMenu/@value now rich:dropDownMenu/@label

  • rich:dropDownMenu/@direction and rich:dropDownMenu/@jointPoint

    The values for these have been changed from {top-left, top-right, bottom-left, bottom-right} and {tl, tr, bl, br} respectively to {topLeft, topRight, bottomLeft, bottomRight}.

  • rich:contextMenu/@submitMode, rich:dropDownMenu/@submitMode, rich:menuItem/@submitMode

    These are now all now rich:<whatever>/@mode, and the value "none" needs to be changed to "client".

  • rich:isUserInRole

    This has simply ceased to work, at least for me, with Mojarra 2.2.08 and EL 2.2. Fortunately with EL 2.2 you don't need it any more and can use request.isUserInRole(...).

  • rich:menuGroup/@value now rich:menuGroup/@label.

  • rich:tab/@label now rich:tab/@header.

  • rich:tab/f:facet/@name[.='label'] now rich:tab/f:facet/@name[.='header'].

  • rich:tabPanel/@activeTabClass, rich:tabPanel/@contentStyle, rich:tabPanel/@disabledTabClass, rich:tabPanel/@inactiveTabClass, rich:tabPanel/@tabClass

    Now tabActiveHeaderClass, tabContentClass, tabDisabledHeaderClass, tabHeaderClass, tabInactiveHeaderClass, tabContentClass respectively.

  • rich:tree/@adviseNodeOpened

    This has been removed and rich:treeNode/@expanded added. This is not well documented: it must be an EL, e.g. "#{true}", not "true", and it can be a bean property of the tree node, e.g. "#{node.expanded}", or of any other bean; must be a boolean. (The same is true of the new rich:collapsibleSubTable/@expanded attribute.)

  • rich:tree/@nodeFace now rich:tree/@nodeType.

  • rich:tree/@switchType now rich:tree/@toggleType and possibly rich:tree/@selectionType.

  • rich:tree/@treeNodeVar now var, or possibly just removed.

  • rich:treeNodesAdaptor

    now rich:treeModelAdaptor, and no longer handles arrays, nodesets, ... or anything not a Map or Iterable. It has also lost its var attribute, which as far as I can see breaks it completely for nested use. The only var attribute now available is that of the ancestor rich:tree. So for example if you wanted the parent node and the current child node at the same time, they are simply not available. This change entails either a non-trivial rewrite, or the following kludge.

    OLD:

      <rich:tree>
          <rich:treeNodesAdapter var="vm_host">
              <rich:treeNode .../>
              <rich:treeNodesAdapter var="vm_guest">
                  <rich:treeNode .../>
              </rich:treeNodesAdapter>
          </rich:treeNodesAdapter>
      </rich:tree>
    

    NEW:

      <rich:tree ... var="node"> <!-- Add a 'var' attribute -->
          <rich:treeModelAdapter>
              <c:set var="vm_host" value="#{node}"/>
              <rich:treeNode .../>
              <rich:treeModelAdapter>
                  <c:set var="vm_guest" value="#{node}"/>
                  <rich:treeNode .../>
              </rich:treeModelAdapter>
          </rich:treeModelAdapter>
      </rich:tree>
    

    You could also use <ui:param> instead of <c:set>.

The conversion process is made a lot more difficult by RichFaces' refusal to error-check attribute names. You can continue to use the old names, but they just don't work. Silently.


is there anything major I should think about or know or think about before migration?

Their recommendation is to follow their own RichFaces 3.3.x - 4.x Migration Guide — which appears to be far from complete, see EJP's answer below for the real experience.


(might be a silly question but...) can you "mix" richfaces 3 with richfaces 4?

No, you can't. It would conflict with itself.