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.
|
* 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
|
||||||
|
|
||||||
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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,11 +117,12 @@ 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);
|
||||||
|
if (td != null) {
|
||||||
return this.conversionService.convert(value, td, TypeDescriptor.valueOf(String.class));
|
return this.conversionService.convert(value, td, TypeDescriptor.valueOf(String.class));
|
||||||
} else {
|
|
||||||
return value;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the custom PropertyEditor for the given field, if any.
|
* Retrieve the custom PropertyEditor for the given field, if any.
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
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 {
|
||||||
@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 {
|
||||||
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
@ -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 {
|
||||||
* @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 {
|
||||||
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 {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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 {
|
||||||
|
|
||||||
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue