JSF with Enum 'Validation Error: Value is not valid'
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);
}
publi开发者_JS百科c 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
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.
Try item.setValue(cos)
instead of item.setValue("" + cos.ordinal())
.
精彩评论