Page 1 of 2 12 LastLast
Results 1 to 10 of 17

Thread: Binding composite properties with DataBinder

  1. #1
    Join Date
    Feb 2005
    Location
    Warwickshire, UK
    Posts
    148

    Default Binding composite properties with DataBinder

    I have frequently come across the problem of binding multiple form fields to a single property. The whole binding infrastructure is geared to mapping a single input field to a single property, which is fine for most cases. It really falls over for things like dates - it seems a lot of people are using plain text input fields and demanding dates in a particular format. A far more common approach is to use multiple select boxes - one for day, month and year. The problem then is how to combine those into a single property value.

    This is a problem I've solved, and seen solved a number of times, and never been entirely happy with the result. I've recently come up with a mechanism that works quite well for me, and I'll post the code up if anyone's interested.

    The basic sequence is as follows:

    Submit a form with a composite property on it. Form fields should follow the convention propertyName_partName. Eg, dateOfBirth might have three fields, dateOfBirth_day, dateOfBirth_month and dateOfBirth_year.

    The controller uses a subclass of ServletRequestDataBinder that manipulates the array of PropertyValues to convert multiple parts of a composite property into a single property, the value of which gives all parts and values in the standard Properties format. Eg.

    Code:
       dateOfBirth_day 13
       dateOfBirth_month 2
       dateOfBirth_year 2005
    Would become:

    Code:
    dateOfBirth day=13\nmonth=2\nyear=2005
    I have an AbstractCompositePropertyEditor that converts the string into a Properties object. Then, you just have to extend it to convert the values in the Properties instance into whatever is expected by the underlying property, and register that PropertyEditor against your field.

    I'm a lot happier with this approach than other ones I've used anyway.
    Dave Hewitt
    ------------------
    Senior Systems Engineer
    OBJECTIVITY
    www.objectivity.co.uk

  2. #2
    Join Date
    Dec 2004
    Posts
    4

    Default

    Dave

    I would be interested in seeing your code for this solution.

    Thanks.

  3. #3
    Join Date
    Feb 2005
    Location
    Warwickshire, UK
    Posts
    148

    Default

    Well at least someone other than me is interested in this

    The first part is the composite property databinder. This extracts all request parameters that contain a '_' character and interpret them as parts of a property named by the portion of the parameter preceded by the '_' character.

    Code:
    package org.mooli.web.bind;
    
    import java.util.HashMap;
    import java.util.Map;
    
    import org.springframework.beans.MutablePropertyValues;
    import org.springframework.beans.PropertyValue;
    import org.springframework.beans.PropertyValues;
    import org.springframework.web.bind.ServletRequestDataBinder;
    
    /**
     * {@link org.springframework.validation.DataBinder} for converting composite properties
     * described by multiple property names into a single named property whose value is a
     * {@link java.util.Properties} instance representing the complex state of this property value. This
     * can then be used by subclasses of {@link org.mooli.web.bind.AbstractCompositePropertyEditor}
     * to convert {@link java.util.Properties} instances into complex objects.
     * @author dhewitt
     */
    public class CompositePropertyDataBinder extends ServletRequestDataBinder {
    
        /** The separator for complex property names. */
        public static final String PROPERTY_SEPARATOR = "_";
    
    
        /**
         * @param target the target to bind to
         * @param objectName the name of the object
         */
        public CompositePropertyDataBinder(final Object target, final String objectName) {
            super(target, objectName);
        }
    
        /**
         * Converts complex {@link PropertyValue}s into single instances with values. In
         * {@link java.util.Properties} string format. eg:
         *
         * <code>
         * name="birthDate_year"   value="1960"
         * name="birthDate_month"  value="10"
         * name="birthDate_date"   value="11"
         * </code>
         *
         * <code>
         * name="birthDate" value="year=1960\nmonth=10\ndate=11"
         * </code>
         * @see org.springframework.validation.DataBinder#bind&#40;org.springframework.beans.PropertyValues&#41;
         */
        public final void bind&#40;final PropertyValues pvs&#41; &#123;
            MutablePropertyValues mpvs = new MutablePropertyValues&#40;pvs&#41;;
            PropertyValue&#91;&#93; pvArray = mpvs.getPropertyValues&#40;&#41;;
            Map boundProperties = new HashMap&#40;&#41;;
            for &#40;int i = 0; i < pvArray.length; i++&#41; &#123;
                if &#40;pvArray&#91;i&#93;.getName&#40;&#41;.indexOf&#40;PROPERTY_SEPARATOR&#41; > 0&#41; &#123;
                    bindProperty&#40;pvArray&#91;i&#93;, boundProperties&#41;;
                &#125;
            &#125;
            mpvs.addPropertyValues&#40;boundProperties&#41;;
            super.bind&#40;mpvs&#41;;
        &#125;
    
        /**
         * Converts complex &#123;@link PropertyValue&#125;s into single instances with values. In
         * &#123;@link java.util.Properties&#125; string format. eg&#58;
         *
         * <code>
         * name="birthDate_year"   value="1960"
         * name="birthDate_month"  value="10"
         * name="birthDate_date"   value="11"
         * </code>
         *
         * <code>
         * name="birthDate" value="year=1960\nmonth=10\ndate=11"
         * </code>
         *
         * @param propertyValue the value to convert
         * @param boundProperties the map to add the converted property to
         */
        private void bindProperty&#40;final PropertyValue propertyValue, final Map boundProperties&#41; &#123;
            String pvName = propertyValue.getName&#40;&#41;;
            String value = pvName.substring&#40;pvName.indexOf&#40;PROPERTY_SEPARATOR&#41; + PROPERTY_SEPARATOR.length&#40;&#41;&#41;;
            value += "=" + propertyValue.getValue&#40;&#41;;
            String property = pvName.substring&#40;0, pvName.indexOf&#40;PROPERTY_SEPARATOR&#41;&#41;;
            if &#40;boundProperties.containsKey&#40;property&#41;&#41; &#123;
                value = boundProperties.get&#40;property&#41; + "\n" + value;
            &#125;
            boundProperties.put&#40;property, value&#41;;
        &#125;
    &#125;

    The second part is the abstract composite property editor that converts a string representation of a properties object into a properties instance for translation into a single object, and vice versa:
    Code:
    package org.mooli.web.bind;
    
    import java.beans.PropertyEditorSupport;
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.util.Properties;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.springframework.beans.propertyeditors.PropertiesEditor;
    
    /**
     * &#123;@link java.beans.PropertyEditor&#125; for converting a string representation of a
     * &#123;@link java.util.Properties&#125; object into an arbitrary instance. Eg. could be used
     * to convert several fields corresponding to a single date into a single instance
     * of &#123;@link Date&#125;.
     * @author dhewitt
     */
    public abstract class AbstractCompositePropertyEditor extends PropertyEditorSupport &#123;
    
        /** Logging support. */
        private final Log logger = LogFactory.getLog&#40;getClass&#40;&#41;&#41;;
    
        /** Whether to ignor errors when binding a composite property. */
        private final boolean ignoreError;
    
        /**
         * @param ignoreError
         */
        public AbstractCompositePropertyEditor&#40;&#41; &#123;
            this&#40;false&#41;;
        &#125;
    
        /**
         * @param ignore if true, errors &#40;such as missing or invalid composite properties&#41;
         *  should be ignored.
         */
        public AbstractCompositePropertyEditor&#40;final boolean ignore&#41; &#123;
            super&#40;&#41;;
            this.ignoreError = ignore;
        &#125;
    
        /**
         * @see java.beans.PropertyEditor#setAsText&#40;java.lang.String&#41;
         */
        public final void setAsText&#40;final String text&#41; throws IllegalArgumentException &#123;
            super.setValue&#40;null&#41;;
            try &#123;
                PropertiesEditor propertiesEditor = new PropertiesEditor&#40;&#41;;
                propertiesEditor.setAsText&#40;text&#41;;
                Properties properties = &#40;Properties&#41;propertiesEditor.getValue&#40;&#41;;
                Object value = convertProperties&#40;properties&#41;;
                super.setValue&#40;value&#41;;
            &#125; catch &#40;IllegalArgumentException e&#41; &#123;
                if &#40;!ignoreError&#41; &#123;
                    throw e;
                &#125; else &#123;
                    logger.debug&#40;"Unable to convert value '" + text
                            + "' but ignoreError is true - ignoring error", e&#41;;
                &#125;
            &#125;
        &#125;
    
        /**
         * Convert an instance of &#123;@link Properties&#125; into an arbitrary object.
         * @param properties the Properties to convert
         * @return the object being edited
         * @throws IllegalArgumentException if the object could not be materialised
         *  from the given properties
         */
        protected abstract Object convertProperties&#40;final Properties properties&#41; throws IllegalArgumentException;
    
        /**
         * Helper method for safely accessing properties, throwing an &#123;@link IllegalArgumentException&#125;
         * if the property does not exist.
         * @param part the property to get
         * @param properties the properties to access
         * @return the value of the given property
         * @throws IllegalArgumentException if the property did not exist
         */
        protected final String getPropertyPart&#40;final String part, final Properties properties&#41; throws IllegalArgumentException &#123;
            if &#40;properties.containsKey&#40;part&#41;
                    && properties.getProperty&#40;part&#41; != null&#41; &#123;
                return properties.getProperty&#40;part&#41;;
            &#125;
            if &#40;ignoreError&#41; &#123;
                logger.debug&#40;"Part '" + part + "' not present, ignoring."&#41;;
                return null;
            &#125; else &#123;
                throw new IllegalArgumentException&#40;"Required part '" + part + "' not present."&#41;;
            &#125;
        &#125;
    
        /**
         * Helper method for safely accessing int properties, throwing an &#123;@link IllegalArgumentException&#125;
         * if the property does not exist or is unparseable.
         * @param part the property to get
         * @param properties the properties to access
         * @return the value of the given property
         * @throws IllegalArgumentException if the property did not exist or is not an int
         */
        protected final int getPropertyPartAsInt&#40;final String part, final Properties properties&#41; throws IllegalArgumentException &#123;
            try &#123;
                String propertyPart = getPropertyPart&#40;part, properties&#41;;
                return propertyPart == null ? 0 &#58; Integer.parseInt&#40;propertyPart&#41;;
            &#125; catch &#40;NumberFormatException e&#41; &#123;
                throw new IllegalArgumentException&#40;"Unparseable part '"
                        + part + "' &#58; '" + properties.getProperty&#40;part&#41; + "'"&#41;;
            &#125;
        &#125;
    
        /**
         * Converts a &#123;@link Properties&#125; instance to a string representation.
         * @param properties the properties to convert
         * @return the string representation
         */
        private String convertStringToProperties&#40;final Properties properties&#41; &#123;
            ByteArrayOutputStream out = new ByteArrayOutputStream&#40;&#41;;
            try &#123;
                properties.store&#40;out, null&#41;;
                return new String&#40;out.toByteArray&#40;&#41;&#41;;
            &#125; catch &#40;IOException e&#41; &#123;
                return e.getMessage&#40;&#41;;
            &#125;
        &#125;
    &#125;
    The final part is a concrete implementation of the property editor for handling dates. This has a configurable strategy for handling several different combinations of date/time part parsing, but the default behaviour is to just parse dates:

    Code:
    package org.mooli.web.bind;
    
    import java.util.Calendar;
    import java.util.Date;
    import java.util.Properties;
    
    /**
     * Editor that converts instances of &#123;@link Properties&#125; to &#123;@link Date&#125; objects.
     * @author dhewitt
     */
    public final class DateTimePropertyEditor extends AbstractCompositePropertyEditor &#123;
    
    
        /** Editor for setting the date portion. */
        public static final DatePartEditor DATE_EDITOR = new DatePartEditor&#40;
                new String&#91;&#93; &#123;"year", "month", "date"&#125;,
                new int &#91;&#93; &#123;Calendar.YEAR, Calendar.MONTH, Calendar.DATE&#125;&#41; &#123;
            /**
             * @see org.mooli.web.bind.DateTimePropertyEditor.DatePartEditor
             * #populateCalendar&#40;java.util.Calendar, java.util.Properties, org.mooli.web.bind.DateTimePropertyEditor&#41;
             */
            public void populateCalendar&#40;final Calendar cal, final Properties props, final DateTimePropertyEditor editor&#41; &#123;
                String&#91;&#93; names = getNames&#40;&#41;;
                int&#91;&#93; fields = getFields&#40;&#41;;
                int year = editor.getPropertyPartAsInt&#40;names&#91;0&#93;, props&#41;;
                if &#40;year > 0&#41; &#123;
                    int month = editor.getPropertyPartAsInt&#40;names&#91;1&#93;, props&#41;;
                    int date = editor.getPropertyPartAsInt&#40;names&#91;2&#93;, props&#41;;
    
                    cal.set&#40;year, month, 1&#41;;
                    int actualMin = cal.getActualMinimum&#40;fields&#91;2&#93;&#41;;
                    int actualMax = cal.getActualMaximum&#40;fields&#91;2&#93;&#41;;
                    int fixedDate = Math.max&#40;actualMin, Math.min&#40;date, actualMax&#41;&#41;;
                    cal.set&#40;fields&#91;2&#93;, fixedDate&#41;;
                &#125;
            &#125;
        &#125;;
    
        /** Editor for setting the hour. */
        public static final DatePartEditor HOUR_EDITOR = new DatePartEditor&#40;"hour", Calendar.HOUR_OF_DAY&#41;;
    
        /** Editor for setting the minute. */
        public static final DatePartEditor MINUTE_EDITOR = new DatePartEditor&#40;"minute", Calendar.MINUTE&#41;;
    
        /** Editor for setting the second. */
        public static final DatePartEditor SECOND_EDITOR = new DatePartEditor&#40;"second", Calendar.SECOND&#41;;
    
        /** The default editors used to convert &#123;@link Properties&#125; to &#123;@link Date&#125;s - only
         * converts the date portion.
         */
        public static final DatePartEditor&#91;&#93; DEFAULT_EDITORS = new DatePartEditor&#91;&#93; &#123;
                DATE_EDITOR&#125;;
    
        /** The editors to use for binding date and time, excluding seconds. */
        public static final DatePartEditor&#91;&#93; DATETIME_EDITORS = new DatePartEditor&#91;&#93; &#123;
                DATE_EDITOR, HOUR_EDITOR, MINUTE_EDITOR&#125;;
    
        /** The editors to use for binding time, excluding seconds. */
        public static final DatePartEditor&#91;&#93; TIME_EDITORS = new DatePartEditor&#91;&#93; &#123;
                HOUR_EDITOR, MINUTE_EDITOR&#125;;
    
        /** The editors to use for binding date and time, including seconds. */
        public static final DatePartEditor&#91;&#93; ALL_EDITORS = new DatePartEditor&#91;&#93; &#123;
                DATE_EDITOR, HOUR_EDITOR, MINUTE_EDITOR, SECOND_EDITOR&#125;;
    
        /** The editors to use for extracting parts of a date. */
        private DatePartEditor&#91;&#93; editors;
    
    
        /**
         * Create a property editor using the default date part editors &#40;date only&#41;.
         */
        public DateTimePropertyEditor&#40;&#41; &#123;
            this&#40;DEFAULT_EDITORS&#41;;
        &#125;
    
        /**
         * Create a property editor using the specified date part editors.
         * @param newEditors the editors to use
         */
        public DateTimePropertyEditor&#40;final DatePartEditor&#91;&#93; newEditors&#41; &#123;
            super&#40;&#41;;
            this.editors = newEditors;
        &#125;
    
        /**
         * @param ignoreEmpty whether to ignore empty properties
         */
        public DateTimePropertyEditor&#40;final boolean ignoreEmpty&#41; &#123;
            this&#40;DEFAULT_EDITORS, ignoreEmpty&#41;;
        &#125;
    
        /**
         *
         * @param newEditors the editors to use
         * @param ignore whether to ignore empty properties
         */
        public DateTimePropertyEditor&#40;final DatePartEditor&#91;&#93; newEditors, final boolean ignore&#41; &#123;
            super&#40;ignore&#41;;
            this.editors = newEditors;
        &#125;
    
    
        /**
         * @see org.mooli.web.bind.AbstractCompositePropertyEditor#getAsProperties&#40;&#41;
         */
        protected Properties getAsProperties&#40;&#41; &#123;
            Calendar cal = Calendar.getInstance&#40;&#41;;
            cal.setTime&#40;&#40;Date&#41;getValue&#40;&#41;&#41;;
            Properties props = new Properties&#40;&#41;;
            for &#40;int i = 0; i < editors.length; i++&#41; &#123;
                editors&#91;i&#93;.populateProperties&#40;cal, props&#41;;
            &#125;
            return props;
        &#125;
    
        /**
         * @see org.mooli.web.bind.AbstractCompositePropertyEditor#convertProperties&#40;java.util.Properties&#41;
         */
        protected Object convertProperties&#40;final Properties properties&#41; &#123;
            Calendar cal = Calendar.getInstance&#40;&#41;;
            cal.clear&#40;&#41;;
            for &#40;int i = 0; i < editors.length; i++&#41; &#123;
                editors&#91;i&#93;.populateCalendar&#40;cal, properties, this&#41;;
            &#125;
            return cal.getTime&#40;&#41;;
        &#125;
    
        /**
         * Class for populating part of a date  from values specified in a
         * &#123;@link Properties&#125; object.
         */
        private static class DatePartEditor &#123;
    
            /** The field names to use when getting keys from the &#123;@link Properties&#125; instance. */
            private final String&#91;&#93; names;
    
            /** The &#123;@link Calendar&#125; fields to populate. */
            private final int&#91;&#93; fields;
    
            /**
             * @param name the name to use
             * @param field the field to set
             */
            public DatePartEditor&#40;final String name, final int field&#41; &#123;
                this&#40;new String&#91;&#93; &#123;name&#125;, new int&#91;&#93; &#123;field&#125;&#41;;
            &#125;
    
            /**
             * @param newNames the names to use
             * @param newFields the corresponding fields to set
             */
            public DatePartEditor&#40;final String&#91;&#93; newNames, final int&#91;&#93; newFields&#41; &#123;
                super&#40;&#41;;
                this.names = newNames;
                this.fields = newFields;
                //assert names.length == fields.length;
            &#125;
    
            /**
             * Populate a &#123;@link Calendar&#125; based on an instance of &#123;@link Properties&#125;.
             * @param cal the calendar to populate
             * @param props the properties to use
             * @param editor the enclosing editor
             */
            public void populateCalendar&#40;final Calendar cal, final Properties props, final DateTimePropertyEditor editor&#41; &#123;
                for &#40;int i = 0; i < names.length && i < fields.length; i++&#41; &#123;
                    cal.set&#40;fields&#91;i&#93;, editor.getPropertyPartAsInt&#40;names&#91;i&#93;, props&#41;&#41;;
                &#125;
            &#125;
    
            /**
             * Populate a &#123;@link Properties&#125; based on an instance of &#123;@link Calendar&#125;.
             * @param cal the calendar to use
             * @param props the properties to populate
             */
            public final void populateProperties&#40;final Calendar cal, final Properties props&#41; &#123;
                for &#40;int i = 0; i < names.length && i < fields.length; i++&#41; &#123;
                    props.setProperty&#40;names&#91;i&#93;, String.valueOf&#40;cal.get&#40;fields&#91;i&#93;&#41;&#41;&#41;;
                &#125;
            &#125;
    
            /**
             * @return Returns the fields.
             */
            public final int&#91;&#93; getFields&#40;&#41; &#123;
                return fields;
            &#125;
            /**
             * @return Returns the names.
             */
            public final String&#91;&#93; getNames&#40;&#41; &#123;
                return names;
            &#125;
    
        &#125;
    
    &#125;
    This could all be tidied up somewhat, but the basic mechanism works well for me, and I have used this approach several times for other complex objects.
    Dave Hewitt
    ------------------
    Senior Systems Engineer
    OBJECTIVITY
    www.objectivity.co.uk

  4. #4
    Join Date
    Aug 2004
    Posts
    1,905

    Default Minor comment

    Dave,

    I would be careful about using "_" as it seems to have a magic meaning within Spring.

    Other than that, looks good

  5. #5

    Default Is all this necessary?

    I'm not sure I see the advantages of your implementation over using nested properties, supported in Spring without requiring a custom binder.

    Code:
    <spring&#58;bind path="myDate.year">
    <select name="$&#123;status.expression&#125;"/>">
    	<option value="0">Year</option>
    	<c&#58;forEach begin="$&#123;begin&#125;" end="$&#123;end&#125;" varStatus="loop">
    		<option value="$&#123;loop.index&#125;"
    			<c&#58;if test="$&#123;current == loop.index&#125;"> selected="selected"</c&#58;if>><c&#58;out
    			value="$&#123;loop.index&#125;" /></option>
    	</c&#58;forEach>
    </select>
    </spring&#58;bind>
    
    // Similar code repeated for month and day
    myDate is a wrapper object I made, a simple bean with month, year and day properties. On submitting this form Spring will call myDate.setYear(year), without a custom binder or property editor.

    What advantages do you think your approach has over using something like the above, which fits within the available Spring structure? In other words, what am I missing?

  6. #6
    Join Date
    Sep 2004
    Posts
    127

    Default simple approach using javacript

    A less generic but simple approach is to use javacript. On form submit, combine the parts into a hidden field. To Spring, that would look as if you were using a plain text input field. IMO, this qualifies as presentation logic and can therefore be handled at the view level.

    Cheers, Dan

  7. #7
    Join Date
    Sep 2005
    Location
    West Bloomfield, MI
    Posts
    32

    Default Complexity and Focus

    Wow, that's one hell of a complex solution! I like that it allows you to use the same mechanisms in Spring that other fields use, but it's an awful lot of code for such a simple requirement.

    Someone else mentioned using an intermediate object with three fields (I assume they were Strings, but it's not important). Does that mean that instead of Date objects in your domain you instead of this FauxDate (or whatever you call it) object? That's not good... now you're hacking your domain just to get around an issue....

    So on page 469 of Java Development with the Spring Framework, it has the proposed solutions to this issue.

    The first is to use Javascript -- as someone already suggested -- to merge the three fields into a single field and then use the CustomDateEditor.

    The second -- which is the way I decided to go on this issue -- is to simply override onBind() to accomplish the task.

    In my JSP, I have three fields -- dateOfBirthMonth, dateOfBirthDay, and dateOfBirthYear. I needed to put them into my command object, which is a Player object containing a java.util.Date for date of birth. Here's how I handled this in onBind():

    Code:
        protected void onBind( HttpServletRequest request, Object command ) throws Exception
        {
            Player p = (Player)command;
            Date dateOfBirth = CommonRequestUtils.getCompositeDate( request, "dateOfBirthMonth", "dateOfBirthDay", "dateOfBirthYear" );        
            p.setBirthDate( dateOfBirth );        
        }
    Nice and simple. Here's the getCompositeDate method which automatically handles invalid or missing date components. I use a custom exception, InvalidCompositeDateBindingException if the date is invalid -- it contains the offending field and value that failed so that I can tailor a validation message if need be.

    Code:
        public static final Date getCompositeDate( 
                HttpServletRequest request,
                String monthFieldName,
                String dayFieldName,
                String yearFieldName )
            throws ServletRequestBindingException
        {
            // Create an empty Calendar object for setting; we don't want any
            // time left over from the getInstance() call.
            Calendar cal = Calendar.getInstance();
            cal.setLenient( false );
            cal.clear();
            
            int year = RequestUtils.getRequiredIntParameter( request, yearFieldName );
            int month = RequestUtils.getRequiredIntParameter( request, monthFieldName ) - 1;
            int day = RequestUtils.getRequiredIntParameter( request, dayFieldName );
            
            cal.set( Calendar.YEAR, year );
            cal.set( Calendar.MONTH,  month );
            cal.set( Calendar.DAY_OF_MONTH, day );       
           
            // If any of the field setters failed, an InvalidCompositeDateBindingException will be thrown
            // containing the offending field.
           try
            {
                return cal.getTime();
            }
            catch ( IllegalArgumentException iiae )
            {            
                int fieldCode = -1;
                int fieldValue = -1;
                try
                {
                    fieldCode = Calendar.class.getField( iiae.getMessage() ).getInt( cal );
                    switch( fieldCode )
                    {
                        case Calendar.YEAR:
                            fieldValue = year;
                            break;
                        case Calendar.MONTH:
                            fieldValue = month;
                            break;
                        case Calendar.DAY_OF_MONTH:
                            fieldValue = day;
                            break;
                    }
                }
                catch ( NoSuchFieldException nsfe )
                {                
                    // ignore
                }
                catch ( IllegalAccessException iae )
                {            
                    // ignore
                }
                
                throw new InvalidCompositeDateBindingException( fieldCode, fieldValue );  
            }
        }
    }
    Hope this helps.

    Dan
    Last edited by dantelope; Jan 6th, 2006 at 09:11 PM.

  8. #8
    Join Date
    Aug 2004
    Location
    Hawaii, US
    Posts
    225

    Default

    You should post a feature request for this exact thing on the JIRA, and then attach your proposed solution. The Spring developers are very good at listening to the community's needs when it comes to stuff like this. (Though, don't be offended if Juergen totally rewrites it. That just means he thought it was a good idea

    FWIW, I've much wanted this functionality, so I hope it gets included into the main Spring.

  9. #9
    Join Date
    Sep 2005
    Location
    West Bloomfield, MI
    Posts
    32

    Red face On second thought...

    After having actually tried to use the method I posted above, I've decided that way sucks...

    I was trying to convert the form into a domain object, but I think that's not a smart way to. Instead, I've created a form object which contains a domain object and a helper bean consisting of the month, day, and year and a date-conversion method that either returns a date or, if the date is invalid, null.

    Then I do standard empty checks in my validator to ensure the date fields are filled in; then I check the date return for null to see if the date is invalid.

    This is significantly easier to deal with and makes much more sense from a development standpoint. It's easier to deal with these objects than to try to shoehorn Spring into doing something tricky like converting an entire form into a very complex domain object.

    Oh well, live and learn.

    Dan

  10. #10
    Join Date
    May 2006
    Location
    Darmstadt - Germany
    Posts
    142

    Default

    is it possible to make this bind withour never talking about day, month, year? to work only with date?
    this code is not working, but i think that there is some way to fix it... am i right?
    Code:
    <Spring:bind path="fxRate.fr_rpd_rp_date">
     <input type="text" name="fr_rpd_rp_date" size="10" value="${status.value}" />
    </Spring:bind>
    the date is shown, like yyyy-mm-dd... without any problem, but when this field is modificated, the onSubmid method is not called because, i think, of some validation of spring, that cannot "translate" this new yyyy-mm-dd in Date again... can u plz help me with that? i dont know, may be that is the best way that dhewitt showed us, but i found it a little bit big... :o
    thks a lot

Similar Threads

  1. FlowExecutionStorage in a DB
    By cacho in forum Web Flow
    Replies: 7
    Last Post: Oct 19th, 2009, 03:36 PM
  2. Replies: 2
    Last Post: May 9th, 2005, 06:25 PM
  3. Replies: 2
    Last Post: Jan 18th, 2005, 04:06 AM
  4. Binding to map properties
    By scroyston in forum Swing
    Replies: 1
    Last Post: Dec 3rd, 2004, 05:44 PM
  5. Replies: 2
    Last Post: Aug 17th, 2004, 04:16 PM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •