Java tutorial
package org.apache.commons.ognl; /* * 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. */ import org.apache.commons.ognl.enhance.ExpressionAccessor; import java.io.StringReader; import java.util.Map; /** * <p> * This class provides static methods for parsing and interpreting OGNL expressions. * </p> * <p> * The simplest use of the Ognl class is to get the value of an expression from an object, without extra context or * pre-parsing. * </p> * * <pre> * * import org.apache.commons.ognl.Ognl; * import org.apache.commons.ognl.OgnlException; * ... * try * { * result = Ognl.getValue( expression, root ); * } * catch ( OgnlException ex ) * { * // Report error or recover * } * * </pre> * <p> * This will parse the expression given and evaluate it against the root object given, returning the result. If there is * an error in the expression, such as the property is not found, the exception is encapsulated into an * {@link org.apache.commons.ognl.OgnlException OgnlException}. * </p> * <p> * Other more sophisticated uses of Ognl can pre-parse expressions. This provides two advantages: in the case of * user-supplied expressions it allows you to catch parse errors before evaluation and it allows you to cache parsed * expressions into an AST for better speed during repeated use. The pre-parsed expression is always returned as an * <code>Object</code> to simplify use for programs that just wish to store the value for repeated use and do not care * that it is an AST. If it does care it can always safely cast the value to an <code>AST</code> type. * </p> * <p> * The Ognl class also takes a <I>context map</I> as one of the parameters to the set and get methods. This allows you * to put your own variables into the available namespace for OGNL expressions. The default context contains only the * <code>#root</code> and <code>#context</code> keys, which are required to be present. The * <code>addDefaultContext(Object, Map)</code> method will alter an existing <code>Map</code> to put the defaults in. * Here is an example that shows how to extract the <code>documentName</code> property out of the root object and append * a string with the current user name in parens: * </p> * * <pre> * * private Map<String, Object> context = new HashMap<String, Object>(); * ... * public void setUserName( String value ) * { * context.put("userName", value); * } * ... * try * { * // get value using our own custom context map * result = Ognl.getValue( "documentName + \" (\" + ((#userName == null) ? \"<nobody>\" : #userName ) + * \")\"", context, root ); * } * catch ( OgnlException ex ) * { * // Report error or recover * } * * </pre> */ public abstract class Ognl { /** * Parses the given OGNL expression and returns a tree representation of the expression that can be used by * <code>Ognl</code> static methods. * * @param expression the OGNL expression to be parsed * @return a tree representation of the expression * @throws ExpressionSyntaxException if the expression is malformed * @throws OgnlException if there is a pathological environmental problem */ public static Object parseExpression(String expression) throws OgnlException { try { OgnlParser parser = new OgnlParser(new StringReader(expression)); return parser.topLevelExpression(); } catch (ParseException e) { throw new ExpressionSyntaxException(expression, e); } catch (TokenMgrError e) { throw new ExpressionSyntaxException(expression, e); } } /** * Parses and compiles the given expression using the {@link org.apache.commons.ognl.enhance.OgnlExpressionCompiler} * returned from * {@link org.apache.commons.ognl.OgnlRuntime#getCompiler(OgnlContext)}. * * @param context The context to use. * @param root The root object for the given expression. * @param expression The expression to compile. * @return The node with a compiled accessor set on {@link org.apache.commons.ognl.Node#getAccessor()} if * compilation was successfull. * In instances where compilation wasn't possible because of a partially null expression the * {@link ExpressionAccessor} instance may be null and the compilation of this expression still possible at * some as yet indertermined point in the future. * @throws Exception If a compilation error occurs. */ public static Node compileExpression(OgnlContext context, Object root, String expression) throws Exception { Node expr = (Node) Ognl.parseExpression(expression); OgnlRuntime.compileExpression(context, expr, root); return expr; } /** * Creates and returns a new standard naming context for evaluating an OGNL expression. * * @param root the root of the object graph * @return a new Map with the keys <code>root</code> and <code>context</code> set appropriately */ public static Map<String, Object> createDefaultContext(Object root) { return addDefaultContext(root, null, null, null, new OgnlContext()); } /** * Creates and returns a new standard naming context for evaluating an OGNL expression. * * @param root The root of the object graph. * @param classResolver The resolver used to instantiate {@link Class} instances referenced in the expression. * @return a new OgnlContext with the keys <code>root</code> and <code>context</code> set appropriately */ public static Map<String, Object> createDefaultContext(Object root, ClassResolver classResolver) { return addDefaultContext(root, classResolver, null, null, new OgnlContext()); } /** * Creates and returns a new standard naming context for evaluating an OGNL expression. * * @param root The root of the object graph. * @param classResolver The resolver used to instantiate {@link Class} instances referenced in the expression. * @param converter Converter used to convert return types of an expression in to their desired types. * @return a new Map with the keys <code>root</code> and <code>context</code> set appropriately */ public static Map<String, Object> createDefaultContext(Object root, ClassResolver classResolver, TypeConverter converter) { return addDefaultContext(root, classResolver, converter, null, new OgnlContext()); } /** * Creates and returns a new standard naming context for evaluating an OGNL expression. * * @param root The root of the object graph. * @param classResolver The resolver used to instantiate {@link Class} instances referenced in the expression. * @param converter Converter used to convert return types of an expression in to their desired types. * @param memberAccess Java security handling object to determine semantics for accessing normally private/protected * methods / fields. * @return a new Map with the keys <code>root</code> and <code>context</code> set appropriately */ public static Map<String, Object> createDefaultContext(Object root, ClassResolver classResolver, TypeConverter converter, MemberAccess memberAccess) { return addDefaultContext(root, classResolver, converter, memberAccess, new OgnlContext()); } /** * Appends the standard naming context for evaluating an OGNL expression into the context given so that cached maps * can be used as a context. * * @param root the root of the object graph * @param context the context to which OGNL context will be added. * @return Context Map with the keys <code>root</code> and <code>context</code> set appropriately */ public static Map<String, Object> addDefaultContext(Object root, Map<String, Object> context) { return addDefaultContext(root, null, null, null, context); } /** * Appends the standard naming context for evaluating an OGNL expression into the context given so that cached maps * can be used as a context. * * @param root The root of the object graph. * @param classResolver The resolver used to instantiate {@link Class} instances referenced in the expression. * @param context The context to which OGNL context will be added. * @return Context Map with the keys <code>root</code> and <code>context</code> set appropriately */ public static Map<String, Object> addDefaultContext(Object root, ClassResolver classResolver, Map<String, Object> context) { return addDefaultContext(root, classResolver, null, null, context); } /** * Appends the standard naming context for evaluating an OGNL expression into the context given so that cached maps * can be used as a context. * * @param root The root of the object graph. * @param classResolver The resolver used to instantiate {@link Class} instances referenced in the expression. * @param converter Converter used to convert return types of an expression in to their desired types. * @param context The context to which OGNL context will be added. * @return Context Map with the keys <code>root</code> and <code>context</code> set appropriately */ public static Map<String, Object> addDefaultContext(Object root, ClassResolver classResolver, TypeConverter converter, Map<String, Object> context) { return addDefaultContext(root, classResolver, converter, null, context); } /** * Appends the standard naming context for evaluating an OGNL expression into the context given so that cached maps * can be used as a context. * * @param root the root of the object graph * @param classResolver The class loading resolver that should be used to resolve class references. * @param converter The type converter to be used by default. * @param memberAccess Definition for handling private/protected access. * @param context Default context to use, if not an {@link OgnlContext} will be dumped into a new * {@link OgnlContext} object. * @return Context Map with the keys <code>root</code> and <code>context</code> set appropriately */ public static Map<String, Object> addDefaultContext(Object root, ClassResolver classResolver, TypeConverter converter, MemberAccess memberAccess, Map<String, Object> context) { OgnlContext result; if (!(context instanceof OgnlContext)) { result = new OgnlContext(); result.setValues(context); } else { result = (OgnlContext) context; } if (classResolver != null) { result.setClassResolver(classResolver); } if (converter != null) { result.setTypeConverter(converter); } if (memberAccess != null) { result.setMemberAccess(memberAccess); } result.setRoot(root); return result; } /** * Configures the {@link ClassResolver} to use for the given context. Will be used during expression parsing / * execution to resolve class names. * * @param context The context to place the resolver. * @param classResolver The resolver to use to resolve classes. */ public static void setClassResolver(Map<String, Object> context, ClassResolver classResolver) { context.put(OgnlContext.CLASS_RESOLVER_CONTEXT_KEY, classResolver); } /** * Gets the previously stored {@link ClassResolver} for the given context - if any. * * @param context The context to get the configured resolver from. * @return The resolver instance, or null if none found. */ public static ClassResolver getClassResolver(Map<String, Object> context) { return (ClassResolver) context.get(OgnlContext.CLASS_RESOLVER_CONTEXT_KEY); } /** * Configures the type converter to use for a given context. This will be used to convert into / out of various java * class types. * * @param context The context to configure it for. * @param converter The converter to use. */ public static void setTypeConverter(Map<String, Object> context, TypeConverter converter) { context.put(OgnlContext.TYPE_CONVERTER_CONTEXT_KEY, converter); } /** * Gets the currently configured {@link TypeConverter} for the given context - if any. * * @param context The context to get the converter from. * @return The converter - or null if none found. */ public static TypeConverter getTypeConverter(Map<String, Object> context) { return (TypeConverter) context.get(OgnlContext.TYPE_CONVERTER_CONTEXT_KEY); } /** * Configures the specified context with a {@link MemberAccess} instance for handling field/method protection * levels. * * @param context The context to configure. * @param memberAccess The access resolver to configure the context with. */ public static void setMemberAccess(Map<String, Object> context, MemberAccess memberAccess) { context.put(OgnlContext.MEMBER_ACCESS_CONTEXT_KEY, memberAccess); } /** * Gets the currently stored {@link MemberAccess} object for the given context - if any. * * @param context The context to get the object from. * @return The configured {@link MemberAccess} instance in the specified context - or null if none found. */ public static MemberAccess getMemberAccess(Map<String, Object> context) { return (MemberAccess) context.get(OgnlContext.MEMBER_ACCESS_CONTEXT_KEY); } /** * Sets the root object to use for all expressions in the given context - doesn't necessarily replace root object * instances explicitly passed in to other expression resolving methods on this class. * * @param context The context to store the root object in. * @param root The root object. */ public static void setRoot(Map<String, Object> context, Object root) { context.put(OgnlContext.ROOT_CONTEXT_KEY, root); } /** * Gets the stored root object for the given context - if any. * * @param context The context to get the root object from. * @return The root object - or null if none found. */ public static Object getRoot(Map<String, Object> context) { return context.get(OgnlContext.ROOT_CONTEXT_KEY); } /** * Gets the last {@link Evaluation} executed on the given context. * * @param context The context to get the evaluation from. * @return The {@link Evaluation} - or null if none was found. */ public static Evaluation getLastEvaluation(Map<String, Object> context) { return (Evaluation) context.get(OgnlContext.LAST_EVALUATION_CONTEXT_KEY); } /** * Evaluates the given OGNL expression tree to extract a value from the given root object. The default context is * set for the given context and root via <code>addDefaultContext()</code>. * * @param tree the OGNL expression tree to evaluate, as returned by parseExpression() * @param context the naming context for the evaluation * @param root the root object for the OGNL expression * @return the result of evaluating the expression * @throws MethodFailedException if the expression called a method which failed * @throws NoSuchPropertyException if the expression referred to a nonexistent property * @throws InappropriateExpressionException if the expression can't be used in this context * @throws OgnlException if there is a pathological environmental problem */ public static <T> T getValue(Object tree, Map<String, Object> context, Object root) throws OgnlException { return Ognl.<T>getValue(tree, context, root, null); } /** * Evaluates the given OGNL expression tree to extract a value from the given root object. The default context is * set for the given context and root via <code>addDefaultContext()</code>. * * @param tree the OGNL expression tree to evaluate, as returned by parseExpression() * @param context the naming context for the evaluation * @param root the root object for the OGNL expression * @param resultType the converted type of the resultant object, using the context's type converter * @return the result of evaluating the expression * @throws MethodFailedException if the expression called a method which failed * @throws NoSuchPropertyException if the expression referred to a nonexistent property * @throws InappropriateExpressionException if the expression can't be used in this context * @throws OgnlException if there is a pathological environmental problem */ @SuppressWarnings("unchecked") // will cause CCE if types are not compatible public static <T> T getValue(Object tree, Map<String, Object> context, Object root, Class<T> resultType) throws OgnlException { T result; OgnlContext ognlContext = (OgnlContext) addDefaultContext(root, context); Node node = (Node) tree; if (node.getAccessor() != null) { result = (T) node.getAccessor().get(ognlContext, root); } else { result = (T) node.getValue(ognlContext, root); } if (resultType != null) { result = getTypeConverter(context).convertValue(context, root, null, null, result, resultType); } return result; } /** * Gets the value represented by the given pre-compiled expression on the specified root object. * * @param expression The pre-compiled expression, as found in {@link Node#getAccessor()}. * @param context The ognl context. * @param root The object to retrieve the expression value from. * @return The value. */ @SuppressWarnings("unchecked") // will cause CCE if types are not compatible public static <T> T getValue(ExpressionAccessor expression, OgnlContext context, Object root) { return (T) expression.get(context, root); } /** * Gets the value represented by the given pre-compiled expression on the specified root object. * * @param expression The pre-compiled expression, as found in {@link Node#getAccessor()}. * @param context The ognl context. * @param root The object to retrieve the expression value from. * @param resultType The desired object type that the return value should be converted to using the * {@link #getTypeConverter(java.util.Map)} . * @return The value. */ public static <T> T getValue(ExpressionAccessor expression, OgnlContext context, Object root, Class<T> resultType) throws OgnlException { return getTypeConverter(context).convertValue(context, root, null, null, expression.get(context, root), resultType); } /** * Evaluates the given OGNL expression to extract a value from the given root object in a given context * * @see #parseExpression(String) * @see #getValue(Object,Object) * @param expression the OGNL expression to be parsed * @param context the naming context for the evaluation * @param root the root object for the OGNL expression * @return the result of evaluating the expression * @throws MethodFailedException if the expression called a method which failed * @throws NoSuchPropertyException if the expression referred to a nonexistent property * @throws InappropriateExpressionException if the expression can't be used in this context * @throws OgnlException if there is a pathological environmental problem */ public static <T> T getValue(String expression, Map<String, Object> context, Object root) throws OgnlException { return Ognl.<T>getValue(expression, context, root, null); } /** * Evaluates the given OGNL expression to extract a value from the given root object in a given context * * @see #parseExpression(String) * @see #getValue(Object,Object) * @param expression the OGNL expression to be parsed * @param context the naming context for the evaluation * @param root the root object for the OGNL expression * @param resultType the converted type of the resultant object, using the context's type converter * @return the result of evaluating the expression * @throws MethodFailedException if the expression called a method which failed * @throws NoSuchPropertyException if the expression referred to a nonexistent property * @throws InappropriateExpressionException if the expression can't be used in this context * @throws OgnlException if there is a pathological environmental problem */ public static <T> T getValue(String expression, Map<String, Object> context, Object root, Class<T> resultType) throws OgnlException { return Ognl.<T>getValue(parseExpression(expression), context, root, resultType); } /** * Evaluates the given OGNL expression tree to extract a value from the given root object. * * @param tree the OGNL expression tree to evaluate, as returned by parseExpression() * @param root the root object for the OGNL expression * @return the result of evaluating the expression * @throws MethodFailedException if the expression called a method which failed * @throws NoSuchPropertyException if the expression referred to a nonexistent property * @throws InappropriateExpressionException if the expression can't be used in this context * @throws OgnlException if there is a pathological environmental problem */ public static <T> T getValue(Object tree, Object root) throws OgnlException { return Ognl.<T>getValue(tree, root, null); } /** * Evaluates the given OGNL expression tree to extract a value from the given root object. * * @param tree the OGNL expression tree to evaluate, as returned by parseExpression() * @param root the root object for the OGNL expression * @param resultType the converted type of the resultant object, using the context's type converter * @return the result of evaluating the expression * @throws MethodFailedException if the expression called a method which failed * @throws NoSuchPropertyException if the expression referred to a nonexistent property * @throws InappropriateExpressionException if the expression can't be used in this context * @throws OgnlException if there is a pathological environmental problem */ public static <T> T getValue(Object tree, Object root, Class<T> resultType) throws OgnlException { return Ognl.<T>getValue(tree, createDefaultContext(root), root, resultType); } /** * Convenience method that combines calls to <code> parseExpression </code> and <code> getValue</code>. * * @see #parseExpression(String) * @see #getValue(Object,Object) * @param expression the OGNL expression to be parsed * @param root the root object for the OGNL expression * @return the result of evaluating the expression * @throws ExpressionSyntaxException if the expression is malformed * @throws MethodFailedException if the expression called a method which failed * @throws NoSuchPropertyException if the expression referred to a nonexistent property * @throws InappropriateExpressionException if the expression can't be used in this context * @throws OgnlException if there is a pathological environmental problem */ public static <T> T getValue(String expression, Object root) throws OgnlException { return Ognl.<T>getValue(expression, root, null); } /** * Convenience method that combines calls to <code> parseExpression </code> and <code> getValue</code>. * * @see #parseExpression(String) * @see #getValue(Object,Object) * @param expression the OGNL expression to be parsed * @param root the root object for the OGNL expression * @param resultType the converted type of the resultant object, using the context's type converter * @return the result of evaluating the expression * @throws ExpressionSyntaxException if the expression is malformed * @throws MethodFailedException if the expression called a method which failed * @throws NoSuchPropertyException if the expression referred to a nonexistent property * @throws InappropriateExpressionException if the expression can't be used in this context * @throws OgnlException if there is a pathological environmental problem */ public static <T> T getValue(String expression, Object root, Class<T> resultType) throws OgnlException { return Ognl.<T>getValue(parseExpression(expression), root, resultType); } /** * Evaluates the given OGNL expression tree to insert a value into the object graph rooted at the given root object. * The default context is set for the given context and root via <code>addDefaultContext()</code>. * * @param tree the OGNL expression tree to evaluate, as returned by parseExpression() * @param context the naming context for the evaluation * @param root the root object for the OGNL expression * @param value the value to insert into the object graph * @throws MethodFailedException if the expression called a method which failed * @throws NoSuchPropertyException if the expression referred to a nonexistent property * @throws InappropriateExpressionException if the expression can't be used in this context * @throws OgnlException if there is a pathological environmental problem */ public static void setValue(Object tree, Map<String, Object> context, Object root, Object value) throws OgnlException { OgnlContext ognlContext = (OgnlContext) addDefaultContext(root, context); Node n = (Node) tree; if (n.getAccessor() != null) { n.getAccessor().set(ognlContext, root, value); return; } n.setValue(ognlContext, root, value); } /** * Sets the value given using the pre-compiled expression on the specified root object. * * @param expression The pre-compiled expression, as found in {@link Node#getAccessor()}. * @param context The ognl context. * @param root The object to set the expression value on. * @param value The value to set. */ public static void setValue(ExpressionAccessor expression, OgnlContext context, Object root, Object value) { expression.set(context, root, value); } /** * Evaluates the given OGNL expression to insert a value into the object graph rooted at the given root object given * the context. * * @param expression the OGNL expression to be parsed * @param root the root object for the OGNL expression * @param context the naming context for the evaluation * @param value the value to insert into the object graph * @throws MethodFailedException if the expression called a method which failed * @throws NoSuchPropertyException if the expression referred to a nonexistent property * @throws InappropriateExpressionException if the expression can't be used in this context * @throws OgnlException if there is a pathological environmental problem */ public static void setValue(String expression, Map<String, Object> context, Object root, Object value) throws OgnlException { setValue(parseExpression(expression), context, root, value); } /** * Evaluates the given OGNL expression tree to insert a value into the object graph rooted at the given root object. * * @param tree the OGNL expression tree to evaluate, as returned by parseExpression() * @param root the root object for the OGNL expression * @param value the value to insert into the object graph * @throws MethodFailedException if the expression called a method which failed * @throws NoSuchPropertyException if the expression referred to a nonexistent property * @throws InappropriateExpressionException if the expression can't be used in this context * @throws OgnlException if there is a pathological environmental problem */ public static void setValue(Object tree, Object root, Object value) throws OgnlException { setValue(tree, createDefaultContext(root), root, value); } /** * Convenience method that combines calls to <code> parseExpression </code> and <code> setValue</code>. * * @see #parseExpression(String) * @see #setValue(Object,Object,Object) * @param expression the OGNL expression to be parsed * @param root the root object for the OGNL expression * @param value the value to insert into the object graph * @throws ExpressionSyntaxException if the expression is malformed * @throws MethodFailedException if the expression called a method which failed * @throws NoSuchPropertyException if the expression referred to a nonexistent property * @throws InappropriateExpressionException if the expression can't be used in this context * @throws OgnlException if there is a pathological environmental problem */ public static void setValue(String expression, Object root, Object value) throws OgnlException { setValue(parseExpression(expression), root, value); } /** * Checks if the specified {@link Node} instance represents a constant expression. * * @param tree The {@link Node} to check. * @param context The context to use. * @return True if the node is a constant - false otherwise. * @throws OgnlException If an error occurs checking the expression. */ public static boolean isConstant(Object tree, Map<String, Object> context) throws OgnlException { return ((SimpleNode) tree).isConstant((OgnlContext) addDefaultContext(null, context)); } /** * Checks if the specified expression represents a constant expression. * * @param expression The expression to check. * @param context The context to use. * @return True if the node is a constant - false otherwise. * @throws OgnlException If an error occurs checking the expression. */ public static boolean isConstant(String expression, Map<String, Object> context) throws OgnlException { return isConstant(parseExpression(expression), context); } /** * Same as {@link #isConstant(Object, java.util.Map)} - only the {@link Map} context is created for you. * * @param tree The {@link Node} to check. * @return True if the node represents a constant expression - false otherwise. * @throws OgnlException If an exception occurs. */ public static boolean isConstant(Object tree) throws OgnlException { return isConstant(tree, createDefaultContext(null)); } /** * Same as {@link #isConstant(String, java.util.Map)} - only the {@link Map} instance is created for you. * * @param expression The expression to check. * @return True if the expression represents a constant - false otherwise. * @throws OgnlException If an exception occurs. */ public static boolean isConstant(String expression) throws OgnlException { return isConstant(parseExpression(expression), createDefaultContext(null)); } public static boolean isSimpleProperty(Object tree, Map<String, Object> context) throws OgnlException { return ((SimpleNode) tree).isSimpleProperty((OgnlContext) addDefaultContext(null, context)); } public static boolean isSimpleProperty(String expression, Map<String, Object> context) throws OgnlException { return isSimpleProperty(parseExpression(expression), context); } public static boolean isSimpleProperty(Object tree) throws OgnlException { return isSimpleProperty(tree, createDefaultContext(null)); } public static boolean isSimpleProperty(String expression) throws OgnlException { return isSimpleProperty(parseExpression(expression), createDefaultContext(null)); } public static boolean isSimpleNavigationChain(Object tree, Map<String, Object> context) throws OgnlException { return ((SimpleNode) tree).isSimpleNavigationChain((OgnlContext) addDefaultContext(null, context)); } public static boolean isSimpleNavigationChain(String expression, Map<String, Object> context) throws OgnlException { return isSimpleNavigationChain(parseExpression(expression), context); } public static boolean isSimpleNavigationChain(Object tree) throws OgnlException { return isSimpleNavigationChain(tree, createDefaultContext(null)); } public static boolean isSimpleNavigationChain(String expression) throws OgnlException { return isSimpleNavigationChain(parseExpression(expression), createDefaultContext(null)); } /** You can't make one of these. */ private Ognl() { } }