Optimize InlineMap and InlineList in SpEL
- Make InlineList#constant and InlineMap#constant final. - Add more assertions for InlineMap tests. Closes gh-30251
This commit is contained in:
parent
baf367831f
commit
0e0c298dcf
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -35,55 +35,57 @@ import org.springframework.util.Assert;
|
|||
*
|
||||
* @author Andy Clement
|
||||
* @author Sam Brannen
|
||||
* @author Harry Yang
|
||||
* @since 3.0.4
|
||||
*/
|
||||
public class InlineList extends SpelNodeImpl {
|
||||
|
||||
// If the list is purely literals, it is a constant value and can be computed and cached
|
||||
@Nullable
|
||||
private TypedValue constant; // TODO must be immutable list
|
||||
private final TypedValue constant;
|
||||
|
||||
|
||||
public InlineList(int startPos, int endPos, SpelNodeImpl... args) {
|
||||
super(startPos, endPos, args);
|
||||
checkIfConstant();
|
||||
this.constant = computeConstantValue();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If all the components of the list are constants, or lists that themselves contain constants, then a constant list
|
||||
* can be built to represent this node. This will speed up later getValue calls and reduce the amount of garbage
|
||||
* If all the components of the list are constants, or lists
|
||||
* that themselves contain constants, then a constant list
|
||||
* can be built to represent this node. This will speed up
|
||||
* later getValue calls and reduce the amount of garbage
|
||||
* created.
|
||||
*/
|
||||
private void checkIfConstant() {
|
||||
boolean isConstant = true;
|
||||
@Nullable
|
||||
private TypedValue computeConstantValue() {
|
||||
for (int c = 0, max = getChildCount(); c < max; c++) {
|
||||
SpelNode child = getChild(c);
|
||||
if (!(child instanceof Literal)) {
|
||||
if (child instanceof InlineList inlineList) {
|
||||
if (!inlineList.isConstant()) {
|
||||
isConstant = false;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
isConstant = false;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isConstant) {
|
||||
List<Object> constantList = new ArrayList<>();
|
||||
int childcount = getChildCount();
|
||||
for (int c = 0; c < childcount; c++) {
|
||||
SpelNode child = getChild(c);
|
||||
if (child instanceof Literal literal) {
|
||||
constantList.add(literal.getLiteralValue().getValue());
|
||||
}
|
||||
else if (child instanceof InlineList inlineList) {
|
||||
constantList.add(inlineList.getConstantValue());
|
||||
}
|
||||
|
||||
List<Object> constantList = new ArrayList<>();
|
||||
int childcount = getChildCount();
|
||||
for (int c = 0; c < childcount; c++) {
|
||||
SpelNode child = getChild(c);
|
||||
if (child instanceof Literal literal) {
|
||||
constantList.add(literal.getLiteralValue().getValue());
|
||||
}
|
||||
else if (child instanceof InlineList inlineList) {
|
||||
constantList.add(inlineList.getConstantValue());
|
||||
}
|
||||
this.constant = new TypedValue(Collections.unmodifiableList(constantList));
|
||||
}
|
||||
return new TypedValue(Collections.unmodifiableList(constantList));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -32,18 +32,19 @@ import org.springframework.util.Assert;
|
|||
*
|
||||
* @author Andy Clement
|
||||
* @author Sam Brannen
|
||||
* @author Harry Yang
|
||||
* @since 4.1
|
||||
*/
|
||||
public class InlineMap extends SpelNodeImpl {
|
||||
|
||||
// If the map is purely literals, it is a constant value and can be computed and cached
|
||||
@Nullable
|
||||
private TypedValue constant;
|
||||
private final TypedValue constant;
|
||||
|
||||
|
||||
public InlineMap(int startPos, int endPos, SpelNodeImpl... args) {
|
||||
super(startPos, endPos, args);
|
||||
checkIfConstant();
|
||||
this.constant = computeConstantValue();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -52,59 +53,55 @@ public class InlineMap extends SpelNodeImpl {
|
|||
* contain constants, then a constant list can be built to represent this node.
|
||||
* This will speed up later getValue calls and reduce the amount of garbage created.
|
||||
*/
|
||||
private void checkIfConstant() {
|
||||
boolean isConstant = true;
|
||||
@Nullable
|
||||
private TypedValue computeConstantValue() {
|
||||
for (int c = 0, max = getChildCount(); c < max; c++) {
|
||||
SpelNode child = getChild(c);
|
||||
if (!(child instanceof Literal)) {
|
||||
if (child instanceof InlineList inlineList) {
|
||||
if (!inlineList.isConstant()) {
|
||||
isConstant = false;
|
||||
break;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else if (child instanceof InlineMap inlineMap) {
|
||||
if (!inlineMap.isConstant()) {
|
||||
isConstant = false;
|
||||
break;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else if (!(c % 2 == 0 && child instanceof PropertyOrFieldReference)) {
|
||||
isConstant = false;
|
||||
break;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isConstant) {
|
||||
Map<Object, Object> constantMap = new LinkedHashMap<>();
|
||||
int childCount = getChildCount();
|
||||
for (int c = 0; c < childCount; c++) {
|
||||
SpelNode keyChild = getChild(c++);
|
||||
SpelNode valueChild = getChild(c);
|
||||
Object key = null;
|
||||
Object value = null;
|
||||
if (keyChild instanceof Literal literal) {
|
||||
key = literal.getLiteralValue().getValue();
|
||||
}
|
||||
else if (keyChild instanceof PropertyOrFieldReference propertyOrFieldReference) {
|
||||
key = propertyOrFieldReference.getName();
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
if (valueChild instanceof Literal literal) {
|
||||
value = literal.getLiteralValue().getValue();
|
||||
}
|
||||
else if (valueChild instanceof InlineList inlineList) {
|
||||
value = inlineList.getConstantValue();
|
||||
}
|
||||
else if (valueChild instanceof InlineMap inlineMap) {
|
||||
value = inlineMap.getConstantValue();
|
||||
}
|
||||
constantMap.put(key, value);
|
||||
|
||||
Map<Object, Object> constantMap = new LinkedHashMap<>();
|
||||
int childCount = getChildCount();
|
||||
for (int c = 0; c < childCount; c++) {
|
||||
SpelNode keyChild = getChild(c++);
|
||||
SpelNode valueChild = getChild(c);
|
||||
Object key;
|
||||
Object value = null;
|
||||
if (keyChild instanceof Literal literal) {
|
||||
key = literal.getLiteralValue().getValue();
|
||||
}
|
||||
this.constant = new TypedValue(Collections.unmodifiableMap(constantMap));
|
||||
else if (keyChild instanceof PropertyOrFieldReference propertyOrFieldReference) {
|
||||
key = propertyOrFieldReference.getName();
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
if (valueChild instanceof Literal literal) {
|
||||
value = literal.getLiteralValue().getValue();
|
||||
}
|
||||
else if (valueChild instanceof InlineList inlineList) {
|
||||
value = inlineList.getConstantValue();
|
||||
}
|
||||
else if (valueChild instanceof InlineMap inlineMap) {
|
||||
value = inlineMap.getConstantValue();
|
||||
}
|
||||
constantMap.put(key, value);
|
||||
}
|
||||
return new TypedValue(Collections.unmodifiableMap(constantMap));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -117,6 +117,9 @@ public class MapTests extends AbstractExpressionTests {
|
|||
checkConstantMap("{#root.name:true}",false);
|
||||
checkConstantMap("{a:1,b:2,c:{d:true,e:false}}", true);
|
||||
checkConstantMap("{a:1,b:2,c:{d:{1,2,3},e:{4,5,6},f:{'a','b','c'}}}", true);
|
||||
// for nested InlineMap
|
||||
checkConstantMap("{a:{k:#d}}", false);
|
||||
checkConstantMap("{@bean:@bean}", false);
|
||||
}
|
||||
|
||||
private void checkConstantMap(String expressionText, boolean expectedToBeConstant) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue