AbstractNestablePropertyAccessor之Bean的属性设置

编程

static class People{

String name;

int age;

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public int getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

}

static class Stu{

List<People> list2;

List<String> list;

People people;

Map<String,People> map;

public List<People> getList2() {

return list2;

}

public void setList2(List<People> list2) {

this.list2 = list2;

}

public List<String> getList() {

return list;

}

public void setList(List<String> list) {

this.list = list;

}

public Map<String, People> getMap() {

return map;

}

public void setMap(Map<String, People> map) {

this.map = map;

}

public People getPeople() {

return people;

}

public void setPeople(People people) {

this.people = people;

}

}

下面看看怎么设置属性

public static void main(String[] args) {

try {

Stu s1 = new Stu();

DirectFieldAccessor d = new DirectFieldAccessor(s1);

d.setAutoGrowNestedPaths(true);

// d.setPropertyValue("list[1]","a1");

// d.setPropertyValue("list2[1].name","liuax");

// d.setPropertyValue("people.name","liuax");

d.setPropertyValue("map["a"].name","liuax");

System.out.println(JSONObject.toJSONString(s1));

} catch (Exception e) {

e.printStackTrace();

}

}

AbstractNestablePropertyAccessor 抽象方法

protected abstract NotWritablePropertyException createNotWritablePropertyException(String propertyName);

创建一个嵌套的处理器,比如上面的list2[1].name,它要先处理list2[1],然后在处理name,类似于递归

protected abstract AbstractNestablePropertyAccessor newNestedPropertyAccessor(Object object, String nestedPath);

通过反射执行属性获取与设置

protected FieldPropertyHandler getLocalPropertyHandler(String propertyName)

AbstractNestablePropertyAccessor源码解读

本篇不包含对象转换

入口

@Override  

public void setPropertyValue(String propertyName, @Nullable Object value) throws BeansException {

AbstractNestablePropertyAccessor nestedPa;

try {

//如果没有嵌套,返回自身,否则新建一个,比如xxx.xxx就是嵌套的,下面看嵌套流程A

nestedPa = getPropertyAccessorForPropertyPath(propertyName);

}

catch (NotReadablePropertyException ex) {

throw new NotWritablePropertyException(getRootClass(), this.nestedPath + propertyName,

"Nested property in path "" + propertyName + "" does not exist", ex);

}

PropertyTokenHolder tokens = getPropertyNameTokens(getFinalPath(nestedPa, propertyName));

nestedPa.setPropertyValue(tokens, new PropertyValue(propertyName, value));

}

流程A

protected AbstractNestablePropertyAccessor getPropertyAccessorForPropertyPath(String propertyPath) {  

int pos = PropertyAccessorUtils.getFirstNestedPropertySeparatorIndex(propertyPath);

// Handle nested properties recursively.

if (pos > -1) {

String nestedProperty = propertyPath.substring(0, pos);

String nestedPath = propertyPath.substring(pos + 1);

AbstractNestablePropertyAccessor nestedPa = getNestedPropertyAccessor(nestedProperty);

//list[1].stu[0].people 先处理list[1],再次处理stu[0]

return nestedPa.getPropertyAccessorForPropertyPath(nestedPath);

}

else {

return this;

}

}

private AbstractNestablePropertyAccessor getNestedPropertyAccessor(String nestedProperty) {

if (this.nestedPropertyAccessors == null) {

this.nestedPropertyAccessors = new HashMap<>();

}

// Get value of bean property.

PropertyTokenHolder tokens = getPropertyNameTokens(nestedProperty);

String canonicalName = tokens.canonicalName;

//获取key对应的值,比如list[1],people,看流程B

Object value = getPropertyValue(tokens);

if (value == null || (value instanceof Optional && !((Optional) value).isPresent())) {

if (isAutoGrowNestedPaths()) {

value = setDefaultValue(tokens);

}

else {

throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + canonicalName);

}

}

// Lookup cached sub-PropertyAccessor, create new one if not found.

AbstractNestablePropertyAccessor nestedPa = this.nestedPropertyAccessors.get(canonicalName);

