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 org.springframework.asm.Label;
20 import org.springframework.asm.MethodVisitor;
21 import org.springframework.expression.EvaluationException;
22 import org.springframework.expression.TypedValue;
23 import org.springframework.expression.spel.CodeFlow;
24 import org.springframework.expression.spel.ExpressionState;
25 import org.springframework.util.StringUtils;
26
27
28
29
30
31
32
33
34
35 public class Elvis extends SpelNodeImpl {
36
37 public Elvis(int pos, SpelNodeImpl... args) {
38 super(pos,args);
39 }
40
41
42
43
44
45
46
47
48
49 @Override
50 public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
51 TypedValue value = this.children[0].getValueInternal(state);
52 if (!StringUtils.isEmpty(value.getValue())) {
53 return value;
54 }
55 else {
56 TypedValue result = this.children[1].getValueInternal(state);
57 computeExitTypeDescriptor();
58 return result;
59 }
60 }
61
62 @Override
63 public String toStringAST() {
64 return getChild(0).toStringAST() + " ?: " + getChild(1).toStringAST();
65 }
66
67 @Override
68 public boolean isCompilable() {
69 SpelNodeImpl condition = this.children[0];
70 SpelNodeImpl ifNullValue = this.children[1];
71 return (condition.isCompilable() && ifNullValue.isCompilable() &&
72 condition.exitTypeDescriptor != null && ifNullValue.exitTypeDescriptor != null);
73 }
74
75 @Override
76 public void generateCode(MethodVisitor mv, CodeFlow cf) {
77
78 computeExitTypeDescriptor();
79 this.children[0].generateCode(mv, cf);
80 Label elseTarget = new Label();
81 Label endOfIf = new Label();
82 mv.visitInsn(DUP);
83 mv.visitJumpInsn(IFNULL, elseTarget);
84 mv.visitJumpInsn(GOTO, endOfIf);
85 mv.visitLabel(elseTarget);
86 mv.visitInsn(POP);
87 this.children[1].generateCode(mv, cf);
88 if (!CodeFlow.isPrimitive(this.exitTypeDescriptor)) {
89 CodeFlow.insertBoxIfNecessary(mv, cf.lastDescriptor().charAt(0));
90 }
91 mv.visitLabel(endOfIf);
92 cf.pushDescriptor(this.exitTypeDescriptor);
93 }
94
95 private void computeExitTypeDescriptor() {
96 if (this.exitTypeDescriptor == null && this.children[0].exitTypeDescriptor != null &&
97 this.children[1].exitTypeDescriptor != null) {
98 String conditionDescriptor = this.children[0].exitTypeDescriptor;
99 String ifNullValueDescriptor = this.children[1].exitTypeDescriptor;
100 if (conditionDescriptor.equals(ifNullValueDescriptor)) {
101 this.exitTypeDescriptor = conditionDescriptor;
102 }
103 else if (conditionDescriptor.equals("Ljava/lang/Object") && !CodeFlow.isPrimitive(ifNullValueDescriptor)) {
104 this.exitTypeDescriptor = ifNullValueDescriptor;
105 }
106 else if (ifNullValueDescriptor.equals("Ljava/lang/Object") && !CodeFlow.isPrimitive(conditionDescriptor)) {
107 this.exitTypeDescriptor = conditionDescriptor;
108 }
109 else {
110
111 this.exitTypeDescriptor = "Ljava/lang/Object";
112 }
113 }
114 }
115
116 }