full support for formatters on array/collection elements (SPR-6504)
This commit is contained in:
parent
388edd7aaa
commit
e161c93f8d
|
|
@ -53,11 +53,12 @@ class BeanTypeDescriptor extends TypeDescriptor {
|
|||
|
||||
/**
|
||||
* Create a new BeanTypeDescriptor for the given bean property.
|
||||
* @param methodParameter the target method parameter
|
||||
* @param propertyDescriptor the corresponding JavaBean PropertyDescriptor
|
||||
* @param methodParameter the target method parameter
|
||||
* @param type the specific type to expose (may be an array/collection element)
|
||||
*/
|
||||
public BeanTypeDescriptor(MethodParameter methodParameter, PropertyDescriptor propertyDescriptor) {
|
||||
super(methodParameter);
|
||||
public BeanTypeDescriptor(PropertyDescriptor propertyDescriptor, MethodParameter methodParameter, Class type) {
|
||||
super(methodParameter, type);
|
||||
this.propertyDescriptor = propertyDescriptor;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -354,13 +354,15 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
|||
|
||||
public TypeDescriptor getPropertyTypeDescriptor(String propertyName) throws BeansException {
|
||||
try {
|
||||
PropertyDescriptor pd = getPropertyDescriptorInternal(propertyName);
|
||||
String canonicalName = PropertyAccessorUtils.getPropertyName(propertyName);
|
||||
PropertyDescriptor pd = getPropertyDescriptorInternal(canonicalName);
|
||||
if (pd != null) {
|
||||
Class type = getPropertyType(propertyName);
|
||||
if (pd.getReadMethod() != null) {
|
||||
return new BeanTypeDescriptor(new MethodParameter(pd.getReadMethod(), -1), pd);
|
||||
return new BeanTypeDescriptor(pd, new MethodParameter(pd.getReadMethod(), -1), type);
|
||||
}
|
||||
else if (pd.getWriteMethod() != null) {
|
||||
return new BeanTypeDescriptor(BeanUtils.getWriteMethodParameter(pd), pd);
|
||||
return new BeanTypeDescriptor(pd, BeanUtils.getWriteMethodParameter(pd), type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -579,7 +581,8 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
|||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + name, "Could not instantiate property type [" + type.getName() + "] to auto-grow nested property path: " + ex);
|
||||
throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + name,
|
||||
"Could not instantiate property type [" + type.getName() + "] to auto-grow nested property path: " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -117,10 +117,11 @@ public abstract class AbstractPropertyBindingResult extends AbstractBindingResul
|
|||
if (this.conversionService != null) {
|
||||
// Try custom formatter...
|
||||
TypeDescriptor td = getPropertyAccessor().getPropertyTypeDescriptor(fixedField);
|
||||
return this.conversionService.convert(value, td, TypeDescriptor.valueOf(String.class));
|
||||
} else {
|
||||
return value;
|
||||
if (td != null) {
|
||||
return this.conversionService.convert(value, td, TypeDescriptor.valueOf(String.class));
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ package org.springframework.format.number;
|
|||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Locale;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.After;
|
||||
import static org.junit.Assert.*;
|
||||
|
|
@ -102,6 +103,43 @@ public class NumberFormattingTests {
|
|||
assertEquals("1,25.00", binder.getBindingResult().getFieldValue("pattern"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPatternArrayFormatting() {
|
||||
MutablePropertyValues propertyValues = new MutablePropertyValues();
|
||||
propertyValues.add("patternArray", new String[] {"1,25.00", "2,35.00"});
|
||||
binder.bind(propertyValues);
|
||||
assertEquals(0, binder.getBindingResult().getErrorCount());
|
||||
assertEquals("1,25.00", binder.getBindingResult().getFieldValue("patternArray[0]"));
|
||||
assertEquals("2,35.00", binder.getBindingResult().getFieldValue("patternArray[1]"));
|
||||
|
||||
propertyValues = new MutablePropertyValues();
|
||||
propertyValues.add("patternArray[0]", "1,25.00");
|
||||
propertyValues.add("patternArray[1]", "2,35.00");
|
||||
binder.bind(propertyValues);
|
||||
assertEquals(0, binder.getBindingResult().getErrorCount());
|
||||
assertEquals("1,25.00", binder.getBindingResult().getFieldValue("patternArray[0]"));
|
||||
assertEquals("2,35.00", binder.getBindingResult().getFieldValue("patternArray[1]"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPatternListFormatting() {
|
||||
MutablePropertyValues propertyValues = new MutablePropertyValues();
|
||||
propertyValues.add("patternList", new String[] {"1,25.00", "2,35.00"});
|
||||
binder.bind(propertyValues);
|
||||
assertEquals(0, binder.getBindingResult().getErrorCount());
|
||||
assertEquals("1,25.00", binder.getBindingResult().getFieldValue("patternList[0]"));
|
||||
assertEquals("2,35.00", binder.getBindingResult().getFieldValue("patternList[1]"));
|
||||
|
||||
propertyValues = new MutablePropertyValues();
|
||||
propertyValues.add("patternList[0]", "1,25.00");
|
||||
propertyValues.add("patternList[1]", "2,35.00");
|
||||
binder.bind(propertyValues);
|
||||
assertEquals(0, binder.getBindingResult().getErrorCount());
|
||||
assertEquals("1,25.00", binder.getBindingResult().getFieldValue("patternList[0]"));
|
||||
assertEquals("2,35.00", binder.getBindingResult().getFieldValue("patternList[1]"));
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static class TestBean {
|
||||
|
||||
|
|
@ -119,6 +157,12 @@ public class NumberFormattingTests {
|
|||
@NumberFormat(pattern="#,##.00")
|
||||
private BigDecimal pattern;
|
||||
|
||||
@NumberFormat(pattern="#,##.00")
|
||||
private BigDecimal[] patternArray;
|
||||
|
||||
@NumberFormat(pattern="#,##.00")
|
||||
private List[] patternList;
|
||||
|
||||
public Integer getNumberDefault() {
|
||||
return numberDefault;
|
||||
}
|
||||
|
|
@ -159,6 +203,21 @@ public class NumberFormattingTests {
|
|||
this.pattern = pattern;
|
||||
}
|
||||
|
||||
|
||||
public BigDecimal[] getPatternArray() {
|
||||
return patternArray;
|
||||
}
|
||||
|
||||
public void setPatternArray(BigDecimal[] patternArray) {
|
||||
this.patternArray = patternArray;
|
||||
}
|
||||
|
||||
public List[] getPatternList() {
|
||||
return patternList;
|
||||
}
|
||||
|
||||
public void setPatternList(List[] patternList) {
|
||||
this.patternList = patternList;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ package org.springframework.core.convert;
|
|||
* Thrown when an attempt to execute a type conversion fails.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
*/
|
||||
public final class ConversionFailedException extends ConversionException {
|
||||
|
|
@ -37,8 +38,8 @@ public final class ConversionFailedException extends ConversionException {
|
|||
* @param cause the cause of the conversion failure
|
||||
*/
|
||||
public ConversionFailedException(TypeDescriptor sourceType, TypeDescriptor targetType, Object value, Throwable cause) {
|
||||
super("Unable to convert value " + value + " from type [" + sourceType.getName() + "] to type [" +
|
||||
targetType.getName() + "]; reason = '" + cause.getMessage() + "'", cause);
|
||||
super("Unable to convert value " + value + " from type '" + sourceType.getName() +
|
||||
"' to type '" + targetType.getName() + "'", cause);
|
||||
this.sourceType = sourceType;
|
||||
this.targetType = targetType;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,6 +77,19 @@ public class TypeDescriptor {
|
|||
this.methodParameter = methodParameter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new type descriptor from a method or constructor parameter.
|
||||
* <p>Use this constructor when a target conversion point originates from a method parameter,
|
||||
* such as a setter method argument.
|
||||
* @param methodParameter the MethodParameter to wrap
|
||||
* @param type the specific type to expose (may be an array/collection element)
|
||||
*/
|
||||
protected TypeDescriptor(MethodParameter methodParameter, Class type) {
|
||||
Assert.notNull(methodParameter, "MethodParameter must not be null");
|
||||
this.methodParameter = methodParameter;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new type descriptor for a field.
|
||||
* Use this constructor when a target conversion point originates from a field.
|
||||
|
|
@ -158,16 +171,11 @@ public class TypeDescriptor {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this type; the fully qualified classname.
|
||||
* Returns the name of this type: the fully qualified class name.
|
||||
*/
|
||||
public String getName() {
|
||||
Class<?> type = getType();
|
||||
if (type != null) {
|
||||
return getType().getName();
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
return (type != null ? ClassUtils.getQualifiedName(type) : null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -396,17 +404,16 @@ public class TypeDescriptor {
|
|||
|
||||
public String toString() {
|
||||
if (this == TypeDescriptor.NULL) {
|
||||
return "[TypeDescriptor.NULL]";
|
||||
return "TypeDescriptor.NULL";
|
||||
}
|
||||
else {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("[TypeDescriptor ");
|
||||
builder.append("TypeDescriptor ");
|
||||
Annotation[] anns = getAnnotations();
|
||||
for (Annotation ann : anns) {
|
||||
builder.append("@").append(ann.annotationType().getName()).append(' ');
|
||||
}
|
||||
builder.append(getType().getName());
|
||||
builder.append("]");
|
||||
builder.append(ClassUtils.getQualifiedName(getType()));
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue