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:
parent
d2e1150c79
commit
35c0ae7b0c
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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<>();
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue