View Javadoc
1   /*
2    * Copyright 2002-2014 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.springframework.expression.spel.ast;
18  
19  import org.springframework.expression.TypedValue;
20  import org.springframework.expression.spel.SpelEvaluationException;
21  import org.springframework.expression.spel.SpelMessage;
22  
23  /**
24   * Represents a reference to a value.  With a reference it is possible to get or set the
25   * value. Passing around value references rather than the values themselves can avoid
26   * incorrect duplication of operand evaluation. For example in 'list[index++]++' without a
27   * value reference for 'list[index++]' it would be necessary to evaluate list[index++]
28   * twice (once to get the value, once to determine where the value goes) and that would
29   * double increment index.
30   *
31   * @author Andy Clement
32   * @since 3.2
33   */
34  public interface ValueRef {
35  
36  	/**
37  	 * Returns the value this ValueRef points to, it should not require expression
38  	 * component re-evaluation.
39  	 * @return the value
40  	 */
41  	TypedValue getValue();
42  
43  	/**
44  	 * Sets the value this ValueRef points to, it should not require expression component
45  	 * re-evaluation.
46  	 * @param newValue the new value
47  	 */
48  	void setValue(Object newValue);
49  
50  	/**
51  	 * Indicates whether calling setValue(Object) is supported.
52  	 * @return true if setValue() is supported for this value reference.
53  	 */
54  	boolean isWritable();
55  
56  
57  	/**
58  	 * A ValueRef for the null value.
59  	 */
60  	static class NullValueRef implements ValueRef {
61  
62  		static final NullValueRef INSTANCE = new NullValueRef();
63  
64  		@Override
65  		public TypedValue getValue() {
66  			return TypedValue.NULL;
67  		}
68  
69  		@Override
70  		public void setValue(Object newValue) {
71  			// The exception position '0' isn't right but the overhead of creating
72  			// instances of this per node (where the node is solely for error reporting)
73  			// would be unfortunate.
74  			throw new SpelEvaluationException(0, SpelMessage.NOT_ASSIGNABLE, "null");
75  		}
76  
77  		@Override
78  		public boolean isWritable() {
79  			return false;
80  		}
81  	}
82  
83  
84  	/**
85  	 * A ValueRef holder for a single value, which cannot be set.
86  	 */
87  	static class TypedValueHolderValueRef implements ValueRef {
88  
89  		private final TypedValue typedValue;
90  
91  		private final SpelNodeImpl node;  // used only for error reporting
92  
93  		public TypedValueHolderValueRef(TypedValue typedValue,SpelNodeImpl node) {
94  			this.typedValue = typedValue;
95  			this.node = node;
96  		}
97  
98  		@Override
99  		public TypedValue getValue() {
100 			return this.typedValue;
101 		}
102 
103 		@Override
104 		public void setValue(Object newValue) {
105 			throw new SpelEvaluationException(this.node.pos, SpelMessage.NOT_ASSIGNABLE, this.node.toStringAST());
106 		}
107 
108 		@Override
109 		public boolean isWritable() {
110 			return false;
111 		}
112 	}
113 
114 }