提交 e161c93f 编写于 作者: J Juergen Hoeller

full support for formatters on array/collection elements (SPR-6504)

上级 388edd7a
...@@ -53,11 +53,12 @@ class BeanTypeDescriptor extends TypeDescriptor { ...@@ -53,11 +53,12 @@ class BeanTypeDescriptor extends TypeDescriptor {
/** /**
* Create a new BeanTypeDescriptor for the given bean property. * Create a new BeanTypeDescriptor for the given bean property.
* @param methodParameter the target method parameter
* @param propertyDescriptor the corresponding JavaBean PropertyDescriptor * @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) { public BeanTypeDescriptor(PropertyDescriptor propertyDescriptor, MethodParameter methodParameter, Class type) {
super(methodParameter); super(methodParameter, type);
this.propertyDescriptor = propertyDescriptor; this.propertyDescriptor = propertyDescriptor;
} }
......
...@@ -354,13 +354,15 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra ...@@ -354,13 +354,15 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
public TypeDescriptor getPropertyTypeDescriptor(String propertyName) throws BeansException { public TypeDescriptor getPropertyTypeDescriptor(String propertyName) throws BeansException {
try { try {
PropertyDescriptor pd = getPropertyDescriptorInternal(propertyName); String canonicalName = PropertyAccessorUtils.getPropertyName(propertyName);
PropertyDescriptor pd = getPropertyDescriptorInternal(canonicalName);
if (pd != null) { if (pd != null) {
Class type = getPropertyType(propertyName);
if (pd.getReadMethod() != null) { 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) { 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 ...@@ -579,7 +581,8 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
} }
} }
catch (Exception ex) { 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 ...@@ -117,10 +117,11 @@ public abstract class AbstractPropertyBindingResult extends AbstractBindingResul
if (this.conversionService != null) { if (this.conversionService != null) {
// Try custom formatter... // Try custom formatter...
TypeDescriptor td = getPropertyAccessor().getPropertyTypeDescriptor(fixedField); TypeDescriptor td = getPropertyAccessor().getPropertyTypeDescriptor(fixedField);
return this.conversionService.convert(value, td, TypeDescriptor.valueOf(String.class)); if (td != null) {
} else { return this.conversionService.convert(value, td, TypeDescriptor.valueOf(String.class));
return value; }
} }
return value;
} }
/** /**
......
...@@ -18,6 +18,7 @@ package org.springframework.format.number; ...@@ -18,6 +18,7 @@ package org.springframework.format.number;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Locale; import java.util.Locale;
import java.util.List;
import org.junit.After; import org.junit.After;
import static org.junit.Assert.*; import static org.junit.Assert.*;
...@@ -102,6 +103,43 @@ public class NumberFormattingTests { ...@@ -102,6 +103,43 @@ public class NumberFormattingTests {
assertEquals("1,25.00", binder.getBindingResult().getFieldValue("pattern")); 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") @SuppressWarnings("unused")
private static class TestBean { private static class TestBean {
...@@ -119,6 +157,12 @@ public class NumberFormattingTests { ...@@ -119,6 +157,12 @@ public class NumberFormattingTests {
@NumberFormat(pattern="#,##.00") @NumberFormat(pattern="#,##.00")
private BigDecimal pattern; private BigDecimal pattern;
@NumberFormat(pattern="#,##.00")
private BigDecimal[] patternArray;
@NumberFormat(pattern="#,##.00")
private List[] patternList;
public Integer getNumberDefault() { public Integer getNumberDefault() {
return numberDefault; return numberDefault;
} }
...@@ -159,6 +203,21 @@ public class NumberFormattingTests { ...@@ -159,6 +203,21 @@ public class NumberFormattingTests {
this.pattern = pattern; 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;
}
} }
}
\ No newline at end of file }
...@@ -20,6 +20,7 @@ package org.springframework.core.convert; ...@@ -20,6 +20,7 @@ package org.springframework.core.convert;
* Thrown when an attempt to execute a type conversion fails. * Thrown when an attempt to execute a type conversion fails.
* *
* @author Keith Donald * @author Keith Donald
* @author Juergen Hoeller
* @since 3.0 * @since 3.0
*/ */
public final class ConversionFailedException extends ConversionException { public final class ConversionFailedException extends ConversionException {
...@@ -37,8 +38,8 @@ public final class ConversionFailedException extends ConversionException { ...@@ -37,8 +38,8 @@ public final class ConversionFailedException extends ConversionException {
* @param cause the cause of the conversion failure * @param cause the cause of the conversion failure
*/ */
public ConversionFailedException(TypeDescriptor sourceType, TypeDescriptor targetType, Object value, Throwable cause) { public ConversionFailedException(TypeDescriptor sourceType, TypeDescriptor targetType, Object value, Throwable cause) {
super("Unable to convert value " + value + " from type [" + sourceType.getName() + "] to type [" + super("Unable to convert value " + value + " from type '" + sourceType.getName() +
targetType.getName() + "]; reason = '" + cause.getMessage() + "'", cause); "' to type '" + targetType.getName() + "'", cause);
this.sourceType = sourceType; this.sourceType = sourceType;
this.targetType = targetType; this.targetType = targetType;
} }
......
...@@ -77,6 +77,19 @@ public class TypeDescriptor { ...@@ -77,6 +77,19 @@ public class TypeDescriptor {
this.methodParameter = methodParameter; 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. * Create a new type descriptor for a field.
* Use this constructor when a target conversion point originates from a field. * Use this constructor when a target conversion point originates from a field.
...@@ -158,16 +171,11 @@ public class TypeDescriptor { ...@@ -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() { public String getName() {
Class<?> type = getType(); Class<?> type = getType();
if (type != null) { return (type != null ? ClassUtils.getQualifiedName(type) : null);
return getType().getName();
}
else {
return null;
}
} }
/** /**
...@@ -396,17 +404,16 @@ public class TypeDescriptor { ...@@ -396,17 +404,16 @@ public class TypeDescriptor {
public String toString() { public String toString() {
if (this == TypeDescriptor.NULL) { if (this == TypeDescriptor.NULL) {
return "[TypeDescriptor.NULL]"; return "TypeDescriptor.NULL";
} }
else { else {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
builder.append("[TypeDescriptor "); builder.append("TypeDescriptor ");
Annotation[] anns = getAnnotations(); Annotation[] anns = getAnnotations();
for (Annotation ann : anns) { for (Annotation ann : anns) {
builder.append("@").append(ann.annotationType().getName()).append(' '); builder.append("@").append(ann.annotationType().getName()).append(' ');
} }
builder.append(getType().getName()); builder.append(ClassUtils.getQualifiedName(getType()));
builder.append("]");
return builder.toString(); return builder.toString();
} }
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册