Announcement Announcement Module
Collapse
No announcement yet.
PropertyEditor for dates Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • PropertyEditor for dates

    In our application we have a class, which extends another class.

    Simple:

    Code:
    public class ObjA
    {
        private Date d;
    
        // Getters and setters
    }
    
    public class ObjB extends ObjA
    {
        private ObjC objC
        // Getters and setters
    }
    
    public class ObjC
    {
        private Date d2;
        // Getters and Setters
    }
    We have a form which contains an input field for field d and d2. So far everything goes well, when we request the page containing the form, we see those fields popup.

    Since you have to enter dates as dd/MM/yyyy, we have a property editor to parse the entered date, corresponding to that pattern, with the SimpleDateFormat-class.

    The problem was that the client wanted an error message, when users entered something like 32/12/2009. So far so good, what I did was format the date and check whether or not it was equal to the entered date. So if you add 32/12/2009 and you parse it, something like Jan 01 2010 should come up and validation fails. An exception is thrown (IllegalArgumentException to be more precise).

    When you return to the page, the previous entered date is still there. Instead, I want to show 32/12/2009, instead of the previous value.

    Now here lies the problem. For some reason, the getAsText() value in my property editor is not called for the field d. d2 is fine, but d somehow doesn't make it.

    Does anyone know what the problem could be? setAsText is called correctly and everything is fine. To manipulate the flow, I do a setValue() when validation fails, so that 32/12/2009 is set as value. But that doesn't matter, since the getAsText()-method isn't called.

    My Property Editor:

    Code:
    public class CustomDateEditor extends PropertyEditorSupport
    {
        /** Dateformat for the given date */
        private SimpleDateFormat dateFormat;
        /** To allow empty entries */
        private boolean allowEmpty;
        /** To be able to make an entry strict */
        private boolean strict;
        /** Logger for this class */
        private Logger logger = Logger.getLogger(CustomDateEditor.class);
    
        /**
         * Constructor
         *
         * @param dateFormat
         * @param allowEmpty
         * @param strict
         */
        public CustomDateEditor(SimpleDateFormat dateFormat, boolean allowEmpty, boolean strict)
        {
            this.dateFormat = dateFormat;
            this.allowEmpty = allowEmpty;
            this.strict = strict;
        }
    
        /**
         * What text to show in the input field, when validation fails.
         * 
         * @param text
         * @throws IllegalArgumentException
         */
        public void setAsText(String text) throws IllegalArgumentException
        {
            if(this.allowEmpty && ! StringUtils.hasText(text))
            {
                setValue(null);
            }
            else
            {
                String pattern = this.dateFormat.toPattern();
                if(strict && pattern.length() != text.length())
                {
                    throw new IllegalArgumentException("Error date Pattern: " + text + ", should be " + pattern);
                }
    
                try{
                    Date dateValue = this.dateFormat.parse(text);
    
                    if(! this.dateFormat.format(dateValue).equals(text))
                    {
                        logger.error("Error while parsing date.  User entered wrong date: " + text);
                        setValue(text);
                        logger.debug("==========VALUE: " + getValue());
                        throw new IllegalArgumentException("Could not parse date: " + text);
                    }
                    else
                    {
                        setValue(this.dateFormat.parse(text));
                    }
                }
                catch(ParseException ex)
                {
                    throw new IllegalArgumentException("Could not parse date: " + ex.getMessage());
                }
            }
        }
    
        /**
         * Get the value as text, for a given date pattern
         *
         * @return text representation of the date
         */
        public String getAsText()
        {
            String returnValue = "";
            Object o = getValue();
            if(o != null)
            {
                // get Value and return wrong date if e.g. 40/12/2009 was entered
            }
    
            return returnValue;
        }
    }
    setAsText is correct, but the application doesn't call the getAsText method for the first date. It does for the second and all the others.

  • #2
    Are both d and d2 bound to the form?

    Comment


    • #3
      Yes they are.

      Comment


      • #4
        Pardon me for asking but how exactly do you know that getAsText() is not being called? I can't see any log statements there.

        Also, can you post the relevant controller code because i'm still trying to understand why you need two fields.

        Comment


        • #5
          The magical concept of debugging ;-). I've added a breakpoint at the start of those two methods (getAsText and setAsText), and when I press submit, I enter the setAsText method twice, but the getAsText method is only called once.

          Which controller are you talking about? Because all this happens before my FormController is called. These methods are also called inside Spring, so I can't control that flow.

          The PropertyEditors are registered this way:

          Code:
          SimpleDateFormat df = new SimpleDateFormat("dd/MM/yyyy");
          binder.registerCustomEditor(java.util.Date.class, new CustomDateEditor(df, true, true));
          There's not a lot I can do about this, except implementing those methods and start praying I guess. I really have no idea what the difference is between those fields.

          What I didn't mention before is that we are working with Tiles and that one of those fields is in 1 tile and the other in another tile. I don't know if that's of any consequence at all.

          Comment


          • #6
            I think I know what the problem is.

            This is my property editor:

            Code:
            public class CustomDateEditor extends PropertyEditorSupport
            {
                /** Dateformat for the given date */
                private SimpleDateFormat dateFormat;
                /** To allow empty entries */
                private boolean allowEmpty;
                /** To be able to make an entry strict */
                private boolean strict;
            
                /**
                 * Constructor
                 *
                 * @param dateFormat
                 * @param allowEmpty
                 * @param strict
                 */
                public CustomDateEditor(SimpleDateFormat dateFormat, boolean allowEmpty, boolean strict)
                {
                    this.dateFormat = dateFormat;
                    this.allowEmpty = allowEmpty;
                    this.strict = strict;
                }
            
                /**
                 * What text to show in the input field, when validation fails.
                 *
                 * @param text
                 * @throws IllegalArgumentException
                 */
                public void setAsText(String text) throws IllegalArgumentException
                {
                    if(this.allowEmpty && ! StringUtils.hasText(text))
                    {
                        setValue(null);
                    }
                    else
                    {
                        String pattern = this.dateFormat.toPattern();
                        if(strict && pattern.length() != text.length())
                        {
                            throw new IllegalArgumentException("Error date Pattern: " + text + ", should be " + pattern);
                        }
            
                        try{
                            Date enteredDate = this.dateFormat.parse(text);
                            if(! this.dateFormat.format(enteredDate).equals(text))
                            {
                                throw new IllegalArgumentException("Could not parse date, illegal date entered: " + text);
                            }
                            else
                            {
                                setValue(this.dateFormat.parse(text));
                            }
                        }
                        catch(ParseException ex)
                        {
                            setValue(text);
                            throw new IllegalArgumentException("Could not parse date: " + ex.getMessage());
                        }
                    }
                }
            
                /**
                 * Get the value as text, for a given date pattern
                 *
                 * @return text representation of the date
                 */
                public String getAsText()
                {
                    return (getValue() == null ? "" : this.dateFormat.format((Date) getValue()));
                }
            }
            When this line is executed:
            Code:
            if(! this.dateFormat.format(enteredDate).equals(text))
            an exception is thrown, but if I do a setValue with the original text, that value is not a date, so the property editor isn't called anymore.

            I don't think there's a way around this :-/. What I need is a solution to keep the value for that date, even if that was 40/12/2009. I'm going to use Javascript validation to validate that particular field, but I don't like this solution very much.

            Comment

            Working...
            X