001/* 002 * Copyright 2002-2014 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.expression.spel.ast; 018 019import org.springframework.asm.Label; 020import org.springframework.asm.MethodVisitor; 021import org.springframework.expression.EvaluationException; 022import org.springframework.expression.spel.CodeFlow; 023import org.springframework.expression.spel.ExpressionState; 024import org.springframework.expression.spel.SpelEvaluationException; 025import org.springframework.expression.spel.SpelMessage; 026import org.springframework.expression.spel.support.BooleanTypedValue; 027 028/** 029 * Represents the boolean OR operation. 030 * 031 * @author Andy Clement 032 * @author Mark Fisher 033 * @author Oliver Becker 034 * @since 3.0 035 */ 036public class OpOr extends Operator { 037 038 public OpOr(int pos, SpelNodeImpl... operands) { 039 super("or", pos, operands); 040 this.exitTypeDescriptor = "Z"; 041 } 042 043 044 @Override 045 public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException { 046 if (getBooleanValue(state, getLeftOperand())) { 047 // no need to evaluate right operand 048 return BooleanTypedValue.TRUE; 049 } 050 return BooleanTypedValue.forValue(getBooleanValue(state, getRightOperand())); 051 } 052 053 private boolean getBooleanValue(ExpressionState state, SpelNodeImpl operand) { 054 try { 055 Boolean value = operand.getValue(state, Boolean.class); 056 assertValueNotNull(value); 057 return value; 058 } 059 catch (SpelEvaluationException ee) { 060 ee.setPosition(operand.getStartPosition()); 061 throw ee; 062 } 063 } 064 065 private void assertValueNotNull(Boolean value) { 066 if (value == null) { 067 throw new SpelEvaluationException(SpelMessage.TYPE_CONVERSION_ERROR, "null", "boolean"); 068 } 069 } 070 071 @Override 072 public boolean isCompilable() { 073 SpelNodeImpl left = getLeftOperand(); 074 SpelNodeImpl right = getRightOperand(); 075 return (left.isCompilable() && right.isCompilable() && 076 CodeFlow.isBooleanCompatible(left.exitTypeDescriptor) && 077 CodeFlow.isBooleanCompatible(right.exitTypeDescriptor)); 078 } 079 080 @Override 081 public void generateCode(MethodVisitor mv, CodeFlow cf) { 082 // pseudo: if (leftOperandValue) { result=true; } else { result=rightOperandValue; } 083 Label elseTarget = new Label(); 084 Label endOfIf = new Label(); 085 cf.enterCompilationScope(); 086 getLeftOperand().generateCode(mv, cf); 087 cf.unboxBooleanIfNecessary(mv); 088 cf.exitCompilationScope(); 089 mv.visitJumpInsn(IFEQ, elseTarget); 090 mv.visitLdcInsn(1); // TRUE 091 mv.visitJumpInsn(GOTO,endOfIf); 092 mv.visitLabel(elseTarget); 093 cf.enterCompilationScope(); 094 getRightOperand().generateCode(mv, cf); 095 cf.unboxBooleanIfNecessary(mv); 096 cf.exitCompilationScope(); 097 mv.visitLabel(endOfIf); 098 cf.pushDescriptor(this.exitTypeDescriptor); 099 } 100 101}