| Author |
Message |
![[Post New]](/JForum/templates/default/images/icon_minipost_new.gif) 17/04/2008 13:19:45
|
errorken
Joined: 23/12/2007 00:00:00
Messages: 59
Offline
|
I have this:
Code:
<ice:selectOneMenu id="type" value="#{someObject.someproperty}">
<f:selectItem itemValue="#{someValue}" itemLabel="test" />
</ice:selectOneMenu>
"someObject.someproperty" refers to a get/set of a certain custom class (ex. "MyClass") . The "someValue" is an instance of "MyClass". When I select "test" (and submit the form) I want that the instance is set on "someObject".
However, I get a : "search:type: An error occurred when processing your submitted information. " message. After some debug I found that it is actually hiding a classCastException. "String" cannot be converted to "MyClass".
So, it seems that the original itemValue is not used. It is so that the component tries to find a converter for "MyClass". But that is not what I want, since I want to original object and not a new one. Suppose MyClass is acutally an "PersonName", I cannot convert the label (which might just be concatentation of firstName + lastName but without all the other information) to a new PersonName obect.
Is this somekind of bug ? I was thinking the ItemValue is explicitly meant to preserve the orginal value:
itemValue
Object. Value to be returned to the server if this option is selected by the user.
...
|
|
|
 |
![[Post New]](/JForum/templates/default/images/icon_minipost_new.gif) 28/04/2008 07:16:31
|
errorken
Joined: 23/12/2007 00:00:00
Messages: 59
Offline
|
Is there anyone of the icefaces team that can comment on this please?
|
|
|
 |
![[Post New]](/JForum/templates/default/images/icon_minipost_new.gif) 28/04/2008 20:05:29
|
hildo

Joined: 14/11/2007 00:00:00
Messages: 111
Offline
|
Is the conversion error due to attempting to call the specified setter, using the preserved object?
So, the object defined by #{someValue} is being passed to the setter. In your example, #{someObject.someproperty}. What is the type of object defined by #{someValue}. Is it one of the types automatically supported by JSF?
|
|
|
 |
![[Post New]](/JForum/templates/default/images/icon_minipost_new.gif) 29/04/2008 01:42:10
|
errorken
Joined: 23/12/2007 00:00:00
Messages: 59
Offline
|
Thanks for your reply.
The type is an object I created, so its a custom type and there are no existing converts for it.
I know that ICEfaces will try to look up a converter prior setting the value. For example; if I use an Enum, I have no problems, since there a out of the box enum converter.
The thing is; why should there be a conversion from object to string and then back from string to object ? why can't the component store the real object value internally and take that exact same value again when setting
|
|
|
 |
![[Post New]](/JForum/templates/default/images/icon_minipost_new.gif) 29/04/2008 17:00:25
|
hildo

