Как зарегистрировать пользовательский рендер в JSF? - PullRequest
0 голосов
/ 04 мая 2010

В нашей базе данных есть числовые значения, представляющие собой состояние с двумя значениями. Конечно, это будет идеально соответствовать логическому значению, но у oracle такого типа данных нет. Тип NUMBER (1,0) из базы данных соответствует типу java.lang.Short в Java (иногда они используют 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";
   }
 }

Конвертер работает нормально для фазы рендеринга (метод 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);  
   }
 }

и зарегистрировал это следующим образом в face-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) и правильный тип рендерера.

Я не хочу редактировать полную модель из-за этого. Любые намеки, как это можно решить?

Ответы [ 2 ]

5 голосов
/ 04 мая 2010

Мы могли бы решить проблему и правильно зарегистрировать наш пользовательский рендер.

Проблема заключалась в том, чтобы найти правильные свойства для предполагаемого средства визуализации. Наши попытки были неверны, так как я узнал, как получить соответствующую информацию. Это немного работы и поиска, но наконец-то все получилось.

Просто запустите ваш контейнер в режиме отладки и добавьте точку останова на уровне класса в производный класс, на котором основан пользовательский рендер (в моем случае com.icesoft.faces.renderkit.dom_html_basic.CheckboxRenderer).

Во время запуска контейнера эта точка останова будет достигнута, и в трассировке стека вы найдете вызов метода FacesConfigurator.configureRenderKits ().

Этот объект содержит ArrayList зарегистрированных средств визуализации. Я искал список для средства визуализации, которое я хотел бы перезаписать, и смог найти информацию, необходимую для регистрации моего пользовательского средства визуализации. В моем случае это правильная запись вface-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: Конечно, есть более разумный способ получить эту информацию, но я недостаточно умен. ; -)

0 голосов
/ 04 мая 2010

Вы не говорите, используете ли вы Hibernate, но я предполагаю, что вы должны быть, чтобы это было проблемой. Вы пытались рассматривать числовое значение как логическое в вашем отображении?

Смотрите эту ветку с форумов Hibernate

...