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 }