Title: [waffle-scm] [753] trunk/examples/freemarker-example/src/main/webapp/people: WAFFLE-90: Added NumberValueConverter to override OGNL number conversion.

Diff

Modified: trunk/examples/freemarker-example/src/main/java/org/codehaus/waffle/example/freemarker/controller/PersonController.java (752 => 753)

--- trunk/examples/freemarker-example/src/main/java/org/codehaus/waffle/example/freemarker/controller/PersonController.java	2008-06-21 15:49:43 UTC (rev 752)
+++ trunk/examples/freemarker-example/src/main/java/org/codehaus/waffle/example/freemarker/controller/PersonController.java	2008-06-21 17:46:54 UTC (rev 753)
@@ -8,6 +8,7 @@
 import java.util.Collection;
 import java.util.List;
 
+import org.codehaus.waffle.action.annotation.ActionMethod;
 import org.codehaus.waffle.example.freemarker.model.Person;
 import org.codehaus.waffle.example.freemarker.model.Person.Type;
 import org.codehaus.waffle.example.freemarker.persister.PersistablePerson;
@@ -22,6 +23,7 @@
     private Person person;
     private List<Long> selectedIds = new ArrayList<Long>();
     private List<String> skills = Arrays.asList("Magician", "Apprentice");
+    private Long id;
 
     public PersonController(PersonPersister persister, DateProvider dateProvider) {
         this.persister = persister;
@@ -36,10 +38,10 @@
         return persister.findAll();
     }
 
-    public List<Type> getTypes(){
+    public List<Type> getTypes() {
         return asList(Type.values());
     }
-    
+
     public List<Long> getSelectedIds() {
         return selectedIds;
     }
@@ -56,6 +58,14 @@
         return selected;
     }
 
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
     public Person getPerson() {
         return person;
     }
@@ -72,10 +82,15 @@
         persister.delete(personId);
     }
 
+    @ActionMethod(parameters = { "id" })
     public void select(Long id) {
         this.person = persister.findById(id);
     }
 
+    public void select() {
+        this.person = persister.findById(id);
+    }
+
     public void show() {
         // do nothing: the selected Ids and people are automatically populated
     }

Modified: trunk/examples/freemarker-example/src/main/java/org/codehaus/waffle/example/freemarker/model/Person.java (752 => 753)

--- trunk/examples/freemarker-example/src/main/java/org/codehaus/waffle/example/freemarker/model/Person.java	2008-06-21 15:49:43 UTC (rev 752)
+++ trunk/examples/freemarker-example/src/main/java/org/codehaus/waffle/example/freemarker/model/Person.java	2008-06-21 17:46:54 UTC (rev 753)
@@ -37,6 +37,8 @@
     
     boolean isWizard();
     
+    double getMagicNumber();
+
     String getNotes();
     
 }

Modified: trunk/examples/freemarker-example/src/main/java/org/codehaus/waffle/example/freemarker/persister/PersistablePerson.java (752 => 753)

--- trunk/examples/freemarker-example/src/main/java/org/codehaus/waffle/example/freemarker/persister/PersistablePerson.java	2008-06-21 15:49:43 UTC (rev 752)
+++ trunk/examples/freemarker-example/src/main/java/org/codehaus/waffle/example/freemarker/persister/PersistablePerson.java	2008-06-21 17:46:54 UTC (rev 753)
@@ -23,6 +23,7 @@
     private List<Double> grades;
     private String notes;
     private boolean wizard;
+    private double magicNumber;
     private Type type;
     private Person bestFriend;
     private List<Person> friends;
@@ -43,6 +44,7 @@
         notes = "";
         type = Type.APPRENTICE;
         wizard = false;
+        magicNumber = 0.d;
     }
 
     public PersistablePerson(Person person) {
@@ -61,6 +63,7 @@
         this.notes = person.getNotes();
         this.type = person.getType();
         this.wizard = person.isWizard();
+        this.magicNumber = person.getMagicNumber();
     }
 
     public Long getId() {
@@ -187,6 +190,14 @@
         this.wizard = wizard;
     }
 
