Skip to main content

Composite Input Components in JSF

Posted by cayhorstmann on January 30, 2010 at 8:50 PM PST

Composite components are a great feature of JSF 2.0. The canonical example is a login component with fields for the username and password:

<mylib:login name="#{user.name}"
      password="#{user.password}"
      loginAction="#{user.login}"/>

This has been well explained elsewhere. But here is what always baffled me. I want to have a composite date component, with three menus for day, month, and year.

But I want it to have a single value of type java.util.Date, so I can use it like this:

<mylib:date value="#{user.birthDay}"/>

and not

<mylib:date day="#{user.birthDate}" month="#{user.birthMonth}" year="#{user.birthYear}"/>

Why do I care?

  • My classes aren't all made up of strings and numbers. I use objects when I can. My User class has a property birthDay of type java.util.Date. I don't want to write boring code to take dates apart and put them back together.
  • I want to use bean validation for the date property, with a @Past or @Future annotation.

I asked around and people told me that this couldn't be done with composite components—I'd have to write an actual custom component.

But, as I discovered, it is not so. With a small dose of knowledge of the JSF lifecycle, and the poorly documented technique of backing components, this is actually pretty easy. Here goes.

When you make a composite component, it is normally turned into a UINamingContainer that contains the child components in the implementation. But you can also force a different component to be used, provided

  • it implements the NamingContainer marker interface
  • its “family” is "javax.faces.NamingContainer" (don't ask...)

The easiest way of using your own component is to make a class whose name is libraryName.compositeComponentName, such as mylib.date. (It's a bit weird to have a lowercase class name, but that's the price to pay for “convention over configuration”.)

package mylib;
public class date extends UIInput implements NamingContainer {
    public String getFamily() { return "javax.faces.NamingContainer"; }
    ...
}

Note that I extend UIInput and not UINamingContainer. In the world of JSF, UIInput is an “editable value holder”, a class that holds a value of an arbitrary type (not necessarily numbers or strings), and to which you can attach validators.

The JSF lifecycle starts out like this:

  • The HTTP request (doesn't actually have to be HTTP—in JSF, everything is pluggable) delivers name/value pairs
  • Each component can pick from the request what it wants in the decode method and sets its submitted value
  • The submitted value is converted to the desired type (integer, date, whatever), becoming the converted value
  • If the converted value passes validation, it becomes the value of the component

For a composite component, the submitted value is a combination of the submitted values of the children. You could combine them by putting them into a map, but I simply say that the submitted value is the composite component:

public class date extends UIInput implements NamingContainer { 
    ...
    public Object getSubmittedValue() { return this; }
    ...
}

(If you don't override this method, the submitted value is null, and that gets into a murky corner of processing that you want to avoid.)

The conversion from a bunch of values to a date happens in getConvertedValue:

public class date extends UIInput implements NamingContainer { 
    ...
    protected Object getConvertedValue(FacesContext context, Object newSubmittedValue) {
        UIInput dayComponent = (UIInput) findComponent("day");
        UIInput monthComponent = (UIInput) findComponent("month");
        UIInput yearComponent = (UIInput) findComponent("year");
        int day = (Integer) dayComponent.getValue();
        int month = (Integer) monthComponent.getValue();
        int year = (Integer) yearComponent.getValue();
        if (isValidDate(day, month, year)) // helper method that checks for month lengths, leap years
           return new Date(year - 1900, month - 1, day);
        else
           throw new ConverterException(new FacesMessage(...));
    }
    ...
}

This is very similar to the usual conversion action, except that I combine the values from multiple child components. (I attached a javax.faces.Integer converter to each of the children so I don't have to convert the submitted strings to integers myself.)

That takes care of processing the input. On the rendering side, I just populate the children before rendering them:

public class date extends UIInput implements NamingContainer { 
    ...
    public void encodeBegin(FacesContext context) throws IOException {
        Date date = (Date) getValue();
        UIInput dayComponent = (UIInput) findComponent("day");
        UIInput monthComponent = (UIInput) findComponent("month");
        UIInput yearComponent = (UIInput) findComponent("year");
        dayComponent.setValue(date.getDate());
        monthComponent.setValue(date.getMonth() + 1);
        yearComponent.setValue(date.getYear() + 1900);
        super.encodeBegin(context);
    }
}

That's all. The same recipe works for any composite component that collects input for a complex data type.

Here is the code of a sample application that works out of the box in GlassFish 3 (but not in Tomcat). Note that the sample application uses the composite component as an input for java.util.Date. It works with bean validation without any effort on the developer's part.

The moral of this is:

  • The much maligned JSF lifecycle is actually pretty good. The decode/convert/validate order is what you need anyway, so why not have the framework manage it for you?
  • The much maligned generality of JSF is pretty good too. They could have said “With HTTP, what comes in is strings, so why not just work with strings?” But here we take advantage that the source and target of the conversion can be any type.
  • The declarative composite components that everyone raves about are great, but sometimes you've got to be able to add code. This blog shows you how to do it.
AttachmentSize
composite-date.zip4.2 KB
Related Topics >>

Comments

Respect

I just want to express my respect. Very useful post for me. Thank you very much.

Convention over configuration

Hi Professor Horstmann. I'm just taking a ride reading about all this JSF stuff (I'm a Rails guy now). So why on earth would they have you using lowercase class names by convention?

They just didn't want to go

They just didn't want to go through the trouble of uppercasing the name, perhaps because they had bad memories of http://java.sun.com/javase/6/docs/api/java/beans/Introspector.html#decap...

Another Backing Component Approach

Cay, I used backing components quite a bit in Mojarra Scales, so I thought I'd share a tip to get you around your lower case class issue. Here's the composite component snippet: <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:composite="http://java.sun.com/jsf/composite"> <composite:interface name="foo" componentType="com.example.Foo" displayName="foo" shortDescription="foo"> </composite:interface> </html> Note the addition of the componentType attribute. My backing component would then look something like this: @FacesComponent("com.example.Foo") public class Bar extends UIInput implements NamingContainer { @Override public String getFamily() { return UINamingContainer.COMPONENT_FAMILY; } // ... } Using @FacesComponent, I set the type of the component to that required by the composite component. Just for grins, I made the class name of the component something completely different, just to highlight the fact that the class name has no necessary bearing on the type or family of the component. I do still implement NamingContainer and return UINamingContainer.COMPONENT_FAMILY as the family, but everything else can be whatever I want. I hope that helps. And that you'll be able to read this after java.net gets finished with it. :|

Re: Another Backing Component Approach

Nope. It seems java.net hates source code. :) In short, add a componentType attribute to composite:interface, then attach @FacesComponent to the backing component, using the value of componentType as the value of the annotation and you're set.

I am somewhat perplexed.

If you are writing as a developer who wants to explore how to expand JSF, this is great. However, if you want to use a better Web GUI framework, it seems to me that this is somewhat of a wasted effort, as ZK has matured quite a bit and provides all the things that you seek. I have used in a substantially large (large in terms of the size of the codebase and functionality) deployed project, and ZK has proved to be very robust. It has quite a few advantages over JSF, including the fact that if you want to write 99% of your web application in pure Java without having to deal with tagged files etc. you can do that as well. Perhaps I missing some intrinsic value in JSF that leads you to ignore something like ZK altogether. (I have no connection with ZK, except as a very satisfied user.)

Re: I am somewhat perplexed.

What I'm guessing you and the Wicket people are missing is that not everyone likes to write user interfaces in pure Java code. Some of us like to use a DSLs, say, a markup language like XHTML, to write our UIs. Even on the thick client side you can see the same sort of thinking with the invention of declarative languages like JavaFX. It's simply a different preference. While you may claim the programmatic, pure-Java approach is superior, I don't think it's a claim that can be proven. While you may be more productive and enjoy your time more working in 100% Java code, some of us are not. For some of us in the latter camp, we find JSF's use of XHTML to be a very nice and capable abstraction for defining the view layer. For what it's worth, I DO have a connection to JSF, as I'm on the Expert Group and a member of the Mojarra Dev team, but I'm in both of those roles because I started off as a very satisfied user. In a nut shell, different strokes for different folks. There's no need to hijack every JSF thread with $OTHER_FRAMEWORK advocacy at every turn.

Stockholm syndrome

"What I'm guessing you and the Wicket people are missing is that not everyone likes to write user interfaces in pure Java code."

Actually, with Wicket you write all the visual part (layout, style, etc.) in XHTML/CSS/JavaScript (plain old web standards), and just the behavior in Java. Yes, you have to build the component tree in Java, but it contains only the dynamic and action components (inputs, buttons, dynamic labels, ajax-refreshed panels, etc.), not the whole layout, like Swing or GWT (1.x), as you imply. The advantage is, you use an UI language to describe the UI (html, css), and an object-oriented, fully-refactorable, static-typed, tool-supported language to describe behavior (Java).

JSF is not refactorable at all, the tools available are little more than plain HTML editors (no static analisys, for example), and pulls too much complexity and logic into XML templates and XML configurations (switch to annotations is not that better). Sweet.

Well, some people do prefer to live in this kind of environment. What do they call it?... oh yes, the Stockholm syndrome! ;)

Re: I am somewhat perplexed.

I think that one of the objectives of site should be (if it is already not) to educate the developers on various alternatives and provide some definitive opinion on the more desirable ways for the development of real applications.

My post was offered in that spirit, and I have no wish, malicious or otherwise, to hijack anyone's platform. Having said that, even if you like to use tags (XHTML) you can use the more mature ZK which already has many of the features that the good professor is groping for in JSF.

Re: wicket

ups forget how to finally use the component: private Date date; public HomePage(final PageParameters pp) { add(new MyDatePicker("datepicker", new PropertyModel(this, "date"))); } so no need for separate properties (year, month, day) and here is the projects home: http://wicket.apache.org/ with a lot of examples and built-in components ... http://wicketstuff.org/wicket14/compref/ such a date picker is already built-in as yui datepicker or datechooser ... but here is what you need http://blog.aparnachaudhary.net/2009/07/29/date-dropdownchoice-apache-wi...

wicket

Hi, don't get me wrong I really appreciate your work, because I worked with JSF for some time. I know how hard it is to create custom components with JSF ... But recently I gave wicket a try and beside the better UI and code separation it is a pleasure (+fast!) to create custom components. This date picker component which you created is easy as sth. like: public MyDatePicker(String id, IModel model) { super(id, model); add(new DropDownChoice("days", createDays())); add(new DropDownChoice("months", createMonths())); add(new DropDownChoice("years", createYears())); } and on the html side: [wicket:panel] day [select wicket:id="days"] [option selected="selected" value="1"]for the sake of a preview 1[/option] [option value="2">2[/option] [/select] month [select wicket:id="months"] [option selected="selected" value="11"]preview 11[/option] [option value="12">12[/option] [/select] year [select wicket:id="years"] [option selected="selected" value="2009"]preview 2009[/option] [option value="2010"]2010[/option] [/select] [/wicket:panel] Afterwards you can easily add ajax behaviour to change the provided days depending on the month. All in all I guess this component will take me < 30min. After that it will work with all the major browsers and wicket even provides non-ajax fallback etc etc. But the best thing is that I can embed this component everywhere I like. So, give wicket a try :-) !

wicket

I'm learning and working with wicket now. I don't find it so easy (maybe it will get easier).  One big disadvantage that I see with wicket compared to JSF, is you have to write a LOT more code because in wicket you have to write java code to build the page's component tree , whereas in jsf you only have this in html.   Also the way you build your tree in java has to match exactly the html or boom, meaning that if you change one you have to change the other. Also it means a  lot of code changes if you change the arangment of your components on the page since this changes the component hierarchy or tree.  Also you have to override a lot of methods, and I find it confusing to know what method to over ride.   In JSF there are only get set or action methods. One more thing wicket does not have enough documentation, only one good book . I think JSF is easier to learn and the code is easier to maintain.

hmmh, okay. maybe this is a

hmmh, okay. maybe this is a personal taste :-). the wicket style is simpler in many ways for me and it was a great experience for me how I changed a normal form into a ajaxified one - within 10 minutes or so. I didn't feel that it is a drawback for me to build a html tree and the java tree side by side, because wicket always explains very detailed whats going wrong. And if you develop with jetty you fix those problems under 5 seconds :-) And once you set up your components you can arrange them as you like. So no, I don't think that JSF is easier to maintain IMHO it leads to more copy and paste actions ...