RichFaces 3.3 - > 4.x migration guide
This developer guide is based on my personal experience and covers migration of the Java project.
Technology | Previous version | New version |
---|---|---|
Spring | 2.5.6 | 3.1.1 |
Spring Web Flow | 2.0.5 | 2.3.1 |
Spring Security | 2.0.7 | 3.1.1 |
JSF | 1.2.0.8 | 2.1.11 |
RichFaces | 3.3.3 | 4.2.2 |
I will focus on RichFaces migration in this article as it took most of the time and development efforts. Firstly I read two books which I found extremely useful:
· Ed Burns, Chris Schalk - JavaServer Faces 2.0, The Complete Reference
· Practical RichFaces 2nd ed. - M. Katz
This allowed me to understand the new concepts implemented in JSF2/RichFaces 4. After that I reviewed the official migration guide
https://community.jboss.org/wiki/RichFacesMigrationGuide33x-4xMigration
and step-by-step upgraded my project components using official forums and related resources.
This article describes cases where backward compatibility was broken and I had to manually upgrade the source code.
Thus this guide is knowledge base where I tried to put all the information about migration issues and how to resolve it.
NOTE: Having faced a project migration of my own I have updated this guide with issues that I found and that weren't already covered. --Michal Petrov
1.Removed/renamed components
Component name | Issue | Resolution | Notes |
a4j:form | Removed in 4.x | Replace with h:form | In case of multiple forms consider using a4j:region and keep only one h:form that covers all. |
rich:spacer | Removed in 4.x | Apply custom CSS/HTML elements |
|
a4j:include | Removed in 4.x | Replace with ui:include |
|
rich:layout | Removed in 4.x | Replace with layout:layout | Layout component is not official RichFaces component |
a4j:loadScript | Removed in 4.x | Replace with h:outputScript | |
rich:toolBar | Renamed in 4.x | Replace with rich:toolbar |
|
rich:toolBarGroup | Renamed in 4.x | Replace with rich:toolbarGroup |
|
a4j:actionparam | Renamed in 4.x | Replace with a4j:param |
|
rich:modalPanel | Renamed in 4.x | Replace with rich:popupPanel |
|
rich:datascroller | Renamed in 4.x | Replace with rich:dataScroller |
|
rich:subTable | Renamed in 4.x | Replace with rich:collapsibleSubTable |
|
a4:support | Renamed in 4.x | Replace with a4:ajax | The “action” attribute is renamed to “listener”, “event” attribute now accepts value without “on” prefix |
rich:toolTip | Renamed in 4.x | Replace with rich:tooltip | The available values for “direction” attribute have changed |
rich:dataList | Renamed in 4.x | Replace with rich:list |
|
2.Renamed/removed attributes
Component name | Issue | Resolution | Notes |
rich:tabPanel | Facet/attribute “label” is not supported | Replace with “header” facet |
|
"selectedTab" attribute was renamed | Replace with “activeItem” attribute |
| |
All components | “reRender” attribute was renamed | Replace with “render” attribute | According to JSF spec. |
ajaxSingle="true" is not supported | Replace with execute="@this" |
| |
"limitToList" attribute was renamed | Replace with "limitRender" |
| |
rich:dataTable | “width” attribute is not supported | Replace with styleClass="customwidth" or style=”width:[width]” | customwidth should be defined in CSS. |
rich:column | “width” attribute is not supported | Define “columnsWidth” attribute for the parent table | Example: columnsWidth =”100,30,30” |
rich:toolBarGroup | “styleClass “ attribute is not supported | Define “itemClass” attribute for the parent toolbar |
|
rich:dataTable | “columnClasses” attribute specifies CSS class for each column | Duplicate CSS class for each column | Example: columnClasses="panel-content,panel-content " |
rich:fileUpload | “error” event is not supported | Use “serverErrorLabel” attribute to define error message |
|
rich:dataGrid | Attributes: "rowClasses", "columnClasses", "footerClass" are not supported | Replace with rich:list | 1) type="definitions" should be added in rich:list 2) rich:dataScroller should be placed outside of the list |
rich:tree | "nodeFace", "switchType" and "treeNodeVar" were renamed | Replace with "nodeType", "toggleType" and "var" respectively |
|
"showConnectingLines" attribute is not supported | Redefine CSS classes "rf-trn" and "rf-tr-nd" | .rf-trn, .rf-tr-nd { background: none; } | |
rich:treeNode | "icon" attribute is not supported | Replace with "iconExpanded" and "iconCollapsed" attributes |
|
rich:dataScroller | "selectedStyleClass" and "inactiveStyleClass" attributes are not supported | Redefine the following CSS:
a.rf-ds-act a.rf-ds-nmb-btn | Example: a.rf-ds-act { background-color: #F4F4F4; border: 1px solid #EBEBEB; font-weight: bold; color: #4262A1; font-size: 8pt; white-space: nowrap; } |
rich:componentControl | "for" attribute was renamed | Replace with "target" | |
"attachTo" attribute is not supported | Put it inside the element it needs to be attached to | ||
rich:contextMenu | "disableDefaultMenu" attribute is not supported | Disables default menu automatically | |
"event" and "attachTo" attributes were renamed | Replace with "showEvent" and "target" respectively | ||
"submitMode" attribute was renamed | Replace with "mode" | value "none" is not suported | |
rich:menuItem | "value" attribute was renamed | Replace with "label" | |
rich:calendar | "cellHeight" and "cellWidth" attributes are not supported | Redefine "rf-cal-c" CSS class | .rf-cal-c { width: 24px; height: 22px; } |
3.Changed components
Affected component | Issue | Old code | Upgraded code |
rich:componentControl | The “controls” facet for popupPanel is not shown if it was inside h:panelGroup | <h:panelGroup> .... </h:panelGroup> | <h:panelGrid> .... </h:panelGrid> |
rich:tabPanel | a4j:ajax is not supported to handle tab changing | <a4j:support event="ontabenter" ajaxSingle="true" reRender="received" > <a4j:actionparam assignTo= "#{messages.direction}" value="received" actionListener= "#{controller.update()}" /> </a4j:support> | itemChangeListener ="#{controller.update ()}" |
tabPanel doesn’t work properly if it’s not inside h:form (or clientType =’client’) | <rich:tabPanel switchType="ajax"> … | <h:form> <rich:tabPanel switchType="ajax"> … </h:form>
| |
rich:tab | Tab width is not auto sized according to content width | <rich:tab><f:facet name="label"> <a4j:outputPanel> <h:outputText value= "#{msg['club.details']}" /></a4j:outputPanel> </f:facet></rich:tab> | .tab-content { width: 95px; }
<f:facet name="header"><div class="tab-content"> <h:outputText value= "#{msg['club.details']}" /></div></f:facet> |
Tab height is not auto sized according to content height | <rich:tab><f:facet name="label"> <h:graphicImage url= "/res/img/home.gif"/> </f:facet></rich:tab> | .rf-tab-hdr-tabline-vis.rf-tab-hdr-tabline-top { height:100%; }
This code should be located in .ecss file which would be dynamically loaded after <h:body> tag:
<h:outputStylesheet library="css" name="app.ecss" /> | |
All data iteration components | “ajaxKeys’ attribute is not supported | <rich:dataGrid ... ajaxKeys= "#{gridBean.ajaxKeys}"> | Use partial rendering:
<rich:dataGrid id="grid"> <h:panelGrid id="cellGrid"> <h:outputText value= "#{memberBean.name}" /> <a4j:ajax event="click" listener= "#{selectBean.update()}" render="grid:@rows (gridBean.ajaxKeys):cellGrid" /></h:panelGrid> </rich:dataGrid> |
rich:componentControl | Component doesn’t close the popup panel | <rich:componentControl for="clubWindow" attachTo="cancel" operation="hide" event="onclick" /> | Move rich:componentControl insde the image
<h:graphicImage value="/res/img/close.png" > <rich:componentControl target="clubWindow" operation="hide" event="click" /> </h:graphicImage> |
a4j:mediaOutput | a4j:mediaOutput doesn't work inside data iteration component | <rich:dataGrid var="file" value="#{files}" <a4j:mediaOutput element="img" session="false" createContent= "#{mediaBean.paint}" value="#{file}" cacheable="false"> <f:param value= "#{timeStamp}" name="time" /> </a4j:mediaOutput> </rich:dataGrid> | Use ordinary type for value attribute(like item index) and retrieve actual item in the createContent method
<rich:list var="file" value="#{files}" type="definitions"> <a4j:mediaOutput element="img" session="false" createContent= "#{mediaBean.paint}" value="#{file.index}" cacheable="false"> <f:param value= "#{timeStamp}" name="time" /> </a4j:mediaOutput></rich:list> |
rich:dataTable | The sorting functionality has changed | <rich:dataTable ... > <rich:column sortBy= "#{account.name}"> <f:facet name="header"> <h:outputText value= "#{msg['user.name']}" /></f:facet> <h:outputText value= "#{account.name}" /></rich:column> | Define managed bean sortBean which will keep sort orders and priorities(if we support multiple column sorting)
<rich:dataTable id="accountsTable" ...> <rich:column sortBy="#{account.name}" sortOrder= "#{sortBean.orders['name']}"> <f:facet name="header"> <h:panelGrid columns="2"> <a4j:commandLink execute="@this" value="#{msg['user.name']}" render="accountsTable" action="#{sortBean.sort}"> <f:param name="sortProperty" value="name" /> </a4j:commandLink> <h:graphicImage url="/res/img/down_icon.gif" rendered= "#{sortBean.oders[name] =='descending'}" /> <h:graphicImage url="/resources/images/up_icon.gif" rendered ="#{sortBean.oders[name] =='ascending'}" /> </h:panelGrid> </f:facet> <h:outputText value="#{account.name}" /> </rich:column> |
rich:dataScroller | Programmatic change of the current page is altered | dataScroller.getDataTable(). getAttributes().put( UIDatascroller. SCROLLER_STATE_ATTRIBUTE, newPage); | dataScroller.getDataTable(). getAttributes() .put( dataScroller.getDataTable(). getClientId(facesContext) + AbstractDataScroller. SCROLLER_STATE_ATTRIBUTE, newPage); |
rich:popupPanel | minWidth and autosized attributes cannot be combined | <rich:modalPanel autosized="true" minWidth="600"> | Leave autosized attribute and put the div inside popupPanel
<div style="width: 600px" /> |
RichFaces panel API has changed | <a4j:commandButton reRender ="clubWindow" oncomplete= "Richfaces.showModalPanel( 'clubWindow');" value="#{msg['club.add']}" />
| <a4j:commandButton render="clubWindow" value= "#{msg['club.add']}" oncomplete= "#{rich:component( 'clubWindow')}.show()" />
| |
Client-side validation has changed | <rich:modalPanel id="clubWindow" … > <h:form id="fieldForm"> <a4j:outputPanel ajaxRendered="true"> <h:messages id="error" /></a4j:outputPanel> … <a4j:commandButton action= "#{controller.update()}" oncomplete ="windowclose();" value= "#{msg['buttons.save']}" /> … <script type="text/javascript"> function windowclose(){ if (document. getElementById( 'fieldForm:error')==null){ Richfaces.hideModalPanel( 'clubWindow'); };};</script> | The following changes should be made: 1) Replaces h:messages with rich:messages 2) Move rich:popupPanel inside parent h:form 3) Use the maximumSeverity attribute to check for errors
<a4j:outputPanel ajaxRendered="true"> <script type="text/javascript"> function windowclose() { if(#{facesContext. maximumSeverity==null}) { #{rich:component( ‘clubWindow’)}.hide(); }} </script></a4j:outputPanel> | |
rich:tree | Data model has changed (TreeNodeImpl class was removed) | protected TreeNode<T> addNode(TreeNode<T> parent, int id, T data) { TreeNodeImpl<T> node = new TreeNodeImpl<T>(); node.setData(data); parent.addChild(id, node); return node; } | The implementation of the TreeNode interface should made.
public class DataTreeNodeImpl<T> implements TreeNode<T>, Serializable { private T data; public T getData() { return data; } |
rich:tree and child components | The handling of "var" attribute has changed, there is now a single var name for the entire tree | <rich:tree> <rich:treeNodesAdaptor nodes="#{bean.albums}" var="album"> <rich:treeNode>#{album.name}</rich:treeNode> <rich:treeNodesAdaptor nodes="#{album.images}" var="image"> <rich:treeNode>#{image.description}</rich:treeNode> </rich:treeNodesAdaptor> </rich:treeNodesAdaptor> </rich:tree> | <rich:tree var="node"> <rich:treeModelAdaptor nodes="#{bean.albums}"> <rich:treeNode>#{node.name}</rich:treeNode> <rich:treeModelAdaptor nodes="#{node.images}"> <rich:treeNode>#{node.description}</rich:treeNode> </rich:treeNodesAdaptor> </rich:treeNodesAdaptor> </rich:tree> |
rich:fileUpload | The classes that handle the uploaded files have changed.
It is not possible to extract filepath (String) from the uploaded file, instead you have access to the InputStream. | org.richfaces.event.UploadEvent; org.richfaces.model.UploadItem; | org.richfaces.event.FileUploadEvent; org.richfaces.model.UploadedFile; |
4.Unresolved issues
Component name | Issue | Notes |
rich:fileUpload | immediateUpload and isAllowFlash attributes is missing | Will be possibly implemented in 4.3 |
rich:fileUpload | Doesn’t work if Spring Web Flow is used in project | Unresolved |
rich:tree | adviseNodeOpened attribute is missing | Unresolved |
Comments