+    public double getMagicNumber() {
+        return magicNumber;
+    }
+
+    public void setMagicNumber(double magicNumber) {
+        this.magicNumber = magicNumber;
+    }
+
     @Override
     public String toString() {
         return ToStringBuilder.reflectionToString(this, SHORT_PREFIX_STYLE);

Modified: trunk/examples/freemarker-example/src/main/webapp/WEB-INF/web.xml (752 => 753)

--- trunk/examples/freemarker-example/src/main/webapp/WEB-INF/web.xml	2008-06-21 15:49:43 UTC (rev 752)
+++ trunk/examples/freemarker-example/src/main/webapp/WEB-INF/web.xml	2008-06-21 17:46:54 UTC (rev 753)
@@ -16,6 +16,10 @@
     <param-value>org.codehaus.waffle.bind.converters.DateValueConverter</param-value>
   </context-param>
   <context-param>
+    <param-name>register:NumberValueConverter</param-name>
+    <param-value>org.codehaus.waffle.bind.converters.NumberValueConverter</param-value>
+  </context-param>
+  <context-param>
     <param-name>register:StringListValueConverter</param-name>
     <param-value>org.codehaus.waffle.bind.converters.StringListValueConverter</param-value>
   </context-param>

Modified: trunk/examples/freemarker-example/src/main/webapp/people/edit.ftl (752 => 753)

--- trunk/examples/freemarker-example/src/main/webapp/people/edit.ftl	2008-06-21 15:49:43 UTC (rev 752)
+++ trunk/examples/freemarker-example/src/main/webapp/people/edit.ftl	2008-06-21 17:46:54 UTC (rev 753)
@@ -81,6 +81,10 @@
             <@w.text "person.wizard" "${person.wizard?string}"/>
         </p>
         <p class="fieldRow">
+            <label for="" Number:</label>
+            <@w.text "person.magicNumber" "${person.magicNumber}"/>
+        </p>
+        <p class="fieldRow">
             <label for=""
             <@w.textarea "person.notes" "${person.notes}" />
         </p>

Modified: trunk/examples/freemarker-example/src/main/webapp/people/manage.ftl (752 => 753)

--- trunk/examples/freemarker-example/src/main/webapp/people/manage.ftl	2008-06-21 15:49:43 UTC (rev 752)
+++ trunk/examples/freemarker-example/src/main/webapp/people/manage.ftl	2008-06-21 17:46:54 UTC (rev 753)
@@ -23,7 +23,7 @@
         <#list people as person>
             <tr class="odd">
                 <td>
-                    <a href=""
+                    <a href=""
                 </td>
                 <td>${person.firstName}</td>
                 <td>${person.lastName}</td>

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

--- trunk/waffle-core/src/main/java/org/codehaus/waffle/bind/converters/NumberValueConverter.java	                        (rev 0)
+++ trunk/waffle-core/src/main/java/org/codehaus/waffle/bind/converters/NumberValueConverter.java	2008-06-21 17:46:54 UTC (rev 753)
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) terms as published in http://waffle.codehaus.org/license.html
+ */
+package org.codehaus.waffle.bind.converters;
+
+import java.lang.reflect.Type;
+import java.text.NumberFormat;
+import java.text.ParseException;
+import java.util.Properties;
+
+import org.codehaus.waffle.i18n.MessageResources;
+
+/**
+ * <p>
+ * <code>ValueConverter</code> that converts a value to a Numbers using the <code>NumberFormat</code> instance
+ * provided (which defaults to <code>NumberFormat.getInstance()</code>).
+ * </p>
+ * The message keys and default values used are:
+ * <ul>
+ * <li>"bind.error.number" ([EMAIL PROTECTED] #BIND_ERROR_NUMBER_KEY}): bind error in number parsing (message defaults to
+ * [EMAIL PROTECTED] #DEFAULT_NUMBER_MESSAGE})</li>
+ * <li>"bind.error.number.missing" ([EMAIL PROTECTED] #BIND_ERROR_NUMBER_MISSING_KEY}): number is <code>null</code> or empty
+ * (message defaults to [EMAIL PROTECTED] #DEFAULT_NUMBER_MISSING_MESSAGE})</li>
+ * </ul>
+ * 
+ * @author Mauro Talevi
+ */
+public class NumberValueConverter extends AbstractValueConverter {
+    public static final String BIND_ERROR_NUMBER_KEY = "bind.error.number";
+    public static final String BIND_ERROR_NUMBER_MISSING_KEY = "bind.error.number.missing";
+    public static final String DEFAULT_NUMBER_MISSING_MESSAGE = "Missing number value for field {0}";
+    public static final String DEFAULT_NUMBER_MESSAGE = "Invalid number {1} (using format {2}) for field {0}";
+
+    private NumberFormat numberFormat;
+
+    public NumberValueConverter(MessageResources messageResources) {
+        this(messageResources, new Properties(), NumberFormat.getInstance());
+    }
+
+    public NumberValueConverter(MessageResources messageResources, Properties patterns, NumberFormat numberFormat) {
+        super(messageResources, patterns);
+        this.numberFormat = numberFormat;
+    }
+
+    public boolean accept(Type type) {
+        if (type instanceof Class) {
+            Class<?> rawType = (Class<?>) type;
+            return Number.class.isAssignableFrom(rawType) || double.class.equals(rawType)
+                    || float.class.equals(rawType) || long.class.equals(rawType) || int.class.equals(rawType);
+        }
+        return false;
+    }
+
+    @SuppressWarnings( { "unchecked" })
+    public Object convertValue(String propertyName, String value, Type toType) {
+        String fieldName = messageFor(propertyName, propertyName);
+        if (missingValue(value)) {
+            return convertMissingValue(BIND_ERROR_NUMBER_MISSING_KEY, DEFAULT_NUMBER_MISSING_MESSAGE, fieldName);
+        }
+
+        try {
+            return numberFormat.parse(value);
+        } catch (ParseException e) {
+            e.printStackTrace();
+            throw newBindException(BIND_ERROR_NUMBER_KEY, DEFAULT_NUMBER_MESSAGE, fieldName, value, numberFormat);
+        }
+    }
+
+}

