001/* 002 * Copyright 2002-2018 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.MethodVisitor; 020import org.springframework.expression.EvaluationContext; 021import org.springframework.expression.EvaluationException; 022import org.springframework.expression.spel.CodeFlow; 023import org.springframework.expression.spel.ExpressionState; 024import org.springframework.expression.spel.support.BooleanTypedValue; 025 026/** 027 * Implements the equality operator. 028 * 029 * @author Andy Clement 030 * @since 3.0 031 */ 032public class OpEQ extends Operator { 033 034 public OpEQ(int pos, SpelNodeImpl... operands) { 035 super("==", pos, operands); 036 this.exitTypeDescriptor = "Z"; 037 } 038 039 040 @Override 041 public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException { 042 Object left = getLeftOperand().getValueInternal(state).getValue(); 043 Object right = getRightOperand().getValueInternal(state).getValue(); 044 this.leftActualDescriptor = CodeFlow.toDescriptorFromObject(left); 045 this.rightActualDescriptor = CodeFlow.toDescriptorFromObject(right); 046 return BooleanTypedValue.forValue(equalityCheck(state.getEvaluationContext(), left, right)); 047 } 048 049 // This check is different to the one in the other numeric operators (OpLt/etc) 050 // because it allows for simple object comparison 051 @Override 052 public boolean isCompilable() { 053 SpelNodeImpl left = getLeftOperand(); 054 SpelNodeImpl right = getRightOperand(); 055 if (!left.isCompilable() || !right.isCompilable()) { 056 return false; 057 } 058 059 String leftDesc = left.exitTypeDescriptor; 060 String rightDesc = right.exitTypeDescriptor; 061 DescriptorComparison dc = DescriptorComparison.checkNumericCompatibility(leftDesc, 062 rightDesc, this.leftActualDescriptor, this.rightActualDescriptor); 063 return (!dc.areNumbers || dc.areCompatible); 064 } 065 066 @Override 067 public void generateCode(MethodVisitor mv, CodeFlow cf) { 068 cf.loadEvaluationContext(mv); 069 String leftDesc = getLeftOperand().exitTypeDescriptor; 070 String rightDesc = getRightOperand().exitTypeDescriptor; 071 boolean leftPrim = CodeFlow.isPrimitive(leftDesc); 072 boolean rightPrim = CodeFlow.isPrimitive(rightDesc); 073 074 cf.enterCompilationScope(); 075 getLeftOperand().generateCode(mv, cf); 076 cf.exitCompilationScope(); 077 if (leftPrim) { 078 CodeFlow.insertBoxIfNecessary(mv, leftDesc.charAt(0)); 079 } 080 cf.enterCompilationScope(); 081 getRightOperand().generateCode(mv, cf); 082 cf.exitCompilationScope(); 083 if (rightPrim) { 084 CodeFlow.insertBoxIfNecessary(mv, rightDesc.charAt(0)); 085 } 086 087 String operatorClassName = Operator.class.getName().replace('.', '/'); 088 String evaluationContextClassName = EvaluationContext.class.getName().replace('.', '/'); 089 mv.visitMethodInsn(INVOKESTATIC, operatorClassName, "equalityCheck", 090 "(L" + evaluationContextClassName + ";Ljava/lang/Object;Ljava/lang/Object;)Z", false); 091 cf.pushDescriptor("Z"); 092 } 093 094}