001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.el;
019:
020: import java.io.Externalizable;
021: import java.io.IOException;
022: import java.io.ObjectInput;
023: import java.io.ObjectOutput;
024:
025: import javax.el.ELContext;
026: import javax.el.ELException;
027: import javax.el.ELResolver;
028: import javax.el.Expression;
029: import javax.el.ExpressionFactory;
030: import javax.el.FunctionMapper;
031: import javax.el.PropertyNotFoundException;
032: import javax.el.PropertyNotWritableException;
033: import javax.el.ValueExpression;
034: import javax.el.VariableMapper;
035:
036: import org.apache.el.lang.ELSupport;
037: import org.apache.el.lang.EvaluationContext;
038: import org.apache.el.lang.ExpressionBuilder;
039: import org.apache.el.parser.AstLiteralExpression;
040: import org.apache.el.parser.Node;
041: import org.apache.el.util.ReflectionUtil;
042:
043: /**
044: * An <code>Expression</code> that can get or set a value.
045: *
046: * <p>
047: * In previous incarnations of this API, expressions could only be read.
048: * <code>ValueExpression</code> objects can now be used both to retrieve a
049: * value and to set a value. Expressions that can have a value set on them are
050: * referred to as l-value expressions. Those that cannot are referred to as
051: * r-value expressions. Not all r-value expressions can be used as l-value
052: * expressions (e.g. <code>"${1+1}"</code> or
053: * <code>"${firstName} ${lastName}"</code>). See the EL Specification for
054: * details. Expressions that cannot be used as l-values must always return
055: * <code>true</code> from <code>isReadOnly()</code>.
056: * </p>
057: *
058: * <p>
059: * <code>The {@link ExpressionFactory#createValueExpression} method
060: * can be used to parse an expression string and return a concrete instance
061: * of <code>ValueExpression</code> that encapsulates the parsed expression.
062: * The {@link FunctionMapper} is used at parse time, not evaluation time,
063: * so one is not needed to evaluate an expression using this class.
064: * However, the {@link ELContext} is needed at evaluation time.</p>
065: *
066: * <p>The {@link #getValue}, {@link #setValue}, {@link #isReadOnly} and
067: * {@link #getType} methods will evaluate the expression each time they are
068: * called. The {@link ELResolver} in the <code>ELContext</code> is used to
069: * resolve the top-level variables and to determine the behavior of the
070: * <code>.</code> and <code>[]</code> operators. For any of the four methods,
071: * the {@link ELResolver#getValue} method is used to resolve all properties
072: * up to but excluding the last one. This provides the <code>base</code>
073: * object. At the last resolution, the <code>ValueExpression</code> will
074: * call the corresponding {@link ELResolver#getValue},
075: * {@link ELResolver#setValue}, {@link ELResolver#isReadOnly} or
076: * {@link ELResolver#getType} method, depending on which was called on
077: * the <code>ValueExpression</code>.
078: * </p>
079: *
080: * <p>See the notes about comparison, serialization and immutability in
081: * the {@link Expression} javadocs.
082: *
083: * @see javax.el.ELResolver
084: * @see javax.el.Expression
085: * @see javax.el.ExpressionFactory
086: * @see javax.el.ValueExpression
087: *
088: * @author Jacob Hookom [jacob@hookom.net]
089: * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: markt $
090: */
091: public final class ValueExpressionImpl extends ValueExpression
092: implements Externalizable {
093:
094: private Class expectedType;
095:
096: private String expr;
097:
098: private FunctionMapper fnMapper;
099:
100: private VariableMapper varMapper;
101:
102: private transient Node node;
103:
104: public ValueExpressionImpl() {
105:
106: }
107:
108: /**
109: *
110: */
111: public ValueExpressionImpl(String expr, Node node,
112: FunctionMapper fnMapper, VariableMapper varMapper,
113: Class expectedType) {
114: this .expr = expr;
115: this .node = node;
116: this .fnMapper = fnMapper;
117: this .varMapper = varMapper;
118: this .expectedType = expectedType;
119: }
120:
121: /*
122: * (non-Javadoc)
123: *
124: * @see java.lang.Object#equals(java.lang.Object)
125: */
126: public boolean equals(Object obj) {
127: return (obj instanceof ValueExpressionImpl && obj.hashCode() == this
128: .hashCode());
129: }
130:
131: /*
132: * (non-Javadoc)
133: *
134: * @see javax.el.ValueExpression#getExpectedType()
135: */
136: public Class getExpectedType() {
137: return this .expectedType;
138: }
139:
140: /**
141: * Returns the type the result of the expression will be coerced to after
142: * evaluation.
143: *
144: * @return the <code>expectedType</code> passed to the
145: * <code>ExpressionFactory.createValueExpression</code> method
146: * that created this <code>ValueExpression</code>.
147: *
148: * @see javax.el.Expression#getExpressionString()
149: */
150: public String getExpressionString() {
151: return this .expr;
152: }
153:
154: /**
155: * @return
156: * @throws ELException
157: */
158: private Node getNode() throws ELException {
159: if (this .node == null) {
160: this .node = ExpressionBuilder.createNode(this .expr);
161: }
162: return this .node;
163: }
164:
165: /*
166: * (non-Javadoc)
167: *
168: * @see javax.el.ValueExpression#getType(javax.el.ELContext)
169: */
170: public Class getType(ELContext context)
171: throws PropertyNotFoundException, ELException {
172: EvaluationContext ctx = new EvaluationContext(context,
173: this .fnMapper, this .varMapper);
174: return this .getNode().getType(ctx);
175: }
176:
177: /*
178: * (non-Javadoc)
179: *
180: * @see javax.el.ValueExpression#getValue(javax.el.ELContext)
181: */
182: public Object getValue(ELContext context)
183: throws PropertyNotFoundException, ELException {
184: EvaluationContext ctx = new EvaluationContext(context,
185: this .fnMapper, this .varMapper);
186: Object value = this .getNode().getValue(ctx);
187: if (this .expectedType != null) {
188: return ELSupport.coerceToType(value, this .expectedType);
189: }
190: return value;
191: }
192:
193: /*
194: * (non-Javadoc)
195: *
196: * @see java.lang.Object#hashCode()
197: */
198: public int hashCode() {
199: return this .expr.hashCode();
200: }
201:
202: /*
203: * (non-Javadoc)
204: *
205: * @see javax.el.ValueExpression#isLiteralText()
206: */
207: public boolean isLiteralText() {
208: try {
209: return this .getNode() instanceof AstLiteralExpression;
210: } catch (ELException ele) {
211: return false;
212: }
213: }
214:
215: /*
216: * (non-Javadoc)
217: *
218: * @see javax.el.ValueExpression#isReadOnly(javax.el.ELContext)
219: */
220: public boolean isReadOnly(ELContext context)
221: throws PropertyNotFoundException, ELException {
222: EvaluationContext ctx = new EvaluationContext(context,
223: this .fnMapper, this .varMapper);
224: return this .getNode().isReadOnly(ctx);
225: }
226:
227: public void readExternal(ObjectInput in) throws IOException,
228: ClassNotFoundException {
229: this .expr = in.readUTF();
230: String type = in.readUTF();
231: if (!"".equals(type)) {
232: this .expectedType = ReflectionUtil.forName(type);
233: }
234: this .fnMapper = (FunctionMapper) in.readObject();
235: this .varMapper = (VariableMapper) in.readObject();
236: }
237:
238: /*
239: * (non-Javadoc)
240: *
241: * @see javax.el.ValueExpression#setValue(javax.el.ELContext,
242: * java.lang.Object)
243: */
244: public void setValue(ELContext context, Object value)
245: throws PropertyNotFoundException,
246: PropertyNotWritableException, ELException {
247: EvaluationContext ctx = new EvaluationContext(context,
248: this .fnMapper, this .varMapper);
249: this .getNode().setValue(ctx, value);
250: }
251:
252: public void writeExternal(ObjectOutput out) throws IOException {
253: out.writeUTF(this .expr);
254: out.writeUTF((this .expectedType != null) ? this .expectedType
255: .getName() : "");
256: out.writeObject(this .fnMapper);
257: out.writeObject(this .varMapper);
258: }
259:
260: public String toString() {
261: return "ValueExpression[" + this .expr + "]";
262: }
263: }
|