Как зарегистрировать пользовательский рендерер в JSF?

StackOverflow https://stackoverflow.com/questions/2763481

Вопрос

У нас есть числовые значения в нашей базе данных, представляющие состояние с двумя значениями.Конечно, это идеально соответствовало бы логическому значению, но у 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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top