View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.jexl3;
19  
20  import java.util.function.Consumer;
21  
22  /**
23   * The JEXL operators.
24   *
25   * These are the operators that are executed by JexlArithmetic methods.
26   *
27   * <p>Each of them  associates a symbol to a method signature.
28   * For instance, '+' is associated to 'T add(L x, R y)'.</p>
29   *
30   * <p>The default JexlArithmetic implements generic versions of these methods using Object as arguments.
31   * You can use your own derived JexlArithmetic that override and/or overload those operator methods.
32   * Note that these are overloads by convention, not actual Java overloads.
33   * The following rules apply to all operator methods:</p>
34   * <ul>
35   * <li>Operator methods should be public</li>
36   * <li>Operators return type should be respected when primitive (int, boolean,...)</li>
37   * <li>Operators may be overloaded multiple times with different signatures</li>
38   * <li>Operators may return JexlEngine.TRY_AGAIN to fallback on default JEXL implementation</li>
39   * </ul>
40   *
41   * For side effect operators, operators that modify the left-hand size value (+=, -=, etc.), the user implemented
42   * overload methods may return:
43   * <ul>
44   *     <li>JexlEngine.TRY_FAIL to let the default fallback behavior be executed.</li>
45   *     <li>Any other value will be used as the new value to be assigned to the left-hand-side.</li>
46   * </ul>
47   * Note that side effect operators always return the left-hand side value (with an exception for postfix ++ and --).
48   *
49   * @since 3.0
50   */
51  public enum JexlOperator {
52      /**
53       * Add operator.
54       * <br><strong>Syntax:</strong> {@code x + y}
55       * <br><strong>Method:</strong> {@code T add(L x, R y);}.
56       * @see JexlArithmetic#add(Object, Object)
57       */
58      ADD("+", "add", 2),
59  
60      /**
61       * Subtract operator.
62       * <br><strong>Syntax:</strong> {@code x - y}
63       * <br><strong>Method:</strong> {@code T subtract(L x, R y);}.
64       * @see JexlArithmetic#subtract(Object, Object)
65       */
66      SUBTRACT("-", "subtract", 2),
67  
68      /**
69       * Multiply operator.
70       * <br><strong>Syntax:</strong> {@code x * y}
71       * <br><strong>Method:</strong> {@code T multiply(L x, R y);}.
72       * @see JexlArithmetic#multiply(Object, Object)
73       */
74      MULTIPLY("*", "multiply", 2),
75  
76      /**
77       * Divide operator.
78       * <br><strong>Syntax:</strong> {@code x / y}
79       * <br><strong>Method:</strong> {@code T divide(L x, R y);}.
80       * @see JexlArithmetic#divide(Object, Object)
81       */
82      DIVIDE("/", "divide", 2),
83  
84      /**
85       * Modulo operator.
86       * <br><strong>Syntax:</strong> {@code x % y}
87       * <br><strong>Method:</strong> {@code T mod(L x, R y);}.
88       * @see JexlArithmetic#mod(Object, Object)
89       */
90      MOD("%", "mod", 2),
91  
92      /**
93       * Bitwise-and operator.
94       * <br><strong>Syntax:</strong> {@code x & y}
95       * <br><strong>Method:</strong> {@code T and(L x, R y);}.
96       * @see JexlArithmetic#and(Object, Object)
97       */
98      AND("&", "and", 2),
99  
100     /**
101      * Bitwise-or operator.
102      * <br><strong>Syntax:</strong> {@code x | y}
103      * <br><strong>Method:</strong> {@code T or(L x, R y);}.
104      * @see JexlArithmetic#or(Object, Object)
105      */
106     OR("|", "or", 2),
107 
108     /**
109      * Bitwise-xor operator.
110      * <br><strong>Syntax:</strong> {@code x ^ y}
111      * <br><strong>Method:</strong> {@code T xor(L x, R y);}.
112      * @see JexlArithmetic#xor(Object, Object)
113      */
114     XOR("^", "xor", 2),
115 
116     /**
117      * Bit-pattern right-shift operator.
118      * <br><strong>Syntax:</strong> {@code x >> y}
119      * <br><strong>Method:</strong> {@code T rightShift(L x, R y);}.
120      * @see JexlArithmetic#shiftRight(Object, Object)
121      */
122     SHIFTRIGHT(">>", "shiftRight", 2),
123 
124     /**
125      * Bit-pattern right-shift unsigned operator.
126      * <br><strong>Syntax:</strong> {@code x >>> y}
127      * <br><strong>Method:</strong> {@code T rightShiftUnsigned(L x, R y);}.
128      * @see JexlArithmetic#shiftRightUnsigned(Object, Object)
129      */
130     SHIFTRIGHTU(">>>", "shiftRightUnsigned", 2),
131 
132     /**
133      * Bit-pattern left-shift operator.
134      * <br><strong>Syntax:</strong> {@code x << y}
135      * <br><strong>Method:</strong> {@code T leftShift(L x, R y);}.
136      * @see JexlArithmetic#shiftLeft(Object, Object)
137      */
138     SHIFTLEFT("<<", "shiftLeft", 2),
139 
140     /**
141      * Equals operator.
142      * <br><strong>Syntax:</strong> {@code x == y}
143      * <br><strong>Method:</strong> {@code boolean equals(L x, R y);}.
144      * @see JexlArithmetic#equals(Object, Object)
145      */
146     EQ("==", "equals", 2),
147 
148     /**
149      * Equal-strict operator.
150      * <br><strong>Syntax:</strong> {@code x === y}
151      * <br><strong>Method:</strong> {@code boolean strictEquals(L x, R y);}.
152      * @see JexlArithmetic#strictEquals(Object, Object)
153      */
154     EQSTRICT("===", "strictEquals", 2),
155 
156     /**
157      * Less-than operator.
158      * <br><strong>Syntax:</strong> {@code x < y}
159      * <br><strong>Method:</strong> {@code boolean lessThan(L x, R y);}.
160      * @see JexlArithmetic#lessThan(Object, Object)
161      */
162     LT("<", "lessThan", 2),
163 
164     /**
165      * Less-than-or-equal operator.
166      * <br><strong>Syntax:</strong> {@code x <= y}
167      * <br><strong>Method:</strong> {@code boolean lessThanOrEqual(L x, R y);}.
168      * @see JexlArithmetic#lessThanOrEqual(Object, Object)
169      */
170     LTE("<=", "lessThanOrEqual", 2),
171 
172     /**
173      * Greater-than operator.
174      * <br><strong>Syntax:</strong> {@code x > y}
175      * <br><strong>Method:</strong> {@code boolean greaterThan(L x, R y);}.
176      * @see JexlArithmetic#greaterThan(Object, Object)
177      */
178     GT(">", "greaterThan", 2),
179 
180     /**
181      * Greater-than-or-equal operator.
182      * <br><strong>Syntax:</strong> {@code x >= y}
183      * <br><strong>Method:</strong> {@code boolean greaterThanOrEqual(L x, R y);}.
184      * @see JexlArithmetic#greaterThanOrEqual(Object, Object)
185      */
186     GTE(">=", "greaterThanOrEqual", 2),
187 
188     /**
189      * Contains operator.
190      * <br><strong>Syntax:</strong> {@code x =~ y}
191      * <br><strong>Method:</strong> {@code boolean contains(L x, R y);}.
192      * @see JexlArithmetic#contains(Object, Object)
193      */
194     CONTAINS("=~", "contains", 2),
195 
196     /**
197      * Starts-with operator.
198      * <br><strong>Syntax:</strong> {@code x =^ y}
199      * <br><strong>Method:</strong> {@code boolean startsWith(L x, R y);}.
200      * @see JexlArithmetic#startsWith(Object, Object)
201      */
202     STARTSWITH("=^", "startsWith", 2),
203 
204     /**
205      * Ends-with operator.
206      * <br><strong>Syntax:</strong> {@code x =$ y}
207      * <br><strong>Method:</strong> {@code boolean endsWith(L x, R y);}.
208      * @see JexlArithmetic#endsWith(Object, Object)
209      */
210     ENDSWITH("=$", "endsWith", 2),
211 
212     /**
213      * Not operator.
214      * <br><strong>Syntax:</strong> {@code !x}
215      * <br><strong>Method:</strong> {@code T not(L x);}.
216      * @see JexlArithmetic#not(Object)
217      */
218     NOT("!", "not", 1),
219 
220     /**
221      * Complement operator.
222      * <br><strong>Syntax:</strong> {@code ~x}
223      * <br><strong>Method:</strong> {@code T complement(L x);}.
224      * @see JexlArithmetic#complement(Object)
225      */
226     COMPLEMENT("~", "complement", 1),
227 
228     /**
229      * Negate operator.
230      * <br><strong>Syntax:</strong> {@code -x}
231      * <br><strong>Method:</strong> {@code T negate(L x);}.
232      * @see JexlArithmetic#negate(Object)
233      */
234     NEGATE("-", "negate", 1),
235 
236     /**
237      * Positivize operator.
238      * <br><strong>Syntax:</strong> {@code +x}
239      * <br><strong>Method:</strong> {@code T positivize(L x);}.
240      * @see JexlArithmetic#positivize(Object)
241      */
242     POSITIVIZE("+", "positivize", 1),
243 
244     /**
245      * Empty operator.
246      * <br><strong>Syntax:</strong> {@code empty x} or {@code empty(x)}
247      * <br><strong>Method:</strong> {@code boolean empty(L x);}.
248      * @see JexlArithmetic#empty(Object)
249      */
250     EMPTY("empty", "empty", 1),
251 
252     /**
253      * Size operator.
254      * <br><strong>Syntax:</strong> {@code size x} or {@code size(x)}
255      * <br><strong>Method:</strong> {@code int size(L x);}.
256      * @see JexlArithmetic#size(Object)
257      */
258     SIZE("size", "size", 1),
259 
260     /**
261      * Self-add operator.
262      * <br><strong>Syntax:</strong> {@code x += y}
263      * <br><strong>Method:</strong> {@code T selfAdd(L x, R y);}.
264      */
265     SELF_ADD("+=", "selfAdd", ADD),
266 
267     /**
268      * Self-subtract operator.
269      * <br><strong>Syntax:</strong> {@code x -= y}
270      * <br><strong>Method:</strong> {@code T selfSubtract(L x, R y);}.
271      */
272     SELF_SUBTRACT("-=", "selfSubtract", SUBTRACT),
273 
274     /**
275      * Self-multiply operator.
276      * <br><strong>Syntax:</strong> {@code x *= y}
277      * <br><strong>Method:</strong> {@code T selfMultiply(L x, R y);}.
278      */
279     SELF_MULTIPLY("*=", "selfMultiply", MULTIPLY),
280 
281     /**
282      * Self-divide operator.
283      * <br><strong>Syntax:</strong> {@code x /= y}
284      * <br><strong>Method:</strong> {@code T selfDivide(L x, R y);}.
285      */
286     SELF_DIVIDE("/=", "selfDivide", DIVIDE),
287 
288     /**
289      * Self-modulo operator.
290      * <br><strong>Syntax:</strong> {@code x %= y}
291      * <br><strong>Method:</strong> {@code T selfMod(L x, R y);}.
292      */
293     SELF_MOD("%=", "selfMod", MOD),
294 
295     /**
296      * Self-and operator.
297      * <br><strong>Syntax:</strong> {@code x &amp;= y}
298      * <br><strong>Method:</strong> {@code T selfAnd(L x, R y);}.
299      */
300     SELF_AND("&=", "selfAnd", AND),
301 
302     /**
303      * Self-or operator.
304      * <br><strong>Syntax:</strong> {@code x |= y}
305      * <br><strong>Method:</strong> {@code T selfOr(L x, R y);}.
306      */
307     SELF_OR("|=", "selfOr", OR),
308 
309     /**
310      * Self-xor operator.
311      * <br><strong>Syntax:</strong> {@code x ^= y}
312      * <br><strong>Method:</strong> {@code T selfXor(L x, R y);}.
313      */
314     SELF_XOR("^=", "selfXor", XOR),
315 
316     /**
317      * Self-right-shift operator.
318      * <br><strong>Syntax:</strong> {@code x >>= y}
319      * <br><strong>Method:</strong> {@code T selfShiftRight(L x, R y);}.
320      */
321     SELF_SHIFTRIGHT(">>=", "selfShiftRight", SHIFTRIGHT),
322 
323     /**
324      * Self-right-shift unsigned operator.
325      * <br><strong>Syntax:</strong> {@code x >>> y}
326      * <br><strong>Method:</strong> {@code T selfShiftRightUnsigned(L x, R y);}.
327      */
328     SELF_SHIFTRIGHTU(">>>=", "selfShiftRightUnsigned", SHIFTRIGHTU),
329 
330     /**
331      * Self-left-shift operator.
332      * <br><strong>Syntax:</strong> {@code x << y}
333      * <br><strong>Method:</strong> {@code T selfShiftLeft(L x, R y);}.
334      */
335     SELF_SHIFTLEFT("<<=", "selfShiftLeft", SHIFTLEFT),
336 
337     /**
338      * Increment pseudo-operator.
339      * <br>No syntax, used as helper for the prefix and postfix versions of {@code ++}.
340      * @see JexlArithmetic#increment(Object)
341      */
342     INCREMENT("+1", "increment", 1),
343 
344     /**
345      * Decrement pseudo-operator.
346      * <br>No syntax, used as helper for the prefix and postfix versions of {@code --}.
347      * @see JexlArithmetic#decrement(Object)
348      */
349     DECREMENT("-1", "decrement", 1),
350 
351     /**
352      * Prefix ++ operator, increments and returns the value after incrementing.
353      * <br><strong>Syntax:</strong> {@code ++x}
354      * <br><strong>Method:</strong> {@code T incrementAndGet(L x);}.
355      */
356     INCREMENT_AND_GET("++.", "incrementAndGet", INCREMENT, 1),
357 
358     /**
359      * Postfix ++, increments and returns the value before incrementing.
360      * <br><strong>Syntax:</strong> {@code x++}
361      * <br><strong>Method:</strong> {@code T getAndIncrement(L x);}.
362      */
363     GET_AND_INCREMENT(".++", "getAndIncrement", INCREMENT, 1),
364 
365     /**
366      * Prefix --, decrements and returns the value after decrementing.
367      * <br><strong>Syntax:</strong> {@code --x}
368      * <br><strong>Method:</strong> {@code T decrementAndGet(L x);}.
369      */
370     DECREMENT_AND_GET("--.", "decrementAndGet", DECREMENT, 1),
371 
372     /**
373      * Postfix --, decrements and returns the value before decrementing.
374      * <br><strong>Syntax:</strong> {@code x--}
375      * <br><strong>Method:</strong> {@code T getAndDecrement(L x);}.
376      */
377     GET_AND_DECREMENT(".--", "getAndDecrement", DECREMENT, 1),
378 
379     /**
380      * Marker for side effect.
381      * <p>
382      * Returns this from 'self*' overload method to let the engine know the side effect has been performed and
383      * there is no need to assign the result.
384      * </p>
385      *
386      * @deprecated 3.5.0
387      */
388     @Deprecated
389     ASSIGN("=", null, null),
390 
391     /**
392      * Property get operator as in: x.y.
393      * <br><strong>Syntax:</strong> {@code x.y}
394      * <br><strong>Method:</strong> {@code Object propertyGet(L x, R y);}.
395      */
396     PROPERTY_GET(".", "propertyGet", 2),
397 
398     /**
399      * Property set operator as in: x.y = z.
400      * <br><strong>Syntax:</strong> {@code x.y = z}
401      * <br><strong>Method:</strong> {@code void propertySet(L x, R y, V z);}.
402      */
403     PROPERTY_SET(".=", "propertySet", 3),
404 
405     /**
406      * Array get operator as in: x[y].
407      * <br><strong>Syntax:</strong> {@code x.y}
408      * <br><strong>Method:</strong> {@code Object arrayGet(L x, R y);}.
409      */
410     ARRAY_GET("[]", "arrayGet", 2),
411 
412     /**
413      * Array set operator as in: x[y] = z.
414      * <br><strong>Syntax:</strong> {@code x[y] = z}
415      * <br><strong>Method:</strong> {@code void arraySet(L x, R y, V z);}.
416      */
417     ARRAY_SET("[]=", "arraySet", 3),
418 
419     /**
420      * Iterator generator as in for(var x : y).
421      * If the returned Iterator is AutoCloseable, close will be called after the last execution of the loop block.
422      * <br><strong>Syntax:</strong> <code>for(var x : y){...}</code>
423      * <br><strong>Method:</strong> {@code Iterator<Object> forEach(R y);}.
424      * @since 3.1
425      */
426     FOR_EACH("for(...)", "forEach", 1),
427 
428     /**
429      * Test condition in if, for, while.
430      * <br><strong>Method:</strong> {@code boolean testCondition(R y);}.
431      * @since 3.3
432      */
433     CONDITION("?", "testCondition", 1),
434 
435     /**
436      * Compare overload as in compare(x, y).
437      * <br><strong>Method:</strong> {@code boolean compare(L x, R y);}.
438      * @since 3.5.0
439      */
440     COMPARE("<>", "compare", 2),
441 
442     /**
443      * Not-Contains operator.
444      * <p>Not overridable, calls !(contain(...))</p>
445      */
446     NOT_CONTAINS("!~", null, CONTAINS),
447 
448     /**
449      * Not-Starts-With operator.
450      * <p>Not overridable, calls !(startsWith(...))</p>
451      */
452     NOT_STARTSWITH("!^", null, STARTSWITH),
453 
454     /**
455      * Not-Ends-With operator.
456      * <p>Not overridable, calls !(endsWith(...))</p>
457      */
458     NOT_ENDSWITH("!$", null, ENDSWITH),;
459 
460     /**
461      * The operator symbol.
462      */
463     private final String operator;
464 
465     /**
466      * The associated operator method name.
467      */
468     private final String methodName;
469 
470     /**
471      * The method arity (ie number of arguments).
472      */
473     private final int arity;
474 
475     /**
476      * The base operator.
477      */
478     private final JexlOperator base;
479 
480     /**
481      * Creates a base operator.
482      *
483      * @param o    the operator name
484      * @param m    the method name associated to this operator in a JexlArithmetic
485      * @param argc the number of parameters for the method
486      */
487     JexlOperator(final String o, final String m, final int argc) {
488         this(o, m, null, argc);
489     }
490 
491     /**
492      * Creates a side effect operator with arity == 2.
493      *
494      * @param o the operator name
495      * @param m the method name associated to this operator in a JexlArithmetic
496      * @param b the base operator, ie + for +=
497      */
498     JexlOperator(final String o, final String m, final JexlOperator b) {
499         this(o, m, b, 2);
500     }
501 
502     /**
503      * Creates a side effect operator.
504      *
505      * @param o the operator name
506      * @param m the method name associated to this operator in a JexlArithmetic
507      * @param b the base operator, ie + for +=
508      * @param a the operator arity
509      */
510     JexlOperator(final String o, final String m, final JexlOperator b, final int a) {
511         this.operator = o;
512         this.methodName = m;
513         this.arity = a;
514         this.base = b;
515     }
516 
517     /**
518      * Gets this operator number of parameters.
519      *
520      * @return the method arity
521      */
522     public int getArity() {
523         return arity;
524     }
525 
526     /**
527      * Gets the base operator.
528      *
529      * @return the base operator
530      */
531     public final JexlOperator getBaseOperator() {
532         return base;
533     }
534 
535     /**
536      * Gets this operator method name in a JexlArithmetic.
537      *
538      * @return the method name
539      */
540     public final String getMethodName() {
541         return methodName;
542     }
543 
544     /**
545      * Gets this operator symbol.
546      *
547      * @return the symbol
548      */
549     public final String getOperatorSymbol() {
550         return operator;
551     }
552 
553     /**
554      * Uberspect that solves and evaluates JexlOperator overloads.
555      * <p>This is used by the interpreter to find and execute operator overloads implemented in a derived
556      * JexlArithmetic - or in some cases, as methods of the left argument type (contains, size, ...).</p>
557      * <p>This also allows reusing the core logic when extending the applicative type-system; for
558      * instance, implementing a Comparator class that calls compare
559      * (<code>operator.tryOverload(this, JexlOperator.COMPARE, left, right)</code>, etc.</p>
560      * @since 3.5.0
561      */
562     public interface Uberspect extends JexlArithmetic.Uberspect {
563         /**
564          * Try to find the most specific method and evaluate an operator.
565          * <p>This method does not call {@link #overloads(JexlOperator)} and shall not be called with an
566          * assignment operator; use {@link #tryAssignOverload(JexlCache.Reference, JexlOperator, Consumer, Object...)}
567          * in that case.</p>
568          *
569          * @param reference an optional reference caching resolved method or failing signature
570          * @param operator the operator
571          * @param args      the arguments
572          * @return TRY_FAILED if no specific method could be found, the evaluation result otherwise
573          */
574         Object tryOverload(JexlCache.Reference reference, JexlOperator operator, Object...args);
575 
576         /**
577          * Evaluates an assign operator.
578          * <p>
579          * This takes care of finding and caching the operator method when appropriate.
580          * If an overloads returns a value not-equal to TRY_FAILED, it means the side-effect is complete.
581          * Otherwise, {@code a += b <=> a = a + b}
582          * </p>
583          * @param node     an optional reference caching resolved method or failing signature
584          * @param operator the operator
585          * @param assign   the actual function that performs the side effect
586          * @param args     the arguments, the first one being the target of assignment
587          * @return JexlEngine.TRY_FAILED if no operation was performed,
588          *         the value to use as the side effect argument otherwise
589          */
590         Object tryAssignOverload(final JexlCache.Reference node,
591                                  final JexlOperator operator,
592                                  final Consumer<Object> assign,
593                                  final Object... args);
594 
595         /**
596          * Calculate the {@code size} of various types:
597          * Collection, Array, Map, String, and anything that has an int size() method.
598          * <p>Seeks an overload or use the default arithmetic implementation.</p>
599          * <p>Note that the result may not be an integer.
600          *
601          * @param node   an optional reference caching resolved method or failing signature
602          * @param object the object to get the size of
603          * @return the evaluation result
604          */
605         Object size(final JexlCache.Reference node, final Object object);
606 
607         /**
608          * Check for emptiness of various types: Collection, Array, Map, String, and anything that has a boolean isEmpty()
609          * method.
610          * <p>Seeks an overload or use the default arithmetic implementation.</p>
611          * <p>Note that the result may not be a boolean.
612          *
613          * @param node   the node holding the object
614          * @param object the object to check the emptiness of
615          * @return the evaluation result
616          */
617         Object empty(final JexlCache.Reference node, final Object object);
618 
619         /**
620          * The 'match'/'in' operator implementation.
621          * <p>Seeks an overload or use the default arithmetic implementation.</p>
622          * <p>
623          * Note that 'x in y' or 'x matches y' means 'y contains x' ;
624          * the JEXL operator arguments order syntax is the reverse of this method call.
625          * </p>
626          * @param node  an optional reference caching resolved method or failing signature
627          * @param operator    the calling operator, =~ or !~
628          * @param right the left operand
629          * @param left  the right operand
630          * @return true if left matches right, false otherwise
631          */
632         boolean contains(final JexlCache.Reference node,
633                          final JexlOperator operator,
634                          final Object left,
635                          final Object right);
636 
637         /**
638          * The 'startsWith' operator implementation.
639          * <p>Seeks an overload or use the default arithmetic implementation.</p>
640          * @param node     an optional reference caching resolved method or failing signature
641          * @param operator the calling operator, $= or $!
642          * @param left     the left operand
643          * @param right    the right operand
644          * @return true if left starts with right, false otherwise
645          */
646         boolean startsWith(final JexlCache.Reference node,
647                            final JexlOperator operator,
648                            final Object left,
649                            final Object right);
650 
651         /**
652          * The 'endsWith' operator implementation.
653          * <p>Seeks an overload or use the default arithmetic implementation.</p>
654          * @param node     an optional reference caching resolved method or failing signature
655          * @param operator the calling operator, ^= or ^!
656          * @param left     the left operand
657          * @param right    the right operand
658          * @return true if left ends with right, false otherwise
659          */
660         boolean endsWith(final JexlCache.Reference node,
661                          final JexlOperator operator,
662                          final Object left,
663                          final Object right);
664     }
665 }