Why Don’t You Write a JSF Composite Component?

Posted on Posted in JSF, simpliying JSF

Composite components: a JSF 2.0 highlight

They say it’s hard to write a JSF component.

That’s rubbish. JSF has been designed with user defined components in mind. Beyondjava.net has a couple of articles on the topic, and my AngularFaces Github repository has a couple of working components you can use as a base. You’ll see creating JSF components isn’t rocket science at all.

But it true, it isn’t done in a minute, either. Thus JSF 2.0 introduced a great feature to create user-defined components. Simple components are created in no time. As for not-so-simple components – well, they are not created in time. I’ll return to that later. First I want to tell you the success story. It’s an inspiring story to tell.

Why don’t you just write a composite component?

Maybe you don’t already know that you want to write a composite component. What about a little experiment? Have a look at your JSF pages (or whichever GUI you use, for that matter). Print them in small letter, pin the print-out upside-down at the wall and look at it from some distance. Now you can see the structure of the code without being distracted from the content.

It’s kind of geometrical, isn’t it? That’s the common patterns of your code shining through. You’ll find groups of similar components repeated over and over again. If you don’t, you’ve probably forgotten to format the code nicely. Or you’ve already read this article :).

What do you do when you find yourself repeating over and over? Yeah, refactoring. In JSF terms this usually means writing a component.

So why don’t you just write a JSF 2.0 composite component? They say it’s the easiest way to write a JSF component.

Getting started with JSF 2.0 composite components

Basically creating a JSF 2.0 component is just extracting a group of JSF components into a file, giving it a name and calling the group by the name. It’s pretty much the same your Java IDE’s “extract method” refactoring does.

Plus the XML overhead. First, you have to put the extracted code into an XML file that has to obey a couple of rules. It’s a little boilerplate code you’ll quickly get used to. Regular readers of BeyondJava.net know I prefer to avoid boilerplate code, but it’s not a showstopper, either.

A very useful example might by an equivalent of the AngularFaces <a:body> component. As it happens, I chose to implement it in native Java in AngularFaces, but in this particular case I might have implemented a composite components just as well. I’ll take it to another level by adding the <h:form> tag:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" 
      xmlns:cc="http://java.sun.com/jsf/composite"
      xmlns:h="http://java.sun.com/jsf/html" 
      xmlns:f="http://java.sun.com/jsf/core" 
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:ui="http://java.sun.com/jsf/facelets" 
      xmlns:ng="http://xmlns.jcp.org/jsf/passthrough"
      xmlns:a="http://beyondjava.net/angularFaces" 
      xmlns:prime="http://primefaces.org/ui">

<h:head></h:head>
<h:body>
  <composite:interface>
    <composite:attribute name="ngapp" required="true" />
    <composite:attribute name="ngcontroller" />
  </composite:interface>

  <composite:implementation>
    <h:body ng:ng-app="#{cc.attrs.ngapp}" 
            ng:ng-controller="#{cc.attrs.ngcontroller}" 
            onload="restoreValues()">
      <script src='../resources/AngularFaces/angular.js'>
      </script>
      <script src='../resources/AngularFaces/glue.js'>
      </script>
      <script src='#{cc.attrs.ngcontroller}.js'>
      </script>
      <h:form>
        <prime:focus minSeverity="error" />
        <h:messages></h:messages>
        <cc:insertChildren />
        <script>storeValues();</script>
      </h:form>
    </h:body>
  </composite:implementation>
</h:body>
</html>

Note I use my own naming conventions for both the PrimeFaces library and JSF 2.2 path-through attributes. I prefer prime: and ng:, respectively. The standard conventions for the libraries seem to be p: in both cases.

Store the file in a subfolder of the “resources” folder of your web application. The file name becomes the component name, and the subfolder name becomes the name of your own component library. You can assign a different library shortcut later, as I did with the PrimeFaces library above, but usually, it’s better to name them all the same. So your web application now has a file \resources\af\form.xhtml.

Looking at the file you’ll notice 34 lines of code, the majority of which are boilerplate code. On the long run, those twenty-three lines of boiler-plate code are negligible. Mind you, that component saves you ten lines of JSF code every time you write an AngularFaces JSF view. Using the component is as simple as can be:

<f:view xmlns="http://www.w3c.org/1999/xhtml" 
        xmlns:f="http://java.sun.com/jsf/core"
        xmlns:h="http://java.sun.com/jsf/html" 
        xmlns:ui="http://java.sun.com/jsf/ui"
        xmlns:ui="http://java.sun.com/jsf/facelets" 
        xmlns:ng="http://xmlns.jcp.org/jsf/passthrough"
        xmlns:a="http://beyondjava.net/angularFaces" 
        xmlns:prime="http://primefaces.org/ui"
        xmlns:af="http://java.sun.com/jsf/composite/af">>
  <h:head />
  <af:body ngapp="mandelbrotApp" ngcontroller="mandelbrotController">
    <a:inputText value="#{mandelbrotController.xMin}" />
    <a:inputText value="#{mandelbrotController.xMax}" />
  </af:body>
