Skip to content

Commit 35c0ae7

Browse files
Martin Knopfsbrannen
Martin Knopf
authored andcommitted
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
1 parent d2e1150 commit 35c0ae7

File tree

3 files changed

+39
-4
lines changed

3 files changed

+39
-4
lines changed

spring-expression/src/main/java/org/springframework/expression/spel/ast/Indexer.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -712,10 +712,10 @@ private void growCollectionIfNecessary() {
712712
}
713713
TypeDescriptor elementType = this.collectionEntryDescriptor.getElementTypeDescriptor();
714714
try {
715-
Constructor<?> ctor = ReflectionUtils.accessibleConstructor(elementType.getType());
715+
Constructor<?> ctor = getConstructor(elementType.getType());
716716
int newElements = this.index - this.collection.size();
717717
while (newElements >= 0) {
718-
this.collection.add(ctor.newInstance());
718+
this.collection.add(ctor == null ? null : ctor.newInstance());
719719
newElements--;
720720
}
721721
}
@@ -725,6 +725,15 @@ private void growCollectionIfNecessary() {
725725
}
726726
}
727727

728+
Constructor<?> getConstructor(Class<?> type) {
729+
try {
730+
return ReflectionUtils.accessibleConstructor(type);
731+
}
732+
catch (Throwable ex) {
733+
return null;
734+
}
735+
}
736+
728737
@Override
729738
public boolean isWritable() {
730739
return true;

spring-expression/src/test/java/org/springframework/expression/spel/IndexingTests.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.lang.annotation.Retention;
2121
import java.lang.annotation.RetentionPolicy;
2222
import java.lang.annotation.Target;
23+
import java.math.BigDecimal;
2324
import java.util.ArrayList;
2425
import java.util.Arrays;
2526
import java.util.HashMap;
@@ -199,6 +200,27 @@ public void setGenericPropertyContainingListAutogrow() {
199200
}
200201
}
201202

203+
public List<BigDecimal> decimals;
204+
205+
@Test
206+
public void autoGrowWithoutDefaultConstructor() {
207+
this.decimals = new ArrayList<>();
208+
SpelExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true));
209+
parser.parseExpression("decimals[0]").setValue(this, "123.4");
210+
assertThat(decimals.get(0)).isEqualTo(BigDecimal.valueOf(123.4));
211+
}
212+
213+
@Test
214+
public void indexIntoPropertyContainingNullList() {
215+
this.decimals = new ArrayList<>();
216+
this.decimals.add(null);
217+
this.decimals.add(BigDecimal.ONE);
218+
SpelExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true));
219+
parser.parseExpression("decimals[0]").setValue(this, "9876.5");
220+
assertThat(decimals.get(0)).isEqualTo(BigDecimal.valueOf(9876.5));
221+
assertThat(decimals.get(1)).isEqualTo(BigDecimal.ONE);
222+
}
223+
202224
@Test
203225
public void indexIntoPropertyContainingList() {
204226
List<Integer> property = new ArrayList<>();

src/docs/asciidoc/core/core-expressions.adoc

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -339,8 +339,12 @@ index into an array or collection and the element at the specified index is `nul
339339
you can automatically create the element. This is useful when using expressions made up of a
340340
chain of property references. If you index into an array or list
341341
and specifying an index that is beyond the end of the current size of the array or
342-
list, you can automatically grow the array or list to accommodate that index. The following
343-
example demonstrates how to automatically grow the list:
342+
list, you can automatically grow the array or list to accommodate that index. In order to add
343+
an element at the specified index, SpEL will try to create the element using a default
344+
constructor before setting the specified value. If the element type does not have a default
345+
constructor, `null` will be added. Note if there is no built-in or custom converter, that knows
346+
how to set the value, `null` will remain in the array or list at the specified index.
347+
The following example demonstrates how to automatically grow the list:
344348

345349
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
346350
.Java

0 commit comments

Comments
 (0)