001/* 002 * Copyright 2002-2017 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 java.math.BigDecimal; 020import java.math.BigInteger; 021 022import org.springframework.expression.EvaluationException; 023import org.springframework.expression.Operation; 024import org.springframework.expression.TypedValue; 025import org.springframework.expression.spel.ExpressionState; 026import org.springframework.expression.spel.SpelEvaluationException; 027import org.springframework.expression.spel.SpelMessage; 028import org.springframework.util.Assert; 029 030/** 031 * Decrement operator. Can be used in a prefix or postfix form. This will throw 032 * appropriate exceptions if the operand in question does not support decrement. 033 * 034 * @author Andy Clement 035 * @author Juergen Hoeller 036 * @author Giovanni Dall'Oglio Risso 037 * @since 3.2 038 */ 039public class OpDec extends Operator { 040 041 private final boolean postfix; // false means prefix 042 043 044 public OpDec(int pos, boolean postfix, SpelNodeImpl... operands) { 045 super("--", pos, operands); 046 this.postfix = postfix; 047 Assert.notEmpty(operands, "Operands must not be empty"); 048 } 049 050 051 @Override 052 public TypedValue getValueInternal(ExpressionState state) throws EvaluationException { 053 SpelNodeImpl operand = getLeftOperand(); 054 055 // The operand is going to be read and then assigned to, we don't want to evaluate it twice. 056 ValueRef lvalue = operand.getValueRef(state); 057 058 TypedValue operandTypedValue = lvalue.getValue(); //operand.getValueInternal(state); 059 Object operandValue = operandTypedValue.getValue(); 060 TypedValue returnValue = operandTypedValue; 061 TypedValue newValue = null; 062 063 if (operandValue instanceof Number) { 064 Number op1 = (Number) operandValue; 065 if (op1 instanceof BigDecimal) { 066 newValue = new TypedValue(((BigDecimal) op1).subtract(BigDecimal.ONE), operandTypedValue.getTypeDescriptor()); 067 } 068 else if (op1 instanceof Double) { 069 newValue = new TypedValue(op1.doubleValue() - 1.0d, operandTypedValue.getTypeDescriptor()); 070 } 071 else if (op1 instanceof Float) { 072 newValue = new TypedValue(op1.floatValue() - 1.0f, operandTypedValue.getTypeDescriptor()); 073 } 074 else if (op1 instanceof BigInteger) { 075 newValue = new TypedValue(((BigInteger) op1).subtract(BigInteger.ONE), operandTypedValue.getTypeDescriptor()); 076 } 077 else if (op1 instanceof Long) { 078 newValue = new TypedValue(op1.longValue() - 1L, operandTypedValue.getTypeDescriptor()); 079 } 080 else if (op1 instanceof Integer) { 081 newValue = new TypedValue(op1.intValue() - 1, operandTypedValue.getTypeDescriptor()); 082 } 083 else if (op1 instanceof Short) { 084 newValue = new TypedValue(op1.shortValue() - (short) 1, operandTypedValue.getTypeDescriptor()); 085 } 086 else if (op1 instanceof Byte) { 087 newValue = new TypedValue(op1.byteValue() - (byte) 1, operandTypedValue.getTypeDescriptor()); 088 } 089 else { 090 // Unknown Number subtype -> best guess is double decrement 091 newValue = new TypedValue(op1.doubleValue() - 1.0d, operandTypedValue.getTypeDescriptor()); 092 } 093 } 094 095 if (newValue == null) { 096 try { 097 newValue = state.operate(Operation.SUBTRACT, returnValue.getValue(), 1); 098 } 099 catch (SpelEvaluationException ex) { 100 if (ex.getMessageCode() == SpelMessage.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES) { 101 // This means the operand is not decrementable 102 throw new SpelEvaluationException(operand.getStartPosition(), 103 SpelMessage.OPERAND_NOT_DECREMENTABLE, operand.toStringAST()); 104 } 105 else { 106 throw ex; 107 } 108 } 109 } 110 111 // set the new value 112 try { 113 lvalue.setValue(newValue.getValue()); 114 } 115 catch (SpelEvaluationException see) { 116 // if unable to set the value the operand is not writable (e.g. 1-- ) 117 if (see.getMessageCode() == SpelMessage.SETVALUE_NOT_SUPPORTED) { 118 throw new SpelEvaluationException(operand.getStartPosition(), 119 SpelMessage.OPERAND_NOT_DECREMENTABLE); 120 } 121 else { 122 throw see; 123 } 124 } 125 126 if (!this.postfix) { 127 // the return value is the new value, not the original value 128 returnValue = newValue; 129 } 130 131 return returnValue; 132 } 133 134 @Override 135 public String toStringAST() { 136 return getLeftOperand().toStringAST() + "--"; 137 } 138 139 @Override 140 public SpelNodeImpl getRightOperand() { 141 return null; 142 } 143 144}