BeanWrapperImpl.getPropertyDescriptor allows for nested paths again
Issue: SPR-13403
This commit is contained in:
parent
90f46f9327
commit
ff9fb9aa88
|
@ -103,7 +103,7 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create new empty accessor. Wrapped instance needs to be set afterwards.
|
* Create a new empty accessor. Wrapped instance needs to be set afterwards.
|
||||||
* Registers default editors.
|
* Registers default editors.
|
||||||
* @see #setWrappedInstance
|
* @see #setWrappedInstance
|
||||||
*/
|
*/
|
||||||
|
@ -112,7 +112,7 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create new empty accessor. Wrapped instance needs to be set afterwards.
|
* Create a new empty accessor. Wrapped instance needs to be set afterwards.
|
||||||
* @param registerDefaultEditors whether to register default editors
|
* @param registerDefaultEditors whether to register default editors
|
||||||
* (can be suppressed if the accessor won't need any type conversion)
|
* (can be suppressed if the accessor won't need any type conversion)
|
||||||
* @see #setWrappedInstance
|
* @see #setWrappedInstance
|
||||||
|
@ -125,7 +125,7 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create new accessor for the given object.
|
* Create a new accessor for the given object.
|
||||||
* @param object object wrapped by this accessor
|
* @param object object wrapped by this accessor
|
||||||
*/
|
*/
|
||||||
protected AbstractNestablePropertyAccessor(Object object) {
|
protected AbstractNestablePropertyAccessor(Object object) {
|
||||||
|
@ -134,7 +134,7 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create new accessor, wrapping a new instance of the specified class.
|
* Create a new accessor, wrapping a new instance of the specified class.
|
||||||
* @param clazz class to instantiate and wrap
|
* @param clazz class to instantiate and wrap
|
||||||
*/
|
*/
|
||||||
protected AbstractNestablePropertyAccessor(Class<?> clazz) {
|
protected AbstractNestablePropertyAccessor(Class<?> clazz) {
|
||||||
|
@ -143,7 +143,7 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create new accessor for the given object,
|
* Create a new accessor for the given object,
|
||||||
* registering a nested path that the object is in.
|
* registering a nested path that the object is in.
|
||||||
* @param object object wrapped by this accessor
|
* @param object object wrapped by this accessor
|
||||||
* @param nestedPath the nested path of the object
|
* @param nestedPath the nested path of the object
|
||||||
|
@ -155,7 +155,7 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create new accessor for the given object,
|
* Create a new accessor for the given object,
|
||||||
* registering a nested path that the object is in.
|
* registering a nested path that the object is in.
|
||||||
* @param object object wrapped by this accessor
|
* @param object object wrapped by this accessor
|
||||||
* @param nestedPath the nested path of the object
|
* @param nestedPath the nested path of the object
|
||||||
|
@ -202,7 +202,7 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
|
||||||
* @param rootObject the root object at the top of the path
|
* @param rootObject the root object at the top of the path
|
||||||
*/
|
*/
|
||||||
public void setWrappedInstance(Object object, String nestedPath, Object rootObject) {
|
public void setWrappedInstance(Object object, String nestedPath, Object rootObject) {
|
||||||
Assert.notNull(object, "Bean object must not be null");
|
Assert.notNull(object, "Target object must not be null");
|
||||||
if (object.getClass().equals(javaUtilOptionalClass)) {
|
if (object.getClass().equals(javaUtilOptionalClass)) {
|
||||||
this.object = OptionalUnwrapper.unwrap(object);
|
this.object = OptionalUnwrapper.unwrap(object);
|
||||||
}
|
}
|
||||||
|
@ -791,7 +791,7 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
|
||||||
* @param nestedPath property path we know is nested
|
* @param nestedPath property path we know is nested
|
||||||
* @return last component of the path (the property on the target bean)
|
* @return last component of the path (the property on the target bean)
|
||||||
*/
|
*/
|
||||||
private String getFinalPath(AbstractNestablePropertyAccessor pa, String nestedPath) {
|
protected String getFinalPath(AbstractNestablePropertyAccessor pa, String nestedPath) {
|
||||||
if (pa == this) {
|
if (pa == this) {
|
||||||
return nestedPath;
|
return nestedPath;
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,8 +73,9 @@ public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements
|
||||||
*/
|
*/
|
||||||
private AccessControlContext acc;
|
private AccessControlContext acc;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create new empty BeanWrapperImpl. Wrapped instance needs to be set afterwards.
|
* Create a new empty BeanWrapperImpl. Wrapped instance needs to be set afterwards.
|
||||||
* Registers default editors.
|
* Registers default editors.
|
||||||
* @see #setWrappedInstance
|
* @see #setWrappedInstance
|
||||||
*/
|
*/
|
||||||
|
@ -83,7 +84,7 @@ public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create new empty BeanWrapperImpl. Wrapped instance needs to be set afterwards.
|
* Create a new empty BeanWrapperImpl. Wrapped instance needs to be set afterwards.
|
||||||
* @param registerDefaultEditors whether to register default editors
|
* @param registerDefaultEditors whether to register default editors
|
||||||
* (can be suppressed if the BeanWrapper won't need any type conversion)
|
* (can be suppressed if the BeanWrapper won't need any type conversion)
|
||||||
* @see #setWrappedInstance
|
* @see #setWrappedInstance
|
||||||
|
@ -93,7 +94,7 @@ public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create new BeanWrapperImpl for the given object.
|
* Create a new BeanWrapperImpl for the given object.
|
||||||
* @param object object wrapped by this BeanWrapper
|
* @param object object wrapped by this BeanWrapper
|
||||||
*/
|
*/
|
||||||
public BeanWrapperImpl(Object object) {
|
public BeanWrapperImpl(Object object) {
|
||||||
|
@ -101,7 +102,7 @@ public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create new BeanWrapperImpl, wrapping a new instance of the specified class.
|
* Create a new BeanWrapperImpl, wrapping a new instance of the specified class.
|
||||||
* @param clazz class to instantiate and wrap
|
* @param clazz class to instantiate and wrap
|
||||||
*/
|
*/
|
||||||
public BeanWrapperImpl(Class<?> clazz) {
|
public BeanWrapperImpl(Class<?> clazz) {
|
||||||
|
@ -109,7 +110,7 @@ public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create new BeanWrapperImpl for the given object,
|
* Create a new BeanWrapperImpl for the given object,
|
||||||
* registering a nested path that the object is in.
|
* registering a nested path that the object is in.
|
||||||
* @param object object wrapped by this BeanWrapper
|
* @param object object wrapped by this BeanWrapper
|
||||||
* @param nestedPath the nested path of the object
|
* @param nestedPath the nested path of the object
|
||||||
|
@ -120,17 +121,18 @@ public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create new BeanWrapperImpl for the given object,
|
* Create a new BeanWrapperImpl for the given object,
|
||||||
* registering a nested path that the object is in.
|
* registering a nested path that the object is in.
|
||||||
* @param object object wrapped by this BeanWrapper
|
* @param object object wrapped by this BeanWrapper
|
||||||
* @param nestedPath the nested path of the object
|
* @param nestedPath the nested path of the object
|
||||||
* @param superBw the containing BeanWrapper (must not be {@code null})
|
* @param parent the containing BeanWrapper (must not be {@code null})
|
||||||
*/
|
*/
|
||||||
private BeanWrapperImpl(Object object, String nestedPath, BeanWrapperImpl superBw) {
|
private BeanWrapperImpl(Object object, String nestedPath, BeanWrapperImpl parent) {
|
||||||
super(object, nestedPath, superBw);
|
super(object, nestedPath, parent);
|
||||||
setSecurityContext(superBw.acc);
|
setSecurityContext(parent.acc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setWrappedInstance(Object object, String nestedPath, Object rootObject) {
|
public void setWrappedInstance(Object object, String nestedPath, Object rootObject) {
|
||||||
super.setWrappedInstance(object, nestedPath, rootObject);
|
super.setWrappedInstance(object, nestedPath, rootObject);
|
||||||
|
@ -177,6 +179,7 @@ public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements
|
||||||
return this.cachedIntrospectionResults;
|
return this.cachedIntrospectionResults;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert the given value for the specified property to the latter's type.
|
* Convert the given value for the specified property to the latter's type.
|
||||||
* <p>This method is only intended for optimizations in a BeanFactory.
|
* <p>This method is only intended for optimizations in a BeanFactory.
|
||||||
|
@ -202,11 +205,10 @@ public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements
|
||||||
}
|
}
|
||||||
|
|
||||||
private Property property(PropertyDescriptor pd) {
|
private Property property(PropertyDescriptor pd) {
|
||||||
GenericTypeAwarePropertyDescriptor typeAware = (GenericTypeAwarePropertyDescriptor) pd;
|
GenericTypeAwarePropertyDescriptor gpd = (GenericTypeAwarePropertyDescriptor) pd;
|
||||||
return new Property(typeAware.getBeanClass(), typeAware.getReadMethod(), typeAware.getWriteMethod(), typeAware.getName());
|
return new Property(gpd.getBeanClass(), gpd.getReadMethod(), gpd.getWriteMethod(), gpd.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected BeanPropertyHandler getLocalPropertyHandler(String propertyName) {
|
protected BeanPropertyHandler getLocalPropertyHandler(String propertyName) {
|
||||||
PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(propertyName);
|
PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(propertyName);
|
||||||
|
@ -236,12 +238,14 @@ public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PropertyDescriptor getPropertyDescriptor(String propertyName) throws InvalidPropertyException {
|
public PropertyDescriptor getPropertyDescriptor(String propertyName) throws InvalidPropertyException {
|
||||||
BeanPropertyHandler propertyHandler = getLocalPropertyHandler(propertyName);
|
BeanWrapperImpl nestedBw = (BeanWrapperImpl) getPropertyAccessorForPropertyPath(propertyName);
|
||||||
if (propertyHandler == null) {
|
String finalPath = getFinalPath(nestedBw, propertyName);
|
||||||
|
PropertyDescriptor pd = nestedBw.getCachedIntrospectionResults().getPropertyDescriptor(finalPath);
|
||||||
|
if (pd == null) {
|
||||||
throw new InvalidPropertyException(getRootClass(), getNestedPath() + propertyName,
|
throw new InvalidPropertyException(getRootClass(), getNestedPath() + propertyName,
|
||||||
"No property '" + propertyName + "' found");
|
"No property '" + propertyName + "' found");
|
||||||
}
|
}
|
||||||
return propertyHandler.pd;
|
return pd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -250,8 +254,7 @@ public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements
|
||||||
private final PropertyDescriptor pd;
|
private final PropertyDescriptor pd;
|
||||||
|
|
||||||
public BeanPropertyHandler(PropertyDescriptor pd) {
|
public BeanPropertyHandler(PropertyDescriptor pd) {
|
||||||
super(pd.getPropertyType(),
|
super(pd.getPropertyType(), pd.getReadMethod() != null, pd.getWriteMethod() != null);
|
||||||
pd.getReadMethod() != null, pd.getWriteMethod() != null);
|
|
||||||
this.pd = pd;
|
this.pd = pd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,7 +290,6 @@ public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements
|
||||||
readMethod.setAccessible(true);
|
readMethod.setAccessible(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (System.getSecurityManager() != null) {
|
if (System.getSecurityManager() != null) {
|
||||||
try {
|
try {
|
||||||
return AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
|
return AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
|
||||||
|
|
|
@ -48,14 +48,27 @@ public class DirectFieldAccessor extends AbstractNestablePropertyAccessor {
|
||||||
|
|
||||||
private final Map<String, FieldPropertyHandler> fieldMap = new HashMap<String, FieldPropertyHandler>();
|
private final Map<String, FieldPropertyHandler> fieldMap = new HashMap<String, FieldPropertyHandler>();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new DirectFieldAccessor for the given object.
|
||||||
|
* @param object object wrapped by this DirectFieldAccessor
|
||||||
|
*/
|
||||||
public DirectFieldAccessor(Object object) {
|
public DirectFieldAccessor(Object object) {
|
||||||
super(object);
|
super(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected DirectFieldAccessor(Object object, String nestedPath, DirectFieldAccessor superBw) {
|
/**
|
||||||
super(object, nestedPath, superBw);
|
* Create a new DirectFieldAccessor for the given object,
|
||||||
|
* registering a nested path that the object is in.
|
||||||
|
* @param object object wrapped by this DirectFieldAccessor
|
||||||
|
* @param nestedPath the nested path of the object
|
||||||
|
* @param parent the containing DirectFieldAccessor (must not be {@code null})
|
||||||
|
*/
|
||||||
|
protected DirectFieldAccessor(Object object, String nestedPath, DirectFieldAccessor parent) {
|
||||||
|
super(object, nestedPath, parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected FieldPropertyHandler getLocalPropertyHandler(String propertyName) {
|
protected FieldPropertyHandler getLocalPropertyHandler(String propertyName) {
|
||||||
FieldPropertyHandler propertyHandler = this.fieldMap.get(propertyName);
|
FieldPropertyHandler propertyHandler = this.fieldMap.get(propertyName);
|
||||||
|
|
|
@ -214,7 +214,6 @@ public abstract class AbstractPropertyAccessorTests {
|
||||||
public void getNestedDeepProperty() {
|
public void getNestedDeepProperty() {
|
||||||
Person target = createPerson("John", "London", "UK");
|
Person target = createPerson("John", "London", "UK");
|
||||||
AbstractPropertyAccessor accessor = createAccessor(target);
|
AbstractPropertyAccessor accessor = createAccessor(target);
|
||||||
|
|
||||||
assertThat(accessor.getPropertyValue("address.country.name"), is("UK"));
|
assertThat(accessor.getPropertyValue("address.country.name"), is("UK"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,15 +36,16 @@ import static org.junit.Assert.*;
|
||||||
* @author Chris Beams
|
* @author Chris Beams
|
||||||
* @author Dave Syer
|
* @author Dave Syer
|
||||||
*/
|
*/
|
||||||
public final class BeanWrapperTests extends AbstractPropertyAccessorTests {
|
public class BeanWrapperTests extends AbstractPropertyAccessorTests {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected BeanWrapperImpl createAccessor(Object target) {
|
protected BeanWrapperImpl createAccessor(Object target) {
|
||||||
return new BeanWrapperImpl(target);
|
return new BeanWrapperImpl(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void setterDoestNotCallGetter() {
|
public void setterDoesNotCallGetter() {
|
||||||
GetterBean target = new GetterBean();
|
GetterBean target = new GetterBean();
|
||||||
BeanWrapper accessor = createAccessor(target);
|
BeanWrapper accessor = createAccessor(target);
|
||||||
accessor.setPropertyValue("name", "tom");
|
accessor.setPropertyValue("name", "tom");
|
||||||
|
@ -133,7 +134,7 @@ public final class BeanWrapperTests extends AbstractPropertyAccessorTests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // Can't be shared: no type mismatch with a field")
|
@Test // Can't be shared: no type mismatch with a field
|
||||||
public void setPropertyTypeMismatch() {
|
public void setPropertyTypeMismatch() {
|
||||||
PropertyTypeMismatch target = new PropertyTypeMismatch();
|
PropertyTypeMismatch target = new PropertyTypeMismatch();
|
||||||
BeanWrapper accessor = createAccessor(target);
|
BeanWrapper accessor = createAccessor(target);
|
||||||
|
@ -143,6 +144,21 @@ public final class BeanWrapperTests extends AbstractPropertyAccessorTests {
|
||||||
assertEquals(8, accessor.getPropertyValue("object"));
|
assertEquals(8, accessor.getPropertyValue("object"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void propertyDescriptors() {
|
||||||
|
TestBean target = new TestBean();
|
||||||
|
target.setSpouse(new TestBean());
|
||||||
|
BeanWrapper accessor = createAccessor(target);
|
||||||
|
accessor.setPropertyValue("name", "a");
|
||||||
|
accessor.setPropertyValue("spouse.name", "b");
|
||||||
|
assertEquals("a", target.getName());
|
||||||
|
assertEquals("b", target.getSpouse().getName());
|
||||||
|
assertEquals("a", accessor.getPropertyValue("name"));
|
||||||
|
assertEquals("b", accessor.getPropertyValue("spouse.name"));
|
||||||
|
assertEquals(String.class, accessor.getPropertyDescriptor("name").getPropertyType());
|
||||||
|
assertEquals(String.class, accessor.getPropertyDescriptor("spouse.name").getPropertyType());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getPropertyWithOptional() {
|
public void getPropertyWithOptional() {
|
||||||
GetterWithOptional target = new GetterWithOptional();
|
GetterWithOptional target = new GetterWithOptional();
|
||||||
|
|
|
@ -27,7 +27,7 @@ import static org.junit.Assert.*;
|
||||||
*
|
*
|
||||||
* @author Jose Luis Martin
|
* @author Jose Luis Martin
|
||||||
* @author Chris Beams
|
* @author Chris Beams
|
||||||
* @@author Stephane Nicoll
|
* @author Stephane Nicoll
|
||||||
*/
|
*/
|
||||||
public class DirectFieldAccessorTests extends AbstractPropertyAccessorTests {
|
public class DirectFieldAccessorTests extends AbstractPropertyAccessorTests {
|
||||||
|
|
||||||
|
@ -39,14 +39,17 @@ public class DirectFieldAccessorTests extends AbstractPropertyAccessorTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void withShadowedField() throws Exception {
|
public void withShadowedField() throws Exception {
|
||||||
|
final StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
TestBean target = new TestBean() {
|
TestBean target = new TestBean() {
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
StringBuilder name = new StringBuilder();
|
StringBuilder name = sb;
|
||||||
};
|
};
|
||||||
|
|
||||||
DirectFieldAccessor dfa = createAccessor(target);
|
DirectFieldAccessor dfa = createAccessor(target);
|
||||||
assertEquals(StringBuilder.class, dfa.getPropertyType("name"));
|
assertEquals(StringBuilder.class, dfa.getPropertyType("name"));
|
||||||
|
assertEquals(sb, dfa.getPropertyValue("name"));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue