我们的数据库中有数值,表示两值状态。当然,这将完全匹配布尔值,但oracle没有这样的数据类型。数据库中的NUMBER(1,0)类型与Java中的java.lang.Short类型匹配(有时它们使用NUMBER(*,0)来表示与java.math.BigDecimal匹配的布尔值)。
由于它有点显而易见,我想提供ice:在视图中将selectBooleanCheckbox作为值表示,向用户提供UIComponent。 (我使用IceFaces作为JSF实现)
由于某些指定JSF的人认为总是将ice的值:selectBooleanCheckbox或JSF h:selectBooleanCheckbox与模型中的布尔值匹配是显而易见的,因此组件的渲染器永远不会调用任何转换器,即使你指定一个: Issue disscused at 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中使用的组件系列)和正确的渲染器类型。
由于这个原因,我不想编辑完整的模型。任何提示,如何解决这个问题?
答案 0 :(得分: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:肯定有一种更聪明的方法可以获得这些信息,但我不够聪明。 ; - )答案 1 :(得分:0)
你没有说你是否正在使用Hibernate,但我认为你必须为此成为一个问题。您是否尝试将数字视为映射中的布尔值?