JSF 2.3带有泛型的自定义转换器

时间:2017-04-05 18:06:26

标签: jsf java-ee cdi tomee jsf-2.3

我们现在开始在现有的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的{​​{1}}。 stacktrace中还有一行可以帮助java.lang.String cannot be cast to MyCustomObject

但转换器泛型定义从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) {} } 接口的目的。

2 个答案:

答案 0 :(得分:2)

我在这里遇到了同样的问题,并提出了以下解决方案,实际上不只是编译而且运行良好:

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代码充满了自定义内容,可能无法正常运行。并且我的转换器编译没有rawtype警告(JSF 2.3+, 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());
    }

}

这个转换器类删除了JNDI查找(我稍后会重写该部分)但它应该足以演示重要部分:

  • Converter<User>User是自定义POJI)防止原始类型警告
  • value="UserConverter"这是您在JSF页面中使用的实际名称
  • 最重要的是,它实际修复了ClassCastException
  • <f:selectItem itemValue="#{null}" itemLabel="#{msg.NONE_SELECTED}" />
  • 省略#{null} 空字符串而不是null正在处理您的getAsString方法!

这最后一个实际修复了所述异常,我的应用程序再次使用更少的警告和更好的类型提示。

需要删除forClass valueFacesConverter is using both value and forClass , only value will be applied.

原始类型警告将会出现(自Java SE 5开始),因为您使用的接口具有通用(在接口名称之后通常称为<T>),您需要满足该接口,因此编译器会停止抛出警告你。

答案 1 :(得分:1)

FacesConverter有两个问题。

首先,当我没有使用forClass = MyCustomObject.class时,我得到了与您完全相同的错误消息。将forClass注释放在@FacesConverter注释中可以解决问题。它也应该为你解决......

其次,我想这是在getAsString方法中发生的?我有另一个字符串转换的问题,我必须这样做:return myCustomObject.getId().toString()其中id是Long类型。之后我调整了我的getAsObject来根据id获取MyCustomObject。也许它与您的问题没有直接关系,但我认为重要的是要提及,因为这是我在编写转换器时经常遇到的问题。