Is there a reason f:selectItems doesn't accept Collections of POJOs?

I am new to JSF, and was surprised to find the <f:selectItems> tag doesn't let you use Collections of POJOs, only of SelectItems.

At the same time, however, SelectItem will happily take a POJO, and infer its label name from its .toString() (and usually this is all I want).

So I wrote the following...

package example;

publicclass UISelectItems

extends javax.faces.component.UISelectItems

{

public Object getValue()

{

Object objToReturn = super.getValue();

if ( objToReturninstanceof Collection )

returnnew CollectionWrapper( (Collection) objToReturn );

return objToReturn;

}

privateclass CollectionWrapper

implements Collection

{

private Collection m_collection;

public CollectionWrapper( Collection p_collection )

{

m_collection = p_collection;

}

publicboolean add( Object p_o )

{

return m_collection.add( p_o );

}

publicboolean addAll( Collection p_c )

{

return m_collection.addAll( p_c );

}

publicvoid clear()

{

m_collection.clear();

}

publicboolean contains( Object p_o )

{

return m_collection.contains( p_o );

}

publicboolean containsAll( Collection p_c )

{

return m_collection.containsAll( p_c );

}

publicboolean equals( Object p_o )

{

return m_collection.equals( p_o );

}

publicint hashCode()

{

return m_collection.hashCode();

}

publicboolean isEmpty()

{

return m_collection.isEmpty();

}

public Iterator iterator()

{

returnnew IteratorWrapper( m_collection.iterator() );

}

publicboolean remove( Object p_o )

{

return m_collection.remove( p_o );

}

publicboolean removeAll( Collection p_c )

{

return m_collection.removeAll( p_c );

}

publicboolean retainAll( Collection p_c )

{

return m_collection.retainAll( p_c );

}

publicint size()

{

return m_collection.size();

}

public Object[] toArray()

{

return m_collection.toArray();

}

public Object[] toArray( Object[] p_a )

{

return m_collection.toArray( p_a );

}

privateclass IteratorWrapper

implements Iterator

{

private Iterator m_iterator;

public IteratorWrapper( Iterator p_iterator )

{

m_iterator = p_iterator;

}

publicboolean hasNext()

{

return m_iterator.hasNext();

}

public Object next()

{

Object objToReturn = m_iterator.next();

if ( !( objToReturninstanceof SelectItem ) )

returnnew SelectItem( objToReturn );

return objToReturn;

}

publicvoid remove()

{

m_iterator.remove();

}

}

}

}

...and hooked it into my faces-config.xml by doing...

<component>

<component-type>javax.faces.SelectItems</component-type>

<component-class>example.UISelectItems</component-class>

</component>

...and it works like a champ, turning POJOs into SelectItems 'just in time'.

This was such a little thing to fix and is so useful I'm guessing there's some big reason why it's a no-no and therefore wasn't done 'out of the box'?

Could anybody please tell me what point I'm missing?

[7144 byte] By [kennardconsultinga] at [2007-10-2 8:54:18]
# 1
It should receive collections of javax.faces.model.SelectItem
oren2000a at 2007-7-16 22:58:12 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 2

oren2000,

Thanks for your reply, however I fear you missed the point of my post.

I know f:selectItems currently expects a collection of javax.faces.model.SelectItem, however I am questioning this design decision. As my post shows, it is easy to make it accept a Collection of POJOs instead, and this seems much more useful.

I am concerned I am missing something by overriding f:selectItems in this way?

kennardconsultinga at 2007-7-16 22:58:12 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 3
Ya know....What *I* wish is that SelectItem was an interface, so my POJOs could implement it.John.
JohnLusk4a at 2007-7-16 22:58:12 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 4

Hello,

In Design Rule, your pojo's don't have to know anything about SelectItems. (it would promote tight coupling).

SelectItems allows you to provide a specific "Label" for each object.

it's just a wrapper.

SelectItems belongs to the view while your beans to the Model.

However, you could create a utility class which would automaticaly return a collection of selectiItems from a collection of Object.

Regards,

Sebastien Degardin

sdegardina at 2007-7-16 22:58:12 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 5
As i understand, you have to write a custom converter for your POJO. Through custom converter, you can add your objects into the selectitem.
Y_NOTa at 2007-7-16 22:58:12 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 6

I'm sorry - I don't seem to be explaining myself very well. Allow me to clarify:

> In Design Rule, your pojo's don't have to know anything about

> SelectItems. (it would promote tight coupling).

I absolutely agree. However, with the way JSF currently is, this is not the way it is.

