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.TypedValue;
23  import org.springframework.expression.spel.CodeFlow;
24  import org.springframework.expression.spel.ExpressionState;
25  import org.springframework.expression.spel.SpelEvaluationException;
26  import org.springframework.expression.spel.SpelMessage;
27  import org.springframework.expression.spel.support.BooleanTypedValue;
28  
29  /**
30   * Represents the boolean AND operation.
31   *
32   * @author Andy Clement
33   * @author Mark Fisher
34   * @author Oliver Becker
35   * @since 3.0
36   */
37  public class OpAnd extends Operator {
38  
39  	public OpAnd(int pos, SpelNodeImpl... operands) {
40  		super("and", pos, operands);
41  		this.exitTypeDescriptor = "Z";
42  	}
43  
44  
45  	@Override
46  	public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
47  		if (getBooleanValue(state, getLeftOperand()) == false) {
48  			// no need to evaluate right operand
49  			return BooleanTypedValue.FALSE;
50  		}
51  		return BooleanTypedValue.forValue(getBooleanValue(state, getRightOperand()));
52  	}
53  
54  	private boolean getBooleanValue(ExpressionState state, SpelNodeImpl operand) {
55  		try {
56  			Boolean value = operand.getValue(state, Boolean.class);
57  			assertValueNotNull(value);
58  			return value;
59  		}
60  		catch (SpelEvaluationException ex) {
61  			ex.setPosition(operand.getStartPosition());
62  			throw ex;
63  		}
64  	}
65  
66  	private void assertValueNotNull(Boolean value) {
67  		if (value == null) {
68  			throw new SpelEvaluationException(SpelMessage.TYPE_CONVERSION_ERROR, "null", "boolean");
69  		}
70  	}
71  
72  	@Override
73  	public boolean isCompilable() {
74  		SpelNodeImpl left = getLeftOperand();
75  		SpelNodeImpl right = getRightOperand();
76  		return (left.isCompilable() && right.isCompilable() &&
77  				CodeFlow.isBooleanCompatible(left.exitTypeDescriptor) &&
78  				CodeFlow.isBooleanCompatible(right.exitTypeDescriptor));
79  	}
80  	
81  	@Override
82  	public void generateCode(MethodVisitor mv, CodeFlow cf) {
83  		// Pseudo: if (!leftOperandValue) { result=false; } else { result=rightOperandValue; }
84  		Label elseTarget = new Label();
85  		Label endOfIf = new Label();
86  		cf.enterCompilationScope();
87  		getLeftOperand().generateCode(mv, cf);
88  		cf.unboxBooleanIfNecessary(mv);
89  		cf.exitCompilationScope();
90  		mv.visitJumpInsn(IFNE, elseTarget);
91  		mv.visitLdcInsn(0); // FALSE
92  		mv.visitJumpInsn(GOTO,endOfIf);
93  		mv.visitLabel(elseTarget);
94  		cf.enterCompilationScope();
95  		getRightOperand().generateCode(mv, cf);
96  		cf.unboxBooleanIfNecessary(mv);
97  		cf.exitCompilationScope();
98  		mv.visitLabel(endOfIf);
99  		cf.pushDescriptor(this.exitTypeDescriptor);
100 	}
101 
102 }