Optimize array creation in SpEL ConstructorReference
- Create primitive arrays directly instead of using Array#newInstance. - Replace if-else blocks with enhanced switch statement. Closes gh-30189
This commit is contained in:
		
							parent
							
								
									ddd6b123bb
								
							
						
					
					
						commit
						47aca90c58
					
				| 
						 | 
					@ -38,7 +38,6 @@ import org.springframework.expression.spel.CodeFlow;
 | 
				
			||||||
import org.springframework.expression.spel.ExpressionState;
 | 
					import org.springframework.expression.spel.ExpressionState;
 | 
				
			||||||
import org.springframework.expression.spel.SpelEvaluationException;
 | 
					import org.springframework.expression.spel.SpelEvaluationException;
 | 
				
			||||||
import org.springframework.expression.spel.SpelMessage;
 | 
					import org.springframework.expression.spel.SpelMessage;
 | 
				
			||||||
import org.springframework.expression.spel.SpelNode;
 | 
					 | 
				
			||||||
import org.springframework.expression.spel.support.ReflectiveConstructorExecutor;
 | 
					import org.springframework.expression.spel.support.ReflectiveConstructorExecutor;
 | 
				
			||||||
import org.springframework.lang.Nullable;
 | 
					import org.springframework.lang.Nullable;
 | 
				
			||||||
import org.springframework.util.Assert;
 | 
					import org.springframework.util.Assert;
 | 
				
			||||||
