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