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:
Harry Yang 2023-03-25 12:02:39 +08:00 committed by Sam Brannen
parent ddd6b123bb
commit 47aca90c58
1 changed files with 64 additions and 94 deletions

View File

@ -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() {