12 Replies Latest reply on Apr 8, 2008 2:49 AM by Michal Malczewski

    JIRA RF-1471 - Incomplete fix? Custom Date types are not ful

    Tim Evers Master

      One of the more important updates for me was the support for custom Date types in the Calendar. I have written a converter for our custom date type.

      Code for converter as follows:

      package gekko.web.jsf.converter;
      
      import javax.faces.component.UIComponent;
      import javax.faces.context.FacesContext;
      import javax.faces.convert.Converter;
      import javax.faces.convert.ConverterException;
      
      import org.jboss.seam.annotations.Name;
      import org.richfaces.component.html.HtmlCalendar;
      import org.springframework.beans.factory.annotation.Autowired;
      
      import com.sun.faces.util.MessageFactory;
      
      import gekko.services.reference.DateService;
      import gekko.type.GekkoDate;
      import gekko.util.FormatUtils;
      import gekko.util.StringUtils;
      import gekko.web.services.SpringAutowirable;
      
      @Name("DateConverter")
      @org.jboss.seam.annotations.faces.Converter(id = "GekkoDateConverter", forClass = GekkoDate.class)
      @SpringAutowirable
      public class DateConverter implements Converter {
      
       @Autowired
       DateService dateSvc;
      
       /**
       * <p>
       * The default message identifier of the
       * {@link javax.faces.application.FacesMessage} to be created if the
       * conversion to <code>GekkoDate</code> fails.
       * </p>
       */
       public static final String CONVERTER_ID = "gekko.web.converter.DateConverter";
      
       /**
       * <p>
       * The message identifier of the
       * {@link javax.faces.application.FacesMessage} to be created if the
       * conversion to <code>GekkoDate</code> fails. The message format string
       * for this message may optionally include the following placeholders:
       * <ul>
       * <li><code>{0}</code> replaced by the unconverted value.</li>
       * <li><code>{1}</code> replaced by the accepted date format.</li>
       * <li><code>{2}</code> replaced by an example value.</li>
       * <li><code>{3}</code> replaced by a <code>String</code> whose value
       * is the label of the input component that produced this message.</li>
       * </ul>
       * </p>
       */
       public static final String DATE_ID = DateConverter.class.getName()
       + ".DATE";
      
       /**
       * <p>
       * The message identifier of the
       * {@link javax.faces.application.FacesMessage} to be created if the
       * conversion of the <code>GekkoDate</code> value to <code>String</code>
       * fails. The message format string for this message may optionally include
       * the following placeholders:
       * <ul>
       * <li><code>{0}</code> replaced by the unconverted value.</li>
       * <li><code>{1}</code> replaced by a <code>String</code> whose value
       * is the label of the input component that produced this message.</li>
       * </ul>
       * </p>
       */
       public static final String STRING_ID = DateConverter.class.getName()
       + ".STRING";
      
       @Override
       public Object getAsObject(FacesContext context,
       UIComponent component,
       String value)
       {
       Object returnValue = null;
      
       if (StringUtils.isBlank(value)) {
       return null;
       }
      
       try {
       returnValue = FormatUtils.parseShortDate(value);
       } catch (IllegalArgumentException e) {
       throw new ConverterException(MessageFactory.getMessage(context,
       DATE_ID, value, getDateFormat(component), dateSvc
       .getCurrentDate(), MessageFactory.getLabel(context,
       component)), e);
       }
       return returnValue;
       }
      
       @Override
       public String getAsString(FacesContext context,
       UIComponent component,
       Object value)
       {
       if (value == null) {
       return "";
       }
       try {
       return FormatUtils.formatDate((GekkoDate) value,
       getDateFormat(component));
       } catch (ConverterException e) {
       throw new ConverterException(MessageFactory.getMessage(context,
       STRING_ID, value, MessageFactory.getLabel(context, component)),
       e);
       }
       }
      
       private String getDateFormat(UIComponent component) {
       String format = FormatUtils.SHORT_DATE_FORMAT.toLowerCase();
      
       if (component instanceof HtmlCalendar) {
       format = ((HtmlCalendar) component).getDatePattern();
       }
       return format;
       }
      }
      


      So as you can see I have registered this converter for my GekkoDate.class.

      The problem is that in the converter on the getAsString is called. getAsObject is never called.

      However! If i specifically specify the converter on the actual richfaces component like this:
      <rich:calendar id="commencementDateInput"
       enableManualInput="true"
       value="#{AccountController.currentAccount.commencementDate}"
       converter="GekkoDateConverter"
       datePattern="#{FormatUtils.shortDateFormat}" />
      


      Then it will work.

      Why does the forClass converter not work for this component properly?

        • 1. Re: JIRA RF-1471 - Incomplete fix? Custom Date types are not
          Tim Evers Master

          Should I raise this as a new JIRA? Or can someone see what I've done wrong?

          • 3. Re: JIRA RF-1471 - Incomplete fix? Custom Date types are not
            Tim Evers Master

            OK...i'm feeling really stupid right now, but I can no longer see the create new jira button. It seems to have just dissapeared!

            Anyone else having this problem? (yes I am logged in)

            • 4. Re: JIRA RF-1471 - Incomplete fix? Custom Date types are not
              mars1412 Apprentice

              make sure you are on the .org site - not on the .com site

              • 5. Re: JIRA RF-1471 - Incomplete fix? Custom Date types are not
                Tim Evers Master

                well, the .org site doesn't seem to be any different.
                I'm rather confused now!

                I've raised jiras before and had no problem LOL

                • 6. Re: JIRA RF-1471 - Incomplete fix? Custom Date types are not
                  Tim Evers Master

                  Ok, well I think I have figured it out.
                  My account has been corrupted. I just created a new account and I can create jiras in it.

                  Anyway I can get my normal account fixed?

                  • 7. Re: JIRA RF-1471 - Incomplete fix? Custom Date types are not
                    Tim Evers Master

                    hmm, actually it gets even weirder!
                    I can log in when I type my username like this "kragoth" or like this "Kragoth" but when I use the capitalised username I can create new issues! how very strange! Seems like a bit of a security bug there.

                    • 8. Re: JIRA RF-1471 - Incomplete fix? Custom Date types are not
                      Sergey Smirnov Master

                      Most likely, you are blogging not at the right place. I hardly believe that guys who are responsible for the Jboss jira read this forum in general.

                      • 10. Re: JIRA RF-1471 - Incomplete fix? Custom Date types are not
                        Michal Malczewski Newbie

                        Hello,

                        I'm having a bit different problem with custom date converters. The workaround proposed here does not work for me. I've tried even following scenarios (following converters.MXDateTime is my registered converter):

                        First:

                        <rich:calendar value="#{fieldValue}" id="#{field.wsName}" datePattern="d/M/yy HH:mm" converter="converters.MXDateTime"/>


                        Second:
                        <rich:calendar value="#{fieldValue}" id="#{field.wsName}" datePattern="d/M/yy HH:mm" converter="converters.MXDateTime">
                         <f:converter converterId="converters.MXDateTime" binding="#{field.converterName}"/>
                        </rich:calendar>


                        Both produces following error:
                        javax.faces.FacesException: Wrong attibute type
                        at org.richfaces.component.UICalendar.getAsDate(UICalendar.java:317)
                        at org.richfaces.component.UICalendar.getCurrentDateOrDefault(UICalendar.java:286)
                        at org.richfaces.renderkit.html.CalendarRenderer.doEncodeEnd(CalendarRenderer.java:351)
                        at org.richfaces.renderkit.html.CalendarRenderer.doEncodeEnd(CalendarRenderer.java:457)
                        at org.ajax4jsf.renderkit.RendererBase.encodeEnd(RendererBase.java:135)
                        at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:856)
                        [...]


                        Following the stack trace, I've examined a source code for UICalendar.java. The interesting part begins at line 314:
                        if (date instanceof String) {
                         DateTimeConverter converter = new DateTimeConverter();
                         converter.setPattern(this.getDatePattern());
                         converter.setLocale(getAsLocale(this.getLocale()));
                         converter.setTimeZone(this.getTimeZone());
                         FacesContext context = FacesContext.getCurrentInstance();
                         return (Date) converter.getAsObject(context, this, (String) date);
                        }


                        Isn't it the case, that default DateTimeConverter always will be used here?

                        regards,
                        YelloY


                        • 11. Re: JIRA RF-1471 - Incomplete fix? Custom Date types are not
                          Tim Evers Master

                          Can you provide more info?

                          Your faces-config
                          Your converter code.
                          Your backing bean. What does #{fieldValue} resolve to?

                          Because custom types do work...so maybe it's just a converter registration issue.


                          • 12. Re: JIRA RF-1471 - Incomplete fix? Custom Date types are not
                            Michal Malczewski Newbie

                             

                            "Kragoth" wrote:
                            Can you provide more info?

                            Your faces-config
                            Your converter code.
                            Your backing bean. What does #{fieldValue} resolve to?

                            Because custom types do work...so maybe it's just a converter registration issue.




                            Perhaps you're right, so here we go:

                            converter registration:
                             <converter>
                             <converter-for-class>com.mro.www.mx.integration.MXDateTime</converter-for-class>
                             <converter-class>
                             aiut.integration.jsf.converters.MXDateTimeConverter
                             </converter-class>
                             </converter>
                            
                             <converter>
                             <converter-id>converters.MXDateTime</converter-id>
                             <converter-class>
                             aiut.integration.jsf.converters.MXDateTimeConverter
                             </converter-class>
                             </converter>
                            

                            as you can see, I tried converter-for-class, and as in your explanation it does work only partially.

                            here's the converter code:
                            public class MXDateTimeConverter implements Converter {
                             public Object getAsObject(FacesContext arg0, UIComponent arg1, String arg2) {
                             MXDateTime converted = new MXDateTime(Calendar.getInstance());
                             if (arg2 != null && !arg2.equals("")) {
                             if (arg1.getClass() == HtmlCalendar.class) {
                             Date parsed = new Date();
                             try {
                             SimpleDateFormat p = new SimpleDateFormat(
                             ((HtmlCalendar) arg1).getDatePattern());
                             parsed = p.parse(arg2);
                             Calendar c = Calendar.getInstance();
                             c.setTime(parsed);
                             converted.set_value(c);
                             return converted;
                             } catch (ParseException e) {
                             FacesMessage message = new FacesMessage("Parsing error");
                             message.setSeverity(FacesMessage.SEVERITY_ERROR);
                             throw new ConverterException(e.getMessage());
                             }
                             }
                             } else {
                             boolean req = ((UIInput) arg1).isRequired();
                             if (req) {
                             FacesMessage message = new FacesMessage("Field is required");
                             message.setSeverity(FacesMessage.SEVERITY_ERROR);
                             throw new ConverterException(message);
                             }
                             }
                             return converted;
                             }
                            
                             public String getAsString(FacesContext arg0, UIComponent arg1, Object arg2) {
                             String ret = "";
                             if (arg2 != null && arg2.getClass() == MXDateTime.class) {
                             if (arg1.getClass() == HtmlCalendar.class) {
                             HtmlCalendar c = (HtmlCalendar) arg1;
                             String pattern = c.getDatePattern();
                             MXDateTime d = (MXDateTime) arg2;
                             Calendar cal = d.get_value();
                             SimpleDateFormat sdf = new SimpleDateFormat(pattern);
                             ret = sdf.format(cal.getTime());
                             }
                             }
                             return ret;
                             }
                            }
                            


                            and #{fieldValue} is an argument used in my facelet. I'm prepaaring a facelet tag, that generates label, input and message, where input may be textbox, checkbox or calendar. facelet works fine with textboxes and checkboxes; it's code:
                            <ui:composition>
                             <c:if test="#{fn:length(field.children) == 0 }">
                             <h:outputText id="#{field.wsName}_label" value="#{field.wsName} #{field.required ? '(*)' : ''} " style="#{fieldValue.changed ? 'font-weight:bold' : 'font-weight:normal'}" />
                             <c:choose>
                             <c:when test="#{field.type == 'MXBoolean'}">
                             <h:selectBooleanCheckbox id="#{field.wsName}" required="#{required}" value="#{fieldValue}" readonly="#{readonly}" />
                             </c:when>
                             <c:when test="#{field.type == 'MXDateTime'}">
                             <rich:calendar value="#{fieldValue}" id="#{field.wsName}" required="#{required}" datePattern="d/M/yy HH:mm" converter="converters.MXDateTime" />
                             </c:when>
                             <c:otherwise>
                             <h:inputText value="#{fieldValue}" id="#{field.wsName}" required="#{required}" readonly="#{readonly}" converter="#{field.converterName}" />
                             </c:otherwise>
                             </c:choose>
                             <h:message for="#{field.wsName}" id="#{field.wsName}_message" />
                             </c:if>
                            </ui:composition>
                            


                            The #{field} above, corresponds to my class containing all necessary info about current field; so #{field} != #{fieldValue}

                            Should I mention, that I'm using RF 3.2.0? ;)

                            regards,
                            YelloY