</f:view>

You have to add your composite component library to the JSF view’s header, and that’s it. Your composite components are used exactly the same way Mojarra or PrimeFaces components are used. In our case, you refer to the component by writing <af:body>.

Passing parameters

You can even pass parameters to your composite component, and that’s where the trouble begins. At first glance, everything is simple. Parameters are defined in the interface section of the composite component:

<composite:interface>
    <composite:attribute name="ngapp" required="true" />
 </composite:interface>

To use the parameter value within the composite component you can u se the EL expression
#{cc.attrs.<parameterName>}:

<h:body ng:ng-app="#{cc.attrs.ngapp}">

So far, so good. So what?

JSF 2.0 composite component parameters can be tricky. They are not just call-by-name parameters. It took me a while to find out why this snippet doesn’t work:

<h:commandButton action="#{cc.attrs.myAction}">

There’s nothing wrong with the snippet. But it won’t work unless you tell JSF the parameter refers to a Java function. So the interface section has to look like so:

<cc:interface>
    <cc:attribute name="myAction" 
                         method-signature="java.lang.String action()"
                         required="true" />
 </cc:interface>

Note that the method signature is just that: a signature. It does not refer to a real function. You have to give the proper types (java.lang.String), but the name of the action doesn’t have to be the name of a real method.

The JSF view using the component have to add the brackets to the method parameter. If you omit the brackets, JSF erroneously looks for a getter.

In this particular example, there’s an alternative. You can also define the parameter as an actionSource:

<cc:interface>
  <c:actionSource name="myAction" />
</cc:interface>

Nested expressions

Another caveat are nested expressions. Today I wanted to define a component consisting of two standard buttons. My idea was just to pass the bean name as a parameter. The methods within the bean should have standard names. So I came up with this solution:

<h:commandButton value="Cancel" action="#{cc.attrs.bean}.cancelAction">
<h:commandButton value="Save"   action="#{cc.attrs.bean}.saveAction">

No go. This translates to action="myBean.saveAction". That’s a fixed name, not an expression language expression calling a bean’s method.

The other approach didn’t work either.

<h:commandButton value="Cancel" action="#{#{cc.attrs.bean}.cancelAction}">
<h:commandButton value="Save"   action="#{#{cc.attrs.bean}.saveAction}">

EL doesn’t allow for nested expressions.

As far as I know, there’s simply no solution to the problem. I had to choose the workaround: passing each method name individually as a parameter.

Conditional code

It’s even possible to use conditions in composite components. The code may be ugly as hell, but it works:

<c:choose>
    <c:when test="${cc.attrs.cancelAction!=null}">
        <h:commandButton value="Cancel"   action="#{cc.attrs.cancelAction}">
    </c:when>
</c:choose>
<c:choose>
    <c:when test="${cc.attrs.saveAction!=null}">
        <h:commandButton value="Save"   action="#{cc.attrs.saveAction}">
    </c:when>
</c:choose>

Again, you have to add a library to the composite components header:

<html xmlns="http://www.w3.org/1999/xhtml" 
      xmlns:cc="http://java.sun.com/jsf/composite"
      xmlns:h="http://java.sun.com/jsf/html" 
      xmlns:f="http://java.sun.com/jsf/core" 
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:ui="http://java.sun.com/jsf/facelets" 
      xmlns:ng="http://xmlns.jcp.org/jsf/passthrough"
      xmlns:a="http://beyondjava.net/angularFaces" 
      xmlns:prime="http://primefaces.org/ui"
      xmlns:c="http://java.sun.com/jsp/jstl/core">

The catch

The problem with the c library is it doesn’t belong to JSF. It’s a JSP library. In most cases, it works, but you should always keep in mind JSP tags are evaluated at a different time than their JSF counterparts. This might lead to all kinds of strange behaviors.

But the real problem with the c library is its verbosity. You can do everything: conditional statements, loops, everything you need. But your code is going to be extremely bloated.

That’s the reason why I frequently say “no” when I asked to write a composite component. Sure, composite components are really nifty tools, but they are heavily restricted. They are not meant to create complex components. Complex components – and that’s the interesting ones – should be written as traditional, Java-centric JSF components.

Another example that can’t be implemented using composite components are labelled input texts. Actually, OIO managed to create a nice labelled input text:
click to see OIO’s composite component
(see the article at How to highlight invalid components in JSF)

