001/* 002 * Copyright 2002-2019 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.expression.TypedValue; 020import org.springframework.expression.spel.SpelEvaluationException; 021import org.springframework.expression.spel.SpelMessage; 022 023/** 024 * Represents a reference to a value. With a reference it is possible to get or set the 025 * value. Passing around value references rather than the values themselves can avoid 026 * incorrect duplication of operand evaluation. For example in 'list[index++]++' without 027 * a value reference for 'list[index++]' it would be necessary to evaluate list[index++] 028 * twice (once to get the value, once to determine where the value goes) and that would 029 * double increment index. 030 * 031 * @author Andy Clement 032 * @since 3.2 033 */ 034public interface ValueRef { 035 036 /** 037 * Returns the value this ValueRef points to, it should not require expression 038 * component re-evaluation. 039 * @return the value 040 */ 041 TypedValue getValue(); 042 043 /** 044 * Sets the value this ValueRef points to, it should not require expression component 045 * re-evaluation. 046 * @param newValue the new value 047 */ 048 void setValue(Object newValue); 049 050 /** 051 * Indicates whether calling setValue(Object) is supported. 052 * @return true if setValue() is supported for this value reference. 053 */ 054 boolean isWritable(); 055 056 057 /** 058 * A ValueRef for the null value. 059 */ 060 class NullValueRef implements ValueRef { 061 062 static final NullValueRef INSTANCE = new NullValueRef(); 063 064 @Override 065 public TypedValue getValue() { 066 return TypedValue.NULL; 067 } 068 069 @Override 070 public void setValue(Object newValue) { 071 // The exception position '0' isn't right but the overhead of creating 072 // instances of this per node (where the node is solely for error reporting) 073 // would be unfortunate. 074 throw new SpelEvaluationException(0, SpelMessage.NOT_ASSIGNABLE, "null"); 075 } 076 077 @Override 078 public boolean isWritable() { 079 return false; 080 } 081 } 082 083 084 /** 085 * A ValueRef holder for a single value, which cannot be set. 086 */ 087 class TypedValueHolderValueRef implements ValueRef { 088 089 private final TypedValue typedValue; 090 091 private final SpelNodeImpl node; // used only for error reporting 092 093 public TypedValueHolderValueRef(TypedValue typedValue, SpelNodeImpl node) { 094 this.typedValue = typedValue; 095 this.node = node; 096 } 097 098 @Override 099 public TypedValue getValue() { 100 return this.typedValue; 101 } 102 103 @Override 104 public void setValue(Object newValue) { 105 throw new SpelEvaluationException( 106 this.node.getStartPosition(), SpelMessage.NOT_ASSIGNABLE, this.node.toStringAST()); 107 } 108 109 @Override 110 public boolean isWritable() { 111 return false; 112 } 113 } 114 115}