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中使用的组件)和正确的渲染器类型.
因此,我不想编辑完整的模型.任何提示,如何解决这个问题?
我们可以解决问题并正确注册我们的自定义渲染器.
问题是为预期的渲染器找到正确的属性.我们的尝试错了,因为我发现了如何获得适当的信息.这是一些工作和搜索,但它终于成功了.
只需在调试模式下启动容器,并在类级别上将断点添加到自定义渲染器所基于的派生类中(在我的例子中为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:肯定有一种更聪明的方法可以获得这些信息,但我还不够聪明.;-)