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    *      http://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      * <br>Returns this from 'self*' overload method to let the engine know the side effect has been performed and
382      * there is no need to assign the result.
383      * @deprecated 3.5.0
384      */
385     ASSIGN("=", null, null),
386 
387     /**
388      * Property get operator as in: x.y.
389      * <br><strong>Syntax:</strong> {@code x.y}
390      * <br><strong>Method:</strong> {@code Object propertyGet(L x, R y);}.
391      */
392     PROPERTY_GET(".", "propertyGet", 2),
393 
394     /**
395      * Property set operator as in: x.y = z.
396      * <br><strong>Syntax:</strong> {@code x.y = z}
397      * <br><strong>Method:</strong> {@code void propertySet(L x, R y, V z);}.
398      */
399     PROPERTY_SET(".=", "propertySet", 3),
400 
401     /**
402      * Array get operator as in: x[y].
403      * <br><strong>Syntax:</strong> {@code x.y}
404      * <br><strong>Method:</strong> {@code Object arrayGet(L x, R y);}.
405      */
406     ARRAY_GET("[]", "arrayGet", 2),
407 
408     /**
409      * Array set operator as in: x[y] = z.
410      * <br><strong>Syntax:</strong> {@code x[y] = z}
411      * <br><strong>Method:</strong> {@code void arraySet(L x, R y, V z);}.
412      */
413     ARRAY_SET("[]=", "arraySet", 3),
414 
415     /**
416      * Iterator generator as in for(var x : y).
417      * If the returned Iterator is AutoCloseable, close will be called after the last execution of the loop block.
418      * <br><strong>Syntax:</strong> <code>for(var x : y){...}</code>
419      * <br><strong>Method:</strong> {@code Iterator<Object> forEach(R y);}.
420      * @since 3.1
421      */
422     FOR_EACH("for(...)", "forEach", 1),
423 
424     /**
425      * Test condition in if, for, while.
426      * <br><strong>Method:</strong> {@code boolean testCondition(R y);}.
427      * @since 3.3
428      */
429     CONDITION("?", "testCondition", 1),
430 
431     /**
432      * Compare overload as in compare(x, y).
433      * <br><strong>Method:</strong> {@code boolean compare(L x, R y);}.
434      * @since 3.5.0
435      */
436     COMPARE("<>", "compare", 2),
437 
438     /**
439      * Not-Contains operator.
440      * <p>Not overridable, calls !(contain(...))</p>
441      */
442     NOT_CONTAINS("!~", null, CONTAINS),
443 
444     /**
445      * Not-Starts-With operator.
446      * <p>Not overridable, calls !(startsWith(...))</p>
447      */
448     NOT_STARTSWITH("!^", null, STARTSWITH),
449 
450     /**
451      * Not-Ends-With operator.
452      * <p>Not overridable, calls !(endsWith(...))</p>
453      */
454     NOT_ENDSWITH("!$", null, ENDSWITH),;
455 
456     /**
457      * The operator symbol.
458      */
459     private final String operator;
460 
461     /**
462      * The associated operator method name.
463      */
464     private final String methodName;
465 
466     /**
467      * The method arity (ie number of arguments).
468      */
469     private final int arity;
470 
471     /**
472      * The base operator.
473      */
474     private final JexlOperator base;
475 
476     /**
477      * Creates a base operator.
478      *
479      * @param o    the operator name
480      * @param m    the method name associated to this operator in a JexlArithmetic
481      * @param argc the number of parameters for the method
482      */
483     JexlOperator(final String o, final String m, final int argc) {
484         this(o, m, null, argc);
485     }
486 
487     /**
488      * Creates a side effect operator with arity == 2.
489      *
490      * @param o the operator name
491      * @param m the method name associated to this operator in a JexlArithmetic
492      * @param b the base operator, ie + for +=
493      */
494     JexlOperator(final String o, final String m, final JexlOperator b) {
495         this(o, m, b, 2);
496     }
497 
498     /**
499      * Creates a side effect operator.
500      *
501      * @param o the operator name
502      * @param m the method name associated to this operator in a JexlArithmetic
503      * @param b the base operator, ie + for +=
504      * @param a the operator arity
505      */
506     JexlOperator(final String o, final String m, final JexlOperator b, final int a) {
507         this.operator = o;
508         this.methodName = m;
509         this.arity = a;
510         this.base = b;
511     }
512 
513     /**
514      * Gets this operator number of parameters.
515      *
516      * @return the method arity
517      */
518     public int getArity() {
519         return arity;
520     }
521 
522     /**
523      * Gets the base operator.
524      *
525      * @return the base operator
526      */
527     public final JexlOperator getBaseOperator() {
528         return base;
529     }
530 
531     /**
532      * Gets this operator method name in a JexlArithmetic.
533      *
534      * @return the method name
535      */
536     public final String getMethodName() {
537         return methodName;
538     }
539 
540     /**
541      * Gets this operator symbol.
542      *
543      * @return the symbol
544      */
545     public final String getOperatorSymbol() {
546         return operator;
547     }
548 
549     /**
550      * Uberspect that solves and evaluates JexlOperator overloads.
551      * <p>This is used by the interpreter to find and execute operator overloads implemented in a derived
552      * JexlArithmetic - or in some cases, as methods of the left argument type (contains, size, ...).</p>
553      * <p>This also allows reusing the core logic when extending the applicative type-system; for
554      * instance, implementing a Comparator class that calls compare
555      * (<code>operator.tryOverload(this, JexlOperator.COMPARE, left, right)</code>, etc.</p>
556      * @since 3.5.0
557      */
558     public interface Uberspect extends JexlArithmetic.Uberspect {
559         /**
560          * Try to find the most specific method and evaluate an operator.
561          * <p>This method does not call {@link #overloads(JexlOperator)} and shall not be called with an
562          * assignment operator; use {@link #tryAssignOverload(JexlCache.Reference, JexlOperator, Consumer, Object...)}
563          * in that case.</p>
564          *
565          * @param reference an optional reference caching resolved method or failing signature
566          * @param operator the operator
567          * @param args      the arguments
568          * @return TRY_FAILED if no specific method could be found, the evaluation result otherwise
569          */
570         Object tryOverload(JexlCache.Reference reference, JexlOperator operator, Object...args);
571 
572         /**
573          * Evaluates an assign operator.
574          * <p>
575          * This takes care of finding and caching the operator method when appropriate.
576          * If an overloads returns a value not-equal to TRY_FAILED, it means the side-effect is complete.
577          * Otherwise, {@code a += b <=> a = a + b}
578          * </p>
579          * @param node     an optional reference caching resolved method or failing signature
580          * @param operator the operator
581          * @param assign   the actual function that performs the side effect
582          * @param args     the arguments, the first one being the target of assignment
583          * @return JexlEngine.TRY_FAILED if no operation was performed,
584          *         the value to use as the side effect argument otherwise
585          */
586         Object tryAssignOverload(final JexlCache.Reference node,
587                                  final JexlOperator operator,
588                                  final Consumer<Object> assign,
589                                  final Object... args);
590 
591         /**
592          * Calculate the {@code size} of various types:
593          * Collection, Array, Map, String, and anything that has an int size() method.
594          * <p>Seeks an overload or use the default arithmetic implementation.</p>
595          * <p>Note that the result may not be an integer.
596          *
597          * @param node   an optional reference caching resolved method or failing signature
598          * @param object the object to get the size of
599          * @return the evaluation result
600          */
601         Object size(final JexlCache.Reference node, final Object object);
602 
603         /**
604          * Check for emptiness of various types: Collection, Array, Map, String, and anything that has a boolean isEmpty()
605          * method.
606          * <p>Seeks an overload or use the default arithmetic implementation.</p>
607          * <p>Note that the result may not be a boolean.
608          *
609          * @param node   the node holding the object
610          * @param object the object to check the emptiness of
611          * @return the evaluation result
612          */
613         Object empty(final JexlCache.Reference node, final Object object);
614 
615         /**
616          * The 'match'/'in' operator implementation.
617          * <p>Seeks an overload or use the default arithmetic implementation.</p>
618          * <p>
619          * Note that 'x in y' or 'x matches y' means 'y contains x' ;
620          * the JEXL operator arguments order syntax is the reverse of this method call.
621          * </p>
622          * @param node  an optional reference caching resolved method or failing signature
623          * @param operator    the calling operator, =~ or !~
624          * @param right the left operand
625          * @param left  the right operand
626          * @return true if left matches right, false otherwise
627          */
628         boolean contains(final JexlCache.Reference node,
629                          final JexlOperator operator,
630                          final Object left,
631                          final Object right);
632 
633         /**
634          * The 'startsWith' operator implementation.
635          * <p>Seeks an overload or use the default arithmetic implementation.</p>
636          * @param node     an optional reference caching resolved method or failing signature
637          * @param operator the calling operator, $= or $!
638          * @param left     the left operand
639          * @param right    the right operand
640          * @return true if left starts with right, false otherwise
641          */
642         boolean startsWith(final JexlCache.Reference node,
643                            final JexlOperator operator,
644                            final Object left,
645                            final Object right);
646 
647         /**
648          * The 'endsWith' operator implementation.
649          * <p>Seeks an overload or use the default arithmetic implementation.</p>
650          * @param node     an optional reference caching resolved method or failing signature
651          * @param operator the calling operator, ^= or ^!
652          * @param left     the left operand
653          * @param right    the right operand
654          * @return true if left ends with right, false otherwise
655          */
656         boolean endsWith(final JexlCache.Reference node,
657                          final JexlOperator operator,
658                          final Object left,
659                          final Object right);
660     }
661 }