All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.commons.jexl3.JexlOperator Maven / Gradle / Ivy

Go to download

The Apache Commons JEXL library is an implementation of the JSTL Expression Language with extensions.

The newest version!
/*
 * 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.commons.jexl3;

import java.util.function.Consumer;

/**
 * The JEXL operators.
 *
 * These are the operators that are executed by JexlArithmetic methods.
 *
 * 

Each of them associates a symbol to a method signature. * For instance, '+' is associated to 'T add(L x, R y)'.

* *

The default JexlArithmetic implements generic versions of these methods using Object as arguments. * You can use your own derived JexlArithmetic that override and/or overload those operator methods. * Note that these are overloads by convention, not actual Java overloads. * The following rules apply to all operator methods:

*
    *
  • Operator methods should be public
  • *
  • Operators return type should be respected when primitive (int, boolean,...)
  • *
  • Operators may be overloaded multiple times with different signatures
  • *
  • Operators may return JexlEngine.TRY_AGAIN to fallback on default JEXL implementation
  • *
* * For side effect operators, operators that modify the left-hand size value (+=, -=, etc.), the user implemented * overload methods may return: *
    *
  • JexlEngine.TRY_FAIL to let the default fallback behavior be executed.
  • *
  • Any other value will be used as the new value to be assigned to the left-hand-side.
  • *
* Note that side effect operators always return the left-hand side value (with an exception for postfix ++ and --). * * @since 3.0 */ public enum JexlOperator { /** * Add operator. *
Syntax: {@code x + y} *
Method: {@code T add(L x, R y);}. * @see JexlArithmetic#add(Object, Object) */ ADD("+", "add", 2), /** * Subtract operator. *
Syntax: {@code x - y} *
Method: {@code T subtract(L x, R y);}. * @see JexlArithmetic#subtract(Object, Object) */ SUBTRACT("-", "subtract", 2), /** * Multiply operator. *
Syntax: {@code x * y} *
Method: {@code T multiply(L x, R y);}. * @see JexlArithmetic#multiply(Object, Object) */ MULTIPLY("*", "multiply", 2), /** * Divide operator. *
Syntax: {@code x / y} *
Method: {@code T divide(L x, R y);}. * @see JexlArithmetic#divide(Object, Object) */ DIVIDE("/", "divide", 2), /** * Modulo operator. *
Syntax: {@code x % y} *
Method: {@code T mod(L x, R y);}. * @see JexlArithmetic#mod(Object, Object) */ MOD("%", "mod", 2), /** * Bitwise-and operator. *
Syntax: {@code x & y} *
Method: {@code T and(L x, R y);}. * @see JexlArithmetic#and(Object, Object) */ AND("&", "and", 2), /** * Bitwise-or operator. *
Syntax: {@code x | y} *
Method: {@code T or(L x, R y);}. * @see JexlArithmetic#or(Object, Object) */ OR("|", "or", 2), /** * Bitwise-xor operator. *
Syntax: {@code x ^ y} *
Method: {@code T xor(L x, R y);}. * @see JexlArithmetic#xor(Object, Object) */ XOR("^", "xor", 2), /** * Bit-pattern right-shift operator. *
Syntax: {@code x >> y} *
Method: {@code T rightShift(L x, R y);}. * @see JexlArithmetic#shiftRight(Object, Object) */ SHIFTRIGHT(">>", "shiftRight", 2), /** * Bit-pattern right-shift unsigned operator. *
Syntax: {@code x >>> y} *
Method: {@code T rightShiftUnsigned(L x, R y);}. * @see JexlArithmetic#shiftRightUnsigned(Object, Object) */ SHIFTRIGHTU(">>>", "shiftRightUnsigned", 2), /** * Bit-pattern left-shift operator. *
Syntax: {@code x << y} *
Method: {@code T leftShift(L x, R y);}. * @see JexlArithmetic#shiftLeft(Object, Object) */ SHIFTLEFT("<<", "shiftLeft", 2), /** * Equals operator. *
Syntax: {@code x == y} *
Method: {@code boolean equals(L x, R y);}. * @see JexlArithmetic#equals(Object, Object) */ EQ("==", "equals", 2), /** * Equal-strict operator. *
Syntax: {@code x === y} *
Method: {@code boolean strictEquals(L x, R y);}. * @see JexlArithmetic#strictEquals(Object, Object) */ EQSTRICT("===", "strictEquals", 2), /** * Less-than operator. *
Syntax: {@code x < y} *
Method: {@code boolean lessThan(L x, R y);}. * @see JexlArithmetic#lessThan(Object, Object) */ LT("<", "lessThan", 2), /** * Less-than-or-equal operator. *
Syntax: {@code x <= y} *
Method: {@code boolean lessThanOrEqual(L x, R y);}. * @see JexlArithmetic#lessThanOrEqual(Object, Object) */ LTE("<=", "lessThanOrEqual", 2), /** * Greater-than operator. *
Syntax: {@code x > y} *
Method: {@code boolean greaterThan(L x, R y);}. * @see JexlArithmetic#greaterThan(Object, Object) */ GT(">", "greaterThan", 2), /** * Greater-than-or-equal operator. *
Syntax: {@code x >= y} *
Method: {@code boolean greaterThanOrEqual(L x, R y);}. * @see JexlArithmetic#greaterThanOrEqual(Object, Object) */ GTE(">=", "greaterThanOrEqual", 2), /** * Contains operator. *
Syntax: {@code x =~ y} *
Method: {@code boolean contains(L x, R y);}. * @see JexlArithmetic#contains(Object, Object) */ CONTAINS("=~", "contains", 2), /** * Starts-with operator. *
Syntax: {@code x =^ y} *
Method: {@code boolean startsWith(L x, R y);}. * @see JexlArithmetic#startsWith(Object, Object) */ STARTSWITH("=^", "startsWith", 2), /** * Ends-with operator. *
Syntax: {@code x =$ y} *
Method: {@code boolean endsWith(L x, R y);}. * @see JexlArithmetic#endsWith(Object, Object) */ ENDSWITH("=$", "endsWith", 2), /** * Not operator. *
Syntax: {@code !x} *
Method: {@code T not(L x);}. * @see JexlArithmetic#not(Object) */ NOT("!", "not", 1), /** * Complement operator. *
Syntax: {@code ~x} *
Method: {@code T complement(L x);}. * @see JexlArithmetic#complement(Object) */ COMPLEMENT("~", "complement", 1), /** * Negate operator. *
Syntax: {@code -x} *
Method: {@code T negate(L x);}. * @see JexlArithmetic#negate(Object) */ NEGATE("-", "negate", 1), /** * Positivize operator. *
Syntax: {@code +x} *
Method: {@code T positivize(L x);}. * @see JexlArithmetic#positivize(Object) */ POSITIVIZE("+", "positivize", 1), /** * Empty operator. *
Syntax: {@code empty x} or {@code empty(x)} *
Method: {@code boolean empty(L x);}. * @see JexlArithmetic#empty(Object) */ EMPTY("empty", "empty", 1), /** * Size operator. *
Syntax: {@code size x} or {@code size(x)} *
Method: {@code int size(L x);}. * @see JexlArithmetic#size(Object) */ SIZE("size", "size", 1), /** * Self-add operator. *
Syntax: {@code x += y} *
Method: {@code T selfAdd(L x, R y);}. */ SELF_ADD("+=", "selfAdd", ADD), /** * Self-subtract operator. *
Syntax: {@code x -= y} *
Method: {@code T selfSubtract(L x, R y);}. */ SELF_SUBTRACT("-=", "selfSubtract", SUBTRACT), /** * Self-multiply operator. *
Syntax: {@code x *= y} *
Method: {@code T selfMultiply(L x, R y);}. */ SELF_MULTIPLY("*=", "selfMultiply", MULTIPLY), /** * Self-divide operator. *
Syntax: {@code x /= y} *
Method: {@code T selfDivide(L x, R y);}. */ SELF_DIVIDE("/=", "selfDivide", DIVIDE), /** * Self-modulo operator. *
Syntax: {@code x %= y} *
Method: {@code T selfMod(L x, R y);}. */ SELF_MOD("%=", "selfMod", MOD), /** * Self-and operator. *
Syntax: {@code x &= y} *
Method: {@code T selfAnd(L x, R y);}. */ SELF_AND("&=", "selfAnd", AND), /** * Self-or operator. *
Syntax: {@code x |= y} *
Method: {@code T selfOr(L x, R y);}. */ SELF_OR("|=", "selfOr", OR), /** * Self-xor operator. *
Syntax: {@code x ^= y} *
Method: {@code T selfXor(L x, R y);}. */ SELF_XOR("^=", "selfXor", XOR), /** * Self-right-shift operator. *
Syntax: {@code x >>= y} *
Method: {@code T selfShiftRight(L x, R y);}. */ SELF_SHIFTRIGHT(">>=", "selfShiftRight", SHIFTRIGHT), /** * Self-right-shift unsigned operator. *
Syntax: {@code x >>> y} *
Method: {@code T selfShiftRightUnsigned(L x, R y);}. */ SELF_SHIFTRIGHTU(">>>=", "selfShiftRightUnsigned", SHIFTRIGHTU), /** * Self-left-shift operator. *
Syntax: {@code x << y} *
Method: {@code T selfShiftLeft(L x, R y);}. */ SELF_SHIFTLEFT("<<=", "selfShiftLeft", SHIFTLEFT), /** * Increment pseudo-operator. *
No syntax, used as helper for the prefix and postfix versions of {@code ++}. * @see JexlArithmetic#increment(Object) */ INCREMENT("+1", "increment", 1), /** * Decrement pseudo-operator. *
No syntax, used as helper for the prefix and postfix versions of {@code --}. * @see JexlArithmetic#decrement(Object) */ DECREMENT("-1", "decrement", 1), /** * Prefix ++ operator, increments and returns the value after incrementing. *
Syntax: {@code ++x} *
Method: {@code T incrementAndGet(L x);}. */ INCREMENT_AND_GET("++.", "incrementAndGet", INCREMENT, 1), /** * Postfix ++, increments and returns the value before incrementing. *
Syntax: {@code x++} *
Method: {@code T getAndIncrement(L x);}. */ GET_AND_INCREMENT(".++", "getAndIncrement", INCREMENT, 1), /** * Prefix --, decrements and returns the value after decrementing. *
Syntax: {@code --x} *
Method: {@code T decrementAndGet(L x);}. */ DECREMENT_AND_GET("--.", "decrementAndGet", DECREMENT, 1), /** * Postfix --, decrements and returns the value before decrementing. *
Syntax: {@code x--} *
Method: {@code T getAndDecrement(L x);}. */ GET_AND_DECREMENT(".--", "getAndDecrement", DECREMENT, 1), /** * Marker for side effect. *
Returns this from 'self*' overload method to let the engine know the side effect has been performed and * there is no need to assign the result. * @deprecated 3.5.0 */ ASSIGN("=", null, null), /** * Property get operator as in: x.y. *
Syntax: {@code x.y} *
Method: {@code Object propertyGet(L x, R y);}. */ PROPERTY_GET(".", "propertyGet", 2), /** * Property set operator as in: x.y = z. *
Syntax: {@code x.y = z} *
Method: {@code void propertySet(L x, R y, V z);}. */ PROPERTY_SET(".=", "propertySet", 3), /** * Array get operator as in: x[y]. *
Syntax: {@code x.y} *
Method: {@code Object arrayGet(L x, R y);}. */ ARRAY_GET("[]", "arrayGet", 2), /** * Array set operator as in: x[y] = z. *
Syntax: {@code x[y] = z} *
Method: {@code void arraySet(L x, R y, V z);}. */ ARRAY_SET("[]=", "arraySet", 3), /** * Iterator generator as in for(var x : y). * If the returned Iterator is AutoCloseable, close will be called after the last execution of the loop block. *
Syntax: for(var x : y){...} *
Method: {@code Iterator forEach(R y);}. * @since 3.1 */ FOR_EACH("for(...)", "forEach", 1), /** * Test condition in if, for, while. *
Method: {@code boolean testCondition(R y);}. * @since 3.3 */ CONDITION("?", "testCondition", 1), /** * Compare overload as in compare(x, y). *
Method: {@code boolean compare(L x, R y);}. * @since 3.5.0 */ COMPARE("<>", "compare", 2), /** * Not-Contains operator. *

Not overridable, calls !(contain(...))

*/ NOT_CONTAINS("!~", null, CONTAINS), /** * Not-Starts-With operator. *

Not overridable, calls !(startsWith(...))

*/ NOT_STARTSWITH("!^", null, STARTSWITH), /** * Not-Ends-With operator. *

Not overridable, calls !(endsWith(...))

*/ NOT_ENDSWITH("!$", null, ENDSWITH),; /** * The operator symbol. */ private final String operator; /** * The associated operator method name. */ private final String methodName; /** * The method arity (ie number of arguments). */ private final int arity; /** * The base operator. */ private final JexlOperator base; /** * Creates a base operator. * * @param o the operator name * @param m the method name associated to this operator in a JexlArithmetic * @param argc the number of parameters for the method */ JexlOperator(final String o, final String m, final int argc) { this(o, m, null, argc); } /** * Creates a side effect operator with arity == 2. * * @param o the operator name * @param m the method name associated to this operator in a JexlArithmetic * @param b the base operator, ie + for += */ JexlOperator(final String o, final String m, final JexlOperator b) { this(o, m, b, 2); } /** * Creates a side effect operator. * * @param o the operator name * @param m the method name associated to this operator in a JexlArithmetic * @param b the base operator, ie + for += * @param a the operator arity */ JexlOperator(final String o, final String m, final JexlOperator b, final int a) { this.operator = o; this.methodName = m; this.arity = a; this.base = b; } /** * Gets this operator number of parameters. * * @return the method arity */ public int getArity() { return arity; } /** * Gets the base operator. * * @return the base operator */ public final JexlOperator getBaseOperator() { return base; } /** * Gets this operator method name in a JexlArithmetic. * * @return the method name */ public final String getMethodName() { return methodName; } /** * Gets this operator symbol. * * @return the symbol */ public final String getOperatorSymbol() { return operator; } /** * Uberspect that solves and evaluates JexlOperator overloads. *

This is used by the interpreter to find and execute operator overloads implemented in a derived * JexlArithmetic - or in some cases, as methods of the left argument type (contains, size, ...).

*

This also allows reusing the core logic when extending the applicative type-system; for * instance, implementing a Comparator class that calls compare * (operator.tryOverload(this, JexlOperator.COMPARE, left, right), etc.

* @since 3.5.0 */ public interface Uberspect extends JexlArithmetic.Uberspect { /** * Try to find the most specific method and evaluate an operator. *

This method does not call {@link #overloads(JexlOperator)} and shall not be called with an * assignment operator; use {@link #tryAssignOverload(JexlCache.Reference, JexlOperator, Consumer, Object...)} * in that case.

* * @param reference an optional reference caching resolved method or failing signature * @param operator the operator * @param args the arguments * @return TRY_FAILED if no specific method could be found, the evaluation result otherwise */ Object tryOverload(JexlCache.Reference reference, JexlOperator operator, Object...args); /** * Evaluates an assign operator. *

* This takes care of finding and caching the operator method when appropriate. * If an overloads returns a value not-equal to TRY_FAILED, it means the side-effect is complete. * Otherwise, {@code a += b <=> a = a + b} *

* @param node an optional reference caching resolved method or failing signature * @param operator the operator * @param assign the actual function that performs the side effect * @param args the arguments, the first one being the target of assignment * @return JexlEngine.TRY_FAILED if no operation was performed, * the value to use as the side effect argument otherwise */ Object tryAssignOverload(final JexlCache.Reference node, final JexlOperator operator, final Consumer assign, final Object... args); /** * Calculate the {@code size} of various types: * Collection, Array, Map, String, and anything that has an int size() method. *

Seeks an overload or use the default arithmetic implementation.

*

Note that the result may not be an integer. * * @param node an optional reference caching resolved method or failing signature * @param object the object to get the size of * @return the evaluation result */ Object size(final JexlCache.Reference node, final Object object); /** * Check for emptiness of various types: Collection, Array, Map, String, and anything that has a boolean isEmpty() * method. *

Seeks an overload or use the default arithmetic implementation.

*

Note that the result may not be a boolean. * * @param node the node holding the object * @param object the object to check the emptiness of * @return the evaluation result */ Object empty(final JexlCache.Reference node, final Object object); /** * The 'match'/'in' operator implementation. *

Seeks an overload or use the default arithmetic implementation.

*

* Note that 'x in y' or 'x matches y' means 'y contains x' ; * the JEXL operator arguments order syntax is the reverse of this method call. *

* @param node an optional reference caching resolved method or failing signature * @param operator the calling operator, =~ or !~ * @param right the left operand * @param left the right operand * @return true if left matches right, false otherwise */ boolean contains(final JexlCache.Reference node, final JexlOperator operator, final Object left, final Object right); /** * The 'startsWith' operator implementation. *

Seeks an overload or use the default arithmetic implementation.

* @param node an optional reference caching resolved method or failing signature * @param operator the calling operator, $= or $! * @param left the left operand * @param right the right operand * @return true if left starts with right, false otherwise */ boolean startsWith(final JexlCache.Reference node, final JexlOperator operator, final Object left, final Object right); /** * The 'endsWith' operator implementation. *

Seeks an overload or use the default arithmetic implementation.

* @param node an optional reference caching resolved method or failing signature * @param operator the calling operator, ^= or ^! * @param left the left operand * @param right the right operand * @return true if left ends with right, false otherwise */ boolean endsWith(final JexlCache.Reference node, final JexlOperator operator, final Object left, final Object right); } }