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" & "not-strict": 065 * <p> 0 & 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" & "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" & "not-strict": 077 * <p>The error control grain is roughly on par with JEXL 1.0</p> 078 * </li> 079 * <li>When "not-silent" & "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"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 ("" , ||) 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}