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