binding string to list
This commit is contained in:
@@ -29,6 +29,8 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.expression.MapAccessor;
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
@@ -350,7 +352,7 @@ public class GenericBinder implements Binder {
|
||||
|
||||
public String format(Object selectableValue) {
|
||||
Formatter formatter = getFormatter();
|
||||
Class<?> formattedType = getFormattedObjectType(formatter);
|
||||
Class<?> formattedType = getFormattedObjectType(formatter.getClass());
|
||||
selectableValue = typeConverter.convert(selectableValue, formattedType);
|
||||
return formatter.format(selectableValue, LocaleContextHolder.getLocale());
|
||||
}
|
||||
@@ -404,7 +406,8 @@ public class GenericBinder implements Binder {
|
||||
private BindingResult setStringValue(String formatted) {
|
||||
Object parsed;
|
||||
try {
|
||||
parsed = getFormatter().parse(formatted, LocaleContextHolder.getLocale());
|
||||
Formatter formatter = getFormatter();
|
||||
parsed = formatter.parse(formatted, LocaleContextHolder.getLocale());
|
||||
} catch (ParseException e) {
|
||||
return new InvalidFormat(property.getExpressionString(), formatted, e);
|
||||
}
|
||||
@@ -413,7 +416,7 @@ public class GenericBinder implements Binder {
|
||||
|
||||
private BindingResult setStringValues(String[] formatted) {
|
||||
Formatter formatter = getFormatter();
|
||||
Class parsedType = getFormattedObjectType(formatter);
|
||||
Class parsedType = getFormattedObjectType(formatter.getClass());
|
||||
if (parsedType == null) {
|
||||
parsedType = String.class;
|
||||
}
|
||||
@@ -466,18 +469,31 @@ public class GenericBinder implements Binder {
|
||||
return new EvaluationError(property.getExpressionString(), userValue, e);
|
||||
}
|
||||
}
|
||||
|
||||
private Class getFormattedObjectType(Formatter formatter) {
|
||||
|
||||
private Class getFormattedObjectType(Class formatterClass) {
|
||||
// TODO consider caching this info
|
||||
Class classToIntrospect = formatter.getClass();
|
||||
Class classToIntrospect = formatterClass;
|
||||
while (classToIntrospect != null) {
|
||||
Type[] genericInterfaces = classToIntrospect.getGenericInterfaces();
|
||||
for (Type genericInterface : genericInterfaces) {
|
||||
if (genericInterface instanceof ParameterizedType) {
|
||||
ParameterizedType pInterface = (ParameterizedType) genericInterface;
|
||||
if (Formatter.class.isAssignableFrom((Class) pInterface.getRawType())) {
|
||||
return getParameterClass(pInterface.getActualTypeArguments()[0], formatter.getClass());
|
||||
Type[] ifcs = classToIntrospect.getGenericInterfaces();
|
||||
for (Type ifc : ifcs) {
|
||||
if (ifc instanceof ParameterizedType) {
|
||||
ParameterizedType paramIfc = (ParameterizedType) ifc;
|
||||
Type rawType = paramIfc.getRawType();
|
||||
if (Formatter.class.equals(rawType)) {
|
||||
Type arg = paramIfc.getActualTypeArguments()[0];
|
||||
if (arg instanceof TypeVariable) {
|
||||
arg = GenericTypeResolver.resolveTypeVariable((TypeVariable) arg, formatterClass);
|
||||
}
|
||||
if (arg instanceof Class) {
|
||||
return (Class) arg;
|
||||
}
|
||||
}
|
||||
else if (ApplicationListener.class.isAssignableFrom((Class) rawType)) {
|
||||
return getFormattedObjectType((Class) rawType);
|
||||
}
|
||||
}
|
||||
else if (ApplicationListener.class.isAssignableFrom((Class) ifc)) {
|
||||
return getFormattedObjectType((Class) ifc);
|
||||
}
|
||||
}
|
||||
classToIntrospect = classToIntrospect.getSuperclass();
|
||||
@@ -485,17 +501,6 @@ public class GenericBinder implements Binder {
|
||||
return null;
|
||||
}
|
||||
|
||||
private Class getParameterClass(Type parameterType, Class converterClass) {
|
||||
if (parameterType instanceof TypeVariable) {
|
||||
parameterType = GenericTypeResolver.resolveTypeVariable((TypeVariable) parameterType, converterClass);
|
||||
}
|
||||
if (parameterType instanceof Class) {
|
||||
return (Class) parameterType;
|
||||
}
|
||||
throw new IllegalArgumentException("Unable to obtain the java.lang.Class for parameterType [" + parameterType
|
||||
+ "] on Formatter [" + converterClass.getName() + "]");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class DefaultFormatter implements Formatter {
|
||||
@@ -736,6 +741,8 @@ public class GenericBinder implements Binder {
|
||||
Throwable cause = accessException.getCause();
|
||||
if (cause instanceof SpelEvaluationException
|
||||
&& ((SpelEvaluationException) cause).getMessageCode() == SpelMessage.TYPE_CONVERSION_ERROR) {
|
||||
// TODO this could be a ConverterExecutorNotFoundException if no suitable converter was found
|
||||
cause.getCause().printStackTrace();
|
||||
ConversionFailedException failure = (ConversionFailedException) cause.getCause();
|
||||
MessageBuilder builder = new MessageBuilder(messageSource);
|
||||
builder.code("conversionFailed");
|
||||
|
||||
@@ -6,6 +6,7 @@ import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -17,6 +18,7 @@ import junit.framework.Assert;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
import org.springframework.ui.binding.Binding;
|
||||
@@ -253,6 +255,49 @@ public class GenericBinderTests {
|
||||
assertEquals("35452", bean.addresses.get(0).zip);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bindToListSingleString() {
|
||||
binder.addBinding("addresses").formatWith(new AddressListFormatter());
|
||||
Map<String, String> values = new LinkedHashMap<String, String>();
|
||||
values.put("addresses", "4655 Macy Lane:Melbourne:FL:35452,1234 Rostock Circle:Palm Bay:FL:32901,1977 Bel Aire Estates:Coker:AL:12345");
|
||||
BindingResults results = binder.bind(values);
|
||||
System.out.println(results);
|
||||
Assert.assertEquals(3, bean.addresses.size());
|
||||
assertEquals("4655 Macy Lane", bean.addresses.get(0).street);
|
||||
assertEquals("Melbourne", bean.addresses.get(0).city);
|
||||
assertEquals("FL", bean.addresses.get(0).state);
|
||||
assertEquals("35452", bean.addresses.get(0).zip);
|
||||
assertEquals("1234 Rostock Circle", bean.addresses.get(1).street);
|
||||
assertEquals("Palm Bay", bean.addresses.get(1).city);
|
||||
assertEquals("FL", bean.addresses.get(1).state);
|
||||
assertEquals("32901", bean.addresses.get(1).zip);
|
||||
assertEquals("1977 Bel Aire Estates", bean.addresses.get(2).street);
|
||||
assertEquals("Coker", bean.addresses.get(2).city);
|
||||
assertEquals("AL", bean.addresses.get(2).state);
|
||||
assertEquals("12345", bean.addresses.get(2).zip);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCollectionAsSingleValue() {
|
||||
binder.addBinding("addresses").formatWith(new AddressListFormatter());
|
||||
Address address1 = new Address();
|
||||
address1.setStreet("s1");
|
||||
address1.setCity("c1");
|
||||
address1.setState("st1");
|
||||
address1.setZip("z1");
|
||||
Address address2 = new Address();
|
||||
address2.setStreet("s2");
|
||||
address2.setCity("c2");
|
||||
address2.setState("st2");
|
||||
address2.setZip("z2");
|
||||
List<Address> addresses = new ArrayList<Address>(2);
|
||||
addresses.add(address1);
|
||||
addresses.add(address2);
|
||||
bean.addresses = addresses;
|
||||
String value = binder.getBinding("addresses").getValue();
|
||||
assertEquals("s1:c1:st1:z1,s2:c2:st2:z2,", value);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bindToListHandleNullValueInNestedPath() {
|
||||
binder.addBinding("addresses.street");
|
||||
@@ -403,6 +448,28 @@ public class GenericBinderTests {
|
||||
|
||||
}
|
||||
|
||||
public static class AddressListFormatter implements Formatter<List<Address>> {
|
||||
|
||||
public String format(List<Address> addresses, Locale locale) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (Address address : addresses) {
|
||||
builder.append(new AddressFormatter().format(address, locale));
|
||||
builder.append(",");
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public List<Address> parse(String formatted, Locale locale) throws ParseException {
|
||||
String[] fields = formatted.split(",");
|
||||
List<Address> addresses = new ArrayList<Address>(fields.length);
|
||||
for (String field : fields) {
|
||||
addresses.add(new AddressFormatter().parse(field, locale));
|
||||
}
|
||||
return addresses;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Formatted(AddressFormatter.class)
|
||||
public static class Address {
|
||||
private String street;
|
||||
|
||||
Reference in New Issue
Block a user