Title: [waffle-scm] [625] trunk/waffle-distribution/src/site/content: WAFFLE-68: Refactored bind value converters to return null for missing values, but allow behaviour to be overridden to throw a bind exception.

Diff

Added: trunk/examples/simple-example/src/main/java/org/codehaus/waffle/example/simple/StrictDateValueConverter.java (0 => 625)

--- trunk/examples/simple-example/src/main/java/org/codehaus/waffle/example/simple/StrictDateValueConverter.java	                        (rev 0)
+++ trunk/examples/simple-example/src/main/java/org/codehaus/waffle/example/simple/StrictDateValueConverter.java	2008-04-19 13:11:22 UTC (rev 625)
@@ -0,0 +1,22 @@
+package org.codehaus.waffle.example.simple;
+
+import org.codehaus.waffle.bind.converters.DateValueConverter;
+import org.codehaus.waffle.i18n.MessageResources;
+
+/**
+ * Extends DateValueConverter to enforce no missing values are allowed.
+ * 
+ * @author Mauro Talevi
+ */
+public class StrictDateValueConverter extends DateValueConverter {
+
+    public StrictDateValueConverter(MessageResources messageResources) {
+        super(messageResources);
+    }
+
+    @Override
+    protected Object convertMissingValue(String key, String defaultMessage, Object... parameters) {
+        throw newBindException(key, defaultMessage, parameters);
+    }
+    
+}

Modified: trunk/examples/simple-example/src/main/webapp/WEB-INF/web.xml (624 => 625)

--- trunk/examples/simple-example/src/main/webapp/WEB-INF/web.xml	2008-04-18 17:03:29 UTC (rev 624)
+++ trunk/examples/simple-example/src/main/webapp/WEB-INF/web.xml	2008-04-19 13:11:22 UTC (rev 625)
@@ -15,7 +15,7 @@
     <!-- 2. We are adding a custom components -->
     <context-param>
         <param-name>register:DateConverter</param-name>
-        <param-value>org.codehaus.waffle.bind.converters.DateValueConverter</param-value>
+        <param-value>org.codehaus.waffle.example.simple.StrictDateValueConverter</param-value>
     </context-param>
     <context-param>
         <param-name>org.codehaus.waffle.monitor.ActionMonitor</param-name>

Added: trunk/waffle-core/src/main/java/org/codehaus/waffle/bind/converters/AbstractValueConverter.java (0 => 625)

--- trunk/waffle-core/src/main/java/org/codehaus/waffle/bind/converters/AbstractValueConverter.java	                        (rev 0)
+++ trunk/waffle-core/src/main/java/org/codehaus/waffle/bind/converters/AbstractValueConverter.java	2008-04-19 13:11:22 UTC (rev 625)
@@ -0,0 +1,55 @@
+/*****************************************************************************
+ * Copyright (c) 2005-2008 Michael Ward                                      *
+ * All rights reserved.                                                      *
+ * ------------------------------------------------------------------------- *
+ * The software in this package is published under the terms of the BSD      *
+ * style license a copy of which has been included with this distribution in *
+ * the LICENSE.txt file.                                                     *
+ *                                                                           *
+ * Original code by: Mauro Talevi                                            *
+ *****************************************************************************/
+package org.codehaus.waffle.bind.converters;
+
+import org.codehaus.waffle.bind.BindException;
+import org.codehaus.waffle.bind.ValueConverter;
+import org.codehaus.waffle.i18n.MessageResources;
+
+/**
+ * Abstract <code>ValueConverter</code> that holds utility functionality common to all value converters.
+ * 
+ * @author Mauro Talevi
+ */
+public abstract class AbstractValueConverter implements ValueConverter {
+
+    protected final MessageResources messageResources;
+
+    protected AbstractValueConverter(MessageResources messageResources) {
+        this.messageResources = messageResources;
+    }
+
+    protected boolean missingValue(String value) {
+        return value == null || value.trim().length() == 0;
+    }
+
+    /**
+     * Handles the case of a missing value.  By default it return a <code>null</code> converted value,
+     * but can be overridden to throw a BindException
+     * 
+     * @param key the error message key
+     * @param defaultMessage the default message if key is not found
+     * @param parameters the message formatting parameters
+     * @return A converted object when value is missing, <code>null</code> by default.
+     */
+    protected Object convertMissingValue(String key, String defaultMessage, Object... parameters) {
+        return null;
+    }
+    
+    protected BindException newBindException(String key, String defaultMessage, Object... parameters) {
+        String message = messageResources.getMessageWithDefault(key, defaultMessage, parameters);
+        return new BindException(message);
+    }
+
+    protected String messageFor(String key, String defaultMessage, Object... parameters) {
+        return messageResources.getMessageWithDefault(key, defaultMessage, parameters);
+    }
+}