Joined: 14/11/2007 00:00:00
Messages: 111
Offline
|
When a page is encoded, objects are converted to strings. When the page is decoded, strings are converted to objects. This happens all the time.
Where I've used this successfully, the itemValue had been ordinal values, and the labels Strings. To react when it's been changed, I get the value from the ValueChangeEvent that's passed to the event handler. Something like this.
Code:
public void runSearchValueChanged(ValueChangeEvent event) {
Object o = ((UISelectOne) event.getComponent()).getValue();
if (o != null) {
Long searchKey = Long.valueOf((String) o);
If you look at the HTML that's rendered, it's not going to pass the full object (#{someValue}) down to the browser. It's got the String representation of that. HTML wouldn't know how to store the full object. You have to be able to convert the String itemValue to whatever it is. Typically, the itemValue is a unique key that can be used to load an object. You're better off storing the key of the custom object in the itemValue. And, it's usually a good idea of define converters for the custom objects.
Hope this helps
|
|
|
 |
![[Post New]](/JForum/templates/default/images/icon_minipost_new.gif) 30/04/2008 01:57:13
|
errorken
Joined: 23/12/2007 00:00:00
Messages: 59
Offline
|
hildo wrote:
When a page is encoded, objects are converted to strings. When the page is decoded, strings are converted to objects. This happens all the time.
Where I've used this successfully, the itemValue had been ordinal values, and the labels Strings. To react when it's been changed, I get the value from the ValueChangeEvent that's passed to the event handler. Something like this.
Code:
public void runSearchValueChanged(ValueChangeEvent event) {
Object o = ((UISelectOne) event.getComponent()).getValue();
if (o != null) {
Long searchKey = Long.valueOf((String) o);
If you look at the HTML that's rendered, it's not going to pass the full object (#{someValue}) down to the browser. It's got the String representation of that. HTML wouldn't know how to store the full object. You have to be able to convert the String itemValue to whatever it is. Typically, the itemValue is a unique key that can be used to load an object. You're better off storing the key of the custom object in the itemValue. And, it's usually a good idea of define converters for the custom objects.
Hope this helps
Yes, towards the view the values are indeed converted to String otherwise they would not be rendered in HTML. But thats not what I'm trying to say.
When the component contacts the model, it should use the original object value and not the string representation. The string representation might be used as a key to find the original value associated with it.
Ex. I haven an object "PersonName" which is rendered in the selectOneMenu. On the view I would endup with a toString representation of the object ex "My Name". When I submit the form its the original value associated with that key which is set on the model and not the toString value itself.
|
|
|
 |
![[Post New]](/JForum/templates/default/images/icon_minipost_new.gif) 30/04/2008 17:05:01
|
hildo

Joined: 14/11/2007 00:00:00
Messages: 111
Offline
|
I don't know for sure why. If you look at the updateModel method of the UIInput class (which is what would be used for the selectOneMenu component), it's using the local value of the component to assign to the model (defined by the value attribute of the component). When the HTTP request comes in, it's coming in as a String. There's not automatic conversion to the defining object.
Also by looking at the UIInput source, if a component has a converter associated with it, then during validation (via the public validate method, which will be called automatically), the String input will be converted to the desired object. So, in the subsequent phase where is updates the Model values, the local object will be defined in the model.
Given that you're working with a custom object, it's not entirely unreasonable to provide a converter to convert the String to the correct object. Once you do that, it will work as you expect.
|
|
|
 |
![[Post New]](/JForum/templates/default/images/icon_minipost_new.gif) 01/05/2008 12:02:58
|
errorken
Joined: 23/12/2007 00:00:00
Messages: 59
Offline
|
Consider the case when you supply two f:selectItem's to a selectOneMenu:
Code:
f:selectItem itemLabel='Volkswagen' itemValue='#{list[0]}'
f:selectItem itemLabel='Mercedes' itemValue='#{list[1]}'
The itemValue's ('Car' objects in this case) are stored somewhere in the component. The component uses the itemLabel text to fill the items in the HTML select, and the toString (or converted value if I'm not mistaking) of the 'itemValue' as the 'value' attribute of the HTML option within the HTML select.
Now, on submit, why can't we use the value of the selected option to correlate it to the original object from which the value was generated in the first place ? For example; it could store the string representation of the 'itemValue' and the original object of 'itemValue' in a map.
So, when I would select 'Volkswagen' I want that the same object as the first element on the list is being set on my backing action.
A converter is (IMHO) completely foolish. Why do you want to convert something to a String (which isn't even displayed, since the string representation of the itemValue is just used in the option 'value') and then , upon selection, convert the same string back to (the same) object when you allready have the object ?
For a large application you would endup with several converters, which can be error-prone and add totally no value.
But maybe I'm missing something here, feel free to point this out :)
|
|
|
 |
![[Post New]](/JForum/templates/default/images/icon_minipost_new.gif) 01/05/2008 17:05:00
|
hildo

Joined: 14/11/2007 00:00:00
Messages: 111
Offline
|
In my opinion, using the converter is not foolish, especially when you start looking at other UI components that have the same requirements, and not just this single instance. Even in this case, the component is working on the value of the UISelectOne component, and the value itself is not the UISelectItem. Yes, it could find the single item in collection of Items in order to ascertain which object it is. And that might be OK if there's 2 or 5 or 10 items. But how does performance get impacted if there are 50 items in that list? 100? And it's comparing Strings anyways. It's probably performs better using the Converter (which knows how to convert a String to the object in question without sifting through a Collection). In my mind, this is a more consistent approach that's used in multiple components, rather than tailoring different approaches for each component. Your suggestion is applicable for UISelectItems, but not for anything else.
But, that's me.
I don't have an answer for you, but you might be better off asking it at http://forum.java.sun.com/forum.jspa?forumID=427. What you're asking about is in the core JSF libraries, and not in ICEfaces itself. ICEfaces works within the confines of JSF.
Good luck
|
|
|
 |
![[Post New]](/JForum/templates/default/images/icon_minipost_new.gif) 03/09/2009 09:26:47
|
jablo
Joined: 28/10/2008 00:00:00
Messages: 8
Offline
|
Hi.
Although this is an old post, I decided to follow up. I have this exact problem, and am really at my wits' end trying to understand the reasoning behind this design decision.
After all, building the selectOneMenu I have code that dynamically creates the <f:selectItems ...> (Java List<SelectItems>). These objects contain a string representation of the menu choice AND the model object that the menu choice represents. Thus, it makes perfectly sense to use that model object in the the value="#{....}" of the selectOneMenu. It specifically does NOT make sense to use the string representation sent through a converter.
Why else do we need the SelectItem? Why does the SelectItem class have both a setValue(Object o) and a setLabel(String s) methods?
When (if ever) does the corresponding getValue() on the SelectItem objects get called?
Or, put in another way: There already is a trivial converter defined in the SelectItems: If you want the model object, use getValue(). If you want the String representaion, use getLabel() method. No converters needed, they are already there!
Best regards,
Jacob.
|
|
|
 |
![[Post New]](/JForum/templates/default/images/icon_minipost_new.gif) 03/09/2009 09:59:21
|
jablo
Joined: 28/10/2008 00:00:00
Messages: 8
Offline
|
Spent some time trying to work around the problem, and thought I would share my solution.
I add a menu helper object to my java code, which builds List<SelectItem> for the f:selectItems tag. And a converter that will run through the list of SelectItems using the String value and pick the correct SelectItem.getValue() as the converted result:
Code:
class MenuHelper {
private ModelBean modelBean; // bind this to the underlying application model object in faces-config.xml
public List<SelectItems> getSelectItems() {
List<SelectItems> result = ...;
for (ModelObject m : modelBean.getAllValues())
result.add(new SelectItem(m.getStringRepresentation(), m));
return result;
}
public Converter getConverter() {
return new Converter() {
public Object getAsObject(FacesContext arg0, UIComponent arg1, String arg2) {
for (SelectItem si : getSelectItems())
if (si.getLabel().equals(arg2))
return si.getValue();
throw new IllegalArgumentException("Item not found: " + arg2);
}
public String getAsString(FacesContext arg0, UIComponent arg1, Object arg2) {
for (SelectItem si : getSelectItems())
if (si.getValue().equals(arg2))
return si.getLabel();
throw new IllegalArgumentException("Item not found: " + arg2);
}
};
}
}
It is in effect completely generic code, which might as well be the standard implementation of the selectOneMenu. As it stands, this generic code will have to be duplicated every time I need a selectOneMenu where the menu items are really objects in the application model.
Come to think of it, this may even be a faces pattern.
Best regards,
Jacob.
|
|
|
 |
![[Post New]](/JForum/templates/default/images/icon_minipost_new.gif) 12/10/2009 20:18:26
|
amanica
Joined: 02/03/2009 00:00:00
Messages: 1
Offline
|
jablo wrote:
Spent some time trying to work around the problem, and thought I would share my solution.
Thanks a lot for explaining the problem so that we could finally figure out how to fix it.
http://amanica.blogspot.com/2009/10/icefaces-hates-me-and-richard.html
|
|
|
 |
|
|