View Javadoc
1   /*
2    * Copyright 2002-2014 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
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.spel.CodeFlow;
23  import org.springframework.expression.spel.ExpressionState;
24  import org.springframework.expression.spel.support.BooleanTypedValue;
25  
26  /**
27   * Implements the not-equal operator.
28   *
29   * @author Andy Clement
30   * @since 3.0
31   */
32  public class OpNE extends Operator {
33  
34  	public OpNE(int pos, SpelNodeImpl... operands) {
35  		super("!=", pos, operands);
36  		this.exitTypeDescriptor = "Z";
37  	}
38  
39  	@Override
40  	public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
41  		Object left = getLeftOperand().getValueInternal(state).getValue();
42  		Object right = getRightOperand().getValueInternal(state).getValue();
43  		leftActualDescriptor = CodeFlow.toDescriptorFromObject(left);
44  		rightActualDescriptor = CodeFlow.toDescriptorFromObject(right);
45  		return BooleanTypedValue.forValue(!equalityCheck(state, left, right));
46  	}
47  
48  	// This check is different to the one in the other numeric operators (OpLt/etc)
49  	// because we allow simple object comparison
50  	@Override
51  	public boolean isCompilable() {
52  		SpelNodeImpl left = getLeftOperand();
53  		SpelNodeImpl right= getRightOperand();
54  		if (!left.isCompilable() || !right.isCompilable()) {
55  			return false;
56  		}
57  
58  		String leftDesc = left.exitTypeDescriptor;
59  		String rightDesc = right.exitTypeDescriptor;
60  		DescriptorComparison dc =  DescriptorComparison.checkNumericCompatibility(leftDesc, rightDesc, leftActualDescriptor, rightActualDescriptor);
61  		return (!dc.areNumbers || dc.areCompatible);
62  	}
63  	
64  	@Override
65  	public void generateCode(MethodVisitor mv, CodeFlow cf) {
66  		String leftDesc = getLeftOperand().exitTypeDescriptor;
67  		String rightDesc = getRightOperand().exitTypeDescriptor;
68  		Label elseTarget = new Label();
69  		Label endOfIf = new Label();
70  		boolean leftPrim = CodeFlow.isPrimitive(leftDesc);
71  		boolean rightPrim = CodeFlow.isPrimitive(rightDesc);
72  
73  		DescriptorComparison dc = DescriptorComparison.checkNumericCompatibility(leftDesc, rightDesc, leftActualDescriptor, rightActualDescriptor);
74  		
75  		if (dc.areNumbers && dc.areCompatible) {
76  			char targetType = dc.compatibleType;
77  			
78  			getLeftOperand().generateCode(mv, cf);
79  			if (!leftPrim) {
80  				CodeFlow.insertUnboxInsns(mv, targetType, leftDesc);
81  			}
82  		
83  			cf.enterCompilationScope();
84  			getRightOperand().generateCode(mv, cf);
85  			cf.exitCompilationScope();
86  			if (!rightPrim) {
87  				CodeFlow.insertUnboxInsns(mv, targetType, rightDesc);
88  			}
89  			// assert: SpelCompiler.boxingCompatible(leftDesc, rightDesc)
90  			if (targetType == 'D') {
91  				mv.visitInsn(DCMPL);
92  				mv.visitJumpInsn(IFEQ, elseTarget);
93  			}
94  			else if (targetType == 'F') {
95  				mv.visitInsn(FCMPL);		
96  				mv.visitJumpInsn(IFEQ, elseTarget);
97  			}
98  			else if (targetType == 'J') {
99  				mv.visitInsn(LCMP);		
100 				mv.visitJumpInsn(IFEQ, elseTarget);
101 			}
102 			else if (targetType == 'I' || targetType == 'Z') {
103 				mv.visitJumpInsn(IF_ICMPEQ, elseTarget);		
104 			}
105 			else {
106 				throw new IllegalStateException("Unexpected descriptor "+leftDesc);
107 			}
108 		}
109 		else {
110 			getLeftOperand().generateCode(mv, cf);
111 			getRightOperand().generateCode(mv, cf);
112 			mv.visitJumpInsn(IF_ACMPEQ, elseTarget);
113 		}
114 		mv.visitInsn(ICONST_1);
115 		mv.visitJumpInsn(GOTO,endOfIf);
116 		mv.visitLabel(elseTarget);
117 		mv.visitInsn(ICONST_0);
118 		mv.visitLabel(endOfIf);
119 		cf.pushDescriptor("Z");
120 	}
121 
122 }