if (nestedPa == null || nestedPa.getWrappedInstance() != ObjectUtils.unwrapOptional(value)) {

if (logger.isTraceEnabled()) {

logger.trace("Creating new nested " + getClass().getSimpleName() + " for property "" + canonicalName + """);

}

nestedPa = newNestedPropertyAccessor(value, this.nestedPath + canonicalName + NESTED\_PROPERTY\_SEPARATOR);

// Inherit all type-specific PropertyEditors.

copyDefaultEditorsTo(nestedPa);

copyCustomEditorsTo(nestedPa, canonicalName);

this.nestedPropertyAccessors.put(canonicalName, nestedPa);

}

else {

if (logger.isTraceEnabled()) {

logger.trace("Using cached nested property accessor for property "" + canonicalName + """);

}

}

return nestedPa;

}

流程B

protected Object getPropertyValue(PropertyTokenHolder tokens) throws BeansException {  

String propertyName = tokens.canonicalName;

String actualName = tokens.actualName;

PropertyHandler ph = getLocalPropertyHandler(actualName);

if (ph == null || !ph.isReadable()) {

throw new NotReadablePropertyException(getRootClass(), this.nestedPath + propertyName);

}

try {

Object value = ph.getValue();

if (tokens.keys != null) {

if (value == null) {

//是否需要自动对NULL进行赋值

if (isAutoGrowNestedPaths()) {

//进入流程C

value = setDefaultValue(new PropertyTokenHolder(tokens.actualName));

}

else {

throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + propertyName,

"Cannot access indexed value of property referenced in indexed " +

"property path "" + propertyName + "": returned null");

}

}

StringBuilder indexedPropertyName = new StringBuilder(tokens.actualName);

// apply indexes and map keys

for (int i = 0; i < tokens.keys.length; i++) {

String key = tokens.keys[i];

if (value == null) {

throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + propertyName,

"Cannot access indexed value of property referenced in indexed " +

"property path "" + propertyName + "": returned null");

}

else if (value.getClass().isArray()) {

int index = Integer.parseInt(key);

value = growArrayIfNecessary(value, index, indexedPropertyName.toString());

value = Array.get(value, index);

}

else if (value instanceof List) {

int index = Integer.parseInt(key);

List<Object> list = (List<Object>) value;

growCollectionIfNecessary(list, index, indexedPropertyName.toString(), ph, i + 1);

value = list.get(index);

}

else if (value instanceof Set) {

// Apply index to Iterator in case of a Set.

Set<Object> set = (Set<Object>) value;

int index = Integer.parseInt(key);

if (index < 0 || index >= set.size()) {

throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,

"Cannot get element with index " + index + " from Set of size " +

set.size() + ", accessed using property path "" + propertyName + """);

}

Iterator<Object> it = set.iterator();

for (int j = 0; it.hasNext(); j++) {

Object elem = it.next();

if (j == index) {

value = elem;

break;

}

}

}

else if (value instanceof Map) {

Map<Object, Object> map = (Map<Object, Object>) value;

Class<?> mapKeyType = ph.getResolvableType().getNested(i + 1).asMap().resolveGeneric(0);

// IMPORTANT: Do not pass full property name in here - property editors

// must not kick in for map keys but rather only for map values. TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(mapKeyType);

Object convertedMapKey = convertIfNecessary(null, null, key, mapKeyType, typeDescriptor);

value = map.get(convertedMapKey);

}

else {

throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,

"Property referenced in indexed property path "" + propertyName +

"" is neither an array nor a List nor a Set nor a Map; returned value was [" + value + "]");

}

indexedPropertyName.append(PROPERTY\_KEY\_PREFIX).append(key).append(PROPERTY\_KEY\_SUFFIX);

}

}

return value;

}

catch (IndexOutOfBoundsException ex) {

throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,

"Index of out of bounds in property path "" + propertyName + """, ex);

}

catch (NumberFormatException | TypeMismatchException ex) {

throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,

"Invalid index in property path "" + propertyName + """, ex);

}

catch (InvocationTargetException ex) {

throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,

"Getter for property "" + actualName + "" threw exception", ex);

}

catch (Exception ex) {

throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,

"Illegal attempt to get property "" + actualName + "" threw exception", ex);

}

}

流程C

private Object setDefaultValue(PropertyTokenHolder tokens) {  

//流程D

PropertyValue pv = createDefaultPropertyValue(tokens);

//流程E

setPropertyValue(tokens, pv);

//再次进入流程B

Object defaultValue = getPropertyValue(tokens);

Assert.state(defaultValue != null, "Default value must not be null");

return defaultValue;

}

