Dienstag, 4. Mai 2010

Java Server Faces and added complexity

Having worked lately on an extremely generic component for one of our JSF (ICEfaces) based products I must really say: You have to jump through a lot of hoops because some useful functionality is missing in JSF. This list is not meant to be complete. It's just what came into my mind today:
  • No parameters for method bindings
  • Insufficient enum support
  • Constructors for Pojos
  • Dynamic method/value bindings using the Expression Language
No parameters for method bindings
I really think this is the worst one - anyone who ever tried to call an action with a parameter came across this issue and used one of the workarounds to actually get it done:
  1. Create an additional parameter object and work with f:setPropertyActionListener (only works for actions and not for parametrized getters)
  2. Use the Map-Hack: Create a Bean that implements the map interface and put all your fancy business logic in the get method - you can call the get method with one parameter (usually the key for the entry you want to access). I must admit I have used this once or twice and it gets the job done - needless to say that it's bad design and I've even read a couple of times that it has some pitfalls (that I haven't encountered so far).
  3. Create a map property on your backing bean: I actually think this is the only valid approach (ok, the parameter object is fine for actions as well) if you need to access data in a parameterized way. Your parameters become the key(s) for the map property and the object you're needing is the value. This has the only downside that you have to initialize the whole content of the backing bean's map when the data is displayed to the user - whether it is really needed or not because you can't control the calling of the getter from the backing bean.
Insufficient enum support
So maybe I'm wrong on this one but I couldn't find a simple way to use enum instances in JSF pages. I couldn't create instances of an enum "on-the-fly" to access certain data or provide it as a parameter. Here are two ways to handle that:
  • Completely abstract from enums in your pages and use String data fields instead (You would then have to transform the String objects into Enum constants on demand)
  • Use a utility bean in that populates Map members on startup with all the elements of your enum. You can then easily get the enum instances by using the members fo this bean with ['enumInstanceName'] to actually get the objects you want right from the start
Constructors for POJOs
Say you want to provide not just a simple parameter/value to your backing bean but already an object (to limit the number of properties for your backing bean) - I didn't find a way to initialize an object from a JSF page and fill some properties. There is some sort of workaround with providing a dummy managed bean for this - the JSF framework takes care of initializing it when you access it for the first time - but it was really a drag. I tried to use this with a request scoped bean - but it kept the value during partial page submits (because for JSF a request ends only when you leave the page - it spans over different partial page submits). So I needed to cleanup the request scoped bean after having retrieved the data. I didn't really find a solution for this and sticked to using multiple properties in my backing bean.

Dynamic method/value bindings using the Expression Language
What I mean by this is: Let's say you have a bean 'A' with the String properties 'a' and 'b'. It is now not possible to use one input text component and link it to either one of them depending on a boolean value (e.g.: #{not empty bean.c ? bean.a : bean.b}). The only way to achieve this is to duplicate the text component and use the rendered flag or create a dynamic value expression in your backing bean and set it on the component programmatically.

Keine Kommentare:

Kommentar veröffentlichen