Modified: trunk/waffle-core/src/main/java/org/codehaus/waffle/bind/converters/DateValueConverter.java (624 => 625)

--- trunk/waffle-core/src/main/java/org/codehaus/waffle/bind/converters/DateValueConverter.java	2008-04-18 17:03:29 UTC (rev 624)
+++ trunk/waffle-core/src/main/java/org/codehaus/waffle/bind/converters/DateValueConverter.java	2008-04-19 13:11:22 UTC (rev 625)
@@ -10,14 +10,12 @@
  *****************************************************************************/
 package org.codehaus.waffle.bind.converters;
 
-import org.codehaus.waffle.bind.BindException;
-import org.codehaus.waffle.bind.ValueConverter;
-import org.codehaus.waffle.i18n.MessageResources;
-
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.Date;
 
+import org.codehaus.waffle.i18n.MessageResources;
+
 /**
  * <code>ValueConverter</code> that converts Date values.  The date format is configurable via the message resources bundle.
  * A <code>null</code>, empty or invalid value will cause a BindException to be thrown.
@@ -31,17 +29,16 @@
  * @author Michael Ward
  * @author Mauro Talevi
  */
-public class DateValueConverter implements ValueConverter {
+public class DateValueConverter extends AbstractValueConverter {
     static final String BIND_ERROR_DATE_KEY = "bind.error.date";
     static final String BIND_ERROR_DATE_MISSING_KEY = "bind.error.date.missing";
     static final String DATE_FORMAT_KEY = "date.format";
     static final String DEFAULT_DATE_FORMAT = "dd/MM/yyyy";
     static final String DEFAULT_DATE_MESSAGE = "Invalid date {1} (using format {2}) for field {0}";
     static final String DEFAULT_DATE_MISSING_MESSAGE = "Missing date value for field {0}";
-    private final MessageResources messageResources;
 
     public DateValueConverter(MessageResources messageResources) {
-        this.messageResources = messageResources;
+        super(messageResources);
     }
 
     public boolean accept(Class<?> type) {
@@ -50,19 +47,17 @@
 
     @SuppressWarnings({"unchecked"})
     public <T> T convertValue(String propertyName, String value, Class<T> toType) {
-        String fieldName = messageResources.getMessageWithDefault(propertyName, propertyName);
-        if (value == null || value.trim().length() == 0) {
-            String message = messageResources.getMessageWithDefault(BIND_ERROR_DATE_MISSING_KEY, DEFAULT_DATE_MISSING_MESSAGE, fieldName);
-            throw new BindException(message);
+        String fieldName = messageFor(propertyName, propertyName);
+        if ( missingValue(value) ) {            
+            return (T) convertMissingValue(BIND_ERROR_DATE_MISSING_KEY, DEFAULT_DATE_MISSING_MESSAGE, fieldName);
         }
 
-        String dateFormat = messageResources.getMessageWithDefault(DATE_FORMAT_KEY, DEFAULT_DATE_FORMAT);
+        String dateFormat = messageFor(DATE_FORMAT_KEY, DEFAULT_DATE_FORMAT);
 
         try {
             return (T) new SimpleDateFormat(dateFormat).parse(value);
         } catch (ParseException e) {
-            String message = messageResources.getMessageWithDefault(BIND_ERROR_DATE_KEY, DEFAULT_DATE_MESSAGE, fieldName, value, dateFormat);
-            throw new BindException(message);
+            throw newBindException(BIND_ERROR_DATE_KEY, DEFAULT_DATE_MESSAGE, fieldName, value, dateFormat);
         }
     }
 

Modified: trunk/waffle-core/src/main/java/org/codehaus/waffle/bind/converters/ListValueConverter.java (624 => 625)

--- trunk/waffle-core/src/main/java/org/codehaus/waffle/bind/converters/ListValueConverter.java	2008-04-18 17:03:29 UTC (rev 624)
+++ trunk/waffle-core/src/main/java/org/codehaus/waffle/bind/converters/ListValueConverter.java	2008-04-19 13:11:22 UTC (rev 625)
@@ -19,8 +19,6 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import org.codehaus.waffle.bind.BindException;
-import org.codehaus.waffle.bind.ValueConverter;
 import org.codehaus.waffle.i18n.MessageResources;
 
 /**
@@ -37,15 +35,14 @@
  * 
  * @author Mauro Talevi
  */
-public class ListValueConverter implements ValueConverter {
+public class ListValueConverter extends AbstractValueConverter {
 
     static final String BIND_ERROR_LIST_KEY = "bind.error.list";
     static final String DEFAULT_LIST_MESSAGE = "Invalid list value for field {0}";
     private static final String COMMA = ",";
-    private final MessageResources messageResources;
 
     public ListValueConverter(MessageResources messageResources) {
-        this.messageResources = messageResources;
+        super(messageResources);
     }
 
     public boolean accept(Class<?> type) {
@@ -54,12 +51,12 @@
 
     @SuppressWarnings( { "unchecked" })
     public <T> T convertValue(String propertyName, String value, Class<T> toType) {
-        if (value == null) {
-            String fieldName = messageResources.getMessageWithDefault(propertyName, propertyName);
-            String message = messageResources.getMessageWithDefault(BIND_ERROR_LIST_KEY,
-                    DEFAULT_LIST_MESSAGE, fieldName);
-            throw new BindException(message);
+
+        if ( missingValue(value)){
+            String fieldName = messageFor(propertyName, propertyName);
+            return (T)convertMissingValue(BIND_ERROR_LIST_KEY, DEFAULT_LIST_MESSAGE, fieldName);
         }
+
         List<String> values = asList(value.split(COMMA));        
         if ( values.size() == 0 ){
             return (T) values;

Modified: trunk/waffle-core/src/test/java/org/codehaus/waffle/bind/converters/DateValueConverterTest.java (624 => 625)

--- trunk/waffle-core/src/test/java/org/codehaus/waffle/bind/converters/DateValueConverterTest.java	2008-04-18 17:03:29 UTC (rev 624)
+++ trunk/waffle-core/src/test/java/org/codehaus/waffle/bind/converters/DateValueConverterTest.java	2008-04-19 13:11:22 UTC (rev 625)
@@ -8,7 +8,9 @@
 import static org.codehaus.waffle.bind.converters.DateValueConverter.DEFAULT_DATE_MESSAGE;
 import static org.codehaus.waffle.bind.converters.DateValueConverter.DEFAULT_DATE_MISSING_MESSAGE;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import java.text.SimpleDateFormat;
 import java.util.Date;
@@ -61,6 +63,15 @@
 
         assertEquals("04/03/2008", new SimpleDateFormat(DEFAULT_DATE_FORMAT).format(date));
     }
+    
+    @Test
+    public void canHandleMissingValues() {
+        DefaultMessageResources resources = new DefaultMessageResources(configuration);
+        DateValueConverter converter = new DateValueConverter(resources);
+        assertNull(converter.convertValue("property-name", null, Date.class));
+        assertNull(converter.convertValue("property-name", "", Date.class));
+        assertNull(converter.convertValue("property-name", " ", Date.class));
+     }
 
     @Test
     public void canFailConversionWithCustomErrorMessages() {
@@ -68,11 +79,19 @@
         DateValueConverter converter = new DateValueConverter(resources);
         try {
             converter.convertValue("property-name", "bad-value", Date.class);
+            fail("Expected BindException");
         } catch ( BindException e) {
             assertEquals(format(resources.getMessage(BIND_ERROR_DATE_KEY), "property-name", "bad-value", resources.getMessage(DATE_FORMAT_KEY)), e.getMessage());
         }
+        DateValueConverter strictConverter = new DateValueConverter(resources){
+            @Override
+            protected Object convertMissingValue(String key, String defaultMessage, Object... parameters) {
+               throw newBindException(key, defaultMessage, parameters);
+            }
+        };
         try {
-            converter.convertValue("property-name", null, Date.class);
+            strictConverter.convertValue("property-name", null, Date.class);
+            fail("Expected BindException");
         } catch ( BindException e) {
             assertEquals(format(resources.getMessage(BIND_ERROR_DATE_MISSING_KEY), "property-name"), e.getMessage());
         }
@@ -83,11 +102,19 @@
         DateValueConverter converter = new DateValueConverter(new DefaultMessageResources());
         try {
             converter.convertValue("property-name", "bad-value", Date.class);
+            fail("Expected BindException");
         } catch ( BindException e) {
             assertEquals(format(DEFAULT_DATE_MESSAGE, "property-name", "bad-value", DEFAULT_DATE_FORMAT), e.getMessage());
         }
+        DateValueConverter strictConverter = new DateValueConverter(new DefaultMessageResources()){
+            @Override
+            protected Object convertMissingValue(String key, String defaultMessage, Object... parameters) {
+               throw newBindException(key, defaultMessage, parameters);
+            }
+        };
         try {
-            converter.convertValue("property-name", null, Date.class);
+            strictConverter.convertValue("property-name", null, Date.class);
+            fail("Expected BindException");
         } catch ( BindException e) {
             assertEquals(format(DEFAULT_DATE_MISSING_MESSAGE, "property-name"), e.getMessage());
         }

Modified: trunk/waffle-core/src/test/java/org/codehaus/waffle/bind/converters/ListValueConverterTest.java (624 => 625)

--- trunk/waffle-core/src/test/java/org/codehaus/waffle/bind/converters/ListValueConverterTest.java	2008-04-18 17:03:29 UTC (rev 624)
+++ trunk/waffle-core/src/test/java/org/codehaus/waffle/bind/converters/ListValueConverterTest.java	2008-04-19 13:11:22 UTC (rev 625)
@@ -3,7 +3,9 @@
 import static java.text.MessageFormat.format;
 import static java.util.Arrays.asList;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import java.util.List;
 import java.util.Locale;
@@ -58,11 +60,26 @@
     }
 
     @Test
+    public void canHandleMissingValues() {
+        ListValueConverter converter = new ListValueConverter(new DefaultMessageResources());
+        assertNull(converter.convertValue("property-name", null, List.class));
+        assertNull(converter.convertValue("property-name", "", List.class));
+        assertNull(converter.convertValue("property-name", " ", List.class));
+     }
+
+    @Test
     public void canFailConversionWithCustomErrorMessages() {
         DefaultMessageResources resources = new DefaultMessageResources(configuration);
-        ListValueConverter converter = new ListValueConverter(resources);
+        ListValueConverter converter = new ListValueConverter(resources){
+
+            @Override
+            protected Object convertMissingValue(String key, String defaultMessage, Object... parameters) {
+               throw newBindException(key, defaultMessage, parameters);
+            }
+        };
         try {
             converter.convertValue("property-name", null, List.class);
+            fail("Expected BindException");
         } catch ( BindException e) {
             assertEquals(format(resources.getMessage(ListValueConverter.BIND_ERROR_LIST_KEY), "property-name"), e.getMessage());
         }
@@ -70,9 +87,15 @@
 
     @Test
     public void canFailConversionWithDefaultErrorMessages() {
-        ListValueConverter converter = new ListValueConverter(new DefaultMessageResources());
+        ListValueConverter converter = new ListValueConverter(new DefaultMessageResources()){
+            @Override
+            protected Object convertMissingValue(String key, String defaultMessage, Object... parameters) {
+               throw newBindException(key, defaultMessage, parameters);
+            }
+        };
         try {
             converter.convertValue("property-name", null, List.class);
+            fail("Expected BindException");
         } catch ( BindException e) {
             assertEquals(format(ListValueConverter.DEFAULT_LIST_MESSAGE, "property-name"), e.getMessage());
         }

Modified: trunk/waffle-core/src/test/java/org/codehaus/waffle/bind/ognl/DelegatingTypeConverterTest.java (624 => 625)

--- trunk/waffle-core/src/test/java/org/codehaus/waffle/bind/ognl/DelegatingTypeConverterTest.java	2008-04-18 17:03:29 UTC (rev 624)
+++ trunk/waffle-core/src/test/java/org/codehaus/waffle/bind/ognl/DelegatingTypeConverterTest.java	2008-04-19 13:11:22 UTC (rev 625)
@@ -2,11 +2,11 @@
 
 import static java.util.Arrays.asList;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
 
 import java.util.List;
 
-import org.codehaus.waffle.bind.BindException;
 import org.codehaus.waffle.bind.ValueConverter;
 import org.codehaus.waffle.bind.converters.ListValueConverter;
 import org.codehaus.waffle.context.ContextLevel;
@@ -30,37 +30,23 @@
     @Test
     public void canConvertValueForEnum() {
         DelegatingTypeConverter converter = new DelegatingTypeConverter();
-        Object result = converter.convertValue("foobar", "APPLICATION", ContextLevel.class);
-
-        assertEquals(ContextLevel.APPLICATION, result);
+        assertEquals(ContextLevel.APPLICATION, converter.convertValue("foobar", "APPLICATION", ContextLevel.class));
     }
 
     @Test
     public void canConvertValueForIntegers() {
         DelegatingTypeConverter converter = new DelegatingTypeConverter();
-        int value = (Integer) converter.convertValue("foobar", "15", Integer.class);
-
-        assertEquals(15, value);
+        assertEquals(15, converter.convertValue("foobar", "15", Integer.class));
     }
     
     @Test
     public void canDelegateToListValueConverter() {
         final ValueConverter valueConverter = new ListValueConverter(new DefaultMessageResources());
-        final List<String> list = asList("one","two");
         DelegatingTypeConverter converter = new DelegatingTypeConverter(new OgnlValueConverterFinder(valueConverter));
-
-        Object convertedValue = converter.convertValue("propertyName", "one,two", List.class);
-        assertEquals(convertedValue, list);
+        assertEquals(asList("one","two"), converter.convertValue("propertyName", "one,two", List.class));
+        assertNull(converter.convertValue("propertyName", "", List.class));
     }
-    
-    @Test(expected=BindException.class)
-    public void cannotDelegateToListValueConverterNullValue() {
-        final ValueConverter valueConverter = new ListValueConverter(new DefaultMessageResources());
-        DelegatingTypeConverter converter = new DelegatingTypeConverter(new OgnlValueConverterFinder(valueConverter));
         
-        converter.convertValue("propertyName", null, List.class);
-    }
-    
     @Test
     public void canDelegateToCustomValueConverter() {
         // Mock ValueConverter 
@@ -75,9 +61,7 @@
             }
         });
         DelegatingTypeConverter converter = new DelegatingTypeConverter(new OgnlValueConverterFinder(valueConverter));
-
-        Object convertedValue = converter.convertValue("propertyName", "foobar", CustomType.class);
-        assertSame(convertedValue, type);
+        assertSame(type, converter.convertValue("propertyName", "foobar", CustomType.class));
     }
     
     private static interface CustomType {};

Modified: trunk/waffle-distribution/src/site/content/binding.html (624 => 625)

--- trunk/waffle-distribution/src/site/content/binding.html	2008-04-18 17:03:29 UTC (rev 624)
+++ trunk/waffle-distribution/src/site/content/binding.html	2008-04-19 13:11:22 UTC (rev 625)
@@ -156,6 +156,25 @@
       </tbody>
     </table>
 
+    <p>
+      Note that by default these converters handle missing values (ie <code>null</code> or empty) by return a <code>null</code> converted value,  
+      The behaviour can be nonetheless overridden by extending the converters to throw a new <code>BindException</code> in the 
+      <code>convertMissingValue</code> method:
+
+    <textarea class="java:nogutter:nocontrols" name="code">
+public class StringDateValueConverter extends DateValueConverter {
+   public StrictDateValueConverter(MessageResources messageResources) {
+        super(messageResources);
+    }
+
+    @Override
+    protected Object convertMissingValue(String key, String defaultMessage, Object... parameters) {
+        throw newBindException(key, defaultMessage, parameters);
+    }
+}
+    </textarea>
+    </p> 
+
   </body>
 
 </html>


To unsubscribe from this list please visit:

http://xircles.codehaus.org/manage_email

Reply via email to