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.lang.reflect.Constructor;
20 import java.lang.reflect.Member;
21 import java.lang.reflect.Method;
22
23 import org.springframework.asm.MethodVisitor;
24 import org.springframework.asm.Opcodes;
25 import org.springframework.expression.EvaluationException;
26 import org.springframework.expression.TypedValue;
27 import org.springframework.expression.common.ExpressionUtils;
28 import org.springframework.expression.spel.CodeFlow;
29 import org.springframework.expression.spel.ExpressionState;
30 import org.springframework.expression.spel.SpelEvaluationException;
31 import org.springframework.expression.spel.SpelMessage;
32 import org.springframework.expression.spel.SpelNode;
33 import org.springframework.expression.spel.support.StandardEvaluationContext;
34 import org.springframework.util.Assert;
35 import org.springframework.util.ObjectUtils;
36
37
38
39
40
41
42
43
44 public abstract class SpelNodeImpl implements SpelNode, Opcodes {
45
46 private static SpelNodeImpl[] NO_CHILDREN = new SpelNodeImpl[0];
47
48
49 protected int pos;
50
51 protected SpelNodeImpl[] children = SpelNodeImpl.NO_CHILDREN;
52
53 private SpelNodeImpl parent;
54
55
56
57
58
59
60
61
62
63
64 protected volatile String exitTypeDescriptor;
65
66
67 public SpelNodeImpl(int pos, SpelNodeImpl... operands) {
68 this.pos = pos;
69
70 Assert.isTrue(pos != 0, "Pos must not be 0");
71 if (!ObjectUtils.isEmpty(operands)) {
72 this.children = operands;
73 for (SpelNodeImpl childNode : operands) {
74 childNode.parent = this;
75 }
76 }
77 }
78
79
80 protected SpelNodeImpl getPreviousChild() {
81 SpelNodeImpl result = null;
82 if (this.parent != null) {
83 for (SpelNodeImpl child : this.parent.children) {
84 if (this == child) {
85 break;
86 }
87 result = child;
88 }
89 }
90 return result;
91 }
92
93
94
95
96 protected boolean nextChildIs(Class<?>... clazzes) {
97 if (this.parent != null) {
98 SpelNodeImpl[] peers = this.parent.children;
99 for (int i = 0, max = peers.length; i < max; i++) {
100 if (this == peers[i]) {
101 if (i + 1 >= max) {
102 return false;
103 }
104 Class<?> clazz = peers[i + 1].getClass();
105 for (Class<?> desiredClazz : clazzes) {
106 if (clazz.equals(desiredClazz)) {
107 return true;
108 }
109 }
110 return false;
111 }
112 }
113 }
114 return false;
115 }
116
117 @Override
118 public final Object getValue(ExpressionState expressionState) throws EvaluationException {
119 if (expressionState != null) {
120 return getValueInternal(expressionState).getValue();
121 }
122 else {
123
124 return getValue(new ExpressionState(new StandardEvaluationContext()));
125 }
126 }
127
128 @Override
129 public final TypedValue getTypedValue(ExpressionState expressionState) throws EvaluationException {
130 if (expressionState != null) {
131 return getValueInternal(expressionState);
132 }
133 else {
134
135 return getTypedValue(new ExpressionState(new StandardEvaluationContext()));
136 }
137 }
138
139
140 @Override
141 public boolean isWritable(ExpressionState expressionState) throws EvaluationException {
142 return false;
143 }
144
145 @Override
146 public void setValue(ExpressionState expressionState, Object newValue) throws EvaluationException {
147 throw new SpelEvaluationException(getStartPosition(),
148 SpelMessage.SETVALUE_NOT_SUPPORTED, getClass());
149 }
150
151 @Override
152 public SpelNode getChild(int index) {
153 return this.children[index];
154 }
155
156 @Override
157 public int getChildCount() {
158 return this.children.length;
159 }
160
161 @Override
162 public Class<?> getObjectClass(Object obj) {
163 if (obj == null) {
164 return null;
165 }
166 return (obj instanceof Class ? ((Class<?>) obj) : obj.getClass());
167 }
168
169 protected final <T> T getValue(ExpressionState state, Class<T> desiredReturnType) throws EvaluationException {
170 return ExpressionUtils.convertTypedValue(state.getEvaluationContext(), getValueInternal(state), desiredReturnType);
171 }
172
173 @Override
174 public int getStartPosition() {
175 return (this.pos >> 16);
176 }
177
178 @Override
179 public int getEndPosition() {
180 return (this.pos & 0xffff);
181 }
182
183 protected ValueRef getValueRef(ExpressionState state) throws EvaluationException {
184 throw new SpelEvaluationException(this.pos, SpelMessage.NOT_ASSIGNABLE, toStringAST());
185 }
186
187
188
189
190
191
192
193 public boolean isCompilable() {
194 return false;
195 }
196
197
198
199
200
201
202
203
204
205 public void generateCode(MethodVisitor mv, CodeFlow cf) {
206 throw new IllegalStateException(getClass().getName() +" has no generateCode(..) method");
207 }
208
209 public String getExitDescriptor() {
210 return this.exitTypeDescriptor;
211 }
212
213 public abstract TypedValue getValueInternal(ExpressionState expressionState) throws EvaluationException;
214
215
216
217
218
219
220
221
222
223
224
225 protected static void generateCodeForArguments(MethodVisitor mv, CodeFlow cf, Member member, SpelNodeImpl[] arguments) {
226 String[] paramDescriptors = null;
227 boolean isVarargs = false;
228 if (member instanceof Constructor) {
229 Constructor<?> ctor = (Constructor<?>)member;
230 paramDescriptors = CodeFlow.toDescriptors(ctor.getParameterTypes());
231 isVarargs = ctor.isVarArgs();
232 }
233 else {
234 Method method = (Method)member;
235 paramDescriptors = CodeFlow.toDescriptors(method.getParameterTypes());
236 isVarargs = method.isVarArgs();
237 }
238 if (isVarargs) {
239
240
241 int p = 0;
242 int childcount = arguments.length;
243
244
245 for (p = 0; p < paramDescriptors.length-1;p++) {
246 generateCodeForArgument(mv, cf, arguments[p], paramDescriptors[p]);
247 }
248
249 SpelNodeImpl lastchild = (childcount == 0 ? null : arguments[childcount-1]);
250 String arraytype = paramDescriptors[paramDescriptors.length-1];
251
252
253 if (lastchild != null && lastchild.getExitDescriptor().equals(arraytype)) {
254 generateCodeForArgument(mv, cf, lastchild, paramDescriptors[p]);
255 }
256 else {
257 arraytype = arraytype.substring(1);
258
259 CodeFlow.insertNewArrayCode(mv, childcount-p, arraytype);
260
261 int arrayindex = 0;
262 while (p < childcount) {
263 SpelNodeImpl child = arguments[p];
264 mv.visitInsn(DUP);
265 CodeFlow.insertOptimalLoad(mv, arrayindex++);
266 generateCodeForArgument(mv, cf, child, arraytype);
267 CodeFlow.insertArrayStore(mv, arraytype);
268 p++;
269 }
270 }
271 }
272 else {
273 for (int i = 0; i < paramDescriptors.length;i++) {
274 generateCodeForArgument(mv, cf, arguments[i], paramDescriptors[i]);
275 }
276 }
277 }
278
279
280
281
282
283 protected static void generateCodeForArgument(MethodVisitor mv, CodeFlow cf, SpelNodeImpl argument, String paramDescriptor) {
284 cf.enterCompilationScope();
285 argument.generateCode(mv, cf);
286 boolean primitiveOnStack = CodeFlow.isPrimitive(cf.lastDescriptor());
287
288 if (primitiveOnStack && paramDescriptor.charAt(0) == 'L') {
289 CodeFlow.insertBoxIfNecessary(mv, cf.lastDescriptor().charAt(0));
290 }
291 else if (paramDescriptor.length() == 1 && !primitiveOnStack) {
292 CodeFlow.insertUnboxInsns(mv, paramDescriptor.charAt(0), cf.lastDescriptor());
293 }
294 else if (!cf.lastDescriptor().equals(paramDescriptor)) {
295
296 CodeFlow.insertCheckCast(mv, paramDescriptor);
297 }
298 cf.exitCompilationScope();
299 }
300 }