diff --git a/org.springframework.context/src/main/java/org/springframework/ui/binding/Binder.java b/org.springframework.context/src/main/java/org/springframework/ui/binding/Binder.java index 233c71fbba0..3a1aaff0046 100644 --- a/org.springframework.context/src/main/java/org/springframework/ui/binding/Binder.java +++ b/org.springframework.context/src/main/java/org/springframework/ui/binding/Binder.java @@ -27,7 +27,7 @@ import org.springframework.ui.format.Formatter; * * @param The kind of model object this binder binds to * @see #add(BindingConfiguration) - * @see #bind(Map) + * @see #bind(UserValues) */ public interface Binder { @@ -39,7 +39,7 @@ public interface Binder { /** * Configures if this binder is strict; a strict binder requires all bindings to be registered explicitly using {@link #add(BindingConfiguration)}. - * An optimistic binder will implicitly create bindings as required to support {@link #bind(Map)} operations. + * An optimistic binder will implicitly create bindings as required to support {@link #bind(UserValues)} operations. * Default is optimistic. * @param strict strict binder status */ @@ -75,9 +75,9 @@ public interface Binder { /** * Bind values in the map to the properties of the model object. * TODO consider returning BindingResults object that makes it easier to query/introspect results - * @param userValues user-entered values to bind + * @param values user-entered values to bind */ - List bind(List userValues); + List bind(UserValues values); /** * Creates a {@link UserValue} list from a Map of user-submitted fields. @@ -85,8 +85,8 @@ public interface Binder { * For example, a Binder might insert empty or default values for fields that are not present. * As another example, a Binder might collapse multiple fields into a single {@link UserValue} object. * @param userMap the map of user-submitted fields - * @return the UserValue list that can be passed to {@link #bind(List)}. + * @return the UserValue list that can be passed to {@link #bind(UserValues)}. */ - List createUserValues(Map userMap); + UserValues createUserValues(Map userMap); } \ No newline at end of file diff --git a/org.springframework.context/src/main/java/org/springframework/ui/binding/BindingResult.java b/org.springframework.context/src/main/java/org/springframework/ui/binding/BindingResult.java index 94b207d3ae3..ff6c8ae4c28 100644 --- a/org.springframework.context/src/main/java/org/springframework/ui/binding/BindingResult.java +++ b/org.springframework.context/src/main/java/org/springframework/ui/binding/BindingResult.java @@ -18,7 +18,7 @@ package org.springframework.ui.binding; /** * The result of a bind operation. * @author Keith Donald - * @see Binder#bind(java.util.List) + * @see Binder#bind(UserValues) * @see Binding#setValue(Object) */ public interface BindingResult { diff --git a/org.springframework.context/src/main/java/org/springframework/ui/binding/UserValue.java b/org.springframework.context/src/main/java/org/springframework/ui/binding/UserValue.java index b019ffe124c..6264c100b09 100644 --- a/org.springframework.context/src/main/java/org/springframework/ui/binding/UserValue.java +++ b/org.springframework.context/src/main/java/org/springframework/ui/binding/UserValue.java @@ -15,9 +15,6 @@ */ package org.springframework.ui.binding; -import java.util.ArrayList; -import java.util.List; - /** * Holds a user-entered value to bind to a model property. * @author Keith Donald @@ -53,16 +50,4 @@ public class UserValue { return value; } - /** - * Creates a new UserValue list with a single element. - * @param property the property - * @param value the actual user-entered value - * @return the singleton user value list - */ - public static List single(String property, Object value) { - List values = new ArrayList(1); - values.add(new UserValue(property, value)); - return values; - } - } diff --git a/org.springframework.context/src/main/java/org/springframework/ui/binding/UserValues.java b/org.springframework.context/src/main/java/org/springframework/ui/binding/UserValues.java new file mode 100644 index 00000000000..9a1989d2943 --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/ui/binding/UserValues.java @@ -0,0 +1,74 @@ +package org.springframework.ui.binding; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +/** + * A simpler holder for a list of UserValues. + * + * @author Keith Donald + * @see Binder#bind(UserValues) + */ +public class UserValues implements Iterable { + + private List values; + + /** + * Creates a new user values list of the default size. + */ + public UserValues() { + values = new ArrayList(); + } + + /** + * Creates a new user values list of the size provided. + */ + public UserValues(int size) { + values = new ArrayList(size); + } + + // implementing Iterable + + public Iterator iterator() { + return values.iterator(); + } + + /** + * The user values list. + * The returned list is not modifiable. + */ + public List asList() { + return Collections.unmodifiableList(values); + } + + /** + * Add a new user value. + * @param property the property the value should be bound to + * @param value the actual user-entered value + */ + public void add(String property, Object value) { + values.add(new UserValue(property, value)); + } + + /** + * The number of user values in the list. + */ + public int size() { + return values.size(); + } + + /** + * Creates a new UserValues list with a single element. + * @param property the property + * @param value the actual user-entered value + * @return the singleton user value list + */ + public static UserValues single(String property, Object value) { + UserValues values = new UserValues(1); + values.add(property, value); + return values; + } + +} \ No newline at end of file diff --git a/org.springframework.context/src/main/java/org/springframework/ui/binding/support/GenericBinder.java b/org.springframework.context/src/main/java/org/springframework/ui/binding/support/GenericBinder.java index 2991699fa57..0398a61dc2b 100644 --- a/org.springframework.context/src/main/java/org/springframework/ui/binding/support/GenericBinder.java +++ b/org.springframework.context/src/main/java/org/springframework/ui/binding/support/GenericBinder.java @@ -48,6 +48,7 @@ import org.springframework.ui.binding.Binding; import org.springframework.ui.binding.BindingConfiguration; import org.springframework.ui.binding.BindingResult; import org.springframework.ui.binding.UserValue; +import org.springframework.ui.binding.UserValues; import org.springframework.ui.format.AnnotationFormatterFactory; import org.springframework.ui.format.Formatter; @@ -55,9 +56,9 @@ import org.springframework.ui.format.Formatter; * Binds user-entered values to properties of a model object. * @author Keith Donald * - * @param The type of model object this binder binds to + * @param The type of model object this binder binds to - TODO is this worth it? * @see #add(BindingConfiguration) - * @see #bind(Map) + * @see #bind(UserValues) */ @SuppressWarnings("unchecked") public class GenericBinder implements Binder { @@ -149,19 +150,19 @@ public class GenericBinder implements Binder { } } - public List bind(List userValues) { - List results = new ArrayList(userValues.size()); - for (UserValue value : userValues) { + public List bind(UserValues values) { + List results = new ArrayList(values.size()); + for (UserValue value : values) { BindingImpl binding = (BindingImpl) getBinding(value.getProperty()); results.add(binding.setValue(value.getValue())); } return results; } - public List createUserValues(Map userMap) { - List values = new ArrayList(); + public UserValues createUserValues(Map userMap) { + UserValues values = new UserValues(userMap.size()); for (Map.Entry entry : userMap.entrySet()) { - values.add(new UserValue(entry.getKey(), entry.getValue())); + values.add(entry.getKey(), entry.getValue()); } return values; } diff --git a/org.springframework.context/src/main/java/org/springframework/ui/binding/support/WebBinder.java b/org.springframework.context/src/main/java/org/springframework/ui/binding/support/WebBinder.java index d1a432243e5..078fac4027b 100644 --- a/org.springframework.context/src/main/java/org/springframework/ui/binding/support/WebBinder.java +++ b/org.springframework.context/src/main/java/org/springframework/ui/binding/support/WebBinder.java @@ -15,11 +15,9 @@ */ package org.springframework.ui.binding.support; -import java.util.ArrayList; -import java.util.List; import java.util.Map; -import org.springframework.ui.binding.UserValue; +import org.springframework.ui.binding.UserValues; /** * A binder designed for use in HTTP (web) environments. @@ -60,24 +58,24 @@ public class WebBinder extends GenericBinder { } @Override - public List createUserValues(Map userMap) { - List values = new ArrayList(); + public UserValues createUserValues(Map userMap) { + UserValues values = new UserValues(); for (Map.Entry entry : userMap.entrySet()) { String field = entry.getKey(); Object value = entry.getValue(); if (field.startsWith(fieldDefaultPrefix)) { field = field.substring(fieldDefaultPrefix.length()); if (!userMap.containsKey(field)) { - values.add(new UserValue(field, value)); + values.add(field, value); } } else if (field.startsWith(fieldMarkerPrefix)) { field = field.substring(fieldMarkerPrefix.length()); if (!userMap.containsKey(field) && !userMap.containsKey(fieldDefaultPrefix + field)) { value = getEmptyValue((BindingImpl) getBinding(field)); - values.add(new UserValue(field, value)); + values.add(field, value); } } else { - values.add(new UserValue(entry.getKey(), entry.getValue())); + values.add(entry.getKey(), entry.getValue()); } } return values; diff --git a/org.springframework.context/src/test/java/org/springframework/ui/binding/support/GenericBinderTests.java b/org.springframework.context/src/test/java/org/springframework/ui/binding/support/GenericBinderTests.java index b19306ddbbc..4d86ad863fb 100644 --- a/org.springframework.context/src/test/java/org/springframework/ui/binding/support/GenericBinderTests.java +++ b/org.springframework.context/src/test/java/org/springframework/ui/binding/support/GenericBinderTests.java @@ -7,7 +7,6 @@ import static org.junit.Assert.assertTrue; import java.math.BigDecimal; import java.text.ParseException; -import java.util.ArrayList; import java.util.Date; import java.util.LinkedHashMap; import java.util.List; @@ -25,7 +24,7 @@ import org.springframework.ui.binding.Binder; import org.springframework.ui.binding.Binding; import org.springframework.ui.binding.BindingConfiguration; import org.springframework.ui.binding.BindingResult; -import org.springframework.ui.binding.UserValue; +import org.springframework.ui.binding.UserValues; import org.springframework.ui.format.date.DateFormatter; import org.springframework.ui.format.number.CurrencyAnnotationFormatterFactory; import org.springframework.ui.format.number.CurrencyFormat; @@ -47,10 +46,10 @@ public class GenericBinderTests { @Test public void bindSingleValuesWithDefaultTypeConverterConversion() { Binder binder = new GenericBinder(new TestBean()); - List values = new ArrayList(); - values.add(new UserValue("string", "test")); - values.add(new UserValue("integer", "3")); - values.add(new UserValue("foo", "BAR")); + UserValues values = new UserValues(); + values.add("string", "test"); + values.add("integer", "3"); + values.add("foo", "BAR"); List results = binder.bind(values); assertEquals(3, results.size()); @@ -77,11 +76,11 @@ public class GenericBinderTests { @Test public void bindSingleValuesWithDefaultTypeCoversionFailure() { Binder binder = new GenericBinder(new TestBean()); - List values = new ArrayList(); - values.add(new UserValue("string", "test")); + UserValues values = new UserValues(); + values.add("string", "test"); // bad value - values.add(new UserValue("integer", "bogus")); - values.add(new UserValue("foo", "BAR")); + values.add("integer", "bogus"); + values.add("foo", "BAR"); List results = binder.bind(values); assertEquals(3, results.size()); assertTrue(results.get(1).isError()); @@ -92,7 +91,7 @@ public class GenericBinderTests { public void bindSingleValuePropertyFormatter() throws ParseException { Binder binder = new GenericBinder(new TestBean()); binder.add(new BindingConfiguration("date", new DateFormatter())); - binder.bind(UserValue.single("date", "2009-06-01")); + binder.bind(UserValues.single("date", "2009-06-01")); assertEquals(new DateFormatter().parse("2009-06-01", Locale.US), binder.getModel().getDate()); } @@ -100,14 +99,14 @@ public class GenericBinderTests { public void bindSingleValuePropertyFormatterParseException() { Binder binder = new GenericBinder(new TestBean()); binder.add(new BindingConfiguration("date", new DateFormatter())); - binder.bind(UserValue.single("date", "bogus")); + binder.bind(UserValues.single("date", "bogus")); } @Test public void bindSingleValueWithFormatterRegistedByType() throws ParseException { Binder binder = new GenericBinder(new TestBean()); binder.add(new DateFormatter(), Date.class); - binder.bind(UserValue.single("date", "2009-06-01")); + binder.bind(UserValues.single("date", "2009-06-01")); assertEquals(new DateFormatter().parse("2009-06-01", Locale.US), binder.getModel().getDate()); } @@ -115,7 +114,7 @@ public class GenericBinderTests { public void bindSingleValueWithFormatterRegisteredByAnnotation() throws ParseException { Binder binder = new GenericBinder(new TestBean()); binder.add(new CurrencyFormatter(), CurrencyFormat.class); - binder.bind(UserValue.single("currency", "$23.56")); + binder.bind(UserValues.single("currency", "$23.56")); assertEquals(new BigDecimal("23.56"), binder.getModel().getCurrency()); } @@ -123,14 +122,14 @@ public class GenericBinderTests { public void bindSingleValueWithnAnnotationFormatterFactoryRegistered() throws ParseException { Binder binder = new GenericBinder(new TestBean()); binder.add(new CurrencyAnnotationFormatterFactory()); - binder.bind(UserValue.single("currency", "$23.56")); + binder.bind(UserValues.single("currency", "$23.56")); assertEquals(new BigDecimal("23.56"), binder.getModel().getCurrency()); } @Test public void bindSingleValuePropertyNotFound() throws ParseException { Binder binder = new GenericBinder(new TestBean()); - List results = binder.bind(UserValue.single("bogus", "2009-06-01")); + List results = binder.bind(UserValues.single("bogus", "2009-06-01")); assertEquals(1, results.size()); assertTrue(results.get(0).isError()); assertEquals("propertyNotFound", results.get(0).getErrorCode()); @@ -142,7 +141,7 @@ public class GenericBinderTests { Map userMap = new LinkedHashMap(); userMap.put("string", "test"); userMap.put("integer", "3"); - List values = binder.createUserValues(userMap); + UserValues values = binder.createUserValues(userMap); List results = binder.bind(values); assertEquals(2, results.size()); assertEquals("test", results.get(0).getUserValue()); @@ -231,7 +230,7 @@ public class GenericBinderTests { public void bindHandleNullValueInNestedPath() { TestBean testbean = new TestBean(); Binder binder = new GenericBinder(testbean); - List values = new ArrayList(); + UserValues values = new UserValues(); // EL configured with some options from SpelExpressionParserConfiguration: // (see where Binder creates the parser) @@ -240,22 +239,22 @@ public class GenericBinderTests { // are new instances of the type of the list entry, they are not null. // not currently doing anything for maps or arrays - values.add(new UserValue("addresses[0].street", "4655 Macy Lane")); - values.add(new UserValue("addresses[0].city", "Melbourne")); - values.add(new UserValue("addresses[0].state", "FL")); - values.add(new UserValue("addresses[0].zip", "35452")); + values.add("addresses[0].street", "4655 Macy Lane"); + values.add("addresses[0].city", "Melbourne"); + values.add("addresses[0].state", "FL"); + values.add("addresses[0].zip", "35452"); // Auto adds new Address at 1 - values.add(new UserValue("addresses[1].street", "1234 Rostock Circle")); - values.add(new UserValue("addresses[1].city", "Palm Bay")); - values.add(new UserValue("addresses[1].state", "FL")); - values.add(new UserValue("addresses[1].zip", "32901")); + values.add("addresses[1].street", "1234 Rostock Circle"); + values.add("addresses[1].city", "Palm Bay"); + values.add("addresses[1].state", "FL"); + values.add("addresses[1].zip", "32901"); // Auto adds new Address at 5 (plus intermediates 2,3,4) - values.add(new UserValue("addresses[5].street", "1234 Rostock Circle")); - values.add(new UserValue("addresses[5].city", "Palm Bay")); - values.add(new UserValue("addresses[5].state", "FL")); - values.add(new UserValue("addresses[5].zip", "32901")); + values.add("addresses[5].street", "1234 Rostock Circle"); + values.add("addresses[5].city", "Palm Bay"); + values.add("addresses[5].state", "FL"); + values.add("addresses[5].zip", "32901"); List results = binder.bind(values); Assert.assertEquals(6,testbean.addresses.size()); diff --git a/org.springframework.context/src/test/java/org/springframework/ui/binding/support/WebBinderTests.java b/org.springframework.context/src/test/java/org/springframework/ui/binding/support/WebBinderTests.java index 18313747abb..cfe206209fe 100644 --- a/org.springframework.context/src/test/java/org/springframework/ui/binding/support/WebBinderTests.java +++ b/org.springframework.context/src/test/java/org/springframework/ui/binding/support/WebBinderTests.java @@ -17,7 +17,7 @@ import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.ui.binding.Binder; import org.springframework.ui.binding.BindingConfiguration; import org.springframework.ui.binding.BindingResult; -import org.springframework.ui.binding.UserValue; +import org.springframework.ui.binding.UserValues; import org.springframework.ui.format.date.DateFormatter; import org.springframework.ui.format.number.CurrencyAnnotationFormatterFactory; import org.springframework.ui.format.number.CurrencyFormat; @@ -47,7 +47,7 @@ public class WebBinderTests { userMap.put("!currency", "$5.00"); userMap.put("_currency", "doesn't matter"); userMap.put("_addresses", "doesn't matter"); - List values = binder.createUserValues(userMap); + UserValues values = binder.createUserValues(userMap); List results = binder.bind(values); assertEquals(6, results.size()); assertEquals("test", results.get(0).getUserValue());