0

我们的数据库中有数值,表示双值状态。当然,这将完全匹配布尔值,但 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";
   }
 }

转换器在渲染阶段工作正常(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);
 }

所以这会导致 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);  
   }
 }

并像这样在 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>

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

因此,我不想编辑完整的模型。任何提示,如何解决?

4

2 回答 2

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>

现在转换器中的 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);
}

否则你会得到一个 NullPointerException。

PS:肯定有更聪明的方法来获取这些信息,但我不够聪明。;-)

于 2010-05-04T09:49:47.793 回答
0

你没有说你是否在使用 Hibernate,但我认为你必须是这个问题。您是否尝试在映射中将数字视为布尔值?

从 Hibernate 论坛中查看此线程

于 2010-05-04T08:40:25.037 回答