/*
* JBoss, Home of Professional Open Source
* Copyright 2011, Red Hat, Inc. and/or its affiliates, and individual
* contributors by the @authors tag. See the copyright.txt in the
* distribution for a full listing of individual contributors.
*
* Licensed 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.jboss.solder.el;
import javax.el.ELContext;
import javax.el.ELException;
import javax.el.ExpressionFactory;
import javax.el.MethodExpression;
import javax.el.MethodNotFoundException;
import javax.el.PropertyNotFoundException;
import javax.el.ValueExpression;
import javax.inject.Inject;
import org.jboss.solder.reflection.Reflections;
/**
* <p>
* Provides various utility methods for working with EL expressions.
* </p>
* <p/>
* <p>
* This utility can be used through injection:
* </p>
* <p/>
* <pre>
* @Inject
* Expressions expressions;
* </pre>
* <p/>
* <p>
* Alternatively, if you aren't working in a CDI environment, it can be
* instantiated using the <code>new</code> keyword:
* </p>
* <p/>
* <pre>
* Expressions expressions = new Expressions(context, expressionFactory);
* </pre>
*
* @author Pete Muir
* @author Dan Allen
* @author Stuart Douglas
*/
public class Expressions {
private final ELContext context;
private final ExpressionFactory expressionFactory;
/**
* Create a new instance of the {@link Expressions} class, providing the
* {@link ELContext} and {@link ExpressionFactory} to be used.
*
* @param context the {@link ELContext} against which to operate
* @param expressionFactory the {@link ExpressionFactory} to use
* @throws IllegalArgumentException if <code>context</code> is null or
* <code>expressionFactory</code> is null
*/
@Inject
public Expressions(ELContext context, ExpressionFactory expressionFactory) {
if (context == null) {
throw new IllegalArgumentException("context must not be null");
}
if (expressionFactory == null) {
throw new IllegalArgumentException("expressionFactory must not be null");
}
this.context = context;
this.expressionFactory = expressionFactory;
}
/**
* Obtain the {@link ELContext} that this instance of {@link Expressions} is
* using.
*
* @return the {@link ELContext} in use
*/
public ELContext getELContext() {
return context;
}
/**
* Obtain the {@link ExpressionFactory} that this instance of
* {@link Expressions} is using.
*
* @return the {@link ExpressionFactory} in use
*/
public ExpressionFactory getExpressionFactory() {
return expressionFactory;
}
/**
* <p>
* Evaluate a {@link ValueExpression}.
* </p>
* <p/>
* <p>
* A {@link ValueExpression} is created by calling
* {@link ExpressionFactory#createValueExpression(ELContext, String, Class)}
* and then {@link ValueExpression#getValue(ELContext)} is called to obtain
* the value. For more details on the semantics of EL, refer to the javadoc
* for these classes and methods.
* </p>
*
* @param <T> the type of the evaluated expression
* @param expression the expression to evaluate
* @param expectedType the expected type of the evaluated expression
* @return the result of evaluating the expression
* @throws NullPointerException if expectedType is <code>null</code>
* @throws ELException if there are syntactical errors in the provided
* expression or if an exception was thrown while performing
* property or variable resolution. The thrown exception will be
* included as the cause property of this exception, if available.
* @throws PropertyNotFoundException if one of the property resolutions
* failed because a specified variable or property does not exist
* or is not readable.
* @throws ClassCastException if the result cannot be cast to the expected
* type
* @see ExpressionFactory#createValueExpression(ELContext, String, Class)
* @see ValueExpression#getValue(ELContext)
*/
public <T> T evaluateValueExpression(String expression, Class<T> expectedType) {
Object result = expressionFactory.createValueExpression(context, expression, expectedType).getValue(context);
if (result != null) {
return expectedType.cast(result);
} else {
return null;
}
}
/**
* <p>
* Evaluate a {@link ValueExpression} inferring the return type.
* </p>
* <p/>
* <p>
* A {@link ValueExpression} is created by calling
* {@link ExpressionFactory#createValueExpression(ELContext, String, Class)}
* and then {@link ValueExpression#getValue(ELContext)} is called to obtain
* the value. For more details on the semantics of EL, refer to the javadoc
* for these methods.
* </p>
*
* @param <T> the type of the evaluated expression
* @param expression expression the expression to evaluate
* @return the result of evaluating the expression
* @throws ELException if there are syntactical errors in the provided
* expression
* @throws ELException if an exception was thrown while performing property
* or variable resolution. The thrown exception will be included
* as the cause property of this exception, if available.
* @throws PropertyNotFoundException if one of the property resolutions
* failed because a specified variable or property does not exist
* or is not readable
* @throws ClassCastException if the result cannot be cast to <code>T</code>
* @see ExpressionFactory#createValueExpression(ELContext, String, Class)
* @see ValueExpression#getValue(ELContext)
*/
public <T> T evaluateValueExpression(String expression) {
Object result = evaluateValueExpression(expression, Object.class);
if (result != null) {
return Reflections.<T>cast(result);
} else {
return null;
}
}
/**
* <p>
* Evaluate a {@link MethodExpression}, passing arguments and argument types
* to the method.
* </p>
* <p/>
* <p>
* A {@link MethodExpression} is created by calling
* {@link ExpressionFactory#createMethodExpression(ELContext, String, Class, Class[])}
* and then {@link MethodExpression#invoke(ELContext, Object[])} is called to
* obtain the value. For more details on the semantics of EL, refer to the
* javadoc for these methods.
* </p>
*
* @param <T> the type of the evaluated expression
* @param expression expression the expression to evaluate
* @param expectedReturnType the expected return type of the evaluated
* expression
* @param params arguments to the method
* @param expectedParamTypes of the arguments to the method
* @return the result of evaluating the expression
* @throws ClassCastException if the result cannot be cast to
* <code>expectedReturnType</code>
* @throws ELException if there are syntactical errors in the provided
* expression.
* @throws NullPointerException if <code>expectedParamTypes</code> is
* <code>null</code>.
* @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 a String literal is specified and
* expectedReturnType of the MethodExpression is void or if the
* coercion of the String literal to the expectedReturnType yields
* an error (see Section "1.18 Type Conversion").
* @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 MethodExpression#invoke(ELContext, Object[])
* @see ExpressionFactory#createMethodExpression(ELContext, String, Class,
* Class[])
*/
public <T> T evaluateMethodExpression(String expression, Class<T> expectedReturnType, Object[] params, Class<?>[] expectedParamTypes) {
Object result = expressionFactory.createMethodExpression(context, expression, expectedReturnType, expectedParamTypes).invoke(context, params);
if (result != null) {
return expectedReturnType.cast(result);
} else {
return null;
}
}
/**
* <p>
* Evaluate a {@link MethodExpression} with no parameters.
* </p>
* <p/>
* <p>
* A {@link MethodExpression} is created by calling
* {@link ExpressionFactory#createMethodExpression(ELContext, String, Class, Class[])}
* and then {@link MethodExpression#invoke(ELContext, Object[])} is called to
* obtain the value. For more details on the semantics of EL, refer to the
* javadoc for these methods.
* </p>
*
* @param <T> the type of the evaluated expression
* @param expression expression the expression to evaluate
* @param expectedReturnType the expected return type of the evaluated
* expression
* @return the result of evaluating the expression
* @throws ClassCastException if the result cannot be cast to
* <code>expectedReturnType</code>
* @throws ELException if there are syntactical errors in the provided
* expression.
* @throws NullPointerException if <code>expectedParamTypes</code> is
* <code>null</code>.
* @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 a String literal is specified and
* expectedReturnType of the MethodExpression is void or if the
* coercion of the String literal to the expectedReturnType yields
* an error (see Section "1.18 Type Conversion").
* @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 MethodExpression#invoke(ELContext, Object[])
* @see ExpressionFactory#createMethodExpression(ELContext, String, Class,
* Class[])
*/
public <T> T evaluateMethodExpression(String expression, Class<T> expectedReturnType) {
return evaluateMethodExpression(expression, expectedReturnType, new Object[0], new Class[0]);
}
/**
* <p>
* Evaluate a {@link MethodExpression} with no parameters, inferring the
* return type.
* </p>
* <p/>
* <p>
* A {@link MethodExpression} is created by calling
* {@link ExpressionFactory#createMethodExpression(ELContext, String, Class, Class[])}
* and then {@link MethodExpression#invoke(ELContext, Object[])} is called to
* obtain the value. For more details on the semantics of EL, refer to the
* javadoc for these methods.
* </p>
*
* @param <T> the type of the evaluated expression
* @param expression expression the expression to evaluate
* @return the result of evaluating the expression
* @throws ClassCastException if the result cannot be cast to <code>T</code>
* @throws ELException if there are syntactical errors in the provided
* expression.
* @throws NullPointerException if <code>expectedParamTypes</code> is
* <code>null</code>.
* @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 a String literal is specified and
* expectedReturnType of the MethodExpression is void or if the
* coercion of the String literal to the expectedReturnType yields
* an error (see Section "1.18 Type Conversion").
* @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 MethodExpression#invoke(ELContext, Object[])
* @see ExpressionFactory#createMethodExpression(ELContext, String, Class,
* Class[])
*/
public <T> T evaluateMethodExpression(String expression) {
Object result = evaluateMethodExpression(expression, Object.class);
if (result != null) {
return Reflections.<T>cast(result);
} else {
return null;
}
}
/**
* <p>
* Evaluate a {@link MethodExpression}, passing arguments to the method. The
* types of the arguments are discoverted from the arguments, and the return
* type is inferred.
* </p>
* <p/>
* <p>
* A {@link MethodExpression} is created by calling
* {@link ExpressionFactory#createMethodExpression(ELContext, String, Class, Class[])}
* and then {@link MethodExpression#invoke(ELContext, Object[])} is called to
* obtain the value. For more details on the semantics of EL, refer to the
* javadoc for these methods.
* </p>
*
* @param <T> the type of the evaluated expression
* @param expression expression the expression to evaluate
* @param params arguments to the method
* @return the result of evaluating the expression
* @throws ClassCastException if the result cannot be cast to <code>T</code>
* @throws ELException if there are syntactical errors in the provided
* expression.
* @throws NullPointerException if <code>expectedParamTypes</code> is
* <code>null</code>.
* @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 a String literal is specified and
* expectedReturnType of the MethodExpression is void or if the
* coercion of the String literal to the expectedReturnType yields
* an error (see Section "1.18 Type Conversion").
* @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 MethodExpression#invoke(ELContext, Object[])
* @see ExpressionFactory#createMethodExpression(ELContext, String, Class,
* Class[])
*/
public <T> T evaluateMethodExpression(String expression, Object... params) {
Object result = evaluateMethodExpression(expression, Object.class, params, new Class[params.length]);
if (result != null) {
return Reflections.<T>cast(result);
} else {
return null;
}
}
/**
* Convert's a bean name to an EL expression string.
*
* @param name the name of the bean to convert
* @return the expression string
*/
public String toExpression(String name) {
return "#{" + name + "}";
}
}