Added: trunk/waffle-core/src/test/java/org/codehaus/waffle/bind/converters/NumberValueConverterTest.java (0 => 753)

--- trunk/waffle-core/src/test/java/org/codehaus/waffle/bind/converters/NumberValueConverterTest.java	                        (rev 0)
+++ trunk/waffle-core/src/test/java/org/codehaus/waffle/bind/converters/NumberValueConverterTest.java	2008-06-21 17:46:54 UTC (rev 753)
@@ -0,0 +1,62 @@
+package org.codehaus.waffle.bind.converters;
+
+import static org.codehaus.waffle.testmodel.FakeControllerWithNumberMethods.methodParameterType;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.beans.IntrospectionException;
+
+import ognl.OgnlException;
+
+import org.codehaus.waffle.bind.BindException;
+import org.codehaus.waffle.i18n.DefaultMessageResources;
+import org.junit.Test;
+
+/**
+ * @author Mauro Talevi
+ */
+public class NumberValueConverterTest extends AbstractValueConverterTest {
+
+    @Test
+    public void canAccept() throws IntrospectionException {
+        NumberValueConverter converter = new NumberValueConverter(new DefaultMessageResources());
+        assertTrue(converter.accept(Number.class));
+        assertTrue(converter.accept(Double.class));
+        assertTrue(converter.accept(methodParameterType("primitiveDouble")));
+        assertTrue(converter.accept(Float.class));
+        assertTrue(converter.accept(methodParameterType("primitiveFloat")));
+        assertTrue(converter.accept(Long.class));
+        assertTrue(converter.accept(methodParameterType("primitiveLong")));
+        assertTrue(converter.accept(Integer.class));
+        assertTrue(converter.accept(methodParameterType("primitiveInteger")));
+        assertFalse(converter.accept(Object.class));
+    }
+    
+    @Test
+    public void canConvertNumbers() throws OgnlException, IntrospectionException {
+        NumberValueConverter converter = new NumberValueConverter(new DefaultMessageResources());
+        assertCanConvertValueToNumber(converter, -1, "-1", Long.class);
+        assertCanConvertValueToNumber(converter, -1E3, "-1,000", Long.class);
+        assertCanConvertValueToNumber(converter, 1E3, "1000", Long.class);
+        assertCanConvertValueToNumber(converter, 1E3, "1,000", Long.class);
+        assertCanConvertValueToNumber(converter, 1E6, "1,000,000", Long.class);
+        assertCanConvertValueToNumber(converter, 0.1, "0.1", Double.class);
+        assertCanConvertValueToNumber(converter, 0.1E-3, ".1E-3", Double.class);
+    }
+
+    @Test(expected=BindException.class)
+    public void cannotParseInvalidNumber() throws OgnlException, IntrospectionException {
+        NumberValueConverter converter = new NumberValueConverter(new DefaultMessageResources());
+        converter.convertValue("property-name", "invalid-number", Number.class); 
+    }
+
+    @SuppressWarnings("unchecked")
+    private void assertCanConvertValueToNumber(NumberValueConverter converter, Number expected, String value,
+            Class<?> expectedType) throws IntrospectionException {
+        Number actual = (Number)converter.convertValue("property-name", value, Number.class);
+        assertEquals(expected.doubleValue(), actual.doubleValue(),1E-6);
+    }
+
+
+}