流程D

private PropertyValue createDefaultPropertyValue(PropertyTokenHolder tokens) {  

TypeDescriptor desc = getPropertyTypeDescriptor(tokens.canonicalName);

if (desc == null) {

throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + tokens.canonicalName,

"Could not determine property type for auto-growing a default value");

}

Object defaultValue = newValue(desc.getType(), desc, tokens.canonicalName);

return new PropertyValue(tokens.canonicalName, defaultValue);

}

private Object newValue(Class<?> type, @Nullable TypeDescriptor desc, String name) {

try {

if (type.isArray()) {

Class<?> componentType = type.getComponentType();

// TODO - only handles 2-dimensional arrays

if (componentType.isArray()) {

Object array = Array.newInstance(componentType, 1);

Array.set(array, 0, Array.newInstance(componentType.getComponentType(), 0));

return array;

}

else {

return Array.newInstance(componentType, 0);

}

}

else if (Collection.class.isAssignableFrom(type)) {

TypeDescriptor elementDesc = (desc != null ? desc.getElementTypeDescriptor() : null);

return CollectionFactory.createCollection(type, (elementDesc != null ? elementDesc.getType() : null), 16);

}

else if (Map.class.isAssignableFrom(type)) {

TypeDescriptor keyDesc = (desc != null ? desc.getMapKeyTypeDescriptor() : null);

return CollectionFactory.createMap(type, (keyDesc != null ? keyDesc.getType() : null), 16);

}

else {

Constructor<?> ctor = type.getDeclaredConstructor();

if (Modifier.isPrivate(ctor.getModifiers())) {

throw new IllegalAccessException("Auto-growing not allowed with private constructor: " + ctor);

}

return BeanUtils.instantiateClass(ctor);

}

}

catch (Throwable ex) {

throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + name,

"Could not instantiate property type [" + type.getName() + "] to auto-grow nested property path", ex);

}

}

流程E

protected void setPropertyValue(PropertyTokenHolder tokens, PropertyValue pv) throws BeansException {  

if (tokens.keys != null) {

//处理list[0] ,list[1],map["a"] 将值塞进Bean中 流程F

processKeyedProperty(tokens, pv);

}

else {

//处理people,这种干对象的情况 流程G

processLocalProperty(tokens, pv);

}

}

流程F

private void processKeyedProperty(PropertyTokenHolder tokens, PropertyValue pv) {  

Object propValue = getPropertyHoldingValue(tokens);

PropertyHandler ph = getLocalPropertyHandler(tokens.actualName);

if (ph == null) {

throw new InvalidPropertyException(

getRootClass(), this.nestedPath + tokens.actualName, "No property handler found");

}

Assert.state(tokens.keys != null, "No token keys");

String lastKey = tokens.keys[tokens.keys.length - 1];

if (propValue.getClass().isArray()) {

Class<?> requiredType = propValue.getClass().getComponentType();

int arrayIndex = Integer.parseInt(lastKey);

Object oldValue = null;

try {

if (isExtractOldValueForEditor() && arrayIndex < Array.getLength(propValue)) {

oldValue = Array.get(propValue, arrayIndex);

}

Object convertedValue = convertIfNecessary(tokens.canonicalName, oldValue, pv.getValue(),

requiredType, ph.nested(tokens.keys.length));

int length = Array.getLength(propValue);

if (arrayIndex >= length && arrayIndex < this.autoGrowCollectionLimit) {

Class<?> componentType = propValue.getClass().getComponentType();

Object newArray = Array.newInstance(componentType, arrayIndex + 1);

System.arraycopy(propValue, 0, newArray, 0, length);

setPropertyValue(tokens.actualName, newArray);

propValue = getPropertyValue(tokens.actualName);

}

Array.set(propValue, arrayIndex, convertedValue);

}

catch (IndexOutOfBoundsException ex) {

throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,

"Invalid array index in property path "" + tokens.canonicalName + """, ex);

}

}

