Allow auto grow for entries w/o default constructor in SpEL

Prior to this commit, The "auto grow" feature in SpEL expressions only
worked for element types with a default constructor. For example, auto
grow did not work for a list of BigDecimal elements.

This commit inserts a null value in the list when no default
constructor can be found for the element type.

Closes gh-25367
This commit is contained in:
Martin Knopf 2020-07-07 14:47:48 +02:00 committed by Sam Brannen
parent d2e1150c79
commit 35c0ae7b0c
3 changed files with 39 additions and 4 deletions

View File

@ -712,10 +712,10 @@ public class Indexer extends SpelNodeImpl {
} }
TypeDescriptor elementType = this.collectionEntryDescriptor.getElementTypeDescriptor(); TypeDescriptor elementType = this.collectionEntryDescriptor.getElementTypeDescriptor();
try { try {
Constructor<?> ctor = ReflectionUtils.accessibleConstructor(elementType.getType()); Constructor<?> ctor = getConstructor(elementType.getType());
int newElements = this.index - this.collection.size(); int newElements = this.index - this.collection.size();
while (newElements >= 0) { while (newElements >= 0) {
this.collection.add(ctor.newInstance()); this.collection.add(ctor == null ? null : ctor.newInstance());
newElements--; newElements--;
} }
} }
@ -725,6 +725,15 @@ public class Indexer extends SpelNodeImpl {
} }
} }
Constructor<?> getConstructor(Class<?> type) {
try {
return ReflectionUtils.accessibleConstructor(type);
}
catch (Throwable ex) {
return null;
}
}
@Override @Override
public boolean isWritable() { public boolean isWritable() {
return true; return true;

View File

@ -20,6 +20,7 @@ import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import java.math.BigDecimal;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
@ -199,6 +200,27 @@ public class IndexingTests {
} }
} }
public List<BigDecimal> decimals;
@Test
public void autoGrowWithoutDefaultConstructor() {
this.decimals = new ArrayList<>();
SpelExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true));
parser.parseExpression("decimals[0]").setValue(this, "123.4");
assertThat(decimals.get(0)).isEqualTo(BigDecimal.valueOf(123.4));
}
@Test
public void indexIntoPropertyContainingNullList() {
this.decimals = new ArrayList<>();
this.decimals.add(null);
this.decimals.add(BigDecimal.ONE);
SpelExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true));
parser.parseExpression("decimals[0]").setValue(this, "9876.5");
assertThat(decimals.get(0)).isEqualTo(BigDecimal.valueOf(9876.5));
assertThat(decimals.get(1)).isEqualTo(BigDecimal.ONE);
}
@Test @Test
public void indexIntoPropertyContainingList() { public void indexIntoPropertyContainingList() {
List<Integer> property = new ArrayList<>(); List<Integer> property = new ArrayList<>();

View File

@ -339,8 +339,12 @@ index into an array or collection and the element at the specified index is `nul
you can automatically create the element. This is useful when using expressions made up of a you can automatically create the element. This is useful when using expressions made up of a
chain of property references. If you index into an array or list chain of property references. If you index into an array or list
and specifying an index that is beyond the end of the current size of the array or and specifying an index that is beyond the end of the current size of the array or
list, you can automatically grow the array or list to accommodate that index. The following list, you can automatically grow the array or list to accommodate that index. In order to add
example demonstrates how to automatically grow the list: an element at the specified index, SpEL will try to create the element using a default
constructor before setting the specified value. If the element type does not have a default
constructor, `null` will be added. Note if there is no built-in or custom converter, that knows
how to set the value, `null` will remain in the array or list at the specified index.
The following example demonstrates how to automatically grow the list:
[source,java,indent=0,subs="verbatim,quotes",role="primary"] [source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java .Java