Martin Marinschek schrieb:
Can you post your suggested changes again, and interweave the existing
code, so that I can look at it step by step and see what your changes
would mean?

regards,

Martin

Hi Martin,

here is a 'little' peace of code for RendererUtils :) It implements, what I've talking about in my early posting. The getBooleanValueForCheckbox() method is intended to replace existing getBooleanValue(), which is currently called from renderer in RenderUtils however wit one more parameter, so this call should be changed too (HtmlCheckboxRendererBase line 62). It is something like proof-of-concept. I've not implement yet the controversy case when custom converter provides the same type as our 'expected' (see comments in code) since IMHO it should be really clarified first. The String2Boolean() can be probably implemented some smarter way too. But I think, this approach can be used in UIComponentTagUtils as well, since it should work in both way.

Regards,
paul

   /**
    * Envelope for results of obtaining converter.
    */
   public static class FoundConverter{
private int converterType = 0; //int due to Java 1.42 compatibility! (Use Enum in 5+ ?)
       private Converter converter = null;
       private Class customClass = null;
/**
        * @return found conwerter if type > 0, otherweis null.
        */
       public final Converter getConverter() {
           return converter;
       }
       public final void setConverter(Converter converter) {
           this.converter = converter;
       }
/**
        * @return -1 not required;<br>
        *  0 not found;<br>
        *  1 custom;<br>
        *  2 standard for object's class<br>
        *  3 standard for target class (last choice!)
        */
       public final int getConverterType() {
           return converterType;
       }
       public final void setConverterType(int converterType) {
           this.converterType = converterType;
       }
public final Class getCustomClass() {
           return customClass;
       }
       public final void setCustomClass(Class customClass) {
           this.customClass = customClass;
       }
} /** * @param value - object, usually returned by getValue() or getSubmittedValue()<br>
    * @param targetClass - class to which value should be converted<br>
    * @param facesContext - Faces context<br>
    * @param component - component<br>
* @param probe - string to be used for determining return type of getAsObject() of custom converter<br>
    *
* @return an instance of envelope class FoundConverter, containing evtl. found converter and
    * information on type of this converter.
    *
    * Obtains apropriative converter in order:<br>
    * custom converter,<br>
    * standard converter registered for value's class,<br>
    * standard converter registered for target class.<br>
    *
    * Returns no converter if:<br>
* - no custom converter provided but value is already of suitable type;<br>
    * - no custom converter provided and value is null.<br>
* If custom converter provided, tries also to call getAsObject() with probe
    * as argument to determine custom type.
    *
    *
* @throws IllegalArgumentException if value is not null, not of suitable type and no converter can be found.
    */
public static FoundConverter obtainConverter(Object value, Class targetClass,
                                           FacesContext facesContext,
                                           UIComponent component,
String probe) throws IllegalArgumentException{ FoundConverter result = new FoundConverter();//result envelope

       //--- check if component is a ValueHolder ---
       if (! (component instanceof ValueHolder))
           throw new IllegalArgumentException("Component : " +
                   getPathToComponent(component) + "is not a ValueHolder");
Converter converter = ((ValueHolder) component).getConverter(); //--- custom converter found ---
       if (converter != null){
try{ //--- try to determine, which type returns getAsObject() of this converter Object x = converter.getAsObject(facesContext, component, probe);
               result.setCustomClass(x.getClass());
           }
           catch(Exception ex){
log.warn("Unable to determine object type returned by custom converter: "+
                       converter.getClass().getName()+
                       " with probe string \""+probe+"\"");
           }
result.setConverterType(1);//custom converter found
           result.setConverter(converter);
return result;
       }
//--- NO custom converter ---
       if(value == null){
result.setConverterType(0);//not found, undefined for null return result;
       }
//--- value not null but already of the same type ---
       if ( targetClass.isAssignableFrom(value.getClass()) ){
result.setConverterType(-1); //not found, not required! return result;
       }
/*
        * If component provides no custom converter, we
        * cann still try to obtain a standard one from Application
        */
       try {
           //--- try first for type of value... ---
           converter = facesContext.getApplication()
                       .createConverter(value.getClass());
result.setConverterType(2);//standard for value's type
           result.setConverter(converter);
           return result;
} catch (FacesException ex) {
           //--- ...then for target type  ---
           try{
               converter = facesContext.getApplication()
                           .createConverter(targetClass);
result.setConverterType(3);//standard for target type
               result.setConverter(converter);
               return result;
           }
catch(FacesException ex2){ throw new IllegalArgumentException("Component : "
                       + getPathToComponent(component)+
                       " expects value of type "+ targetClass.getName() +
" but " + value.getClass().getName() + " was passed and"+
                       " no suitable converter found.");
           }
       }
   }
/**
    * @param str - string to convert into Boolean
    * @return Boolean
    *
* null-safe conversion of strings like "true","yes", "on" etc. to Boolean.
    */
   public static Boolean String2Boolean(String str){
       if(null != str &&
           (
               str.equalsIgnoreCase("true") ||
               str.equalsIgnoreCase("yes") ||
               str.equalsIgnoreCase("on") ||
               str.equalsIgnoreCase("1")
           )
         )
           return Boolean.TRUE;
       else
           return Boolean.FALSE;
   }
public static Boolean getBooleanValueForCheckbox(FacesContext facesContext,
           UIComponent component) {
/*
        * The value is returned in order: getSubmittedValue(), getValue()
        */
       Object value = getObjectValue(component);
FoundConverter xConverter = obtainConverter(value,Boolean.class,facesContext,component,"true"); String valueClassName = (null != value) ? value.getClass().getName() : "null"; String strExceptionMsg = "Component: " + getPathToComponent(component)+
                                " expects value of type Boolean, but "+
                                valueClassName + " passed.";
try{
           switch (xConverter.getConverterType()){
               case -1:
                   return (Boolean)value;
               case 0:
log.warn(strExceptionMsg + " FALSE assumed since no converter provided.");
                   return Boolean.FALSE; // Boolean(null) -> false
/* * Custom converter(1) as well as standard converter for value's type(2) * provide conversion [String <-> custom-type] so if we are going
                * to use it, we have to call getAsString() and then
                * try to convert that String into our expected type
                */
               case 1:
//The conversion logic in case when custom converter produce the same //type of 'object' as our expected type, that I've describe in my posting
                   //early, can be implemented here... i.e.:
                   //
                   //if(xConverter.getCustomClass() != null){
// if (Boolean.class.isAssignableFrom(xConverter.getCustomClass())){ // ... // }
                   //}
               case 2:
String xString = xConverter.getConverter().getAsString(facesContext, component, value);
                   return String2Boolean(xString);
/* * Standard converter for target type(3) provide conversion [String <-> our-expected-type] * so we can get value.toString() first and then call getAsObject()
                */
               case 3:
                   String yString = value.toString();
return (Boolean)xConverter.getConverter().getAsObject(facesContext, component, yString);
               default:
throw new IllegalArgumentException(strExceptionMsg + " No suitable converter available.");
           }//case
       }
       catch(ConverterException ex){
           throw new IllegalArgumentException(strExceptionMsg +
" Conversion with " + xConverter.getConverter().getClass().getName()+
                   " failed."
                   );
       }

   }
//----------------------- END OF CODE --------------------------------

Reply via email to