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.math.BigDecimal;
20 import java.math.BigInteger;
21
22 import org.springframework.asm.MethodVisitor;
23 import org.springframework.expression.EvaluationException;
24 import org.springframework.expression.Operation;
25 import org.springframework.expression.TypedValue;
26 import org.springframework.expression.spel.CodeFlow;
27 import org.springframework.expression.spel.ExpressionState;
28 import org.springframework.util.NumberUtils;
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52 public class OpMultiply extends Operator {
53
54 public OpMultiply(int pos, SpelNodeImpl... operands) {
55 super("*", pos, operands);
56 }
57
58
59
60
61
62
63
64
65
66
67
68
69 @Override
70 public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
71 Object leftOperand = getLeftOperand().getValueInternal(state).getValue();
72 Object rightOperand = getRightOperand().getValueInternal(state).getValue();
73
74 if (leftOperand instanceof Number && rightOperand instanceof Number) {
75 Number leftNumber = (Number) leftOperand;
76 Number rightNumber = (Number) rightOperand;
77
78 if (leftNumber instanceof BigDecimal || rightNumber instanceof BigDecimal) {
79 BigDecimal leftBigDecimal = NumberUtils.convertNumberToTargetClass(leftNumber, BigDecimal.class);
80 BigDecimal rightBigDecimal = NumberUtils.convertNumberToTargetClass(rightNumber, BigDecimal.class);
81 return new TypedValue(leftBigDecimal.multiply(rightBigDecimal));
82 }
83 else if (leftNumber instanceof Double || rightNumber instanceof Double) {
84 if (leftNumber.getClass() == rightNumber.getClass()) {
85 this.exitTypeDescriptor = "D";
86 }
87 return new TypedValue(leftNumber.doubleValue() * rightNumber.doubleValue());
88 }
89 else if (leftNumber instanceof Float || rightNumber instanceof Float) {
90 if (leftNumber.getClass() == rightNumber.getClass()) {
91 this.exitTypeDescriptor = "F";
92 }
93 return new TypedValue(leftNumber.floatValue() * rightNumber.floatValue());
94 }
95 else if (leftNumber instanceof BigInteger || rightNumber instanceof BigInteger) {
96 BigInteger leftBigInteger = NumberUtils.convertNumberToTargetClass(leftNumber, BigInteger.class);
97 BigInteger rightBigInteger = NumberUtils.convertNumberToTargetClass(rightNumber, BigInteger.class);
98 return new TypedValue(leftBigInteger.multiply(rightBigInteger));
99 }
100 else if (leftNumber instanceof Long || rightNumber instanceof Long) {
101 if (leftNumber.getClass() == rightNumber.getClass()) {
102 this.exitTypeDescriptor = "J";
103 }
104 return new TypedValue(leftNumber.longValue() * rightNumber.longValue());
105 }
106 else if (CodeFlow.isIntegerForNumericOp(leftNumber) || CodeFlow.isIntegerForNumericOp(rightNumber)) {
107 if (leftNumber instanceof Integer && rightNumber instanceof Integer) {
108 this.exitTypeDescriptor = "I";
109 }
110 return new TypedValue(leftNumber.intValue() * rightNumber.intValue());
111 }
112 else {
113
114 return new TypedValue(leftNumber.doubleValue() * rightNumber.doubleValue());
115 }
116 }
117
118 if (leftOperand instanceof String && rightOperand instanceof Integer) {
119 int repeats = (Integer) rightOperand;
120 StringBuilder result = new StringBuilder();
121 for (int i = 0; i < repeats; i++) {
122 result.append(leftOperand);
123 }
124 return new TypedValue(result.toString());
125 }
126
127 return state.operate(Operation.MULTIPLY, leftOperand, rightOperand);
128 }
129
130 @Override
131 public boolean isCompilable() {
132 if (!getLeftOperand().isCompilable()) {
133 return false;
134 }
135 if (this.children.length > 1) {
136 if (!getRightOperand().isCompilable()) {
137 return false;
138 }
139 }
140 return (this.exitTypeDescriptor != null);
141 }
142
143 @Override
144 public void generateCode(MethodVisitor mv, CodeFlow cf) {
145 getLeftOperand().generateCode(mv, cf);
146 String leftDesc = getLeftOperand().exitTypeDescriptor;
147 if (!CodeFlow.isPrimitive(leftDesc)) {
148 CodeFlow.insertUnboxInsns(mv, this.exitTypeDescriptor.charAt(0), leftDesc);
149 }
150 if (this.children.length > 1) {
151 cf.enterCompilationScope();
152 getRightOperand().generateCode(mv, cf);
153 String rightDesc = getRightOperand().exitTypeDescriptor;
154 cf.exitCompilationScope();
155 if (!CodeFlow.isPrimitive(rightDesc)) {
156 CodeFlow.insertUnboxInsns(mv, this.exitTypeDescriptor.charAt(0), rightDesc);
157 }
158 switch (this.exitTypeDescriptor.charAt(0)) {
159 case 'I':
160 mv.visitInsn(IMUL);
161 break;
162 case 'J':
163 mv.visitInsn(LMUL);
164 break;
165 case 'F':
166 mv.visitInsn(FMUL);
167 break;
168 case 'D':
169 mv.visitInsn(DMUL);
170 break;
171 default:
172 throw new IllegalStateException(
173 "Unrecognized exit type descriptor: '" + this.exitTypeDescriptor + "'");
174 }
175 }
176 cf.pushDescriptor(this.exitTypeDescriptor);
177 }
178
179 }