SPR-6984: auto grow collections on write through indexer
This commit is contained in:
parent
0cb7e4dcb3
commit
d932c043da
|
|
@ -61,7 +61,6 @@ public class Indexer extends SpelNodeImpl {
|
|||
super(pos, expr);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
TypedValue context = state.getActiveContextObject();
|
||||
|
|
@ -119,28 +118,7 @@ public class Indexer extends SpelNodeImpl {
|
|||
} else if (targetObject instanceof Collection) {
|
||||
Collection c = (Collection) targetObject;
|
||||
if (idx >= c.size()) {
|
||||
if (state.getConfiguration().isAutoGrowCollections()) {
|
||||
// Grow the collection
|
||||
Object newCollectionElement = null;
|
||||
try {
|
||||
int newElements = idx-c.size();
|
||||
Class elementClass = targetObjectTypeDescriptor.getElementType();
|
||||
if (elementClass == null) {
|
||||
throw new SpelEvaluationException(getStartPosition(), SpelMessage.UNABLE_TO_GROW_COLLECTION_UNKNOWN_ELEMENT_TYPE);
|
||||
}
|
||||
while (newElements>0) {
|
||||
c.add(elementClass.newInstance());
|
||||
newElements--;
|
||||
}
|
||||
newCollectionElement = targetObjectTypeDescriptor.getElementType().newInstance();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new SpelEvaluationException(getStartPosition(), ex, SpelMessage.UNABLE_TO_GROW_COLLECTION);
|
||||
}
|
||||
c.add(newCollectionElement);
|
||||
return new TypedValue(newCollectionElement,TypeDescriptor.valueOf(targetObjectTypeDescriptor.getElementType()));
|
||||
}
|
||||
else {
|
||||
if (!growCollection(state, targetObjectTypeDescriptor.getElementType(), idx, c)) {
|
||||
throw new SpelEvaluationException(getStartPosition(),SpelMessage.COLLECTION_INDEX_OUT_OF_BOUNDS, c.size(), idx);
|
||||
}
|
||||
}
|
||||
|
|
@ -234,8 +212,10 @@ public class Indexer extends SpelNodeImpl {
|
|||
int idx = (Integer)state.convertValue(index, TypeDescriptor.valueOf(Integer.class));
|
||||
Collection c = (Collection) targetObject;
|
||||
if (idx >= c.size()) {
|
||||
if (!growCollection(state, targetObjectTypeDescriptor.getElementType(), idx, c)) {
|
||||
throw new SpelEvaluationException(getStartPosition(),SpelMessage.COLLECTION_INDEX_OUT_OF_BOUNDS, c.size(), idx);
|
||||
}
|
||||
}
|
||||
if (targetObject instanceof List) {
|
||||
List list = (List)targetObject;
|
||||
Object possiblyConvertedValue = state.convertValue(newValue,TypeDescriptor.valueOf(targetObjectTypeDescriptor.getElementType()));
|
||||
|
|
@ -282,6 +262,40 @@ public class Indexer extends SpelNodeImpl {
|
|||
throw new SpelEvaluationException(getStartPosition(),SpelMessage.INDEXING_NOT_SUPPORTED_FOR_TYPE, targetObjectTypeDescriptor.asString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to grow the specified collection so that the specified index is valid.
|
||||
*
|
||||
* @param state the expression state
|
||||
* @param elementType the type of the elements in the collection
|
||||
* @param index the index into the collection that needs to be valid
|
||||
* @param collection the collection to grow with elements
|
||||
* @return true if collection growing succeeded, otherwise false
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private boolean growCollection(ExpressionState state, Class<?> elementType, int index,
|
||||
Collection collection) {
|
||||
if (state.getConfiguration().isAutoGrowCollections()) {
|
||||
Object newCollectionElement = null;
|
||||
try {
|
||||
int newElements = index-collection.size();
|
||||
if (elementType == null) {
|
||||
throw new SpelEvaluationException(getStartPosition(), SpelMessage.UNABLE_TO_GROW_COLLECTION_UNKNOWN_ELEMENT_TYPE);
|
||||
}
|
||||
while (newElements>0) {
|
||||
collection.add(elementType.newInstance());
|
||||
newElements--;
|
||||
}
|
||||
newCollectionElement = elementType.newInstance();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new SpelEvaluationException(getStartPosition(), ex, SpelMessage.UNABLE_TO_GROW_COLLECTION);
|
||||
}
|
||||
collection.add(newCollectionElement);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toStringAST() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import org.springframework.expression.spel.standard.SpelExpression;
|
|||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.expression.spel.support.StandardTypeLocator;
|
||||
import org.springframework.expression.spel.testresources.TestPerson;
|
||||
|
||||
/**
|
||||
* Tests the evaluation of real expressions in a real context.
|
||||
|
|
@ -522,4 +523,31 @@ public class EvaluationTests extends ExpressionTestCase {
|
|||
Assert.assertEquals(String.class,stringClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* SPR-6984: attempting to index a collection on write using an index that doesn't currently exist in the collection (address.crossStreets[0] below)
|
||||
*/
|
||||
@Test
|
||||
public void initializingCollectionElementsOnWrite() throws Exception {
|
||||
TestPerson person = new TestPerson();
|
||||
EvaluationContext context = new StandardEvaluationContext(person);
|
||||
SpelParserConfiguration config = new SpelParserConfiguration(true, true);
|
||||
ExpressionParser parser = new SpelExpressionParser(config);
|
||||
Expression expression = parser.parseExpression("name");
|
||||
expression.setValue(context, "Oleg");
|
||||
Assert.assertEquals("Oleg",person.getName());
|
||||
|
||||
expression = parser.parseExpression("address.street");
|
||||
expression.setValue(context, "123 High St");
|
||||
Assert.assertEquals("123 High St",person.getAddress().getStreet());
|
||||
|
||||
expression = parser.parseExpression("address.crossStreets[0]");
|
||||
expression.setValue(context, "Blah");
|
||||
Assert.assertEquals("Blah",person.getAddress().getCrossStreets().get(0));
|
||||
|
||||
expression = parser.parseExpression("address.crossStreets[3]");
|
||||
expression.setValue(context, "Wibble");
|
||||
Assert.assertEquals("Blah",person.getAddress().getCrossStreets().get(0));
|
||||
Assert.assertEquals("Wibble",person.getAddress().getCrossStreets().get(3));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
package org.springframework.expression.spel.testresources;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class TestAddress{
|
||||
private String street;
|
||||
private List<String> crossStreets;
|
||||
|
||||
public String getStreet() {
|
||||
return street;
|
||||
}
|
||||
public void setStreet(String street) {
|
||||
this.street = street;
|
||||
}
|
||||
public List<String> getCrossStreets() {
|
||||
return crossStreets;
|
||||
}
|
||||
public void setCrossStreets(List<String> crossStreets) {
|
||||
this.crossStreets = crossStreets;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package org.springframework.expression.spel.testresources;
|
||||
|
||||
public class TestPerson {
|
||||
private String name;
|
||||
private TestAddress address;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
public TestAddress getAddress() {
|
||||
return address;
|
||||
}
|
||||
public void setAddress(TestAddress address) {
|
||||
this.address = address;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue