Indexed objects (arrays/maps/lists) now settable
This commit is contained in:
@@ -17,6 +17,7 @@
|
|||||||
package org.springframework.expression.spel.ast;
|
package org.springframework.expression.spel.ast;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.antlr.runtime.Token;
|
import org.antlr.runtime.Token;
|
||||||
@@ -90,6 +91,94 @@ public class Indexer extends SpelNodeImpl {
|
|||||||
throw new SpelException(SpelMessages.INDEXING_NOT_SUPPORTED_FOR_TYPE, ctx.getClass().getName());
|
throw new SpelException(SpelMessages.INDEXING_NOT_SUPPORTED_FOR_TYPE, ctx.getClass().getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isWritable(ExpressionState expressionState) throws SpelException {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public void setValue(ExpressionState state, Object newValue) throws EvaluationException {
|
||||||
|
Object ctx = state.getActiveContextObject();
|
||||||
|
Object index = getChild(0).getValueInternal(state);
|
||||||
|
|
||||||
|
// Indexing into a Map
|
||||||
|
if (ctx instanceof Map) {
|
||||||
|
((Map) ctx).put(index,newValue); // TODO missing conversion for both index and newValue
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int idx = state.convertValue(index, Integer.class);
|
||||||
|
|
||||||
|
if (ctx.getClass().isArray()) {
|
||||||
|
setArrayElement(state, ctx, idx, newValue);
|
||||||
|
} else if (ctx instanceof List) {
|
||||||
|
List<Object> c = (List<Object>) ctx;
|
||||||
|
if (idx >= c.size()) {
|
||||||
|
throw new SpelException(SpelMessages.COLLECTION_INDEX_OUT_OF_BOUNDS, c.size(), idx);
|
||||||
|
}
|
||||||
|
c.set(idx,newValue); // TODO missing conversion
|
||||||
|
} else {
|
||||||
|
throw new SpelException(SpelMessages.INDEXING_NOT_SUPPORTED_FOR_TYPE, ctx.getClass().getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toStringAST() {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("[");
|
||||||
|
for (int i = 0; i < getChildCount(); i++) {
|
||||||
|
if (i > 0)
|
||||||
|
sb.append(",");
|
||||||
|
sb.append(getChild(i).toStringAST());
|
||||||
|
}
|
||||||
|
sb.append("]");
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setArrayElement(ExpressionState state, Object ctx, int idx, Object newValue) throws EvaluationException {
|
||||||
|
Class<?> arrayComponentType = ctx.getClass().getComponentType();
|
||||||
|
if (arrayComponentType == Integer.TYPE) {
|
||||||
|
int[] array = (int[]) ctx;
|
||||||
|
checkAccess(array.length, idx);
|
||||||
|
array[idx] = state.convertValue(newValue, Integer.class);
|
||||||
|
} else if (arrayComponentType == Boolean.TYPE) {
|
||||||
|
boolean[] array = (boolean[]) ctx;
|
||||||
|
checkAccess(array.length, idx);
|
||||||
|
array[idx] = state.convertValue(newValue, Boolean.class);
|
||||||
|
} else if (arrayComponentType == Character.TYPE) {
|
||||||
|
char[] array = (char[]) ctx;
|
||||||
|
checkAccess(array.length, idx);
|
||||||
|
array[idx] = state.convertValue(newValue, Character.class);
|
||||||
|
} else if (arrayComponentType == Long.TYPE) {
|
||||||
|
long[] array = (long[]) ctx;
|
||||||
|
checkAccess(array.length, idx);
|
||||||
|
array[idx] = state.convertValue(newValue, Long.class);
|
||||||
|
} else if (arrayComponentType == Short.TYPE) {
|
||||||
|
short[] array = (short[]) ctx;
|
||||||
|
checkAccess(array.length, idx);
|
||||||
|
array[idx] = state.convertValue(newValue, Short.class);
|
||||||
|
} else if (arrayComponentType == Double.TYPE) {
|
||||||
|
double[] array = (double[]) ctx;
|
||||||
|
checkAccess(array.length, idx);
|
||||||
|
array[idx] = state.convertValue(newValue, Double.class);
|
||||||
|
} else if (arrayComponentType == Float.TYPE) {
|
||||||
|
float[] array = (float[]) ctx;
|
||||||
|
checkAccess(array.length, idx);
|
||||||
|
array[idx] = state.convertValue(newValue, Float.class);
|
||||||
|
} else if (arrayComponentType == Byte.TYPE) {
|
||||||
|
byte[] array = (byte[]) ctx;
|
||||||
|
checkAccess(array.length, idx);
|
||||||
|
array[idx] = state.convertValue(newValue, Byte.class);
|
||||||
|
} else {
|
||||||
|
Object[] array = (Object[]) ctx;
|
||||||
|
checkAccess(array.length, idx);
|
||||||
|
array[idx] = state.convertValue(newValue, arrayComponentType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private Object accessArrayElement(Object ctx, int idx) throws SpelException {
|
private Object accessArrayElement(Object ctx, int idx) throws SpelException {
|
||||||
Class<?> arrayComponentType = ctx.getClass().getComponentType();
|
Class<?> arrayComponentType = ctx.getClass().getComponentType();
|
||||||
if (arrayComponentType == Integer.TYPE) {
|
if (arrayComponentType == Integer.TYPE) {
|
||||||
@@ -131,23 +220,6 @@ public class Indexer extends SpelNodeImpl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toStringAST() {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
sb.append("[");
|
|
||||||
for (int i = 0; i < getChildCount(); i++) {
|
|
||||||
if (i > 0)
|
|
||||||
sb.append(",");
|
|
||||||
sb.append(getChild(i).toStringAST());
|
|
||||||
}
|
|
||||||
sb.append("]");
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isWritable(ExpressionState expressionState) throws SpelException {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkAccess(int arrayLength, int index) throws SpelException {
|
private void checkAccess(int arrayLength, int index) throws SpelException {
|
||||||
if (index > arrayLength) {
|
if (index > arrayLength) {
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.antlr.runtime.Token;
|
import org.antlr.runtime.Token;
|
||||||
|
|
||||||
import org.springframework.expression.AccessException;
|
import org.springframework.expression.AccessException;
|
||||||
import org.springframework.expression.EvaluationContext;
|
import org.springframework.expression.EvaluationContext;
|
||||||
import org.springframework.expression.PropertyAccessor;
|
import org.springframework.expression.PropertyAccessor;
|
||||||
@@ -141,7 +140,7 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
|
|||||||
for (PropertyAccessor accessor : accessorsToTry) {
|
for (PropertyAccessor accessor : accessorsToTry) {
|
||||||
if (accessor.canWrite(eContext, contextObject, name)) {
|
if (accessor.canWrite(eContext, contextObject, name)) {
|
||||||
this.cachedWriteAccessor = accessor;
|
this.cachedWriteAccessor = accessor;
|
||||||
accessor.write(eContext, contextObject, name, newValue);
|
accessor.write(eContext, contextObject, name, newValue); // TODO missing conversion of newValue to the type of the property
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user