JSF 2.3 带有泛型的自定义转换器
JSF 2.3 Custom converter with generics
我们现在开始在现有的 JSF 2.2 项目上使用 JSF 2.3。在我们的自定义转换器上,我们收到警告 Converter is a raw type. References to generic type Converter<T> should be parameterized.
我们遇到的问题是当我们尝试使用泛型修复该警告时:
@FacesConverter(value = "myConverter", managed = true)
public class MyConverter implements Converter<MyCustomObject>{
@Override
public MyCustomObject getAsObject(FacesContext context, UIComponent component, String submittedValue){}
@Override
public String getAsString(FacesContext context, UIComponent component, MyCustomObject modelValue) {}
}
并且在
中使用转换器时
<!DOCTYPE html>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:selectOneMenu id="#{componentId}" value="#{componentValue}">
<f:converter converterId="myConverter" />
<f:selectItem itemLabel="label"
itemValue="" />
<f:selectItems value="listOfValues"
var="singleValue"
itemValue="singleValue.value"
itemLabel="singleValue.label" />
</h:selectOneMenu>
然后 ClassCastException
和消息 java.lang.String cannot be cast to MyCustomObject
被抛出。 stacktrace 中还有一行也许可以帮助 com.sun.faces.cdi.CdiConverter.getAsString(CdiConverter.java:109)
.
但是当转换器泛型定义从 MyCustomObject
更改为 Object
时:
@FacesConverter(value = "myConverter", managed = true)
public class MyConverter implements Converter<Object>{
@Override
public Object getAsObject(FacesContext context, UIComponent component, String submittedValue){}
@Override
public String getAsString(FacesContext context, UIComponent component, Object modelValue) {}
}
然后一切都按预期工作,但这显然超出了 Converter<T>
界面的目的。
我在使用 FacesConverter 时遇到了两个问题。
第一个,当我没有使用 forClass = MyCustomObject.class
时,我收到了与您完全相同的错误消息。将 forClass
属性放在 @FacesConverter
注释中解决了这个问题。它应该也能为你解决...
其次,我想这是在 getAsString 方法中发生的?我在字符串转换方面遇到了另一个问题,我必须这样做:return myCustomObject.getId().toString()
其中 id 是 Long 类型。之后,我修改了 getAsObject 以根据 id 获取 MyCustomObject。也许它与您的问题没有直接关系,但我认为提及它很重要,因为这是我在编写转换器时经常遇到的问题。
我在这里遇到了同样的问题并提出了以下解决方案,该解决方案实际上不仅可以编译而且运行良好:
some_page.xhtml
(相关摘录):
<h:selectOneMenu styleClass="select" id="companyUserOwner" value="#{adminCompanyDataController.companyUserOwner}">
<f:converter converterId="UserConverter" />
<f:selectItem itemValue="#{null}" itemLabel="#{msg.NONE_SELECTED}" />
<f:selectItems value="#{userController.allUsers()}" var="companyUserOwner" itemValue="#{companyUserOwner}" itemLabel="#{companyUserOwner.userContact.contactFirstName} #{companyUserOwner.userContact.contactFamilyName} (#{companyUserOwner.userName})" />
</h:selectOneMenu>
请注意,上面的 JSF 代码充满了自定义内容,可能无法在您的端运行。而且我的转换器编译时没有原始类型警告(JSF 2.3+,not 2.2!):
SomeUserConverter.java
:
@FacesConverter (value = "UserConverter")
public class SomeUserConverter implements Converter<User> {
/**
* User EJB
*/
private static UserSessionBeanRemote USER_BEAN;
/**
* Default constructor
*/
public SomeUserConverter () {
}
@Override
public User getAsObject (final FacesContext context, final UIComponent component, final String submittedValue) {
// Is the value null or empty?
if ((null == submittedValue) || (submittedValue.trim().isEmpty())) {
// Return null
return null;
}
// Init instance
User user = null;
try {
// Try to parse the value as long
final Long userId = Long.valueOf(submittedValue);
// Try to get user instance from it
user = USER_BEAN.findUserById(userId);
} catch (final NumberFormatException ex) {
// Throw again
throw new ConverterException(ex);
} catch (final UserNotFoundException ex) {
// User was not found, return null
}
// Return it
return user;
}
@Override
public String getAsString (final FacesContext context, final UIComponent component, final User value) {
// Is the object null?
if ((null == value) || (String.valueOf(value).isEmpty())) {
// Is null
return ""; //NOI18N
}
// Return id number
return String.valueOf(value.getUserId());
}
}
此转换器 class 删除了 JNDI 查找(我稍后会重写该部分)但它应该足以演示重要部分:
Converter<User>
(User
是自定义 POJI)防止原始类型警告
value="UserConverter"
这是您在 JSF 页面中使用的实际名称
- 最重要的是,它实际上修复了
ClassCastException
:
<f:selectItem itemValue="#{null}" itemLabel="#{msg.NONE_SELECTED}" />
- 通过省略
#{null}
,一个 空字符串 而不是 null
被处理到您的 getAsString
方法!
最后一个实际上修复了上述异常,我的应用程序再次运行,警告更少,类型提示更好。
需要删除 forClass
,因为 value
在那里:FacesConverter is using both value and
forClass, only value will be applied.
会出现原始类型警告(自 Java SE 5 起),因为您使用的接口具有您需要满足的泛型(通常在接口名称后表示为 <T>
)所以编译器停止向您发出警告。
我们现在开始在现有的 JSF 2.2 项目上使用 JSF 2.3。在我们的自定义转换器上,我们收到警告 Converter is a raw type. References to generic type Converter<T> should be parameterized.
我们遇到的问题是当我们尝试使用泛型修复该警告时:
@FacesConverter(value = "myConverter", managed = true)
public class MyConverter implements Converter<MyCustomObject>{
@Override
public MyCustomObject getAsObject(FacesContext context, UIComponent component, String submittedValue){}
@Override
public String getAsString(FacesContext context, UIComponent component, MyCustomObject modelValue) {}
}
并且在
中使用转换器时<!DOCTYPE html>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:selectOneMenu id="#{componentId}" value="#{componentValue}">
<f:converter converterId="myConverter" />
<f:selectItem itemLabel="label"
itemValue="" />
<f:selectItems value="listOfValues"
var="singleValue"
itemValue="singleValue.value"
itemLabel="singleValue.label" />
</h:selectOneMenu>
然后 ClassCastException
和消息 java.lang.String cannot be cast to MyCustomObject
被抛出。 stacktrace 中还有一行也许可以帮助 com.sun.faces.cdi.CdiConverter.getAsString(CdiConverter.java:109)
.
但是当转换器泛型定义从 MyCustomObject
更改为 Object
时:
@FacesConverter(value = "myConverter", managed = true)
public class MyConverter implements Converter<Object>{
@Override
public Object getAsObject(FacesContext context, UIComponent component, String submittedValue){}
@Override
public String getAsString(FacesContext context, UIComponent component, Object modelValue) {}
}
然后一切都按预期工作,但这显然超出了 Converter<T>
界面的目的。
我在使用 FacesConverter 时遇到了两个问题。
第一个,当我没有使用 forClass = MyCustomObject.class
时,我收到了与您完全相同的错误消息。将 forClass
属性放在 @FacesConverter
注释中解决了这个问题。它应该也能为你解决...
其次,我想这是在 getAsString 方法中发生的?我在字符串转换方面遇到了另一个问题,我必须这样做:return myCustomObject.getId().toString()
其中 id 是 Long 类型。之后,我修改了 getAsObject 以根据 id 获取 MyCustomObject。也许它与您的问题没有直接关系,但我认为提及它很重要,因为这是我在编写转换器时经常遇到的问题。
我在这里遇到了同样的问题并提出了以下解决方案,该解决方案实际上不仅可以编译而且运行良好:
some_page.xhtml
(相关摘录):
<h:selectOneMenu styleClass="select" id="companyUserOwner" value="#{adminCompanyDataController.companyUserOwner}">
<f:converter converterId="UserConverter" />
<f:selectItem itemValue="#{null}" itemLabel="#{msg.NONE_SELECTED}" />
<f:selectItems value="#{userController.allUsers()}" var="companyUserOwner" itemValue="#{companyUserOwner}" itemLabel="#{companyUserOwner.userContact.contactFirstName} #{companyUserOwner.userContact.contactFamilyName} (#{companyUserOwner.userName})" />
</h:selectOneMenu>
请注意,上面的 JSF 代码充满了自定义内容,可能无法在您的端运行。而且我的转换器编译时没有原始类型警告(JSF 2.3+,not 2.2!):
SomeUserConverter.java
:
@FacesConverter (value = "UserConverter")
public class SomeUserConverter implements Converter<User> {
/**
* User EJB
*/
private static UserSessionBeanRemote USER_BEAN;
/**
* Default constructor
*/
public SomeUserConverter () {
}
@Override
public User getAsObject (final FacesContext context, final UIComponent component, final String submittedValue) {
// Is the value null or empty?
if ((null == submittedValue) || (submittedValue.trim().isEmpty())) {
// Return null
return null;
}
// Init instance
User user = null;
try {
// Try to parse the value as long
final Long userId = Long.valueOf(submittedValue);
// Try to get user instance from it
user = USER_BEAN.findUserById(userId);
} catch (final NumberFormatException ex) {
// Throw again
throw new ConverterException(ex);
} catch (final UserNotFoundException ex) {
// User was not found, return null
}
// Return it
return user;
}
@Override
public String getAsString (final FacesContext context, final UIComponent component, final User value) {
// Is the object null?
if ((null == value) || (String.valueOf(value).isEmpty())) {
// Is null
return ""; //NOI18N
}
// Return id number
return String.valueOf(value.getUserId());
}
}
此转换器 class 删除了 JNDI 查找(我稍后会重写该部分)但它应该足以演示重要部分:
Converter<User>
(User
是自定义 POJI)防止原始类型警告value="UserConverter"
这是您在 JSF 页面中使用的实际名称- 最重要的是,它实际上修复了
ClassCastException
: <f:selectItem itemValue="#{null}" itemLabel="#{msg.NONE_SELECTED}" />
- 通过省略
#{null}
,一个 空字符串 而不是null
被处理到您的getAsString
方法!
最后一个实际上修复了上述异常,我的应用程序再次运行,警告更少,类型提示更好。
需要删除 forClass
,因为 value
在那里:FacesConverter is using both value and
forClass, only value will be applied.
会出现原始类型警告(自 Java SE 5 起),因为您使用的接口具有您需要满足的泛型(通常在接口名称后表示为 <T>
)所以编译器停止向您发出警告。