Modified: trunk/waffle-core/src/test/java/org/codehaus/waffle/bind/ognl/OgnlControllerDataBinderTest.java (752 => 753)

--- trunk/waffle-core/src/test/java/org/codehaus/waffle/bind/ognl/OgnlControllerDataBinderTest.java	2008-06-21 15:49:43 UTC (rev 752)
+++ trunk/waffle-core/src/test/java/org/codehaus/waffle/bind/ognl/OgnlControllerDataBinderTest.java	2008-06-21 17:46:54 UTC (rev 753)
@@ -16,9 +16,11 @@
 import org.codehaus.waffle.bind.BindErrorMessageResolver;
 import org.codehaus.waffle.bind.BindException;
 import org.codehaus.waffle.bind.ControllerDataBinder;
+import org.codehaus.waffle.bind.converters.NumberValueConverter;
 import org.codehaus.waffle.bind.converters.StringListValueConverter;
 import org.codehaus.waffle.context.ContextLevel;
 import org.codehaus.waffle.i18n.DefaultMessageResources;
+import org.codehaus.waffle.i18n.MessageResources;
 import org.codehaus.waffle.monitor.SilentMonitor;
 import org.codehaus.waffle.testmodel.FakeBean;
 import org.codehaus.waffle.testmodel.FakeController;
@@ -40,6 +42,8 @@
 @RunWith(JMock.class)
 public class OgnlControllerDataBinderTest {
 
+    private static final MessageResources MESSAGE_RESOURCES = new DefaultMessageResources();
+    private static final SilentMonitor MONITOR = new SilentMonitor();
     private Mockery mockery = new Mockery();
 
     @Test
@@ -63,7 +67,7 @@
         });
 
         FakeController fakeController = new FakeController();
