|
|
@ -20,9 +20,9 @@ import java.beans.PropertyDescriptor; |
|
|
|
import java.lang.reflect.Method; |
|
|
|
import java.lang.reflect.Method; |
|
|
|
|
|
|
|
|
|
|
|
import org.springframework.core.ResolvableType; |
|
|
|
import org.springframework.core.ResolvableType; |
|
|
|
import org.springframework.core.convert.Property; |
|
|
|
|
|
|
|
import org.springframework.core.convert.TypeDescriptor; |
|
|
|
import org.springframework.core.convert.TypeDescriptor; |
|
|
|
import org.springframework.lang.Nullable; |
|
|
|
import org.springframework.lang.Nullable; |
|
|
|
|
|
|
|
import org.springframework.util.Assert; |
|
|
|
import org.springframework.util.ReflectionUtils; |
|
|
|
import org.springframework.util.ReflectionUtils; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
@ -183,23 +183,15 @@ public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements |
|
|
|
throw new InvalidPropertyException(getRootClass(), getNestedPath() + propertyName, |
|
|
|
throw new InvalidPropertyException(getRootClass(), getNestedPath() + propertyName, |
|
|
|
"No property '" + propertyName + "' found"); |
|
|
|
"No property '" + propertyName + "' found"); |
|
|
|
} |
|
|
|
} |
|
|
|
TypeDescriptor td = cachedIntrospectionResults.getTypeDescriptor(pd); |
|
|
|
TypeDescriptor td = ((GenericTypeAwarePropertyDescriptor) pd).getTypeDescriptor(); |
|
|
|
if (td == null) { |
|
|
|
|
|
|
|
td = cachedIntrospectionResults.addTypeDescriptor(pd, new TypeDescriptor(property(pd))); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return convertForProperty(propertyName, null, value, td); |
|
|
|
return convertForProperty(propertyName, null, value, td); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private Property property(PropertyDescriptor pd) { |
|
|
|
|
|
|
|
GenericTypeAwarePropertyDescriptor gpd = (GenericTypeAwarePropertyDescriptor) pd; |
|
|
|
|
|
|
|
return new Property(gpd.getBeanClass(), gpd.getReadMethod(), gpd.getWriteMethod(), gpd.getName()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
@Nullable |
|
|
|
@Nullable |
|
|
|
protected BeanPropertyHandler getLocalPropertyHandler(String propertyName) { |
|
|
|
protected BeanPropertyHandler getLocalPropertyHandler(String propertyName) { |
|
|
|
PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(propertyName); |
|
|
|
PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(propertyName); |
|
|
|
return (pd != null ? new BeanPropertyHandler(pd) : null); |
|
|
|
return (pd != null ? new BeanPropertyHandler((GenericTypeAwarePropertyDescriptor) pd) : null); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
@ -234,58 +226,55 @@ public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements |
|
|
|
|
|
|
|
|
|
|
|
private class BeanPropertyHandler extends PropertyHandler { |
|
|
|
private class BeanPropertyHandler extends PropertyHandler { |
|
|
|
|
|
|
|
|
|
|
|
private final PropertyDescriptor pd; |
|
|
|
private final GenericTypeAwarePropertyDescriptor pd; |
|
|
|
|
|
|
|
|
|
|
|
private final TypeDescriptor typeDescriptor; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public BeanPropertyHandler(PropertyDescriptor pd) { |
|
|
|
public BeanPropertyHandler(GenericTypeAwarePropertyDescriptor pd) { |
|
|
|
super(pd.getPropertyType(), pd.getReadMethod() != null, pd.getWriteMethod() != null); |
|
|
|
super(pd.getPropertyType(), pd.getReadMethod() != null, pd.getWriteMethod() != null); |
|
|
|
this.pd = pd; |
|
|
|
this.pd = pd; |
|
|
|
this.typeDescriptor = new TypeDescriptor(property(pd)); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public TypeDescriptor toTypeDescriptor() { |
|
|
|
public TypeDescriptor toTypeDescriptor() { |
|
|
|
return this.typeDescriptor; |
|
|
|
return this.pd.getTypeDescriptor(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public ResolvableType getResolvableType() { |
|
|
|
public ResolvableType getResolvableType() { |
|
|
|
return this.typeDescriptor.getResolvableType(); |
|
|
|
return this.pd.getReadMethodType(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public TypeDescriptor getMapValueType(int nestingLevel) { |
|
|
|
public TypeDescriptor getMapValueType(int nestingLevel) { |
|
|
|
return new TypeDescriptor( |
|
|
|
return new TypeDescriptor( |
|
|
|
this.typeDescriptor.getResolvableType().getNested(nestingLevel).asMap().getGeneric(1), |
|
|
|
this.pd.getReadMethodType().getNested(nestingLevel).asMap().getGeneric(1), |
|
|
|
null, this.typeDescriptor.getAnnotations()); |
|
|
|
null, this.pd.getTypeDescriptor().getAnnotations()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public TypeDescriptor getCollectionType(int nestingLevel) { |
|
|
|
public TypeDescriptor getCollectionType(int nestingLevel) { |
|
|
|
return new TypeDescriptor( |
|
|
|
return new TypeDescriptor( |
|
|
|
this.typeDescriptor.getResolvableType().getNested(nestingLevel).asCollection().getGeneric(), |
|
|
|
this.pd.getReadMethodType().getNested(nestingLevel).asCollection().getGeneric(), |
|
|
|
null, this.typeDescriptor.getAnnotations()); |
|
|
|
null, this.pd.getTypeDescriptor().getAnnotations()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
@Nullable |
|
|
|
@Nullable |
|
|
|
public TypeDescriptor nested(int level) { |
|
|
|
public TypeDescriptor nested(int level) { |
|
|
|
return TypeDescriptor.nested(property(this.pd), level); |
|
|
|
return this.pd.getTypeDescriptor().nested(level); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
@Nullable |
|
|
|
@Nullable |
|
|
|
public Object getValue() throws Exception { |
|
|
|
public Object getValue() throws Exception { |
|
|
|
Method readMethod = this.pd.getReadMethod(); |
|
|
|
Method readMethod = this.pd.getReadMethod(); |
|
|
|
|
|
|
|
Assert.state(readMethod != null, "No read method available"); |
|
|
|
ReflectionUtils.makeAccessible(readMethod); |
|
|
|
ReflectionUtils.makeAccessible(readMethod); |
|
|
|
return readMethod.invoke(getWrappedInstance(), (Object[]) null); |
|
|
|
return readMethod.invoke(getWrappedInstance(), (Object[]) null); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public void setValue(@Nullable Object value) throws Exception { |
|
|
|
public void setValue(@Nullable Object value) throws Exception { |
|
|
|
Method writeMethod = (this.pd instanceof GenericTypeAwarePropertyDescriptor typeAwarePd ? |
|
|
|
Method writeMethod = this.pd.getWriteMethodForActualAccess(); |
|
|
|
typeAwarePd.getWriteMethodForActualAccess() : this.pd.getWriteMethod()); |
|
|
|
|
|
|
|
ReflectionUtils.makeAccessible(writeMethod); |
|
|
|
ReflectionUtils.makeAccessible(writeMethod); |
|
|
|
writeMethod.invoke(getWrappedInstance(), value); |
|
|
|
writeMethod.invoke(getWrappedInstance(), value); |
|
|
|
} |
|
|
|
} |
|
|
|