何时在 JSF 中命名转换器
When to name a converter in JSF
我一直在我的 PrimeFaces SelectOneMenu 对象中使用转换器。如果我只告诉转换器指的是哪个class,它们就可以正常工作:
@FacesConverter(forClass = DescriptorVO.class)
public class DescriptorVOConverter implements Converter { ... }
这样,我不必明确告诉 JSF 组件在填充 class DescriptorVO
.
的对象时应该使用哪个转换器
但是,我创建了一个使用 p:SelectManyCheckbox
的页面,但我终究无法知道为什么它没有调用我的转换器。然后我给它起了个名字,像这样:
@FacesConverter(forClass = RoleVO.class, value = "roleVOConverter")
public class RoleVOConverter implements Converter { ... }
并将其作为组件的属性之一传递
<p:selectManyCheckbox id="cbx_roles" required="true" converter="roleVOConverter"
requiredMessage="At least one role must be selected."
value="#{userView.selectedRoles}" layout="responsive">
<f:selectItems value="#{userView.roles}" var="role"
itemLabel="#{role.title}" itemValue="#{role}" />
</p:selectManyCheckbox>
和voi la,它开始正确调用转换器。这向我提出了一个问题,关于何时我应该命名我的转换器(通过 value
属性)以及何时告诉他们转换器应该与哪个 class 一起使用(使用 forClass
属性)是足够。在使用 PrimeFaces 时,我从来不需要命名任何转换器,只是为了这个特定的 SelectManyCheckbox
组件。不同的组件是否对转换器有不同的要求,还是我只是误解了转换器的概念?
当 UISelectMany
组件的 value
引用通用 java.util.Collection
类型(例如 List<Role>
而不是数组 Role[]
时,就会发生这种情况。这在 javadoc of UISelectMany
中指定(强调我的):
Obtain the Converter
using the following algorithm:
If the component has an attached Converter
, use it.
If not, look for a ValueExpression
for value (if any). The ValueExpression
must point to something that is:
- An array of primitives (such as
int[]
). Look up the registered by-class Converter
for this primitive type.
- An array of objects (such as
Integer[]
or String[]
). Look up the registered by-class Converter
for the underlying element type.
- A
java.util.Collection
. Do not convert the values.
If for any reason a Converter
cannot be found, assume the type to be a String
array.
原因是,泛型类型 <Role>
在运行时丢失,无法直接确定。当您使用 MyFaces instead of Mojarra 时它会起作用,因为它会在 java.util.Collection
的情况下通过手动迭代 <f:selectItem(s)>
检查实际类型并根据第一个非 - 确定 Converter
null
值。
我为此创建了规范 issue 1422 以在 JSF 规范中获得它并改进 Mojarra。
另请参阅:
- UISelectMany on a List<T> causes java.lang.ClassCastException: java.lang.String cannot be cast to T
- Why does JSF put String values in a Map<..., Integer>? And how to work around it?
- Use enum in h:selectManyCheckbox
我一直在我的 PrimeFaces SelectOneMenu 对象中使用转换器。如果我只告诉转换器指的是哪个class,它们就可以正常工作:
@FacesConverter(forClass = DescriptorVO.class)
public class DescriptorVOConverter implements Converter { ... }
这样,我不必明确告诉 JSF 组件在填充 class DescriptorVO
.
但是,我创建了一个使用 p:SelectManyCheckbox
的页面,但我终究无法知道为什么它没有调用我的转换器。然后我给它起了个名字,像这样:
@FacesConverter(forClass = RoleVO.class, value = "roleVOConverter")
public class RoleVOConverter implements Converter { ... }
并将其作为组件的属性之一传递
<p:selectManyCheckbox id="cbx_roles" required="true" converter="roleVOConverter"
requiredMessage="At least one role must be selected."
value="#{userView.selectedRoles}" layout="responsive">
<f:selectItems value="#{userView.roles}" var="role"
itemLabel="#{role.title}" itemValue="#{role}" />
</p:selectManyCheckbox>
和voi la,它开始正确调用转换器。这向我提出了一个问题,关于何时我应该命名我的转换器(通过 value
属性)以及何时告诉他们转换器应该与哪个 class 一起使用(使用 forClass
属性)是足够。在使用 PrimeFaces 时,我从来不需要命名任何转换器,只是为了这个特定的 SelectManyCheckbox
组件。不同的组件是否对转换器有不同的要求,还是我只是误解了转换器的概念?
当 UISelectMany
组件的 value
引用通用 java.util.Collection
类型(例如 List<Role>
而不是数组 Role[]
时,就会发生这种情况。这在 javadoc of UISelectMany
中指定(强调我的):
Obtain the
Converter
using the following algorithm:
If the component has an attached
Converter
, use it.If not, look for a
ValueExpression
for value (if any). TheValueExpression
must point to something that is:
- An array of primitives (such as
int[]
). Look up the registered by-classConverter
for this primitive type.- An array of objects (such as
Integer[]
orString[]
). Look up the registered by-classConverter
for the underlying element type.- A
java.util.Collection
. Do not convert the values.If for any reason a
Converter
cannot be found, assume the type to be aString
array.
原因是,泛型类型 <Role>
在运行时丢失,无法直接确定。当您使用 MyFaces instead of Mojarra 时它会起作用,因为它会在 java.util.Collection
的情况下通过手动迭代 <f:selectItem(s)>
检查实际类型并根据第一个非 - 确定 Converter
null
值。
我为此创建了规范 issue 1422 以在 JSF 规范中获得它并改进 Mojarra。
另请参阅:
- UISelectMany on a List<T> causes java.lang.ClassCastException: java.lang.String cannot be cast to T
- Why does JSF put String values in a Map<..., Integer>? And how to work around it?
- Use enum in h:selectManyCheckbox