|
|
|
@ -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. |
|
|
|
@ -41,20 +41,31 @@ import org.springframework.expression.spel.support.ReflectivePropertyAccessor; |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public class PropertyOrFieldReference extends SpelNodeImpl { |
|
|
|
public class PropertyOrFieldReference extends SpelNodeImpl { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private final boolean nullSafe; |
|
|
|
|
|
|
|
|
|
|
|
private final String name; |
|
|
|
private final String name; |
|
|
|
|
|
|
|
|
|
|
|
private volatile PropertyAccessor cachedReadAccessor; |
|
|
|
private volatile PropertyAccessor cachedReadAccessor; |
|
|
|
|
|
|
|
|
|
|
|
private volatile PropertyAccessor cachedWriteAccessor; |
|
|
|
private volatile PropertyAccessor cachedWriteAccessor; |
|
|
|
|
|
|
|
|
|
|
|
private final boolean nullSafe; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public PropertyOrFieldReference(boolean nullSafe, String propertyOrFieldName, int pos) { |
|
|
|
public PropertyOrFieldReference(boolean nullSafe, String propertyOrFieldName, int pos) { |
|
|
|
super(pos); |
|
|
|
super(pos); |
|
|
|
name = propertyOrFieldName; |
|
|
|
|
|
|
|
this.nullSafe = nullSafe; |
|
|
|
this.nullSafe = nullSafe; |
|
|
|
|
|
|
|
this.name = propertyOrFieldName; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public boolean isNullSafe() { |
|
|
|
|
|
|
|
return this.nullSafe; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public String getName() { |
|
|
|
|
|
|
|
return this.name; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException { |
|
|
|
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException { |
|
|
|
TypedValue result = readProperty(state, this.name); |
|
|
|
TypedValue result = readProperty(state, this.name); |
|
|
|
@ -70,28 +81,38 @@ public class PropertyOrFieldReference extends SpelNodeImpl { |
|
|
|
try { |
|
|
|
try { |
|
|
|
if (isWritable(state)) { |
|
|
|
if (isWritable(state)) { |
|
|
|
List newList = ArrayList.class.newInstance(); |
|
|
|
List newList = ArrayList.class.newInstance(); |
|
|
|
writeProperty(state, name, newList); |
|
|
|
writeProperty(state, this.name, newList); |
|
|
|
result = readProperty(state, this.name); |
|
|
|
result = readProperty(state, this.name); |
|
|
|
} |
|
|
|
} |
|
|
|
} catch (InstantiationException e) { |
|
|
|
|
|
|
|
throw new SpelEvaluationException(getStartPosition(), e, SpelMessage.UNABLE_TO_CREATE_LIST_FOR_INDEXING); |
|
|
|
|
|
|
|
} catch (IllegalAccessException e) { |
|
|
|
|
|
|
|
throw new SpelEvaluationException(getStartPosition(), e, SpelMessage.UNABLE_TO_CREATE_LIST_FOR_INDEXING); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
catch (InstantiationException ex) { |
|
|
|
|
|
|
|
throw new SpelEvaluationException(getStartPosition(), ex, |
|
|
|
|
|
|
|
SpelMessage.UNABLE_TO_CREATE_LIST_FOR_INDEXING); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
catch (IllegalAccessException ex) { |
|
|
|
|
|
|
|
throw new SpelEvaluationException(getStartPosition(), ex, |
|
|
|
|
|
|
|
SpelMessage.UNABLE_TO_CREATE_LIST_FOR_INDEXING); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
try { |
|
|
|
try { |
|
|
|
if (isWritable(state)) { |
|
|
|
if (isWritable(state)) { |
|
|
|
Map newMap = HashMap.class.newInstance(); |
|
|
|
Map newMap = HashMap.class.newInstance(); |
|
|
|
writeProperty(state, name, newMap); |
|
|
|
writeProperty(state, name, newMap); |
|
|
|
result = readProperty(state, this.name); |
|
|
|
result = readProperty(state, this.name); |
|
|
|
} |
|
|
|
} |
|
|
|
} catch (InstantiationException e) { |
|
|
|
} |
|
|
|
throw new SpelEvaluationException(getStartPosition(), e, SpelMessage.UNABLE_TO_CREATE_MAP_FOR_INDEXING); |
|
|
|
catch (InstantiationException ex) { |
|
|
|
} catch (IllegalAccessException e) { |
|
|
|
throw new SpelEvaluationException(getStartPosition(), ex, |
|
|
|
throw new SpelEvaluationException(getStartPosition(), e, SpelMessage.UNABLE_TO_CREATE_MAP_FOR_INDEXING); |
|
|
|
SpelMessage.UNABLE_TO_CREATE_MAP_FOR_INDEXING); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
catch (IllegalAccessException ex) { |
|
|
|
|
|
|
|
throw new SpelEvaluationException(getStartPosition(), ex, |
|
|
|
|
|
|
|
SpelMessage.UNABLE_TO_CREATE_MAP_FOR_INDEXING); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
// 'simple' object
|
|
|
|
// 'simple' object
|
|
|
|
try { |
|
|
|
try { |
|
|
|
if (isWritable(state)) { |
|
|
|
if (isWritable(state)) { |
|
|
|
@ -99,10 +120,14 @@ public class PropertyOrFieldReference extends SpelNodeImpl { |
|
|
|
writeProperty(state, name, newObject); |
|
|
|
writeProperty(state, name, newObject); |
|
|
|
result = readProperty(state, this.name); |
|
|
|
result = readProperty(state, this.name); |
|
|
|
} |
|
|
|
} |
|
|
|
} catch (InstantiationException e) { |
|
|
|
} |
|
|
|
throw new SpelEvaluationException(getStartPosition(), e, SpelMessage.UNABLE_TO_DYNAMICALLY_CREATE_OBJECT,result.getTypeDescriptor().getType()); |
|
|
|
catch (InstantiationException ex) { |
|
|
|
} catch (IllegalAccessException e) { |
|
|
|
throw new SpelEvaluationException(getStartPosition(), ex, |
|
|
|
throw new SpelEvaluationException(getStartPosition(), e, SpelMessage.UNABLE_TO_DYNAMICALLY_CREATE_OBJECT,result.getTypeDescriptor().getType()); |
|
|
|
SpelMessage.UNABLE_TO_DYNAMICALLY_CREATE_OBJECT, result.getTypeDescriptor().getType()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
catch (IllegalAccessException ex) { |
|
|
|
|
|
|
|
throw new SpelEvaluationException(getStartPosition(), ex, |
|
|
|
|
|
|
|
SpelMessage.UNABLE_TO_DYNAMICALLY_CREATE_OBJECT, result.getTypeDescriptor().getType()); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -176,7 +201,8 @@ public class PropertyOrFieldReference extends SpelNodeImpl { |
|
|
|
} |
|
|
|
} |
|
|
|
if (contextObject.getValue() == null) { |
|
|
|
if (contextObject.getValue() == null) { |
|
|
|
throw new SpelEvaluationException(SpelMessage.PROPERTY_OR_FIELD_NOT_READABLE_ON_NULL, name); |
|
|
|
throw new SpelEvaluationException(SpelMessage.PROPERTY_OR_FIELD_NOT_READABLE_ON_NULL, name); |
|
|
|
} else { |
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
throw new SpelEvaluationException(getStartPosition(),SpelMessage.PROPERTY_OR_FIELD_NOT_READABLE, name, |
|
|
|
throw new SpelEvaluationException(getStartPosition(),SpelMessage.PROPERTY_OR_FIELD_NOT_READABLE, name, |
|
|
|
FormatHelper.formatClassNameForMessage(contextObjectClass)); |
|
|
|
FormatHelper.formatClassNameForMessage(contextObjectClass)); |
|
|
|
} |
|
|
|
} |
|
|
|
@ -215,33 +241,34 @@ public class PropertyOrFieldReference extends SpelNodeImpl { |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} catch (AccessException ae) { |
|
|
|
} |
|
|
|
|
|
|
|
catch (AccessException ae) { |
|
|
|
throw new SpelEvaluationException(getStartPosition(), ae, SpelMessage.EXCEPTION_DURING_PROPERTY_WRITE, |
|
|
|
throw new SpelEvaluationException(getStartPosition(), ae, SpelMessage.EXCEPTION_DURING_PROPERTY_WRITE, |
|
|
|
name, ae.getMessage()); |
|
|
|
name, ae.getMessage()); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if (contextObject.getValue()==null) { |
|
|
|
if (contextObject.getValue()==null) { |
|
|
|
throw new SpelEvaluationException(getStartPosition(),SpelMessage.PROPERTY_OR_FIELD_NOT_WRITABLE_ON_NULL, name); |
|
|
|
throw new SpelEvaluationException(getStartPosition(), SpelMessage.PROPERTY_OR_FIELD_NOT_WRITABLE_ON_NULL, name); |
|
|
|
} else { |
|
|
|
} |
|
|
|
throw new SpelEvaluationException(getStartPosition(),SpelMessage.PROPERTY_OR_FIELD_NOT_WRITABLE, name, FormatHelper |
|
|
|
else { |
|
|
|
.formatClassNameForMessage(contextObjectClass)); |
|
|
|
throw new SpelEvaluationException(getStartPosition(), SpelMessage.PROPERTY_OR_FIELD_NOT_WRITABLE, name, |
|
|
|
|
|
|
|
FormatHelper.formatClassNameForMessage(contextObjectClass)); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public boolean isWritableProperty(String name, ExpressionState state) throws SpelEvaluationException { |
|
|
|
public boolean isWritableProperty(String name, ExpressionState state) throws SpelEvaluationException { |
|
|
|
Object contextObject = state.getActiveContextObject().getValue(); |
|
|
|
Object contextObject = state.getActiveContextObject().getValue(); |
|
|
|
// TypeDescriptor td = state.getActiveContextObject().getTypeDescriptor();
|
|
|
|
// TypeDescriptor td = state.getActiveContextObject().getTypeDescriptor();
|
|
|
|
EvaluationContext eContext = state.getEvaluationContext(); |
|
|
|
EvaluationContext eContext = state.getEvaluationContext(); |
|
|
|
|
|
|
|
List<PropertyAccessor> resolversToTry = getPropertyAccessorsToTry(getObjectClass(contextObject), state); |
|
|
|
List<PropertyAccessor> resolversToTry = getPropertyAccessorsToTry(getObjectClass(contextObject),state); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (resolversToTry != null) { |
|
|
|
if (resolversToTry != null) { |
|
|
|
for (PropertyAccessor pfResolver : resolversToTry) { |
|
|
|
for (PropertyAccessor pfResolver : resolversToTry) { |
|
|
|
try { |
|
|
|
try { |
|
|
|
if (pfResolver.canWrite(eContext, contextObject, name)) { |
|
|
|
if (pfResolver.canWrite(eContext, contextObject, name)) { |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
} catch (AccessException ae) { |
|
|
|
} |
|
|
|
|
|
|
|
catch (AccessException ae) { |
|
|
|
// let others try
|
|
|
|
// let others try
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -288,9 +315,5 @@ public class PropertyOrFieldReference extends SpelNodeImpl { |
|
|
|
resolvers.addAll(generalAccessors); |
|
|
|
resolvers.addAll(generalAccessors); |
|
|
|
return resolvers; |
|
|
|
return resolvers; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
String getName() { |
|
|
|
|
|
|
|
return name; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|