fixed DataBinder's conversion error handling for direct field access with ConversionService (SPR-6953)

This commit is contained in:
Juergen Hoeller 2010-03-24 17:40:45 +00:00
parent 65b0a8fcb2
commit 53b6e1c1b0
4 changed files with 99 additions and 7 deletions

View File

@ -781,7 +781,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
"Getter for property '" + actualName + "' threw exception", ex); "Getter for property '" + actualName + "' threw exception", ex);
} }
catch(IllegalAccessException ex) { catch (IllegalAccessException ex) {
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName, throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
"Illegal attempt to get property '" + actualName + "' threw exception", ex); "Illegal attempt to get property '" + actualName + "' threw exception", ex);
} }
@ -813,7 +813,8 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
} }
setPropertyValue(name, newArray); setPropertyValue(name, newArray);
return newArray; return newArray;
} else { }
else {
return array; return array;
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2009 the original author or authors. * Copyright 2002-2010 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -22,6 +22,8 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.springframework.core.MethodParameter; import org.springframework.core.MethodParameter;
import org.springframework.core.convert.ConversionException;
import org.springframework.core.convert.ConverterNotFoundException;
import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.TypeDescriptor;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils; import org.springframework.util.ReflectionUtils;
@ -125,10 +127,11 @@ public class DirectFieldAccessor extends AbstractPropertyAccessor {
Object convertedValue = this.typeConverterDelegate.convertIfNecessary(oldValue, newValue, field); Object convertedValue = this.typeConverterDelegate.convertIfNecessary(oldValue, newValue, field);
field.set(this.target, convertedValue); field.set(this.target, convertedValue);
} }
catch (IllegalAccessException ex) { catch (ConverterNotFoundException ex) {
throw new InvalidPropertyException(this.target.getClass(), propertyName, "Field is not accessible", ex); PropertyChangeEvent pce = new PropertyChangeEvent(this.target, propertyName, oldValue, newValue);
throw new ConversionNotSupportedException(pce, field.getType(), ex);
} }
catch (IllegalArgumentException ex) { catch (ConversionException ex) {
PropertyChangeEvent pce = new PropertyChangeEvent(this.target, propertyName, oldValue, newValue); PropertyChangeEvent pce = new PropertyChangeEvent(this.target, propertyName, oldValue, newValue);
throw new TypeMismatchException(pce, field.getType(), ex); throw new TypeMismatchException(pce, field.getType(), ex);
} }
@ -136,6 +139,13 @@ public class DirectFieldAccessor extends AbstractPropertyAccessor {
PropertyChangeEvent pce = new PropertyChangeEvent(this.target, propertyName, oldValue, newValue); PropertyChangeEvent pce = new PropertyChangeEvent(this.target, propertyName, oldValue, newValue);
throw new ConversionNotSupportedException(pce, field.getType(), ex); throw new ConversionNotSupportedException(pce, field.getType(), ex);
} }
catch (IllegalArgumentException ex) {
PropertyChangeEvent pce = new PropertyChangeEvent(this.target, propertyName, oldValue, newValue);
throw new TypeMismatchException(pce, field.getType(), ex);
}
catch (IllegalAccessException ex) {
throw new InvalidPropertyException(this.target.getClass(), propertyName, "Field is not accessible", ex);
}
} }
public <T> T convertIfNecessary( public <T> T convertIfNecessary(

View File

@ -495,7 +495,11 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter {
* property values, as an alternative to JavaBeans PropertyEditors. * property values, as an alternative to JavaBeans PropertyEditors.
*/ */
public void setConversionService(ConversionService conversionService) { public void setConversionService(ConversionService conversionService) {
Assert.state(this.conversionService == null, "DataBinder is already initialized with ConversionService");
this.conversionService = conversionService; this.conversionService = conversionService;
if (this.bindingResult != null && conversionService != null) {
this.bindingResult.initConversion(conversionService);
}
} }
/** /**

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2009 the original author or authors. * Copyright 2002-2010 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -327,6 +327,83 @@ public class DataBinderTests extends TestCase {
} }
} }
public void testBindingErrorWithFormatter() {
TestBean tb = new TestBean();
DataBinder binder = new DataBinder(tb);
FormattingConversionService conversionService = new FormattingConversionService();
ConversionServiceFactory.addDefaultConverters(conversionService);
conversionService.addFormatterForFieldType(Float.class, new NumberFormatter());
binder.setConversionService(conversionService);
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.add("myFloat", "1x2");
LocaleContextHolder.setLocale(Locale.GERMAN);
try {
binder.bind(pvs);
assertEquals(new Float(0.0), tb.getMyFloat());
assertEquals("1x2", binder.getBindingResult().getFieldValue("myFloat"));
assertTrue(binder.getBindingResult().hasFieldErrors("myFloat"));
}
finally {
LocaleContextHolder.resetLocaleContext();
}
}
public void testBindingWithFormatterAgainstFields() {
TestBean tb = new TestBean();
DataBinder binder = new DataBinder(tb);
FormattingConversionService conversionService = new FormattingConversionService();
ConversionServiceFactory.addDefaultConverters(conversionService);
conversionService.addFormatterForFieldType(Float.class, new NumberFormatter());
binder.setConversionService(conversionService);
binder.initDirectFieldAccess();
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.add("myFloat", "1,2");
LocaleContextHolder.setLocale(Locale.GERMAN);
try {
binder.bind(pvs);
assertEquals(new Float(1.2), tb.getMyFloat());
assertEquals("1,2", binder.getBindingResult().getFieldValue("myFloat"));
PropertyEditor editor = binder.getBindingResult().findEditor("myFloat", Float.class);
assertNotNull(editor);
editor.setValue(new Float(1.4));
assertEquals("1,4", editor.getAsText());
editor = binder.getBindingResult().findEditor("myFloat", null);
assertNotNull(editor);
editor.setAsText("1,6");
assertEquals(new Float(1.6), editor.getValue());
}
finally {
LocaleContextHolder.resetLocaleContext();
}
}
public void testBindingErrorWithFormatterAgainstFields() {
TestBean tb = new TestBean();
DataBinder binder = new DataBinder(tb);
binder.initDirectFieldAccess();
FormattingConversionService conversionService = new FormattingConversionService();
ConversionServiceFactory.addDefaultConverters(conversionService);
conversionService.addFormatterForFieldType(Float.class, new NumberFormatter());
binder.setConversionService(conversionService);
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.add("myFloat", "1x2");
LocaleContextHolder.setLocale(Locale.GERMAN);
try {
binder.bind(pvs);
assertEquals(new Float(0.0), tb.getMyFloat());
assertEquals("1x2", binder.getBindingResult().getFieldValue("myFloat"));
assertTrue(binder.getBindingResult().hasFieldErrors("myFloat"));
}
finally {
LocaleContextHolder.resetLocaleContext();
}
}
public void testBindingWithAllowedFields() throws Exception { public void testBindingWithAllowedFields() throws Exception {
TestBean rod = new TestBean(); TestBean rod = new TestBean();
DataBinder binder = new DataBinder(rod); DataBinder binder = new DataBinder(rod);