else if (propValue instanceof List) {

Class<?> requiredType = ph.getCollectionType(tokens.keys.length);

List<Object> list = (List<Object>) propValue;

int index = Integer.parseInt(lastKey);

Object oldValue = null;

if (isExtractOldValueForEditor() && index < list.size()) {

oldValue = list.get(index);

}

Object convertedValue = convertIfNecessary(tokens.canonicalName, oldValue, pv.getValue(),

requiredType, ph.nested(tokens.keys.length));

int size = list.size();

if (index >= size && index < this.autoGrowCollectionLimit) {

for (int i = size; i < index; i++) {

try {

list.add(null);

}

catch (NullPointerException ex) {

throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,

"Cannot set element with index " + index + " in List of size " +

size + ", accessed using property path "" + tokens.canonicalName +

"": List does not support filling up gaps with null elements");

}

}

list.add(convertedValue);

}

else {

try {

list.set(index, convertedValue);

}

catch (IndexOutOfBoundsException ex) {

throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,

"Invalid list index in property path "" + tokens.canonicalName + """, ex);

}

}

}

else if (propValue instanceof Map) {

Class<?> mapKeyType = ph.getMapKeyType(tokens.keys.length);

Class<?> mapValueType = ph.getMapValueType(tokens.keys.length);

Map<Object, Object> map = (Map<Object, Object>) propValue;

// IMPORTANT: Do not pass full property name in here - property editors

// must not kick in for map keys but rather only for map values. TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(mapKeyType);

Object convertedMapKey = convertIfNecessary(null, null, lastKey, mapKeyType, typeDescriptor);

Object oldValue = null;

if (isExtractOldValueForEditor()) {

oldValue = map.get(convertedMapKey);

}

// Pass full property name and old value in here, since we want full

// conversion ability for map values. Object convertedMapValue = convertIfNecessary(tokens.canonicalName, oldValue, pv.getValue(),

mapValueType, ph.nested(tokens.keys.length));

map.put(convertedMapKey, convertedMapValue);

}

else {

throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,

"Property referenced in indexed property path "" + tokens.canonicalName +

"" is neither an array nor a List nor a Map; returned value was [" + propValue + "]");

}

}

流程G

private void processLocalProperty(PropertyTokenHolder tokens, PropertyValue pv) {  

PropertyHandler ph = getLocalPropertyHandler(tokens.actualName);

if (ph == null || !ph.isWritable()) {

if (pv.isOptional()) {

if (logger.isDebugEnabled()) {

logger.debug("Ignoring optional value for property "" + tokens.actualName +

"" - property not found on bean class [" + getRootClass().getName() + "]");

}

return;

}

else {

throw createNotWritablePropertyException(tokens.canonicalName);

}

}

Object oldValue = null;

try {

Object originalValue = pv.getValue();

Object valueToApply = originalValue;

if (!Boolean.FALSE.equals(pv.conversionNecessary)) {

if (pv.isConverted()) {

valueToApply = pv.getConvertedValue();

}

else {

if (isExtractOldValueForEditor() && ph.isReadable()) {

try {

oldValue = ph.getValue();

}

catch (Exception ex) {

if (ex instanceof PrivilegedActionException) {

ex = ((PrivilegedActionException) ex).getException();

}

if (logger.isDebugEnabled()) {

logger.debug("Could not read previous value of property "" +

this.nestedPath + tokens.canonicalName + """, ex);

}

}

}

valueToApply = convertForProperty(

tokens.canonicalName, oldValue, originalValue, ph.toTypeDescriptor());

}

pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue);

}

ph.setValue(valueToApply);

}

catch (TypeMismatchException ex) {

throw ex;

}

catch (InvocationTargetException ex) {

PropertyChangeEvent propertyChangeEvent = new PropertyChangeEvent(

getRootInstance(), this.nestedPath + tokens.canonicalName, oldValue, pv.getValue());

if (ex.getTargetException() instanceof ClassCastException) {

throw new TypeMismatchException(propertyChangeEvent, ph.getPropertyType(), ex.getTargetException());

}

else {

Throwable cause = ex.getTargetException();

if (cause instanceof UndeclaredThrowableException) {

// May happen e.g. with Groovy-generated methods

cause = cause.getCause();

}

throw new MethodInvocationException(propertyChangeEvent, cause);

}

}

catch (Exception ex) {

PropertyChangeEvent pce = new PropertyChangeEvent(

getRootInstance(), this.nestedPath + tokens.canonicalName, oldValue, pv.getValue());

throw new MethodInvocationException(pce, ex);

}

}

以上是 AbstractNestablePropertyAccessor之Bean的属性设置 的全部内容, 来源链接: utcz.com/z/513335.html

回到顶部