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.Modifier;
20
21 import org.springframework.asm.MethodVisitor;
22 import org.springframework.expression.EvaluationContext;
23 import org.springframework.expression.TypedValue;
24 import org.springframework.expression.spel.CodeFlow;
25 import org.springframework.expression.spel.ExpressionState;
26 import org.springframework.expression.spel.SpelEvaluationException;
27
28
29
30
31
32
33
34
35 public class VariableReference extends SpelNodeImpl {
36
37
38 private static final String THIS = "this";
39
40 private static final String ROOT = "root";
41
42
43 private final String name;
44
45
46 public VariableReference(String variableName, int pos) {
47 super(pos);
48 this.name = variableName;
49 }
50
51
52 @Override
53 public ValueRef getValueRef(ExpressionState state) throws SpelEvaluationException {
54 if (this.name.equals(THIS)) {
55 return new ValueRef.TypedValueHolderValueRef(state.getActiveContextObject(),this);
56 }
57 if (this.name.equals(ROOT)) {
58 return new ValueRef.TypedValueHolderValueRef(state.getRootContextObject(),this);
59 }
60 TypedValue result = state.lookupVariable(this.name);
61
62 return new VariableRef(this.name,result,state.getEvaluationContext());
63 }
64
65 @Override
66 public TypedValue getValueInternal(ExpressionState state) throws SpelEvaluationException {
67 if (this.name.equals(THIS)) {
68 return state.getActiveContextObject();
69 }
70 if (this.name.equals(ROOT)) {
71 TypedValue result = state.getRootContextObject();
72 this.exitTypeDescriptor = CodeFlow.toDescriptorFromObject(result.getValue());
73 return result;
74 }
75 TypedValue result = state.lookupVariable(this.name);
76 Object value = result.getValue();
77 if (value == null || !Modifier.isPublic(value.getClass().getModifiers())) {
78
79
80
81
82 this.exitTypeDescriptor = "Ljava/lang/Object";
83 }
84 else {
85 this.exitTypeDescriptor = CodeFlow.toDescriptorFromObject(value);
86 }
87
88 return result;
89 }
90
91 @Override
92 public void setValue(ExpressionState state, Object value) throws SpelEvaluationException {
93 state.setVariable(this.name, value);
94 }
95
96 @Override
97 public String toStringAST() {
98 return "#" + this.name;
99 }
100
101 @Override
102 public boolean isWritable(ExpressionState expressionState) throws SpelEvaluationException {
103 return !(this.name.equals(THIS) || this.name.equals(ROOT));
104 }
105
106
107 class VariableRef implements ValueRef {
108
109 private final String name;
110
111 private final TypedValue value;
112
113 private final EvaluationContext evaluationContext;
114
115
116 public VariableRef(String name, TypedValue value,
117 EvaluationContext evaluationContext) {
118 this.name = name;
119 this.value = value;
120 this.evaluationContext = evaluationContext;
121 }
122
123
124 @Override
125 public TypedValue getValue() {
126 return this.value;
127 }
128
129 @Override
130 public void setValue(Object newValue) {
131 this.evaluationContext.setVariable(this.name, newValue);
132 }
133
134 @Override
135 public boolean isWritable() {
136 return true;
137 }
138 }
139
140 @Override
141 public boolean isCompilable() {
142 return this.exitTypeDescriptor!=null;
143 }
144
145 @Override
146 public void generateCode(MethodVisitor mv, CodeFlow cf) {
147 if (this.name.equals(ROOT)) {
148 mv.visitVarInsn(ALOAD,1);
149 }
150 else {
151 mv.visitVarInsn(ALOAD, 2);
152 mv.visitLdcInsn(name);
153 mv.visitMethodInsn(INVOKEINTERFACE, "org/springframework/expression/EvaluationContext", "lookupVariable", "(Ljava/lang/String;)Ljava/lang/Object;",true);
154 }
155 CodeFlow.insertCheckCast(mv,this.exitTypeDescriptor);
156 cf.pushDescriptor(this.exitTypeDescriptor);
157 }
158
159
160 }