В нашей базе данных есть числовые значения, представляющие состояние с двумя значениями. Конечно, это идеально соответствовало бы логическому значению, но у оракула нет такого типа данных. Тип NUMBER(1,0) из базы данных сопоставляется с типом java.lang.Short в Java (иногда они использовали NUMBER(*,0) для представления логических значений, которые сопоставляются с java.math.BigDecimal).
Поскольку это как-то очевидно, я хочу предложить пользователю ice:selectBooleanCheckbox в виде представления значения и UIComponent. (Я использую IceFaces как реализацию JSF)
Поскольку некоторые люди, указавшие JSF, считают очевидным всегда сопоставлять значение ice:selectBooleanCheckbox или h:selectBooleanCheckbox в JSF с логическим значением в модели, поэтому визуализатор компонента никогда не вызывает какой-либо преобразователь, даже если вы его укажете: Проблема обсуждалась на 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) и правильный тип рендерера.
Из-за этого я не хочу редактировать всю модель. Любые подсказки, как это можно решить?