JSF List Converter
How do I write a converter for a list of items of class A in JSF2? I have written a converter for class A, but the items show up using the default toString() function: "A@hashcode".
I need to use a converter rather than a backing bean method so that validation can take place (Hibernate Validator).
more info
This is how I use the list:
<h:inputText id="destinations" value="#{rule.destinations}" converter="gr.panayk.vi开发者_开发技巧nyls.Destination"/>
Where #{rule.destinations} is of List<Destination>
type. I am expecting a comma separated list of converted Destinations.
solution
I attach the List converter that BalusC proposed.
@FacesConverter(value="gr.panayk.vinyls.converter.DestinationList")
public class DestinationListConverter implements Converter
{
@Override
public Object getAsObject(final FacesContext context, final UIComponent component, final String values)
{
final Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
final List<Destination> result = new ArrayList<Destination>();
for (String value : values.split(",", -1))
{
final String trimmedValue = value.trim();
final Set<ConstraintViolation<Destination>> violations = validator.validateValue(Destination.class, "data", trimmedValue);
if (!violations.isEmpty())
{
throw new ConverterException(new FacesMessage(violations.iterator().next().getMessage()));
}
result.add(new Destination(trimmedValue));
}
final Set<ConstraintViolation<Rule>> violations = validator.validateValue(Rule.class, "destinations", result);
if (!violations.isEmpty())
{
throw new ConverterException(new FacesMessage(violations.iterator().next().getMessage()));
}
return result;
}
@Override
public String getAsString(final FacesContext context, final UIComponent component, final Object value)
{
if (value instanceof List<?>)
{
final StringBuffer result = new StringBuffer();
final List<?> list = (List<?>) value;
for (int i = 0; i < list.size()-1; i++)
{
if (list.get(i) instanceof Destination)
{
result.append(((Destination) list.get(i)).getData());
result.append(", ");
}
else
{
throw new IllegalArgumentException( "Cannot convert " + value + " object to Destination in DestinationConverter." );
}
}
if (!list.isEmpty())
{
if (list.get(list.size()-1) instanceof Destination)
{
result.append(((Destination) list.get(list.size()-1)).getData());
}
else
{
throw new IllegalArgumentException( "Cannot convert " + value + " object to Destination in DestinationConverter." );
}
}
return result.toString();
}
else
{
throw new IllegalArgumentException( "Cannot convert " + value + " object to List in DestinationConverter." );
}
}
}
I have written a converter for class A, but the items show up using the default toString() function: "A@hashcode".
That can happen if you didn't explicitly declare the converter on the component. In for example <h:selectManyCheckbox>
and <h:selectManyListbox>
explicitly declaring the converter is mandatory as all JSF/EL knows is that the value is of type List
, not List<A>
(generic types are lost during runtime). If you don't declare a converter, then the values will be treated as String
(as that's what HTML output and HTTP request parameter values default to).
E.g.
<h:selectManyCheckbox converter="aConverter">
with
@FacesConverter(value="aConverter", forClass=A.class)
public class AConverter implements Converter {
// ...
}
Explicitly declaring the above converter is not necessary when you're using single-item inputs like <h:selectOneMenu>
as the forClass
would match it anyway.
精彩评论