setPropertyListener and setActionListener might fire too late when using Facelets!

Introduction

As of JDeveloper 11.1.2.x, you can use Facelets to build your web pages. Facelets is recommended over JSP pages as it is the JSF-native view technology. However, when migration your existing .jspx pages to facelets, you might run into some unexpected behavior when you are using the af:setPropertyListener or af:setActionListener tags.

Main Article

A few days ago I ran into this strange issue where I was setting a managed bean property using the setPropertyListener tag, and then I tried to use the property value in an actionListener method within the same bean. Let me explain using an example: I want to display a “Hello Steven” message in the log, so I use a setPropertyListener to set the name property:

<af:commandButton text="Say Hello" id="cb1"
                  actionListener="#{viewScope.SayHello.sayHello}">
  <af:setPropertyListener from="Steven" to="#{viewScope.SayHello.name}" type="action"/>
</af:commandButton>

And the sayHello action listener method looks like this:

public void sayHello(ActionEvent actionEvent)
{
  System.err.println("Hello "+getName());
}

Very simple example, should work fine right? Well, using JSP pages in JDeveloper 11.1.1.x it does run fine, however using Facelets in JDeveleoper 11.1.2.x it doesn’t work, at least not the first time! The first time it will print out “Hello null”, and the second time it will correctly print “Hello Steven”. Note that it doesn’t matter whether you use the setPropertyListener tag or the setActionListener tag, you will get the same behavior.

I browsed the bug database and actually found an explanation of this strange behavior in bug 12908218 – FOR FACELET PG, VALUE SET IN SETPROPERTYLISTENER NOT AVAILABLE IN BACKING BEAN:

This is an unfortunate consequence of the way JSP did things before and how facelets does things now, which sadly may be the correct behavior. There is a difference between how facelets and jsp add the 2 listeners to the command – actionListener and setPropertyListener.

In facelets, the actionListener method is added first to the list of actionListeners for the command (ActionSource.addActionListener()) when commandButton tag is processed, and then the SetPropertyListener gets added second. This means that when the user clicks the command, the actionListener gets called first before the property gets pushed into the ‘pageFlowScope’ – this is why the property is not available right away in your actionListener. If the pageFlow property were to change every time you click this problem can be even more obvious.

In jsp, the above works fine because the command tag only stores the actionListener in it’s internal faces bean property and the setPropertyListener gets called first. When you click the command all registered actionListeners get called of which there is only one – setPropertyListener, and then the actionListener property.

It appears to me that facelets behavior is the expected and correct behavior and also the order in which listeners get added or called cannot be guaranteed.

So, quite tricky indeed. It is expected behavior with Facelets, at the same time it might break existing JSP-based ADF applications that are migrated to Facelets. The good news is that the bug is marked as fixed in JDeveloper release 12.1.2.

So, what are your options for now? You basically have two options to work around this issue:

  • Use the action property instead of the actionListener property on the button, which means you have to change the signature of the method, and possible merge the logic with another method if you are already using the action property as well.
  • Use the f:actionListener tag instead of the actionListener property and sequence this tag after the setPropertyListener tag.

Here is a screen shot of the small sample that illustrates the behavior:

SetPropertyListenerFacelets

You can download the JDev 11.1.2.x sample here.

Add Your Comment