Как зарегистрировать пользовательский рендерер в JSF?
-
02-10-2019 - |
Вопрос
У нас есть числовые значения в нашей базе данных, представляющие состояние с двумя значениями.Конечно, это идеально соответствовало бы логическому значению, но у oracle нет такого типа данных.Тип NUMBER(1,0) из базы данных соответствует java.lang.Короткий тип в Java (иногда они использовали ЧИСЛО (*,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 ) и правильный тип средства визуализации.
Из-за этого я не хочу редактировать полную модель.Есть какие-нибудь намеки, как это можно решить?
Решение
Мы могли бы устранить проблему и правильно зарегистрировать наш пользовательский рендерер.
Проблема заключалась в том, чтобы найти правильные свойства для предполагаемого средства визуализации.Наши попытки оказались неудачными, так как я узнал, как получить соответствующую информацию.Потребовалось немного поработать и поискать, но в конце концов это сделало свое дело.
Просто запустите свой контейнер в режиме отладки и добавьте точку останова на уровне класса в производный класс, на котором основан пользовательский рендерер (в моем случае com.icesoft.faces.renderkit.dom_html_basic.CheckBoxRenderer).
Во время запуска контейнера эта точка останова будет достигнута, и в stacktrace вы найдете вызов метода 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:Конечно, есть более разумный способ получить эту информацию, но я недостаточно умен.;-)
Другие советы
Вы не говорите, используете ли вы Hibernate, но я предполагаю, что это должно быть так, чтобы это было проблемой.Вы пробовали рассматривать числовое значение как логическое в своем отображении?
Видишь это тема с форумов Hibernate