-        ControllerDataBinder binder = new OgnlControllerDataBinder(new OgnlValueConverterFinder(), null, new SilentMonitor());
+        ControllerDataBinder binder = new OgnlControllerDataBinder(new OgnlValueConverterFinder(), null, MONITOR);
         ErrorsContext errorsContext = new DefaultErrorsContext(null);
         binder.bind(request, null, errorsContext, fakeController);
 
@@ -73,8 +77,36 @@
     }
     
     @Test
-    public void canBindListValues() {
+    public void canBindNumberValues() {
         List<String> parameters = new ArrayList<String>();
+        parameters.add("number");
+        final Enumeration<String> enumeration = Collections.enumeration(parameters);
+
+        // Mock HttpServletRequest
+        final String[] values = new String[]{"1,000"};
+        final HttpServletRequest request = mockery.mock(HttpServletRequest.class);
+        mockery.checking(new Expectations() {
+            {
+                one(request).getParameterNames();
+                will(returnValue(enumeration));
+                one(request).getParameterValues("number");
+                will(returnValue(values));
+            }
+        });
+
+        FakeController fakeController = new FakeController();
+        OgnlValueConverterFinder finder = new OgnlValueConverterFinder(new NumberValueConverter(MESSAGE_RESOURCES));
+        ControllerDataBinder binder = new OgnlControllerDataBinder(finder, null, MONITOR);
+        ErrorsContext errorsContext = new DefaultErrorsContext(null);
+        binder.bind(request, null, errorsContext, fakeController);
+
+        assertEquals(1000L, fakeController.getNumber());
+        assertFalse(errorsContext.hasErrorMessages());
+    }    
+    
+    @Test
+    public void canBindStringListValues() {
+        List<String> parameters = new ArrayList<String>();
         parameters.add("list");
         final Enumeration<String> enumeration = Collections.enumeration(parameters);
 
@@ -91,13 +123,15 @@
         });
 
         FakeController fakeController = new FakeController();
-        ControllerDataBinder binder = new OgnlControllerDataBinder(new OgnlValueConverterFinder(new StringListValueConverter(new DefaultMessageResources())), null, new SilentMonitor());
+        OgnlValueConverterFinder finder = new OgnlValueConverterFinder(new StringListValueConverter(MESSAGE_RESOURCES));
+        ControllerDataBinder binder = new OgnlControllerDataBinder(finder, null, MONITOR);
         ErrorsContext errorsContext = new DefaultErrorsContext(null);
         binder.bind(request, null, errorsContext, fakeController);
 
         assertEquals(asList(values), fakeController.getList());
         assertFalse(errorsContext.hasErrorMessages());
     }
+        
        
     @Test
     public void canBindEmptyValueForEnum() {
@@ -117,7 +151,7 @@
         });
 
         FakeController fakeController = new FakeController();
-        ControllerDataBinder binder = new OgnlControllerDataBinder(new OgnlValueConverterFinder(), null, new SilentMonitor());
+        ControllerDataBinder binder = new OgnlControllerDataBinder(new OgnlValueConverterFinder(), null, MONITOR);
         ErrorsContext errorsContext = new DefaultErrorsContext(null);
         binder.bind(request, null, errorsContext, fakeController);
 
@@ -143,7 +177,7 @@
         });
 
         FakeController fakeController = new FakeController();
-        ControllerDataBinder binder = new OgnlControllerDataBinder(new OgnlValueConverterFinder(), null, new SilentMonitor());
+        ControllerDataBinder binder = new OgnlControllerDataBinder(new OgnlValueConverterFinder(), null, MONITOR);
 
         ErrorsContext errorsContext = new DefaultErrorsContext(null);
         binder.bind(request, null, errorsContext, fakeController);
@@ -172,7 +206,7 @@
         });
 
         FakeController fakeController = new FakeController();
-        ControllerDataBinder binder = new OgnlControllerDataBinder(new OgnlValueConverterFinder(), null, new SilentMonitor());
+        ControllerDataBinder binder = new OgnlControllerDataBinder(new OgnlValueConverterFinder(), null, MONITOR);
 
         ErrorsContext errorsContext = new DefaultErrorsContext(null);
         binder.bind(request, null, errorsContext, fakeController);
