/*
* Licensed to the Apache Software Foundation ( ASF ) under one or more
* contributor license agreements . See the NOTICE file distributed with
* this work for additional information regarding copyright ownership .
* The ASF licenses this file to You under the Apache License , Version 2 . 0
* ( the " License " ) ; you may not use this file except in compliance with
* the License . You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an " AS IS " BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
*/
package org.apache.el;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import jakarta.el.ELContext;
import jakarta.el.ELException;
import jakarta.el.FunctionMapper;
import jakarta.el.MethodExpression;
import jakarta.el.MethodInfo;
import jakarta.el.MethodNotFoundException;
import jakarta.el.MethodReference;
import jakarta.el.PropertyNotFoundException;
import jakarta.el.VariableMapper;
import org.apache.el.lang.EvaluationContext;
import org.apache.el.lang.ExpressionBuilder;
import org.apache.el.parser.Node;
import org.apache.el.util.ReflectionUtil;
/**
* An < code > Expression < / code > that refers to a method on an object .
*
* < p >
* The { @ link jakarta . el . ExpressionFactory # createMethodExpression } method
* can be used to parse an expression string and return a concrete instance
* of < code > MethodExpression < / code > that encapsulates the parsed expression .
* The { @ link FunctionMapper } is used at parse time , not evaluation time ,
* so one is not needed to evaluate an expression using this class .
* However , the { @ link ELContext } is needed at evaluation time . < / p >
*
* < p > The { @ link # getMethodInfo } and { @ link # invoke } methods will evaluate the
* expression each time they are called . The { @ link jakarta . el . ELResolver } in the
* < code > ELContext < / code > is used to resolve the top - level variables and to
* determine the behavior of the < code > . < / code > and < code > [ ] < / code >
* operators . For any of the two methods , the
* { @ link jakarta . el . ELResolver # getValue } method is used to resolve all properties
* up to but excluding the last one . This provides the < code > base < / code > object
* on which the method appears . If the < code > base < / code > object is null , a
* < code > NullPointerException < / code > must be thrown . At the last resolution ,
* the final < code > property < / code > is then coerced to a < code > String < / code > ,
* which provides the name of the method to be found . A method matching the
* name and expected parameters provided at parse time is found and it is
* either queried or invoked ( depending on the method called on this
* < code > MethodExpression < / code > ) . < / p >
*
* < p > See the notes about comparison , serialization and immutability in
* the { @ link jakarta . el . Expression } javadocs .
*
* @ see jakarta . el . ELResolver
* @ see jakarta . el . Expression
* @ see jakarta . el . ExpressionFactory
* @ see jakarta . el . MethodExpression
*
* @ author Jacob Hookom [ jacob @ hookom . net ]
*/
public final class MethodExpressionImpl extends MethodExpression implements
Externalizable {
private Class <?> expectedType;
private String expr;
private FunctionMapper fnMapper;
private VariableMapper varMapper;
private transient Node node;
private Class <?>[] paramTypes;
public MethodExpressionImpl() {
super ();
}
public MethodExpressionImpl(String expr, Node node,
FunctionMapper fnMapper, VariableMapper varMapper,
Class <?> expectedType, Class <?>[] paramTypes) {
super ();
this .expr = expr;
this .node = node;
this .fnMapper = fnMapper;
this .varMapper = varMapper;
this .expectedType = expectedType;
this .paramTypes = paramTypes;
}
/**
* Determines whether the specified object is equal to this
* < code > Expression < / code > .
*
* < p >
* The result is < code > true < / code > if and only if the argument is not
* < code > null < / code > , is an < code > Expression < / code > object that is the
* of the same type ( < code > ValueExpression < / code > or
* < code > MethodExpression < / code > ) , and has an identical parsed
* representation .
* < / p >
*
* < p >
* Note that two expressions can be equal if their expression Strings are
* different . For example , < code > $ { fn1 : foo ( ) } < / code > and
* < code > $ { fn2 : foo ( ) } < / code > are equal if their corresponding
* < code > FunctionMapper < / code > s mapped < code > fn1 : foo < / code > and
* < code > fn2 : foo < / code > to the same method .
* < / p >
*
* @ param obj
* the < code > Object < / code > to test for equality .
* @ return < code > true < / code > if < code > obj < / code > equals this
* < code > Expression < / code > ; < code > false < / code > otherwise .
* @ see java . util . Hashtable
* @ see java . lang . Object # equals ( java . lang . Object )
*/
@Override
public boolean equals(Object obj) {
return (obj instanceof MethodExpressionImpl && obj.hashCode() == this
.hashCode());
}
/**
* Returns the original String used to create this < code > Expression < / code > ,
* unmodified .
*
* < p >
* This is used for debugging purposes but also for the purposes of
* comparison ( e . g . to ensure the expression in a configuration file has not
* changed ) .
* < / p >
*
* < p >
* This method does not provide sufficient information to re - create an
* expression . Two different expressions can have exactly the same
* expression string but different function mappings . Serialization should
* be used to save and restore the state of an < code > Expression < / code > .
* < / p >
*
* @ return The original expression String .
*
* @ see jakarta . el . Expression # getExpressionString ( )
*/
@Override
public String getExpressionString() {
return this .expr;
}
/**
* Evaluates the expression relative to the provided context , and returns
* information about the actual referenced method .
*
* @ param context
* The context of this evaluation
* @ return an instance of < code > MethodInfo < / code > containing information
* about the method the expression evaluated to .
* @ throws NullPointerException
* if context is < code > null < / code > or the base object is
* < code > null < / code > on the last resolution .
* @ throws PropertyNotFoundException
* if one of the property resolutions failed because a specified
* variable or property does not exist or is not readable .
* @ throws MethodNotFoundException
* if no suitable method can be found .
* @ throws ELException
* if an exception was thrown while performing property or
* variable resolution . The thrown exception must be included as
* the cause property of this exception , if available .
* @ see jakarta . el . MethodExpression # getMethodInfo ( jakarta . el . ELContext )
*/
@Override
public MethodInfo getMethodInfo(ELContext context)
throws PropertyNotFoundException, MethodNotFoundException,
ELException {
Node n = this .getNode();
EvaluationContext ctx = new EvaluationContext(context, this .fnMapper,
this .varMapper);
ctx.notifyBeforeEvaluation(getExpressionString());
MethodInfo result = n.getMethodInfo(ctx, this .paramTypes);
ctx.notifyAfterEvaluation(getExpressionString());
return result;
}
private Node getNode() throws ELException {
if (this .node == null ) {
this .node = ExpressionBuilder.createNode(this .expr);
}
return this .node;
}
/**
* Returns the hash code for this < code > Expression < / code > .
*
* < p >
* See the note in the { @ link # equals } method on how two expressions can be
* equal if their expression Strings are different . Recall that if two
* objects are equal according to the < code > equals ( Object ) < / code > method ,
* then calling the < code > hashCode < / code > method on each of the two
* objects must produce the same integer result . Implementations must take
* special note and implement < code > hashCode < / code > correctly .
* < / p >
*
* @ return The hash code for this < code > Expression < / code > .
* @ see # equals
* @ see java . util . Hashtable
* @ see java . lang . Object # hashCode ( )
*/
@Override
public int hashCode() {
return this .expr.hashCode();
}
/**
* Evaluates the expression relative to the provided context , invokes the
* method that was found using the supplied parameters , and returns the
* result of the method invocation .
*
* @ param context
* The context of this evaluation .
* @ param params
* The parameters to pass to the method , or < code > null < / code >
* if no parameters .
* @ return the result of the method invocation ( < code > null < / code > if the
* method has a < code > void < / code > return type ) .
* @ throws NullPointerException
* if context is < code > null < / code > or the base object is
* < code > null < / code > on the last resolution .
* @ throws PropertyNotFoundException
* if one of the property resolutions failed because a specified
* variable or property does not exist or is not readable .
* @ throws MethodNotFoundException
* if no suitable method can be found .
* @ throws ELException
* if an exception was thrown while performing property or
* variable resolution . The thrown exception must be included as
* the cause property of this exception , if available . If the
* exception thrown is an < code > InvocationTargetException < / code > ,
* extract its < code > cause < / code > and pass it to the
* < code > ELException < / code > constructor .
* @ see jakarta . el . MethodExpression # invoke ( jakarta . el . ELContext ,
* java . lang . Object [ ] )
*/
@Override
public Object invoke(ELContext context, Object[] params)
throws PropertyNotFoundException, MethodNotFoundException,
ELException {
EvaluationContext ctx = new EvaluationContext(context, this .fnMapper,
this .varMapper);
ctx.notifyBeforeEvaluation(getExpressionString());
Object result = this .getNode().invoke(ctx, this .paramTypes, params);
ctx.notifyAfterEvaluation(getExpressionString());
return result;
}
/*
* ( non - Javadoc )
*
* @ see java . io . Externalizable # readExternal ( java . io . ObjectInput )
*/
@Override
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
this .expr = in.readUTF();
String type = in.readUTF();
if (!type.isEmpty()) {
this .expectedType = ReflectionUtil.forName(type);
}
this .paramTypes = ReflectionUtil.toTypeArray(((String[]) in
.readObject()));
this .fnMapper = (FunctionMapper) in.readObject();
this .varMapper = (VariableMapper) in.readObject();
}
/*
* ( non - Javadoc )
*
* @ see java . io . Externalizable # writeExternal ( java . io . ObjectOutput )
*/
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeUTF(this .expr);
out.writeUTF((this .expectedType != null ) ? this .expectedType.getName()
: "" );
out.writeObject(ReflectionUtil.toTypeNameArray(this .paramTypes));
out.writeObject(this .fnMapper);
out.writeObject(this .varMapper);
}
@Override
public boolean isLiteralText() {
return false ;
}
/**
* @ since EL 3 . 0
*/
@Override
public boolean isParametersProvided() {
return this .getNode().isParametersProvided();
}
@Override
public MethodReference getMethodReference(ELContext context) {
EvaluationContext ctx = new EvaluationContext(context, this .fnMapper, this .varMapper);
ctx.notifyBeforeEvaluation(getExpressionString());
MethodReference methodReference = this .getNode().getMethodReference(ctx);
ctx.notifyAfterEvaluation(getExpressionString());
return methodReference;
}
}
Messung V0.5 in Prozent C=92 H=90 G=90
¤ Dauer der Verarbeitung: 0.17 Sekunden
¤
*© Formatika GbR, Deutschland