I've been a zone leader with DZone since 2008, and I'm crazy about community. Every day I get to work with the best that JavaScript, HTML5, Android and iOS has to offer, creating apps that truly make at difference, as principal front-end architect at Avego. James is a DZone Zone Leader and has posted 639 posts at DZone. You can read more from them at their website. View Full User Profile

Apache MyFaces - Antipatterns and Pitfalls

10.15.2008
| 16715 views |
  • submit to reddit

The Map Trick

The Map Trick antipattern is a hack used to invoke business methods from view templates via an obscure limitation in the JSP and JSF specifications. By invoking business methods from a template, the view and model become tightly coupled.
JSF EL and Unified EL do not support parameterized method invocation. You get ternary logic, and you can call getters, but that’s about it. Tapestry developers, or anyone else familiar with the Object-Graph Navigation Language (OGNL) expression language, are often disappointed to learn this because OGNL supports parameterized method invocation. The closest thing to parameterized method invocation is static method invocation via JSP EL or Facelets.
The Map interface is the only exception to this rule. JSP EL, JSF EL, and Unified EL all support invocation of the get method, a parameterized method of the Map interface:

#{myManagedBean.silvert} // pulls 'silvert' from managed bean Map
#{param['lubke']} // pulls 'lubke' request parameter

Some developers have implemented their own Map to take advantage of this.

public class MapTrick implements Map {

public Object get(Object key) {
return new BusinessLogic().doSomething(key);
}
public void clear() { }
public boolean containsKey(Object arg) { return false; }
public boolean containsValue(Object arg) { return false; }
public Set entrySet() {return null; }
public boolean isEmpty() { return false; }
public Set keySet() { return null; }
public Object put(Object key, Object value) { return null; }
public void putAll(Map arg) { }
public Object remove(Object arg) { return null; }
public int size() { return 0; }
public Collection values() { return null; }
}


When the EL Resolver invokes the get method the parameter is then used by business logic. We once saw a project where an entire miniature framework was built around the map trick. Needless to say, the view and model were severely tightly coupled. There are always better alternatives to the map trick using plain methods and value expressions.

The Déjà Vu PhaseListener


The JSF request life cycle is broken into phases. The beginning and end of each phase is considered an event, and these events can be subscribed to via a PhaseListener. If a PhaseListener subscribes to the restore view phase of the request life cycle, MyFaces will invoke a callback method on the PhaseListener instance each time the restore view phase begins and ends for a request. When PhaseListener callback methods are invoked twice, it is a referred to as a Déjà Vu PhaseListener, an old problem that often crops up on the MyFaces mailing list.

Tip
One of the most active mailing lists for the Apache Software Foundation is users@myfaces.apache.org. It is a wonderful place for exchanging new ideas, trading technical solutions, and engaging in flame wars. After all these years, MyFaces remains an open source project where the development team still interacts with application developers.

Let’s look at how PhaseListeners are registered at start-up time. PhaseListeners can be registered in any JSF configuration file:

<lifecycle>
<phase-listener>
org.apache.myfaces.PhaseListenerImpl
</phase-listener>
</lifecycle>
JSF configuration files are specified via the javax.faces.CONFIG_FILES context parameter
in the deployment descriptor:
<context-param>
<description>comma separated list of JSF conf files</description>
<param-name>javax.faces.CONFIG_FILES</param-name>
<param-value>
/WEB-INF/faces-config.xml,/WEB-INF/burns.xml
</param-value>
</context-param>

Per the JSF specification, MyFaces automatically parses /WEB-INF/faces-config.xml as well as all files specified in the comma-separated list of the javax.faces.CONFIG_FILES context parameter. When /WEB-INF/faces-config.xml is specified in the javax.faces.CONFIG_FILES context parameter it is parsed twice. The PhaseListeners configured in this file are consequently registered twice at start-up and invoked twice at runtime. MyFaces tries to warn you about this in the log files:

WARN org.apache.myfaces.config.FacesConfigurator - /WEB-INF/faces-config.xml has been specified in the javax.faces.CONFIG_FILES context parameter of the deployment descriptor. This should be removed, as it will be loaded twice. See JSF spec 1.2, 10.1.3

XML Hell++

JSF 1.1 and 1.2 are compatible with Java 1.4. This requirement limits the JSF specification from using Java annotations to declare things such as navigation rules or dependency injection. These things are declared in XML instead. We once looked at a project in development with a configuration file similar to the following.
The “contact us” page was to be accessible from just about every page on the site, and a separate action rule was used for each page.

<navigation-rule>
<from-view-id>/home.xhtml</from-view-id>
<navigation-case>
<from-outcome>contact_us</from-outcome>
<to-view-id>/contact.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
<navigation-rule>
<from-view-id>/site_map.xhtml</from-view-id>
<navigation-case>
<from-outcome>contact_us</from-outcome>
<to-view-id>/contact.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
<navigation-rule>
<from-view-id>/about_us.xhtml</from-view-id>
<navigation-case>
<from-outcome>contact_us</from-outcome>
<to-view-id>/contact.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
<!-- continued ... -->

A global navigation rule was used to reduce the configuration file by more than a hundred lines:

<navigation-rule>
<from-view-id>*</from-view-id>
<navigation-case>
<from-outcome>contact_us</from-outcome>
<to-view-id>/contact.xhtml</to-view-id>
</navigation-case>
</navigation-rule>

 

If you like this excerpt from the Apress book The Definitive Guide to Apache MyFaces and Facelets. You can download the chapter here.

 

Legacy