1

I have a simple JSF web app as follows. The Java class contains:

private String myString;

public String getMyString()
{
  return myString;
}

public void setMyString( String radioValue )
{
  myString = someHashMap.get( radioValue );
  doStuffWith( myString );
}

And the JSF page source contains:

<h:form>
 <h:selectOneRadio id="topicSelectOneRadio" required="true"
    requiredMessage="Choose a thing"
    value="#{someBean.myString}">
    <f:selectItem itemValue="radioValue1" itemLabel="1"/>
    <f:selectItem itemValue="radioValue2" itemLabel="2"/>
 </h:selectOneRadio>
 <p><h:commandButton value="Do it"/></p>
</h:form>

As I understand it, the radioValueX string from the webpage is being used in the Java class as the parameter to the myString setter method. So I wanted to extend it one step further to use any class:

private Foo myFoo;

public Foo getMyFoo()
{
  return myFoo;
}

public void setMyFoo( String radioValue )
{
  myFoo = someHashMap.get( radioValue );
  doStuffWith( myFoo );
}

and

<h:form>
 <h:selectOneRadio id="topicSelectOneRadio" required="true"
    requiredMessage="Choose a thing"
    value="#{someBean.myFoo}">
    <f:selectItem itemValue="radioValue1" itemLabel="1"/>
    <f:selectItem itemValue="radioValue2" itemLabel="2"/>
 </h:selectOneRadio>
 <p><h:commandButton value="Do it"/></p>
</h:form>

However, I get the following error:

Conversion Error setting value 'radioValue' for 'null Converter'.

I'm not sure I understand where any sort of "conversion" needs to take place. In both cases, the String value from the radio button is being used as a parameter to a setter method which takes a String value as the parameter. True, in the latter case, it is actually setting the value for something that isn't a String, but that shouldn't matter, should it? I'm not trying to convert the radioValueX String in the latter case to any other type, just using it as the key to a hashmap, same as in the first case.

Can anybody help me understand what I'm missing? Thanks!

The111
  • 5,757
  • 4
  • 39
  • 55
  • 2
    As a side note, your object as currently defined breaks the "bean" contract. Is the property `myFoo` an object of type `Foo`, as implied by the getter, or a `String` as implied by the setter? This kind of asymmetry should generally be avoided. – Ian McLaird Apr 06 '12 at 18:43
  • How does the setter imply it is a String? The setter uses a String as a parameter, but it sets the object as a Foo. I.e., the HashMap referenced is of type ... something I forgot to mention. Does that change your concern, or am I still misunderstanding? Thanks. – The111 Apr 06 '12 at 19:21
  • 2
    Normally bean setters should take a parameter of the same type as the field to be set. That's the "bean contract". – Matt Handy Apr 06 '12 at 19:28

1 Answers1

4

JSF tries to convert your String to Object before the setter is called. And since you have no converter registered for your object, you get this error.

Conversion is performed in JSF's lifecycle phase 3 (PROCESS VALIDATIONS). The setters are called in phase 4 (UPDATE MODEL VALUES).

You need to add a converter to make it work:

import javax.faces.convert.Converter;
...
@FacesConverter("FooConverter")
public class FooConverter implements Converter{
  @Override
  public Object getAsObject(FacesContext context, UIComponent component,
            String value) {
    someHashMap.get(value);
  }
  @Override
  public String getAsString(FacesContext context, UIComponent component,
            Object value) {
    // convert from Object to String
   }    
}

Use the converter this way:

<h:selectOneRadio id="topicSelectOneRadio" required="true"
    requiredMessage="Choose a thing"
    value="#{someBean.myFoo}">
    <f:converter converterId="FooConverter"/>
    <f:selectItem itemValue="radioValue1" itemLabel="1"/>
    <f:selectItem itemValue="radioValue2" itemLabel="2"/>
</h:selectOneRadio>

Then (as correctly stated in Ian's comment to your question) you should change your setter since you don't need the conversion here anymore:

public void setMyFoo(Foo newFoo)
{
  myFoo = newFoo;
}
Matt Handy
  • 29,855
  • 2
  • 89
  • 112
  • 1
    Thanks. That seems somewhat overly complex though. I wonder if there is a simpler way, such as creating an extra "radioValue" property in my Foo class for the radio value, and then having the setter method in there also set the the myFoo property. I guess this would be doing the same thing as the converter just more directly? I'll have to try it out later along with your version. Thanks for your solution. :-) – The111 Apr 06 '12 at 19:24