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(); | ||||
| 				try { | ||||
| 					Constructor<?> ctor = ReflectionUtils.accessibleConstructor(elementType.getType()); | ||||
| 					Constructor<?> ctor = getConstructor(elementType.getType()); | ||||
| 					int newElements = this.index - this.collection.size(); | ||||
| 					while (newElements >= 0) { | ||||
| 						this.collection.add(ctor.newInstance()); | ||||
| 						this.collection.add(ctor == null ? null : ctor.newInstance()); | ||||
| 						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 | ||||
| 		public boolean isWritable() { | ||||
| 			return true; | ||||
|  |  | |||
|  | @ -20,6 +20,7 @@ import java.lang.annotation.ElementType; | |||
| import java.lang.annotation.Retention; | ||||
| import java.lang.annotation.RetentionPolicy; | ||||
| import java.lang.annotation.Target; | ||||
| import java.math.BigDecimal; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Arrays; | ||||
| 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 | ||||
| 	public void indexIntoPropertyContainingList() { | ||||
| 		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 | ||||
| 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 | ||||
| list, you can automatically grow the array or list to accommodate that index. The following | ||||
| example demonstrates how to automatically grow the list: | ||||
| list, you can automatically grow the array or list to accommodate that index. In order to add | ||||
| 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"] | ||||
| .Java | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue