如何在JSF中注册自定义渲染器?

bl4*_*0l7 0 jsf icefaces renderer custom-renderer

我们的数据库中有数值,表示两值状态.当然,这将完全匹配布尔值,但oracle没有这样的数据类型.数据库中的NUMBER(1,0)类型与Java中的java.lang.Short类型匹配(有时它们使用NUMBER(*,0)来表示与java.math.BigDecimal匹配的布尔值).

由于它在某种程度上是显而易见的,我想在视图中提供ice:selectBooleanCheckbox作为值表示,向用户提供UIComponent.(我使用IceFaces作为JSF实现)

由于某些指定JSF的人认为总是将ice的值:selectBooleanCheckbox或JSF h:selectBooleanCheckbox与模型中的布尔值匹配是显而易见的,因此组件的渲染器永远不会调用任何转换器,即使您指定了一个: 问题在java.net上讨论过

因此我尝试了以下方法:

我创建了一个转换器来在UIComponent中指定它:

public class BooleanBigDecimalConverter implements Converter {

   public Object getAsObject(FacesContext context, UIComponent component, String str) {
     if (StringUtils.isEmptyString(str)) {
       return new BigDecimal(0);
     }
     if (str.equals("true")) {
       return new BigDecimal(1);
     } else {
       return new BigDecimal(0);
     }
   }

   public String getAsString(FacesContext context, UIComponent component, Object obj) {
     if (obj != null) {
       String str = obj.toString();
       if (str.equalsIgnoreCase("1")
       || str.equalsIgnoreCase("yes")
       || str.equalsIgnoreCase("true")
       || str.equalsIgnoreCase("on")) {
         return "true";
       } else {
         return "false";
       }
     }
     return "false";
   }
 }
Run Code Online (Sandbox Code Playgroud)

转换器适用于渲染阶段(正确调用getAsString方法),但是getAsObject方法(忽略它当前不正确,因为它不会被调用,所以如果它被调用它将被修复!)是从未调用过,因为在UIComponent的渲染器中没有预见到转换器,就像你在这里看到的那样(从com.icesoft.faces.renderkit.dom_html_basic.CheckboxRenderer剪辑):

 public Object getConvertedValue(FacesContext facesContext, UIComponent uiComponent, Object submittedValue)  throws ConverterException
 {
   if(!(submittedValue instanceof String))
     throw new ConverterException("Expecting submittedValue to be String");
   else
     return Boolean.valueOf((String)submittedValue);
 }
Run Code Online (Sandbox Code Playgroud)

因此,这会导致IllegalArgumentException,因为在UpdateModelValues阶段,尝试将布尔值应用于数值(请忽略BigDecimal/Short混淆......在任何情况下它都只是一个数值类型!).

所以我试图用这样一个新的覆盖渲染器:

import com.icesoft.faces.component.ext.renderkit.CheckboxRenderer;

 public class CustomHtmlSelectBooleanCheckbox extends CheckboxRenderer {

   public Object getConvertedValue(FacesContext context, UIComponent component, Object submittedValue) throws ConverterException {
   Converter converter = ((ValueHolder) component).getConverter();
   return converter.getAsObject(context, component, (String) submittedValue);  
   }
 }
Run Code Online (Sandbox Code Playgroud)

并在faces-config.xml中将其注册为:

 <render-kit>
   <renderer>
     <component-family>com.icesoft.faces.HtmlSelectBooleanCheckbox</component-family>
     <renderer-type>com.icesoft.faces.Checkbox</renderer-type>
     <renderer-class>com.myapp.web.util.CustomHtmlSelectBooleanCheckbox</renderer-class>
   </renderer>
 </render-kit>
Run Code Online (Sandbox Code Playgroud)

我想这应该是正确的,但是被覆盖的方法"getConvertedValue"永远不会被调用,getAsObject()方法也不会被调用,所以我想我在注册自定义渲染器时犯了一个错误,但我找不到更多的文档或提示如何正确地执行此操作,尤其是如何找到正确的组件系列(我查找了我在icefaces.taglib.xml中使用的组件)和正确的渲染器类型.

因此,我不想编辑完整的模型.任何提示,如何解决这个问题?

bl4*_*0l7 5

我们可以解决问题并正确注册我们的自定义渲染器.

问题是为预期的渲染器找到正确的属性.我们的尝试错了,因为我发现了如何获得适当的信息.这是一些工作和搜索,但它终于成功了.

只需在调试模式下启动容器,并在类级别上将断点添加到自定义渲染器所基于的派生类中(在我的例子中为com.icesoft.faces.renderkit.dom_html_basic.CheckboxRenderer).

在容器启动期间,将到达此断点,在堆栈跟踪中,您将找到FacesConfigurator.configureRenderKits()方法的调用.

此对象包含已注册的渲染器的ArrayList.我在列表中搜索了我想要覆盖的渲染器,并且可以找到注册我的自定义渲染器所需的信息.在我的例子中,这是faces-config.xml中的正确条目:

<render-kit>
    <description>The ICEsoft Renderers.</description>
    <render-kit-id>ICEfacesRenderKit</render-kit-id>
    <render-kit-class>com.icesoft.faces.renderkit.D2DRenderKit</render-kit-class>
    <renderer>
            <component-family>javax.faces.SelectBoolean</component-family>
            <renderer-type>com.icesoft.faces.Checkbox</renderer-type>
            <renderer-class>com.myapp.web.util.CustomHtmlSelectBooleanCheckbox</renderer-class>
    </renderer>
 </render-kit>
Run Code Online (Sandbox Code Playgroud)

现在转换器中的getAsObject()方法由自定义渲染器调用.如果您不希望每个SelectBooleanCheckbox对象都有转换器,请务必正确覆盖该方法:

public Object getConvertedValue(FacesContext context,
        UIComponent component, Object submittedValue)
        throws ConverterException {
    Converter converter = ((ValueHolder) component).getConverter();
    if (converter == null) {
        if(!(submittedValue instanceof String))
            throw new ConverterException("Expecting submittedValue to be String");
        else
            return Boolean.valueOf((String)submittedValue);
    }
    return converter.getAsObject(context, component,
            (String) submittedValue);
}
Run Code Online (Sandbox Code Playgroud)

否则你会得到一个NullPointerException.

PS:肯定有一种更聪明的方法可以获得这些信息,但我还不够聪明.;-)