If you try to put the labels in front of the input field and the error message behind it, you’ll inevitably fail. Usually, labels, fields, and error messages are aligned by means of a table-like structure – be it an HTML table, a panel grid or div tags. However, composite components are treated as a single component by JSF. Put a composite component in a panel grid, and you’ll find the label, the input field and the error message cramped into the same HTML cell (the same <td>). There’s no way to avoid this behavior. Most people get very pensive when I show them the problem (“there has to be a solution!”), but having tried quite a few approaches I’m pretty sure it simply can’t be done.

On the other side this kind of components are created very easily by using the older JSF component framework. Actually that’s what the AngularFaces InputText does:

@FacesComponent("de.beyondjava.InputText")
public class NGInputText extends org.primefaces.component.inputtext.InputText implements SystemEventListener,
      NGUIComponent {
   public static final String COMPONENT_FAMILY = "javax.faces.Input";
   public NGInputText() {
      FacesContext context = FacesContext.getCurrentInstance();
      UIViewRoot root = context.getViewRoot();
      root.subscribeToViewEvent(PreRenderViewEvent.class, this);
  }
  private void insertLabelBeforeThisInputField() {
      OutputLabel l = new OutputLabel();
      l.setFor(getId());
      l.setValue(getLabel());
      List<UIComponent> tree = getParent().getChildren();
      for (int i = 0; i < tree.size(); i++) {
         if (tree.get(i) == this) {
            tree.add(i, l);
            break;
         }
      }
   }

   private void insertMessageBehindThisInputField() {
      NGMessage l = new NGMessage();
      l.setFor(getId());
      l.setDisplay("text");
      l.setTarget(this);
      List<UIComponent> tree = getParent().getChildren();
      for (int i = 0; i < tree.size(); i++) {
         if (tree.get(i) == this) {
            tree.add(i + 1, l);
            break;
         }
      }
   }

   @Override
   public boolean isListenerForSource(Object source) {
      return (source instanceof UIViewRoot);
   }
  @Override
   public void processEvent(SystemEvent event) throws AbortProcessingException {
      if (!FacesContext.getCurrentInstance().isPostback()) {
         if (!(getParent() instanceof Column)) {
            insertLabelBeforeThisInputField();
            insertMessageBehindThisInputField();
         }
      }
   }
}

Putting it all together

I’m very fond of JSF 2.0’s composite component framework. However, almost every time I try to use it it sucks. It’s meant to do simple things, but my idea of creating a framework isn’t restricted to solving simple problems. I want to solve the hard and nasty problems. I don’t want my team to repeat the same errors over and over again if I can help them by providing a framework.

So in most cases I abandon the composite component approach pretty soon. Nonetheless it’s a very nifty approach allowing you to create really nice components. Actually, it offers more options than I told you. Have a look at Oracle’s documentation to learn about the more exotic parameter types, such as clientBehavior, valueHolder, editableValueHolder, facet, insertFacet and renderFacet. It’s astonishing such a well-thought library lacks the flexibility I need so often.

7 thoughts on “Why Don’t You Write a JSF Composite Component?

  1. Hi. Since you abandoned the composite component approach. What do you do instead in order to achieve reusable parts in a JSF view? And how does it compare to composite components?

    1. I prefer the traditional way of writing JSF components: writing a component class and a renderer class and registering them with JSF by adding annotations and the taglib file. Many developers will tell you that this is hard work, but the BootsFaces DSL eclipse plugin makes this pretty simple. The performance of these components is a lot better than the performance of composite components. The drawback is that it’s a bit more cumbersome to generate the HTML code. It’s like the difference between a WYSIWYG editor and the source code view of, say, Confluence. The advantage is you can use the full power of a programming language, including loops and if statements.

  2. What about Facelet tags? Is it possible to replace use of composite components with facelet tags? i’m always confused which one I should use. To be honest I want to get rid of composite component (we’re facing too many problems with them, don’t know if it’s an impl issue or spec issue), and try to find a solution as simple as CC.

    1. Like you, I’m pretty disappointed about composite components. Since I’ve written this article, I’ve learned how simple it is to create components with Angular. One day or another, I’ll try to port the ideas of Angular to JSF.

      In the meantime, it’s a good idea to create a traditional JSF component using Facelets. Most people believe that’s too complicated for the average programmer, but that’s rubbish. Using the BootsFaces component generator, it’s a matter of minutes (plus the time needed for setting up the tool). But even without the generator, creating a JSF component is not a big deal. On the plus side, you’ve got the full programming power of Java. Every once in a while you’ll be annoyed by the weird API of JSF, but that’s only when you’re trying to do advanced stuff.

  3. Thanks for your quick answer, I’ll have a look on JSFLibraryGenerator once I’ll go back to my JSF devs 😉 What do you have a mind regarding this statement “One day or another, I’ll try to port the ideas of Angular to JSF”

Leave a Reply

Your email address will not be published.