Let us say we have a class Order with a method getLineItems(), which returns a List of class LineItem.

To suit JSF, either we have to add a second method on Order called getLineItemsAsSelectItems (thereby adding JSF dependencies into our Order POJO), or we have to add a method to our OrderController called getLineItemsAsSelectItems (which is just painful).

> SelectItems allows you to provide a specific "Label" for each object.

> it's just a wrapper

I understand, and in some cases your label may well be different than your object's .toString, however in a lot of cases it's not (this is even acknowledged by the SelectItem class' constructor, which takes a single object and calls .toString on it).

> However, you could create a utility class which would automaticaly

> return a collection of selectiItems from a collection of Object.

Yes you could, but it is painful to have to call this for every List in your application. My first post demonstrates a technique which overrides the default JSF handling to provide POJO support directly to f:selectItems.

My question is simply why this isn't valid, or if it is valid why it wasn't done 'out of the box'.

Regards,

Richard.

kennardconsultinga at 2007-7-16 22:58:12 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 7

This could be another result of theoretical design running up against actual practice. The painful approach seems more strictly "correct" if you want to be an MVC fanatic -- as you point out, the model objects (POJOs) don't have any view dependencies and the controller provides the needed bridge. That in no way dulls the pain of having to work with the darn thing.

kcounsella at 2007-7-16 22:58:12 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 8
In that case may I recommend my fix posted in my first message? :)It requires no code changes and elegantly wraps POJO collections into SelectItem lists in much the same way that UIData.createDataModel wraps POJO collections into DataModels.
kennardconsultinga at 2007-7-16 22:58:12 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 9

> I'm sorry - I don't seem to be explaining myself very

> well. Allow me to clarify:

>

> > In Design Rule, your pojo's don't have to know

> anything about

> > SelectItems. (it would promote tight coupling).

>

> I absolutely agree. However, with the way JSF

> currently is, this is not the way it is.

>

> Let us say we have a class Order with a method

> getLineItems(), which returns a List of class

> LineItem.

>

> To suit JSF, either we have to add a second method on

> Order called getLineItemsAsSelectItems (thereby

> adding JSF dependencies into our Order POJO), or we

> have to add a method to our OrderController called

> getLineItemsAsSelectItems (which is just painful).

Of couse, that's in your Backing Bean that you have to write this method.

not in your BusinessAbstraction.

Otherwise, if you would swich from JSF to another GUI, you'll have to rewrite all of you BusinessAbstraction.

>

> > SelectItems allows you to provide a specific

> "Label" for each object.

> > it's just a wrapper

>

> I understand, and in some cases your label may well

> be different than your object's .toString, however in

> a lot of cases it's not (this is even acknowledged by

> the SelectItem class' constructor, which takes a

> single object and calls .toString on it).

NO, in almost all application, multilanguage must be provided.

So, you'll rely on specific services to get label depending on the currentLanguage.

Are you planing to modify your Pojo everytime you add a new language ?

View is not Model !

>

> > However, you could create a utility class which

> would automaticaly

> > return a collection of selectiItems from a

> collection of Object.

>

> Yes you could, but it is painful to have to call this

> for every List in your application. My first post

> demonstrates a technique which overrides the default

> JSF handling to provide POJO support directly to

> f:selectItems.

Sure, but, scalability, reutilisability, and so , all have a cost.

>

> My question is simply why this isn't valid, or if it

> is valid why it wasn't done 'out of the box'.

>

> Regards,

>

> Richard.

that's my point of view.

Maybe not the best, but, having read a lot of book on Object Oriented design and Design pattern, that' s the way i think.

It doesn't mean, that is a final solution.

Regards,

Sebastien Degardin

sdegardina at 2007-7-16 22:58:12 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 10

Sebastien,

Many thanks for your reply. Your comment about internationalization is well taken.

However, in general my .toString() methods return user-entered values, not localizable constants, so that becomes a moot point.

To reuse my earlier Order/LineItem example, my LineItem might simply be...

public LineItem

{

public void setName( String p_strName )

{

m_strName = p_strName;

}

public String getName()

{

return m_strName;

}

public String toString()

{

return m_strName;

}

}

...so it would be perfectly valid to display this in a select box by calling its .toString() method.

As I mentioned before, there is a SelectItem constructor that (sort of) validates this approach by accepting only one argument (a POJO) and calling .toString() on it to derive the label.

I'd speculate this would be more useful, in the majority of cases, that having to create SelectItem lists everywhere.

kennardconsultinga at 2007-7-16 22:58:12 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...