tags:

views:

802

answers:

2

I have an enum whose code is like this -

public enum COSOptionType {

    NOTAPPLICABLE,
    OPTIONAL,
    MANDATORY;

    private String[] label = { "Not Applicable", "Optional", "Mandatory"};

    @Override
    public String toString() {

        return label[this.ordinal()];
    }

    public static COSOptionType getCOSOption(String value) {
        int ivalue = Integer.parseInt(value);
        switch(ivalue) {
        case 0:
            return NOTAPPLICABLE;
        case 1: 
            return OPTIONAL;
        case 2:
            return MANDATORY;
         default:
                throw new RuntimeException("Should not get this far ever!");
        }
    }

}

I have the converter to convert the enum type

public class COSEnumConverter implements Converter {

    public Object getAsObject(FacesContext context, UIComponent comp, String value) {

        return COSOptionType.getCOSOption(value);
    }

    public String getAsString(FacesContext context, UIComponent comp, Object obj) {
        if (obj instanceof String) {
            return (String) obj;
        }
        COSOptionType type = (COSOptionType) obj;
        int index = type.ordinal();
        return ""+index;
    }

}

The view looks like this

 <h:selectOneMenu value="#{controller.type}" id="smoking">                                           
   <f:selectItems value="#{jnyController.choices}" />
 </h:selectOneMenu>

Here is the code for create choices

private List<SelectItem> createChoicies() {
    List<SelectItem> list = new ArrayList<SelectItem>();
    for (COSOptionType cos : COSOptionType.values()) {
        SelectItem item = new SelectItem();
        item.setLabel(cos.toString());
        item.setValue("" + cos.ordinal());
        list.add(item);
    }
    return list;
}

I do not understand why this would throw "validation error" all the time ? I can debug and see that the converter is working fine.

NOTE: I am using JSF 1.1
+2  A: 

Try item.setValue(cos) instead of item.setValue("" + cos.ordinal()).

lexicore
This did solve the problem. Thank you.
Shamik
Weird, the `getAsString()` of your converter does exactly the same.
BalusC
Ah I see, the root cause is that the converter returns a fullworthy `COSOptionType` instead of `"" + cos.ordinal()` in `getAsObject()`, which thus don't appear at all in the existing options.
BalusC
Yes thats the issue. Thanks BalusC for explaining.
Shamik
+2  A: 

The root cause is that the converter returns a fullworthy COSOptionType object instead of the string "" + cos.ordinal() in getAsObject(), which thus don't appear at all in the existing options.

At any way, this approach is overcomplicated, especially the enum and the converter. I recommend you to reconsider this approach as follows:

Option:

package com.example;

public enum Option {

    NOTAPPLICABLE("Not Applicable"),
    OPTIONAL("Optional"),
    MANDATORY("Mandatory");

    private String label;

    private Option(String label) {
        this.label = label;
    }

    public String getLabel() {
        return label;
    }

}

Bean:

package com.example;

import java.util.ArrayList;
import java.util.List;

import javax.faces.model.SelectItem;

public class Bean {

    private List<SelectItem> options = new ArrayList<SelectItem>();
    private Option option;

    public Bean() {
        for (Option option : Option.values()) {
            options.add(new SelectItem(option, option.getLabel()));
        }
    }

    public void submit() {
        System.out.println(option);
    }

    public List<SelectItem> getOptions() {
        return options;
    }

    public Option getOption() {
        return option;
    }

    public void setOption(Option option) {
        this.option = option;
    }

}

OptionConverter:

package com.example;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;

public class OptionConverter implements Converter {

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) {
        return Option.valueOf(value);
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value) {
        return ((Option) value).name();
    }

}

faces-config.xml:

<managed-bean>
    <managed-bean-name>bean</managed-bean-name>
    <managed-bean-class>com.example.Bean</managed-bean-class>
    <managed-bean-scope>request</managed-bean-scope>
</managed-bean>

<converter>
    <converter-class>com.example.OptionConverter</converter-class>
    <converter-for-class>com.example.Option</converter-for-class>
</converter>

Relevant part of JSF page:

<h:form>
    <h:selectOneMenu value="#{bean.option}">                                           
        <f:selectItems value="#{bean.options}" />
    </h:selectOneMenu>
    <h:commandButton value="submit" action="#{bean.submit}" />
    <h:messages />
</h:form>

No need to hassle with Enum#ordinal() which is considered evil.

If you were using JSF 1.2 or newer which ships with a builtin generic EnumConverter, the OptionConverter is totally superfluous and can be safely removed.

BalusC