From 78c1d085d584c3754e6843ebba6f911c2804f745 Mon Sep 17 00:00:00 2001 From: Andy Clement Date: Mon, 30 Mar 2009 19:40:20 +0000 Subject: [PATCH] Indexed objects (arrays/maps/lists) now settable git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@879 50f2f4bb-b051-0410-bef5-90022cba6387 --- .../expression/spel/ast/Indexer.java | 106 +++++++++++++++--- .../spel/ast/PropertyOrFieldReference.java | 3 +- 2 files changed, 90 insertions(+), 19 deletions(-) diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Indexer.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Indexer.java index fe605e88d25..5f8fc6b072f 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Indexer.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Indexer.java @@ -17,6 +17,7 @@ package org.springframework.expression.spel.ast; import java.util.Collection; +import java.util.List; import java.util.Map; 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()); } + + @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 c = (List) 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 { Class arrayComponentType = ctx.getClass().getComponentType(); 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 { if (index > arrayLength) { diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/PropertyOrFieldReference.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/PropertyOrFieldReference.java index 3e7654d181c..fc26c3a7738 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/PropertyOrFieldReference.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/PropertyOrFieldReference.java @@ -20,7 +20,6 @@ import java.util.ArrayList; import java.util.List; import org.antlr.runtime.Token; - import org.springframework.expression.AccessException; import org.springframework.expression.EvaluationContext; import org.springframework.expression.PropertyAccessor; @@ -141,7 +140,7 @@ public class PropertyOrFieldReference extends SpelNodeImpl { for (PropertyAccessor accessor : accessorsToTry) { if (accessor.canWrite(eContext, contextObject, name)) { 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; } }