Search |
|||||||
Cay Horstmann's blogComposite Input Components in JSFPosted 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
<mylib:date value="#{user.birthDay}"/>
and not
<mylib:date day="#{user.birthDate}" month="#{user.birthMonth}" year="#{user.birthYear}"/>
Why do I care?
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
The easiest way of using your own component is to make a class whose name is libraryName.compositeComponentName, such as
package mylib;
public class date extends UIInput implements NamingContainer {
public String getFamily() { return "javax.faces.NamingContainer"; }
...
}
Note that I extend The JSF lifecycle starts out like this:
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 The conversion from a bunch of values to a date happens in
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 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 The moral of this is:
»
Comments
Comments are listed in date ascending order (oldest first)
Another Backing Component Approach
Submitted by jdlee on Mon, 2010-02-01 08:01.
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
Submitted by jdlee on Mon, 2010-02-01 08:02.
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.
Submitted by varan on Mon, 2010-02-01 00:31.
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.
Submitted by jdlee on Mon, 2010-02-01 08:33.
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
Submitted by ronaldtm on Mon, 2010-02-01 17:30.
"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.
Submitted by varan on Mon, 2010-02-01 11:05.
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
Submitted by peat_hal on Sun, 2010-01-31 10:29.
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
Submitted by peat_hal on Sun, 2010-01-31 10:19.
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
Submitted by caroljmcdonald on Mon, 2010-02-01 07:50.
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
Submitted by peat_hal on Mon, 2010-02-01 13:33.
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 ...
|
CategoriesArchivesJanuary 2010
December 2009 November 2009 October 2009 September 2009 August 2009 July 2009 June 2009 May 2009 April 2009 February 2009 January 2009 December 2008 November 2008 October 2008 September 2008 July 2008 June 2008 May 2008 April 2008 March 2008 January 2008 December 2007 August 2007 July 2007 June 2007 May 2007 April 2007 January 2007 October 2006 September 2006 August 2006 July 2006 June 2006 |
||||||
|
I know a very nice prom