| 
						 | 
					@ -60,6 +59,7 @@ import org.springframework.util.Assert;
 | 
				
			||||||
 * @author Andy Clement
 | 
					 * @author Andy Clement
 | 
				
			||||||
 * @author Juergen Hoeller
 | 
					 * @author Juergen Hoeller
 | 
				
			||||||
 * @author Sam Brannen
 | 
					 * @author Sam Brannen
 | 
				
			||||||
 | 
					 * @author <a href="https://github.com/TAKETODAY">Harry Yang</a>
 | 
				
			||||||
 * @since 3.0
 | 
					 * @since 3.0
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public class ConstructorReference extends SpelNodeImpl {
 | 
					public class ConstructorReference extends SpelNodeImpl {
 | 
				
			||||||
| 
						 | 
					@ -332,39 +332,18 @@ public class ConstructorReference extends SpelNodeImpl {
 | 
				
			||||||
					throw new SpelEvaluationException(getStartPosition(), SpelMessage.INITIALIZER_LENGTH_INCORRECT);
 | 
										throw new SpelEvaluationException(getStartPosition(), SpelMessage.INITIALIZER_LENGTH_INCORRECT);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			// Build the array and populate it
 | 
					
 | 
				
			||||||
			int arraySize = initializer.getChildCount();
 | 
								newArray = switch (arrayTypeCode) {
 | 
				
			||||||
			newArray = Array.newInstance(componentType, arraySize);
 | 
									case OBJECT -> createReferenceTypeArray(state, typeConverter, initializer.children, componentType);
 | 
				
			||||||
			if (arrayTypeCode == TypeCode.OBJECT) {
 | 
									case BOOLEAN -> createBooleanArray(state, typeConverter, initializer.children);
 | 
				
			||||||
				populateReferenceTypeArray(state, newArray, typeConverter, initializer, componentType);
 | 
									case BYTE -> createByteArray(state, typeConverter, initializer.children);
 | 
				
			||||||
			}
 | 
									case CHAR -> createCharArray(state, typeConverter, initializer.children);
 | 
				
			||||||
			else if (arrayTypeCode == TypeCode.BOOLEAN) {
 | 
									case DOUBLE -> createDoubleArray(state, typeConverter, initializer.children);
 | 
				
			||||||
				populateBooleanArray(state, newArray, typeConverter, initializer);
 | 
									case FLOAT -> createFloatArray(state, typeConverter, initializer.children);
 | 
				
			||||||
			}
 | 
									case INT -> createIntArray(state, typeConverter, initializer.children);
 | 
				
			||||||
			else if (arrayTypeCode == TypeCode.BYTE) {
 | 
									case LONG -> createLongArray(state, typeConverter, initializer.children);
 | 
				
			||||||
				populateByteArray(state, newArray, typeConverter, initializer);
 | 
									case SHORT -> createShortArray(state, typeConverter, initializer.children);
 | 
				
			||||||
			}
 | 
								};
 | 
				
			||||||
			else if (arrayTypeCode == TypeCode.CHAR) {
 | 
					 | 
				
			||||||
				populateCharArray(state, newArray, typeConverter, initializer);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			else if (arrayTypeCode == TypeCode.DOUBLE) {
 | 
					 | 
				
			||||||
				populateDoubleArray(state, newArray, typeConverter, initializer);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			else if (arrayTypeCode == TypeCode.FLOAT) {
 | 
					 | 
				
			||||||
				populateFloatArray(state, newArray, typeConverter, initializer);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			else if (arrayTypeCode == TypeCode.INT) {
 | 
					 | 
				
			||||||
				populateIntArray(state, newArray, typeConverter, initializer);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			else if (arrayTypeCode == TypeCode.LONG) {
 | 
					 | 
				
			||||||
				populateLongArray(state, newArray, typeConverter, initializer);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			else if (arrayTypeCode == TypeCode.SHORT) {
 | 
					 | 
				
			||||||
				populateShortArray(state, newArray, typeConverter, initializer);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			else {
 | 
					 | 
				
			||||||
				throw new IllegalStateException(arrayTypeCode.name());
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return new TypedValue(newArray);
 | 
							return new TypedValue(newArray);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -376,97 +355,88 @@ public class ConstructorReference extends SpelNodeImpl {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private void populateReferenceTypeArray(ExpressionState state, Object newArray, TypeConverter typeConverter,
 | 
						private Object createReferenceTypeArray(ExpressionState state,
 | 
				
			||||||
			InlineList initializer, Class<?> componentType) {
 | 
								TypeConverter typeConverter, SpelNodeImpl[] children, Class<?> componentType) {
 | 
				
			||||||
 | 
							Object[] newArray = (Object[]) Array.newInstance(componentType, children.length);
 | 
				
			||||||
		TypeDescriptor toTypeDescriptor = TypeDescriptor.valueOf(componentType);
 | 
							TypeDescriptor toTypeDescriptor = TypeDescriptor.valueOf(componentType);
 | 
				
			||||||
		Object[] newObjectArray = (Object[]) newArray;
 | 
							for (int i = 0; i < newArray.length; i++) {
 | 
				
			||||||
		for (int i = 0; i < newObjectArray.length; i++) {
 | 
								Object arrayEntry = children[i].getValue(state);
 | 
				
			||||||
			SpelNode elementNode = initializer.getChild(i);
 | 
								newArray[i] = typeConverter.convertValue(arrayEntry,
 | 
				
			||||||
			Object arrayEntry = elementNode.getValue(state);
 | 
					 | 
				
			||||||
			newObjectArray[i] = typeConverter.convertValue(arrayEntry,
 | 
					 | 
				
			||||||
					TypeDescriptor.forObject(arrayEntry), toTypeDescriptor);
 | 
										TypeDescriptor.forObject(arrayEntry), toTypeDescriptor);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							return newArray;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private void populateByteArray(ExpressionState state, Object newArray, TypeConverter typeConverter,
 | 
						private byte[] createByteArray(ExpressionState state, TypeConverter converter, SpelNodeImpl[] children) {
 | 
				
			||||||
			InlineList initializer) {
 | 
							byte[] byteArray = new byte[children.length];
 | 
				
			||||||
 | 
							for (int i = 0; i < byteArray.length; i++) {
 | 
				
			||||||
		byte[] newByteArray = (byte[]) newArray;
 | 
								TypedValue typedValue = children[i].getTypedValue(state);
 | 
				
			||||||
		for (int i = 0; i < newByteArray.length; i++) {
 | 
								byteArray[i] = ExpressionUtils.toByte(converter, typedValue);
 | 
				
			||||||
			TypedValue typedValue = initializer.getChild(i).getTypedValue(state);
 | 
					 | 
				
			||||||
			newByteArray[i] = ExpressionUtils.toByte(typeConverter, typedValue);
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							return byteArray;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private void populateFloatArray(ExpressionState state, Object newArray, TypeConverter typeConverter,
 | 
						private float[] createFloatArray(ExpressionState state, TypeConverter typeConverter, SpelNodeImpl[] children) {
 | 
				
			||||||
			InlineList initializer) {
 | 
							float[] floatArray = new float[children.length];
 | 
				
			||||||
 | 
							for (int i = 0; i < floatArray.length; i++) {
 | 
				
			||||||
		float[] newFloatArray = (float[]) newArray;
 | 
								TypedValue typedValue = children[i].getTypedValue(state);
 | 
				
			||||||
		for (int i = 0; i < newFloatArray.length; i++) {
 | 
								floatArray[i] = ExpressionUtils.toFloat(typeConverter, typedValue);
 | 
				
			||||||
			TypedValue typedValue = initializer.getChild(i).getTypedValue(state);
 | 
					 | 
				
			||||||
			newFloatArray[i] = ExpressionUtils.toFloat(typeConverter, typedValue);
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							return floatArray;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private void populateDoubleArray(ExpressionState state, Object newArray, TypeConverter typeConverter,
 | 
						private double[] createDoubleArray(ExpressionState state, TypeConverter typeConverter, SpelNodeImpl[] children) {
 | 
				
			||||||
			InlineList initializer) {
 | 
							double[] doubleArray = new double[children.length];
 | 
				
			||||||
 | 
							for (int i = 0; i < doubleArray.length; i++) {
 | 
				
			||||||
		double[] newDoubleArray = (double[]) newArray;
 | 
								TypedValue typedValue = children[i].getTypedValue(state);
 | 
				
			||||||
		for (int i = 0; i < newDoubleArray.length; i++) {
 | 
								doubleArray[i] = ExpressionUtils.toDouble(typeConverter, typedValue);
 | 
				
			||||||
			TypedValue typedValue = initializer.getChild(i).getTypedValue(state);
 | 
					 | 
				
			||||||
			newDoubleArray[i] = ExpressionUtils.toDouble(typeConverter, typedValue);
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							return doubleArray;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private void populateShortArray(ExpressionState state, Object newArray, TypeConverter typeConverter,
 | 
						private short[] createShortArray(ExpressionState state, TypeConverter typeConverter, SpelNodeImpl[] children) {
 | 
				
			||||||
			InlineList initializer) {
 | 
							short[] shortArray = new short[children.length];
 | 
				
			||||||
 | 
							for (int i = 0; i < shortArray.length; i++) {
 | 
				
			||||||
		short[] newShortArray = (short[]) newArray;
 | 
								TypedValue typedValue = children[i].getTypedValue(state);
 | 
				
			||||||
		for (int i = 0; i < newShortArray.length; i++) {
 | 
								shortArray[i] = ExpressionUtils.toShort(typeConverter, typedValue);
 | 
				
			||||||
			TypedValue typedValue = initializer.getChild(i).getTypedValue(state);
 | 
					 | 
				
			||||||
			newShortArray[i] = ExpressionUtils.toShort(typeConverter, typedValue);
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							return shortArray;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private void populateLongArray(ExpressionState state, Object newArray, TypeConverter typeConverter,
 | 
						private long[] createLongArray(ExpressionState state, TypeConverter converter, SpelNodeImpl[] children) {
 | 
				
			||||||
			InlineList initializer) {
 | 
							long[] longArray = new long[children.length];
 | 
				
			||||||
 | 
							for (int i = 0; i < longArray.length; i++) {
 | 
				
			||||||
		long[] newLongArray = (long[]) newArray;
 | 
								TypedValue typedValue = children[i].getTypedValue(state);
 | 
				
			||||||
		for (int i = 0; i < newLongArray.length; i++) {
 | 
								longArray[i] = ExpressionUtils.toLong(converter, typedValue);
 | 
				
			||||||
			TypedValue typedValue = initializer.getChild(i).getTypedValue(state);
 | 
					 | 
				
			||||||
			newLongArray[i] = ExpressionUtils.toLong(typeConverter, typedValue);
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							return longArray;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private void populateCharArray(ExpressionState state, Object newArray, TypeConverter typeConverter,
 | 
						private char[] createCharArray(ExpressionState state, TypeConverter typeConverter, SpelNodeImpl[] children) {
 | 
				
			||||||
			InlineList initializer) {
 | 
							char[] newCharArray = new char[children.length];
 | 
				
			||||||
 | 
					 | 
				
			||||||
		char[] newCharArray = (char[]) newArray;
 | 
					 | 
				
			||||||
		for (int i = 0; i < newCharArray.length; i++) {
 | 
							for (int i = 0; i < newCharArray.length; i++) {
 | 
				
			||||||
			TypedValue typedValue = initializer.getChild(i).getTypedValue(state);
 | 
								TypedValue typedValue = children[i].getTypedValue(state);
 | 
				
			||||||
			newCharArray[i] = ExpressionUtils.toChar(typeConverter, typedValue);
 | 
								newCharArray[i] = ExpressionUtils.toChar(typeConverter, typedValue);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							return newCharArray;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private void populateBooleanArray(ExpressionState state, Object newArray, TypeConverter typeConverter,
 | 
						private boolean[] createBooleanArray(ExpressionState state, TypeConverter typeConverter, SpelNodeImpl[] children) {
 | 
				
			||||||
			InlineList initializer) {
 | 
							boolean[] newBooleanArray = new boolean[children.length];
 | 
				
			||||||
 | 
					 | 
				
			||||||
		boolean[] newBooleanArray = (boolean[]) newArray;
 | 
					 | 
				
			||||||
		for (int i = 0; i < newBooleanArray.length; i++) {
 | 
							for (int i = 0; i < newBooleanArray.length; i++) {
 | 
				
			||||||
			TypedValue typedValue = initializer.getChild(i).getTypedValue(state);
 | 
								TypedValue typedValue = children[i].getTypedValue(state);
 | 
				
			||||||
			newBooleanArray[i] = ExpressionUtils.toBoolean(typeConverter, typedValue);
 | 
								newBooleanArray[i] = ExpressionUtils.toBoolean(typeConverter, typedValue);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							return newBooleanArray;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private void populateIntArray(ExpressionState state, Object newArray, TypeConverter typeConverter,
 | 
						private int[] createIntArray(ExpressionState state, TypeConverter typeConverter, SpelNodeImpl[] children) {
 | 
				
			||||||
			InlineList initializer) {
 | 
							int[] intArray = new int[children.length];
 | 
				
			||||||
 | 
							for (int i = 0; i < intArray.length; i++) {
 | 
				
			||||||
		int[] newIntArray = (int[]) newArray;
 | 
								TypedValue typedValue = children[i].getTypedValue(state);
 | 
				
			||||||
		for (int i = 0; i < newIntArray.length; i++) {
 | 
								intArray[i] = ExpressionUtils.toInt(typeConverter, typedValue);
 | 
				
			||||||
			TypedValue typedValue = initializer.getChild(i).getTypedValue(state);
 | 
					 | 
				
			||||||
			newIntArray[i] = ExpressionUtils.toInt(typeConverter, typedValue);
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							return intArray;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private boolean hasInitializer() {
 | 
						private boolean hasInitializer() {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue