001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      https://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package org.apache.commons.jexl3;
019
020import java.nio.charset.Charset;
021import java.util.Arrays;
022import java.util.Collection;
023import java.util.Map;
024import java.util.function.IntFunction;
025import java.util.function.Supplier;
026
027import org.apache.commons.jexl3.internal.Engine;
028import org.apache.commons.jexl3.internal.SoftCache;
029import org.apache.commons.jexl3.introspection.JexlPermissions;
030import org.apache.commons.jexl3.introspection.JexlSandbox;
031import org.apache.commons.jexl3.introspection.JexlUberspect;
032import org.apache.commons.jexl3.parser.JexlScriptParser;
033import org.apache.commons.logging.Log;
034
035/**
036 * Configures and builds a JexlEngine.
037 *
038 * <p>
039 *     The builder allow fine-tuning an engine instance behavior according to various control needs.
040 *     Check <em>{@link #JexlBuilder()}</em> for permission impacts starting with <em>JEXL 3.3</em>.
041 * </p><p>
042 *     Broad configurations elements are controlled through the features ({@link JexlFeatures}) that can restrict JEXL
043 *  syntax - for instance, only expressions with no-side effects - and permissions ({@link JexlPermissions}) that control
044 *  the visible set of objects - for instance, avoiding access to any object in java.rmi.* -.
045 *  </p><p>
046 *     Fine error control and runtime-overridable behaviors are implemented through options ({@link JexlOptions}). Most
047 * common flags accessible from the builder are reflected in its options ({@link #options()}).
048 * </p><p>
049 *     The {@code silent} flag tells the engine what to do with the error; when true, errors are logged as
050 * warning, when false, they throw {@link JexlException} exceptions.
051 * </p><p>
052 *     The {@code strict} flag tells the engine when and if null as operand is considered an error. The {@code safe}
053 * flog determines if safe-navigation is used. Safe-navigation allows an  evaluation shortcut and return null in expressions
054 * that attempts dereferencing null, typically a method call or accessing a property.
055 * </p><p>
056 *     The {@code lexical} and {@code lexicalShade} flags can be used to enforce a lexical scope for
057 * variables and parameters. The {@code lexicalShade} can be used to further ensure no global variable can be
058 * used with the same name as a local one even after it goes out of scope. The corresponding feature flags should be
059 * preferred since they will detect violations at parsing time. (see {@link JexlFeatures})
060 * </p><p>
061 *     The following rules apply on silent and strict flags:
062 * </p>
063 * <ul>
064 * <li>When "silent" &amp; "not-strict":
065 * <p> 0 &amp; null should be indicators of "default" values so that even in an case of error,
066 * something meaningful can still be inferred; may be convenient for configurations.
067 * </p>
068 * </li>
069 * <li>When "silent" &amp; "strict":
070 * <p>One should probably consider using null as an error case - ie, every object
071 * manipulated by JEXL should be valued; the ternary operator, especially the '?:' form
072 * can be used to workaround exceptional cases.
073 * Use case could be configuration with no implicit values or defaults.
074 * </p>
075 * </li>
076 * <li>When "not-silent" &amp; "not-strict":
077 * <p>The error control grain is roughly on par with JEXL 1.0</p>
078 * </li>
079 * <li>When "not-silent" &amp; "strict":
080 * <p>The finest error control grain is obtained; it is the closest to Java code -
081 * still augmented by "script" capabilities regarding automated conversions and type matching.
082 * </p>
083 * </li>
084 * </ul>
085 */
086public class JexlBuilder {
087
088    /**
089     * The set of default permissions used when creating a new builder.
090     * <p>Static but modifiable so these default permissions can be changed to a purposeful set.</p>
091     * <p>In JEXL 3.3, these are {@link JexlPermissions#RESTRICTED}.</p>
092     * <p>In JEXL 3.2, these were equivalent to {@link JexlPermissions#UNRESTRICTED}.</p>
093     */
094    private static JexlPermissions PERMISSIONS = JexlPermissions.RESTRICTED;
095
096    /** The default maximum expression length to hit the expression cache. */
097    protected static final int CACHE_THRESHOLD = 64;
098
099    /**
100     * Sets the default permissions.
101     *
102     * @param permissions the permissions
103     */
104    public static void setDefaultPermissions(final JexlPermissions permissions) {
105        PERMISSIONS = permissions == null ? JexlPermissions.RESTRICTED : permissions;
106    }
107
108    /** The JexlUberspect instance. */
109    private JexlUberspect uberspect;
110
111    /** The {@link JexlUberspect} resolver strategy. */
112    private JexlUberspect.ResolverStrategy strategy;
113
114    /** The set of permissions. */
115    private JexlPermissions permissions;
116
117    /** The sandbox. */
118    private JexlSandbox sandbox;
119
120    /** The Log to which all JexlEngine messages will be logged. */
121    private Log logger;
122
123    /** Whether error messages will carry debugging information. */
124    private Boolean debug;
125
126    /** Whether interrupt throws JexlException.Cancel. */
127    private Boolean cancellable;
128
129    /** The options. */
130    private final JexlOptions options = new JexlOptions();
131
132    /** Whether getVariables considers all potential equivalent syntactic forms. */
133    private int collectMode = 1;
134
135    /** The {@link JexlArithmetic} instance. */
136    private JexlArithmetic arithmetic;
137
138    /** The cache size. */
139    private int cache = -1;
140
141    /** The cache class factory. */
142    private IntFunction<JexlCache<?,?>> cacheFactory = SoftCache::new;
143
144   /** The parser class factory. */
145   private Supplier<JexlScriptParser> parserFactory;
146
147    /** The stack overflow limit. */
148    private int stackOverflow = Integer.MAX_VALUE;
149
150    /** The maximum expression length to hit the expression cache. */
151    private int cacheThreshold = CACHE_THRESHOLD;
152
153    /** The charset. */
154    private Charset charset = Charset.defaultCharset();
155
156    /** The class loader. */
157    private ClassLoader loader;
158
159    /** The features. */
160    private JexlFeatures features;
161
162    /**
163     * Default constructor.
164     * <p>
165     * As of JEXL 3.3, to reduce the security risks inherent to JEXL&quot;s purpose, the builder will use a set of
166     * restricted permissions as a default to create the {@link JexlEngine} instance. This will greatly reduce which classes
167     * and methods are visible to JEXL and usable in scripts using default implicit behaviors.
168     * </p><p>
169     * However, without mitigation, this change will likely break some scripts at runtime, especially those exposing
170     * your own class instances through arguments, contexts or namespaces.
171     * The new default set of allowed packages and denied classes is described by {@link JexlPermissions#RESTRICTED}.
172     * </p><p>
173     * The recommended mitigation if your usage of JEXL is impacted is to first thoroughly review what should be
174     * allowed and exposed to script authors and implement those through a set of {@link JexlPermissions};
175     * those are easily created using {@link JexlPermissions#parse(String...)}.
176     * </p><p>
177     * In the urgent case of a strict 3.2 compatibility, the simplest and fastest mitigation is to use the 'unrestricted'
178     * set of permissions. The builder must be explicit about it either by setting the default permissions with a
179     * statement like {@code JexlBuilder.setDefaultPermissions(JexlPermissions.UNRESTRICTED);} or with a more precise
180     * one like {@code new JexlBuilder().permissions({@link JexlPermissions#UNRESTRICTED})}.
181     * </p><p>
182     * Note that an explicit call to {@link #uberspect(JexlUberspect)} will supersede any permissions related behavior
183     * by using the {@link JexlUberspect} provided as argument used as-is in the created {@link JexlEngine}.
184     * </p>
185     *
186     * @since 3.3
187     */
188    public JexlBuilder() {
189        this.permissions = PERMISSIONS;
190    }
191
192    /**
193     * Is antish resolution enabled?
194     *
195     * @return whether antish resolution is enabled
196     */
197    public boolean antish() {
198        return options.isAntish();
199    }
200
201    /**
202     * Sets whether the engine will resolve antish variable names.
203     *
204     * @param flag true means antish resolution is enabled, false disables it
205     * @return this builder
206     */
207    public JexlBuilder antish(final boolean flag) {
208        options.setAntish(flag);
209        return this;
210    }
211
212    /**
213     * Gets the JexlArithmetic instance the engine will use.
214     *
215     * @return the arithmetic
216     */
217    public JexlArithmetic arithmetic() {
218        return this.arithmetic;
219    }
220
221    /**
222     * Sets the JexlArithmetic instance the engine will use.
223     *
224     * @param a the arithmetic
225     * @return this builder
226     */
227    public JexlBuilder arithmetic(final JexlArithmetic a) {
228        this.arithmetic = a;
229        options.setStrictArithmetic(a.isStrict());
230        options.setMathContext(a.getMathContext());
231        options.setMathScale(a.getMathScale());
232        return this;
233    }
234
235    /**
236     * Sets whether logical expressions (&quot;&quot; , ||) coerce their result to boolean.
237     *
238     * @param flag true or false
239     * @return this builder
240     */
241    public JexlBuilder booleanLogical(final boolean flag) {
242      options.setBooleanLogical(flag);
243      return this;
244    }
245
246    /**
247     * Gets the expression cache size the engine will use.
248     *
249     * @return the cache size
250     */
251    public int cache() {
252      return cache;
253    }
254
255    /**
256     * Sets the expression cache size the engine will use.
257     * <p>The cache will contain at most {@code size} expressions of at most {@code cacheThreshold} length.
258     * Note that all JEXL caches are held through SoftReferences and may be garbage-collected.</p>
259     *
260     * @param size if not strictly positive, no cache is used.
261     * @return this builder
262     */
263    public JexlBuilder cache(final int size) {
264        this.cache = size;
265        return this;
266    }
267
268    /**
269     * Gets the expression-cache factory the engine will use.
270     *
271     * @return the cache factory
272     */
273    public IntFunction<JexlCache<?, ?>> cacheFactory() {
274      return this.cacheFactory;
275    }
276
277    /**
278     * Sets the expression-cache factory the engine will use.
279     *
280     * @param factory the function to produce a cache.
281     * @return this builder
282     */
283    public JexlBuilder cacheFactory(final IntFunction<JexlCache<?, ?>> factory) {
284      this.cacheFactory = factory;
285      return this;
286    }
287
288  /**
289   * Gets the Jexl script parser factory the engine will use.
290   *
291   * @return the cache factory
292   * @since 3.5.0
293   */
294  public Supplier<JexlScriptParser> parserFactory() {
295    return this.parserFactory;
296  }
297
298  /**
299   * Sets the Jexl script parser factory the engine will use.
300   *
301   * @param factory the function to produce a cache.
302   * @return this builder
303   * @since 3.5.0
304   */
305    public JexlBuilder parserFactory(final Supplier<JexlScriptParser> factory) {
306      this.parserFactory = factory;
307      return this;
308    }
309
310    /**
311     * Gets the maximum length for an expression to be cached.
312     *
313     * @return the cache threshold
314     */
315    public int cacheThreshold() {
316        return cacheThreshold;
317    }
318
319    /**
320     * Sets the maximum length for an expression to be cached.
321     * <p>Expression whose length is greater than this expression cache length threshold will
322     * bypass the cache.</p>
323     * <p>It is expected that a "long" script will be parsed once and its reference kept
324     * around in user-space structures; the jexl expression cache has no added-value in this case.</p>
325     *
326     * @param length if not strictly positive, the value is silently replaced by the default value (64).
327     * @return this builder
328     */
329    public JexlBuilder cacheThreshold(final int length) {
330        this.cacheThreshold = length > 0? length : CACHE_THRESHOLD;
331        return this;
332    }
333
334    /**
335     * Gets the cancellable information flag
336     *
337     * @return the cancellable information flag
338     * @since 3.1
339     */
340    public Boolean cancellable() {
341        return this.cancellable;
342    }
343
344    /**
345     * Sets the engine behavior upon interruption: throw an JexlException.Cancel or terminates the current evaluation
346     * and return null.
347     *
348     * @param flag true implies the engine throws the exception, false makes the engine return null.
349     * @return this builder
350     * @since 3.1
351     */
352    public JexlBuilder cancellable(final boolean flag) {
353        this.cancellable = flag;
354        options.setCancellable(flag);
355        return this;
356    }
357
358    /**
359     * Gets the charset
360     *
361     * @return the charset
362     */
363    public Charset charset() {
364        return charset;
365    }
366
367    /**
368     * Sets the charset to use.
369     *
370     * @param arg the charset
371     * @return this builder
372     * @since 3.1
373     */
374    public JexlBuilder charset(final Charset arg) {
375        this.charset = arg;
376        return this;
377    }
378
379    /**
380     * Does the variable collection follow strict syntactic rule?
381     *
382     * @return true if variable collection follows strict syntactic rule
383     * @since 3.2
384     */
385    public boolean collectAll() {
386        return this.collectMode != 0;
387    }
388
389    /**
390     * Sets whether the engine variable collectors considers all potential forms of variable syntaxes.
391     *
392     * @param flag true means var collections considers constant array accesses equivalent to dotted references
393     * @return this builder
394     * @since 3.2
395     */
396    public JexlBuilder collectAll(final boolean flag) {
397        return collectMode(flag? 1 : 0);
398    }
399
400    /**
401     * Gets the collection mode.
402     *
403     * @return 0 if variable collection follows strict syntactic rule
404     * @since 3.2
405     */
406    public int collectMode() {
407        return this.collectMode;
408    }
409
410    /**
411     * Experimental collector mode setter.
412     *
413     * @param mode 0 or 1 as equivalents to false and true, other values are experimental
414     * @return this builder
415     * @since 3.2
416     */
417    public JexlBuilder collectMode(final int mode) {
418        this.collectMode = mode;
419        return this;
420    }
421
422    /**
423     * Create a new engine
424     *
425     * @return a {@link JexlEngine} instance
426     */
427    public JexlEngine create() {
428        return new Engine(this);
429    }
430
431    /**
432     * Gets the debug flag.
433     *
434     * @return the debugging information flag
435     */
436    public Boolean debug() {
437        return this.debug;
438    }
439
440    /**
441     * Sets whether the engine will report debugging information when error occurs.
442     *
443     * @see JexlEngine#isDebug()
444     * @param flag true implies debug is on, false implies debug is off.
445     * @return this builder
446     */
447    public JexlBuilder debug(final boolean flag) {
448        this.debug = flag;
449        return this;
450    }
451
452    /**
453     * Gets the features the engine will use as a base by default.
454     *
455     * @return the features
456     */
457    public JexlFeatures features() {
458        return this.features;
459    }
460
461    /**
462     * Sets the features the engine will use as a base by default.
463     * <p>Note that the script flag will be ignored; the engine will be able to parse expressions and scripts.
464     * <p>Note also that these will apply to template expressions and scripts.
465     * <p>As a last remark, if lexical or lexicalShade are set as features, this
466     * method will also set the corresponding options.
467     *
468     * @param f the features
469     * @return this builder
470     */
471    public JexlBuilder features(final JexlFeatures f) {
472        this.features = f;
473        if (features != null) {
474            if (features.isLexical()) {
475                options.setLexical(true);
476            }
477            if (features.isLexicalShade()) {
478                options.setLexicalShade(true);
479            }
480        }
481        return this;
482    }
483
484    /**
485     * Gets the optional set of imported packages.
486     *
487     * @return the set of imports, may be empty, not null
488     */
489    public Collection<String> imports() {
490        return options.getImports();
491    }
492
493    /**
494     * Sets the optional set of imports.
495     *
496     * @param imports the imported packages
497     * @return this builder
498     */
499    public JexlBuilder imports(final Collection<String> imports) {
500        options.setImports(imports);
501        return this;
502    }
503
504    /**
505     * Sets the optional set of imports.
506     *
507     * @param imports the imported packages
508     * @return this builder
509     */
510    public JexlBuilder imports(final String... imports) {
511        return imports(Arrays.asList(imports));
512    }
513
514    /**
515     * Is lexical scope enabled?
516     *
517     * @see JexlOptions#isLexical()
518     * @return whether lexical scope is enabled
519     * @deprecated 3.5.0
520     */
521    @Deprecated
522    public boolean lexical() {
523        return options.isLexical();
524    }
525
526    /**
527     * Sets whether the engine is in lexical mode.
528     *
529     * @param flag true means lexical function scope is in effect, false implies non-lexical scoping
530     * @return this builder
531     * @since 3.2
532     */
533    public JexlBuilder lexical(final boolean flag) {
534        options.setLexical(flag);
535        return this;
536    }
537
538    /**
539     * Checks whether lexical shading is enabled.
540     *
541     * @see JexlOptions#isLexicalShade()
542     * @return whether lexical shading is enabled
543     * @deprecated 3.5.0
544     */
545    @Deprecated
546    public boolean lexicalShade() {
547        return options.isLexicalShade();
548    }
549
550    /**
551     * Sets whether the engine is in lexical shading mode.
552     *
553     * @param flag true means lexical shading is in effect, false implies no lexical shading
554     * @return this builder
555     * @since 3.2
556     */
557    public JexlBuilder lexicalShade(final boolean flag) {
558        options.setLexicalShade(flag);
559        return this;
560    }
561
562    /**
563     * Gets the classloader
564     *
565     * @return the class loader
566     */
567    public ClassLoader loader() {
568        return loader;
569    }
570
571    /**
572     * Sets the charset to use.
573     *
574     * @param arg the charset
575     * @return this builder
576     * @deprecated since 3.1 use {@link #charset(Charset)} instead
577     */
578    @Deprecated
579    public JexlBuilder loader(final Charset arg) {
580        return charset(arg);
581    }
582
583    /**
584     * Sets the class loader to use.
585     *
586     * @param l the class loader
587     * @return this builder
588     */
589    public JexlBuilder loader(final ClassLoader l) {
590        this.loader = l;
591        return this;
592    }
593
594    /**
595     * Gets the logger
596     *
597     * @return the logger
598     */
599    public Log logger() {
600        return this.logger;
601    }
602
603    /**
604     * Sets the o.a.c.Log instance to use.
605     *
606     * @param log the logger
607     * @return this builder
608     */
609    public JexlBuilder logger(final Log log) {
610        this.logger = log;
611        return this;
612    }
613
614    /**
615     * Gets the map of namespaces.
616     *
617     * @return the map of namespaces.
618     */
619    public Map<String, Object> namespaces() {
620        return options.getNamespaces();
621    }
622
623    /**
624     * Sets the default namespaces map the engine will use.
625     * <p>
626     * Each entry key is used as a prefix, each entry value used as a bean implementing
627     * methods; an expression like 'nsx:method(123)' will thus be solved by looking at
628     * a registered bean named 'nsx' that implements method 'method' in that map.
629     * If all methods are static, you may use the bean class instead of an instance as value.
630     * </p>
631     * <p>
632     * If the entry value is a class that has one constructor taking a JexlContext as argument, an instance
633     * of the namespace will be created at evaluation time. It might be a good idea to derive a JexlContext
634     * to carry the information used by the namespace to avoid variable space pollution and strongly type
635     * the constructor with this specialized JexlContext.
636     * </p>
637     * <p>
638     * The key or prefix allows to retrieve the bean that plays the role of the namespace.
639     * If the prefix is null, the namespace is the top-level namespace allowing to define
640     * top-level user-defined namespaces ( ie: myfunc(...) )
641     * </p>
642     * <p>Note that the JexlContext is also used to try to solve top-level namespaces. This allows ObjectContext
643     * derived instances to call methods on the wrapped object.</p>
644     *
645     * @param ns the map of namespaces
646     * @return this builder
647     */
648    public JexlBuilder namespaces(final Map<String, Object> ns) {
649        options.setNamespaces(ns);
650        return this;
651    }
652
653    /**
654     * Gets the current set of options
655     *
656     * @return the current set of options
657     */
658    public JexlOptions options() {
659      return options;
660    }
661
662    /**
663     * Gets the permissions
664     *
665     * @return the permissions
666     */
667    public JexlPermissions permissions() {
668        return this.permissions;
669    }
670
671    /**
672     * Sets the JexlPermissions instance the engine will use.
673     *
674     * @param p the permissions
675     * @return this builder
676     */
677    public JexlBuilder permissions(final JexlPermissions p) {
678        this.permissions = p;
679        return this;
680    }
681
682    /**
683     * Is it safe to dereference null?
684     *
685     * @return true if safe, false otherwise
686     */
687    public Boolean safe() {
688        return options.isSafe();
689    }
690
691    /**
692     * Sets whether the engine considers dereferencing null in navigation expressions
693     * as null or triggers an error.
694     * <p>{@code x.y()} if x is null throws an exception when not safe,
695     * return null and warns if it is.</p>
696     * <p>It is recommended to use <em>safe(false)</em> as an explicit default.</p>
697     *
698     * @param flag true means safe navigation, false throws exception when dereferencing null
699     * @return this builder
700     */
701    public JexlBuilder safe(final boolean flag) {
702        options.setSafe(flag);
703        return this;
704    }
705
706    /**
707     * Gets the sandbox
708     *
709     * @return the sandbox
710     */
711    public JexlSandbox sandbox() {
712        return this.sandbox;
713    }
714
715    /**
716     * Sets the sandbox the engine will use.
717     *
718     * @param box the sandbox
719     * @return this builder
720     */
721    public JexlBuilder sandbox(final JexlSandbox box) {
722        this.sandbox = box;
723        return this;
724    }
725
726    /**
727     * Is error handling silent?
728     *
729     * @return the silent error handling flag
730     */
731    public Boolean silent() {
732        return options.isSilent();
733    }
734
735    /**
736     * Sets whether the engine will throw JexlException during evaluation when an error is triggered.
737     * <p>When <em>not</em> silent, the engine throws an exception when the evaluation triggers an exception or an
738     * error.</p>
739     * <p>It is recommended to use <em>silent(true)</em> as an explicit default.</p>
740     *
741     * @param flag true means no JexlException will occur, false allows them
742     * @return this builder
743     */
744    public JexlBuilder silent(final boolean flag) {
745        options.setSilent(flag);
746        return this;
747    }
748
749    /**
750     * Gets the cache size
751     *
752     * @return the cache size
753     */
754    public int stackOverflow() {
755        return stackOverflow;
756    }
757
758    /**
759     * Sets the number of script/expression evaluations that can be stacked.
760     *
761     * @param size if not strictly positive, limit is reached when Java StackOverflow is thrown.
762     * @return this builder
763     */
764    public JexlBuilder stackOverflow(final int size) {
765        this.stackOverflow = size;
766        return this;
767    }
768
769    /**
770     * Gets the JexlUberspect strategy
771     *
772     * @return the JexlUberspect strategy */
773    public JexlUberspect.ResolverStrategy strategy() {
774        return this.strategy;
775    }
776
777    /**
778     * Sets the JexlUberspect strategy the engine will use.
779     * <p>This is ignored if the uberspect has been set.
780     *
781     * @param rs the strategy
782     * @return this builder
783     */
784    public JexlBuilder strategy(final JexlUberspect.ResolverStrategy rs) {
785        this.strategy = rs;
786        return this;
787    }
788
789    /**
790     * Is it strict mode?
791     *
792     * @return true if strict, false otherwise */
793    public Boolean strict() {
794        return options.isStrict();
795    }
796
797    /**
798     * Sets whether the engine considers unknown variables, methods, functions and constructors as errors or
799     * evaluates them as null.
800     * <p>When <em>not</em> strict, operators or functions using null operands return null on evaluation. When
801     * strict, those raise exceptions.</p>
802     * <p>It is recommended to use <em>strict(true)</em> as an explicit default.</p>
803     *
804     * @param flag true means strict error reporting, false allows them to be evaluated as null
805     * @return this builder
806     */
807    public JexlBuilder strict(final boolean flag) {
808        options.setStrict(flag);
809        return this;
810    }
811
812    /**
813     * Is interpolation strict?
814     *
815     * @see JexlOptions#setStrictInterpolation(boolean)
816     * @param flag strict interpolation flag
817     * @return this builder
818     */
819    public JexlBuilder strictInterpolation(final boolean flag) {
820        options.setStrictInterpolation(flag);
821        return this;
822    }
823
824    /**
825     * Gets the uberspect
826     *
827     * @return the uberspect */
828    public JexlUberspect uberspect() {
829        return this.uberspect;
830    }
831
832    /**
833     * Sets the JexlUberspect instance the engine will use.
834     *
835     * @param u the uberspect
836     * @return this builder
837     */
838    public JexlBuilder uberspect(final JexlUberspect u) {
839        this.uberspect = u;
840        return this;
841    }
842}