1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.expression.spel.ast;
18
19 import java.util.ArrayList;
20 import java.util.Collections;
21 import java.util.List;
22
23 import org.springframework.asm.ClassWriter;
24 import org.springframework.asm.MethodVisitor;
25 import org.springframework.expression.EvaluationException;
26 import org.springframework.expression.TypedValue;
27 import org.springframework.expression.spel.CodeFlow;
28 import org.springframework.expression.spel.ExpressionState;
29 import org.springframework.expression.spel.SpelNode;
30
31
32
33
34
35
36
37 public class InlineList extends SpelNodeImpl {
38
39
40 private TypedValue constant = null;
41
42
43 public InlineList(int pos, SpelNodeImpl... args) {
44 super(pos, args);
45 checkIfConstant();
46 }
47
48
49
50
51
52
53
54 private void checkIfConstant() {
55 boolean isConstant = true;
56 for (int c = 0, max = getChildCount(); c < max; c++) {
57 SpelNode child = getChild(c);
58 if (!(child instanceof Literal)) {
59 if (child instanceof InlineList) {
60 InlineList inlineList = (InlineList) child;
61 if (!inlineList.isConstant()) {
62 isConstant = false;
63 }
64 }
65 else {
66 isConstant = false;
67 }
68 }
69 }
70 if (isConstant) {
71 List<Object> constantList = new ArrayList<Object>();
72 int childcount = getChildCount();
73 for (int c = 0; c < childcount; c++) {
74 SpelNode child = getChild(c);
75 if ((child instanceof Literal)) {
76 constantList.add(((Literal) child).getLiteralValue().getValue());
77 }
78 else if (child instanceof InlineList) {
79 constantList.add(((InlineList) child).getConstantValue());
80 }
81 }
82 this.constant = new TypedValue(Collections.unmodifiableList(constantList));
83 }
84 }
85
86 @Override
87 public TypedValue getValueInternal(ExpressionState expressionState) throws EvaluationException {
88 if (this.constant != null) {
89 return this.constant;
90 }
91 else {
92 List<Object> returnValue = new ArrayList<Object>();
93 int childCount = getChildCount();
94 for (int c = 0; c < childCount; c++) {
95 returnValue.add(getChild(c).getValue(expressionState));
96 }
97 return new TypedValue(returnValue);
98 }
99 }
100
101 @Override
102 public String toStringAST() {
103 StringBuilder sb = new StringBuilder("{");
104
105 int count = getChildCount();
106 for (int c = 0; c < count; c++) {
107 if (c > 0) {
108 sb.append(",");
109 }
110 sb.append(getChild(c).toStringAST());
111 }
112 sb.append("}");
113 return sb.toString();
114 }
115
116
117
118
119 public boolean isConstant() {
120 return (this.constant != null);
121 }
122
123 @SuppressWarnings("unchecked")
124 public List<Object> getConstantValue() {
125 return (List<Object>) this.constant.getValue();
126 }
127
128 @Override
129 public boolean isCompilable() {
130 return isConstant();
131 }
132
133 @Override
134 public void generateCode(MethodVisitor mv, CodeFlow codeflow) {
135 final String constantFieldName = "inlineList$"+codeflow.nextFieldId();
136 final String clazzname = codeflow.getClassname();
137
138 codeflow.registerNewField(new CodeFlow.FieldAdder() {
139 public void generateField(ClassWriter cw, CodeFlow codeflow) {
140 cw.visitField(ACC_PRIVATE|ACC_STATIC|ACC_FINAL, constantFieldName, "Ljava/util/List;", null, null);
141 }
142 });
143
144 codeflow.registerNewClinit(new CodeFlow.ClinitAdder() {
145 public void generateCode(MethodVisitor mv, CodeFlow codeflow) {
146 generateClinitCode(clazzname,constantFieldName, mv,codeflow,false);
147 }
148 });
149
150 mv.visitFieldInsn(GETSTATIC, clazzname, constantFieldName, "Ljava/util/List;");
151 codeflow.pushDescriptor("Ljava/util/List");
152 }
153
154 void generateClinitCode(String clazzname, String constantFieldName, MethodVisitor mv, CodeFlow codeflow, boolean nested) {
155 mv.visitTypeInsn(NEW, "java/util/ArrayList");
156 mv.visitInsn(DUP);
157 mv.visitMethodInsn(INVOKESPECIAL, "java/util/ArrayList", "<init>", "()V", false);
158 if (!nested) {
159 mv.visitFieldInsn(PUTSTATIC, clazzname, constantFieldName, "Ljava/util/List;");
160 }
161 int childcount = getChildCount();
162 for (int c=0; c < childcount; c++) {
163 if (!nested) {
164 mv.visitFieldInsn(GETSTATIC, clazzname, constantFieldName, "Ljava/util/List;");
165 }
166 else {
167 mv.visitInsn(DUP);
168 }
169
170
171
172 if (children[c] instanceof InlineList) {
173 ((InlineList)children[c]).generateClinitCode(clazzname, constantFieldName, mv, codeflow, true);
174 }
175 else {
176 children[c].generateCode(mv, codeflow);
177 if (CodeFlow.isPrimitive(codeflow.lastDescriptor())) {
178 CodeFlow.insertBoxIfNecessary(mv, codeflow.lastDescriptor().charAt(0));
179 }
180 }
181 mv.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "add", "(Ljava/lang/Object;)Z", true);
182 mv.visitInsn(POP);
183 }
184 }
185
186 }