@@ -204,7 +238,7 @@
             }
         });
 
-        ControllerDataBinder binder = new OgnlControllerDataBinder(new OgnlValueConverterFinder(), resolver, new SilentMonitor());
+        ControllerDataBinder binder = new OgnlControllerDataBinder(new OgnlValueConverterFinder(), resolver, MONITOR);
 
         ErrorsContext errorsContext = new DefaultErrorsContext(null);
         binder.bind(request, null, errorsContext, new FakeBean());
@@ -235,7 +269,7 @@
             }
         });
 
-        ControllerDataBinder binder = new OgnlControllerDataBinder(new OgnlValueConverterFinder(), null, new SilentMonitor()) {
+        ControllerDataBinder binder = new OgnlControllerDataBinder(new OgnlValueConverterFinder(), null, MONITOR) {
             protected Object handleConvert(String parameterName, String parameterValue, Object model) {
                 throw new BindException("fake from test");
             }

Modified: trunk/waffle-core/src/test/java/org/codehaus/waffle/testmodel/FakeController.java (752 => 753)

--- trunk/waffle-core/src/test/java/org/codehaus/waffle/testmodel/FakeController.java	2008-06-21 15:49:43 UTC (rev 752)
+++ trunk/waffle-core/src/test/java/org/codehaus/waffle/testmodel/FakeController.java	2008-06-21 17:46:54 UTC (rev 753)
@@ -18,7 +18,7 @@
     private String name;
     private String[] values;
     private List<String> list;
-    private Long numericValue;
+    private Number number;
     private ContextLevel contextLevel;
     private HttpServletRequest request;
     private HttpServletResponse response;
@@ -31,15 +31,15 @@
     public void setName(String name) {
         this.name = name;
     }
+    
+    public Number getNumber() {
+        return number;
+    }
 
-    public Long getNumericValue() {
-        return numericValue;
+    public void setNumber(Number number) {
+        this.number = number;
     }
 
-    public void setNumericValue(Long numericValue) {
-        this.numericValue = numericValue;
-    }// used to prove we can set an enum with ognl
-
     public ContextLevel getContextLevel() {
         return contextLevel;
     }

Added: trunk/waffle-core/src/test/java/org/codehaus/waffle/testmodel/FakeControllerWithNumberMethods.java (0 => 753)

--- trunk/waffle-core/src/test/java/org/codehaus/waffle/testmodel/FakeControllerWithNumberMethods.java	                        (rev 0)
+++ trunk/waffle-core/src/test/java/org/codehaus/waffle/testmodel/FakeControllerWithNumberMethods.java	2008-06-21 17:46:54 UTC (rev 753)
@@ -0,0 +1,26 @@
+package org.codehaus.waffle.testmodel;
+
+import java.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.MethodDescriptor;
+import java.lang.reflect.Type;
+
+public class FakeControllerWithNumberMethods {       
+    public static Type methodParameterType(String methodName) throws IntrospectionException {
+        BeanInfo beanInfo = Introspector.getBeanInfo(FakeControllerWithNumberMethods.class);
+        for (MethodDescriptor md : beanInfo.getMethodDescriptors()) {
+            if (md.getMethod().getName().equals(methodName)) {
+                return md.getMethod().getGenericParameterTypes()[0];
+            }
+        }
+        return null;
+    }
+
+    @SuppressWarnings("unchecked")
+    public void primitiveDouble(double number){};
+    public void primitiveFloat(float number){};
+    public void primitiveLong(long number){};
+    public void primitiveInteger(int number){};
+    public void object(Object object){};
+}
\ No newline at end of file


To unsubscribe from this list please visit:

http://xircles.codehaus.org/manage_email

Reply via email to