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

org.apache.commons.text.lookup.StringLookupFactory Maven / Gradle / Ivy

The newest version!
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements. See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache license, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the license for the specific language governing permissions and
 * limitations under the license.
 */

package org.apache.commons.text.lookup;

import java.net.InetAddress;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.Base64;
import java.util.Collections;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;

import javax.xml.xpath.XPathFactory;

import org.apache.commons.text.StringSubstitutor;

/**
 * Create instances of string lookups or access singleton string lookups implemented in this package.
 * 

* The "classic" look up is {@link #mapStringLookup(Map)}. *

*

* The methods for variable interpolation (A.K.A. variable substitution) are: *

*
    *
  • {@link #interpolatorStringLookup()}.
  • *
  • {@link #interpolatorStringLookup(Map)}.
  • *
  • {@link #interpolatorStringLookup(StringLookup)}.
  • *
  • {@link #interpolatorStringLookup(Map, StringLookup, boolean)}.
  • *
*

* Unless explicitly requested otherwise, a set of default lookups are included for convenience with these variable interpolation methods. These defaults are * listed in the table below. However, the exact lookups included can be configured through the use of the {@value #DEFAULT_STRING_LOOKUPS_PROPERTY} system * property. If present, this system property will be parsed as a comma-separated list of lookup names, with the names being those defined by the * {@link DefaultStringLookup} enum. For example, setting this system property to {@code "BASE64_ENCODER,ENVIRONMENT"} will only include the * {@link DefaultStringLookup#BASE64_ENCODER BASE64_ENCODER} and {@link DefaultStringLookup#ENVIRONMENT ENVIRONMENT} lookups. Setting the property to the empty * string will cause no defaults to be configured. Note that not all lookups defined here and in {@link DefaultStringLookup} are included by default. * Specifically, lookups that can execute code (e.g., {@link DefaultStringLookup#SCRIPT SCRIPT}) and those that can result in contact with remote servers (e.g., * {@link DefaultStringLookup#URL URL} and {@link DefaultStringLookup#DNS DNS}) are not included by default. The current set of default lookups can be accessed * directly with {@link #addDefaultStringLookups(Map)}. *

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Default String Lookups
KeyInterfaceFactory MethodSince
{@value #KEY_BASE64_DECODER}{@link StringLookup}{@link #base64DecoderStringLookup()}1.6
{@value #KEY_BASE64_ENCODER}{@link StringLookup}{@link #base64EncoderStringLookup()}1.6
{@value #KEY_CONST}{@link StringLookup}{@link #constantStringLookup()}1.5
{@value #KEY_DATE}{@link StringLookup}{@link #dateStringLookup()}1.5
{@value #KEY_ENV}{@link StringLookup}{@link #environmentVariableStringLookup()}1.3
{@value #KEY_FILE}{@link StringLookup}{@link #fileStringLookup(Path...)}1.5
{@value #KEY_JAVA}{@link StringLookup}{@link #javaPlatformStringLookup()}1.5
{@value #KEY_LOCALHOST}{@link StringLookup}{@link #localHostStringLookup()}1.3
{@value #KEY_LOOPBACK_ADDRESS}{@link StringLookup}{@link #loopbackAddressStringLookup()}1.13.0
{@value #KEY_PROPERTIES}{@link StringLookup}{@link #propertiesStringLookup(Path...)}1.5
{@value #KEY_RESOURCE_BUNDLE}{@link StringLookup}{@link #resourceBundleStringLookup()}1.6
{@value #KEY_SYS}{@link StringLookup}{@link #systemPropertyStringLookup()}1.3
{@value #KEY_URL_DECODER}{@link StringLookup}{@link #urlDecoderStringLookup()}1.5
{@value #KEY_URL_ENCODER}{@link StringLookup}{@link #urlEncoderStringLookup()}1.5
{@value #KEY_XML}{@link StringLookup}{@link #xmlStringLookup(Map, Path...)}1.5
{@value #KEY_XML_DECODER}{@link StringLookup}{@link #xmlDecoderStringLookup()}1.11.0
{@value #KEY_XML_ENCODER}{@link StringLookup}{@link #xmlEncoderStringLookup()}1.11.0
* * * * * * * * * * * * * * * * * * * * * * * * * * * *
Additional String Lookups (not included by default)
KeyInterfaceFactory MethodSince
{@value #KEY_DNS}{@link StringLookup}{@link #dnsStringLookup()}1.8
{@value #KEY_URL}{@link StringLookup}{@link #urlStringLookup()}1.5
{@value #KEY_SCRIPT}{@link StringLookup}{@link #scriptStringLookup()}1.5
* *

* This class also provides functional lookups used as building blocks for other lookups. *

* * * * * * * * * * * * * * * * *
Functional String Lookups
InterfaceFactory MethodSince
{@link BiStringLookup}{@link #biFunctionStringLookup(BiFunction)}1.9
{@link StringLookup}{@link #functionStringLookup(Function)}1.9
* * @since 1.3 */ public final class StringLookupFactory { /** * Builds instance of {@link StringLookupFactory}. * * @since 1.12.0 */ public static final class Builder implements Supplier { /** * Fences. */ private Path[] fences; @Override public StringLookupFactory get() { return new StringLookupFactory(fences); } /** * Sets Path resolution fences. *

* Path Fences apply to the file, property, and XML string lookups. *

* * @param fences Path resolution fences. * @return {@code this} instance. */ public Builder setFences(final Path... fences) { this.fences = fences; return this; } } /** * Internal class used to construct the default {@link StringLookup} map used by {@link StringLookupFactory#addDefaultStringLookups(Map)}. */ static final class DefaultStringLookupsHolder { /** Singleton instance, initialized with the system properties. */ static final DefaultStringLookupsHolder INSTANCE = new DefaultStringLookupsHolder(System.getProperties()); /** * Adds the key and string lookup from {@code lookup} to {@code map}, also adding any additional key aliases if needed. Keys are normalized using the * {@link #toKey(String)} method. * * @param lookup lookup to add * @param map map to add to */ private static void addLookup(final DefaultStringLookup lookup, final Map map) { map.put(toKey(lookup.getKey()), lookup.getStringLookup()); if (DefaultStringLookup.BASE64_DECODER.equals(lookup)) { // "base64" is deprecated in favor of KEY_BASE64_DECODER. map.put(toKey("base64"), lookup.getStringLookup()); } } /** * Creates the lookup map used when the user has requested no customization. * * @return default lookup map */ private static Map createDefaultStringLookups() { final Map lookupMap = new HashMap<>(); addLookup(DefaultStringLookup.BASE64_DECODER, lookupMap); addLookup(DefaultStringLookup.BASE64_ENCODER, lookupMap); addLookup(DefaultStringLookup.CONST, lookupMap); addLookup(DefaultStringLookup.DATE, lookupMap); addLookup(DefaultStringLookup.ENVIRONMENT, lookupMap); addLookup(DefaultStringLookup.FILE, lookupMap); addLookup(DefaultStringLookup.JAVA, lookupMap); addLookup(DefaultStringLookup.LOCAL_HOST, lookupMap); addLookup(DefaultStringLookup.LOCAL_HOST, lookupMap); addLookup(DefaultStringLookup.PROPERTIES, lookupMap); addLookup(DefaultStringLookup.RESOURCE_BUNDLE, lookupMap); addLookup(DefaultStringLookup.SYSTEM_PROPERTIES, lookupMap); addLookup(DefaultStringLookup.URL_DECODER, lookupMap); addLookup(DefaultStringLookup.URL_ENCODER, lookupMap); addLookup(DefaultStringLookup.XML, lookupMap); addLookup(DefaultStringLookup.XML_DECODER, lookupMap); addLookup(DefaultStringLookup.XML_ENCODER, lookupMap); return lookupMap; } /** * Constructs a lookup map by parsing the given string. The string is expected to contain comma or space-separated names of values from the * {@link DefaultStringLookup} enum. If the given string is null or empty, an empty map is returned. * * @param str string to parse; may be null or empty * @return lookup map parsed from the given string */ private static Map parseStringLookups(final String str) { final Map lookupMap = new HashMap<>(); try { for (final String lookupName : str.split("[\\s,]+")) { if (!lookupName.isEmpty()) { addLookup(DefaultStringLookup.valueOf(lookupName.toUpperCase()), lookupMap); } } } catch (final IllegalArgumentException exc) { throw new IllegalArgumentException("Invalid default string lookups definition: " + str, exc); } return lookupMap; } /** Default string lookup map. */ private final Map defaultStringLookups; /** * Constructs a new instance initialized with the given properties. * * @param props initialization properties */ DefaultStringLookupsHolder(final Properties props) { final Map lookups = props.containsKey(StringLookupFactory.DEFAULT_STRING_LOOKUPS_PROPERTY) ? parseStringLookups(props.getProperty(StringLookupFactory.DEFAULT_STRING_LOOKUPS_PROPERTY)) : createDefaultStringLookups(); defaultStringLookups = Collections.unmodifiableMap(lookups); } /** * Gets the default string lookups map. * * @return default string lookups map */ Map getDefaultStringLookups() { return defaultStringLookups; } } /** * Name of the system property used to determine the string lookups added by the {@link #addDefaultStringLookups(Map)} method. Use of this property is only * required in cases where the set of default lookups must be modified. (See the class documentation for details.) * * @since 1.10.0 */ public static final String DEFAULT_STRING_LOOKUPS_PROPERTY = "org.apache.commons.text.lookup.StringLookupFactory.defaultStringLookups"; /** * Defines the singleton for this class. */ public static final StringLookupFactory INSTANCE = new StringLookupFactory(); /** * Decodes Base64 Strings. *

* Using a {@link StringLookup} from the {@link StringLookupFactory}: *

* *
     * StringLookupFactory.INSTANCE.base64DecoderStringLookup().lookup("SGVsbG9Xb3JsZCE=");
     * 
*

* Using a {@link StringSubstitutor}: *

* *
     * StringSubstitutor.createInterpolator().replace("... ${base64Decoder:SGVsbG9Xb3JsZCE=} ..."));
     * 
*

* The above examples convert {@code "SGVsbG9Xb3JsZCE="} to {@code "HelloWorld!"}. *

*/ static final FunctionStringLookup INSTANCE_BASE64_DECODER = FunctionStringLookup .on(key -> new String(Base64.getDecoder().decode(key), StandardCharsets.ISO_8859_1)); /** * Encodes Base64 Strings. *

* Using a {@link StringLookup} from the {@link StringLookupFactory}: *

* *
     * StringLookupFactory.INSTANCE.base64EncoderStringLookup().lookup("HelloWorld!");
     * 
*

* Using a {@link StringSubstitutor}: *

* *
     * StringSubstitutor.createInterpolator().replace("... ${base64Encoder:HelloWorld!} ..."));
     * 
*

* The above examples convert {@code "HelloWorld!"} to {@code "SGVsbG9Xb3JsZCE="}. *

* Defines the singleton for this class. */ static final FunctionStringLookup INSTANCE_BASE64_ENCODER = FunctionStringLookup .on(key -> Base64.getEncoder().encodeToString(key.getBytes(StandardCharsets.ISO_8859_1))); /** * Looks up keys from environment variables. *

* Using a {@link StringLookup} from the {@link StringLookupFactory}: *

* *
     * StringLookupFactory.INSTANCE.environmentVariableStringLookup().lookup("USER");
     * 
*

* Using a {@link StringSubstitutor}: *

* *
     * StringSubstitutor.createInterpolator().replace("... ${env:USER} ..."));
     * 
*

* The above examples convert (on Linux) {@code "USER"} to the current user name. On Windows 10, you would use {@code "USERNAME"} to the same effect. *

*/ static final FunctionStringLookup INSTANCE_ENVIRONMENT_VARIABLES = FunctionStringLookup.on(System::getenv); /** * Defines the FunctionStringLookup singleton that always returns null. */ static final FunctionStringLookup INSTANCE_NULL = FunctionStringLookup.on(key -> null); /** * Defines the FunctionStringLookup singleton for looking up system properties. */ static final FunctionStringLookup INSTANCE_SYSTEM_PROPERTIES = FunctionStringLookup.on(System::getProperty); /** * Default lookup key for interpolation {@value #KEY_BASE64_DECODER}. * * @since 1.6 */ public static final String KEY_BASE64_DECODER = "base64Decoder"; /** * Default lookup key for interpolation {@value #KEY_BASE64_ENCODER}. * * @since 1.6 */ public static final String KEY_BASE64_ENCODER = "base64Encoder"; /** * Default lookup key for interpolation {@value #KEY_CONST}. * * @since 1.6 */ public static final String KEY_CONST = "const"; /** * Default lookup key for interpolation {@value #KEY_DATE}. * * @since 1.6 */ public static final String KEY_DATE = "date"; /** * Default lookup key for interpolation {@value #KEY_DNS}. * * @since 1.8 */ public static final String KEY_DNS = "dns"; /** * Default lookup key for interpolation {@value #KEY_ENV}. * * @since 1.6 */ public static final String KEY_ENV = "env"; /** * Default lookup key for interpolation {@value #KEY_FILE}. * * @since 1.6 */ public static final String KEY_FILE = "file"; /** * Default lookup key for interpolation {@value #KEY_JAVA}. * * @since 1.6 */ public static final String KEY_JAVA = "java"; /** * Default lookup key for interpolation {@value #KEY_LOCALHOST}. * * @since 1.6 */ public static final String KEY_LOCALHOST = "localhost"; /** * Default lookup key for interpolation {@value #KEY_LOOPBACK_ADDRESS}. * * @since 1.13.0 */ public static final String KEY_LOOPBACK_ADDRESS = "loobackAddress"; /** * Default lookup key for interpolation {@value #KEY_PROPERTIES}. * * @since 1.6 */ public static final String KEY_PROPERTIES = "properties"; /** * Default lookup key for interpolation {@value #KEY_RESOURCE_BUNDLE}. * * @since 1.6 */ public static final String KEY_RESOURCE_BUNDLE = "resourceBundle"; /** * Default lookup key for interpolation {@value #KEY_SCRIPT}. * * @since 1.6 */ public static final String KEY_SCRIPT = "script"; /** * Default lookup key for interpolation {@value #KEY_SYS}. * * @since 1.6 */ public static final String KEY_SYS = "sys"; /** * Default lookup key for interpolation {@value #KEY_URL}. * * @since 1.6 */ public static final String KEY_URL = "url"; /** * Default lookup key for interpolation {@value #KEY_URL_DECODER}. * * @since 1.6 */ public static final String KEY_URL_DECODER = "urlDecoder"; /** * Default lookup key for interpolation {@value #KEY_URL_ENCODER}. * * @since 1.6 */ public static final String KEY_URL_ENCODER = "urlEncoder"; /** * Default lookup key for interpolation {@value #KEY_XML}. * * @since 1.6 */ public static final String KEY_XML = "xml"; /** * Default lookup key for interpolation {@value #KEY_XML_DECODER}. * * @since 1.11.0 */ public static final String KEY_XML_DECODER = "xmlDecoder"; /** * Default lookup key for interpolation {@value #KEY_XML_ENCODER}. * * @since 1.11.0 */ public static final String KEY_XML_ENCODER = "xmlEncoder"; /** * Constructs a new {@link Builder}. * * @return a new {@link Builder} * @since 1.12.0 */ public static Builder builder() { return new Builder(); } /** * Clears any static resources. * * @since 1.5 */ public static void clear() { ConstantStringLookup.clear(); } /** * Gets a string suitable for use as a key in the string lookup map. * * @param key string to convert to a string lookup map key * @return string lookup map key */ static String toKey(final String key) { return key.toLowerCase(Locale.ROOT); } /** * Returns the given map if the input is non-null or an empty immutable map if the input is null. * * @param the class of the map keys * @param the class of the map values * @param map The map to test * @return the given map if the input is non-null or an empty immutable map if the input is null. */ static Map toMap(final Map map) { return map == null ? Collections.emptyMap() : map; } /** * Fences. */ private final Path[] fences; /** * Constructs a new instance. */ private StringLookupFactory() { this(null); } /** * Constructs a new instance. */ private StringLookupFactory(final Path[] fences) { this.fences = fences; } /** * Adds the default string lookups for this class to {@code stringLookupMap}. The default string lookups are a set of built-in lookups added for convenience * during string interpolation. The defaults may be configured using the {@value #DEFAULT_STRING_LOOKUPS_PROPERTY} system property. See the class * documentation for details and a list of lookups. * * @param stringLookupMap the map of string lookups to edit. * @since 1.5 */ public void addDefaultStringLookups(final Map stringLookupMap) { if (stringLookupMap != null) { stringLookupMap.putAll(DefaultStringLookupsHolder.INSTANCE.getDefaultStringLookups()); } } /** * Returns the Base64DecoderStringLookup singleton instance to decode Base64 strings. *

* Using a {@link StringLookup} from the {@link StringLookupFactory}: *

* *
     * StringLookupFactory.INSTANCE.base64DecoderStringLookup().lookup("SGVsbG9Xb3JsZCE=");
     * 
*

* Using a {@link StringSubstitutor}: *

* *
     * StringSubstitutor.createInterpolator().replace("... ${base64Decoder:SGVsbG9Xb3JsZCE=} ..."));
     * 
*

* The above examples convert {@code "SGVsbG9Xb3JsZCE="} to {@code "HelloWorld!"}. *

* * @return The Base64DecoderStringLookup singleton instance. * @since 1.5 */ public StringLookup base64DecoderStringLookup() { return StringLookupFactory.INSTANCE_BASE64_DECODER; } /** * Returns the Base64EncoderStringLookup singleton instance to encode strings to Base64. *

* Using a {@link StringLookup} from the {@link StringLookupFactory}: *

* *
     * StringLookupFactory.INSTANCE.base64EncoderStringLookup().lookup("HelloWorld!");
     * 
*

* Using a {@link StringSubstitutor}: *

* *
     * StringSubstitutor.createInterpolator().replace("... ${base64Encoder:HelloWorld!} ..."));
     * 
*

* The above examples convert {@code } to {@code "SGVsbG9Xb3JsZCE="}. *

* * @return The Base64EncoderStringLookup singleton instance. * @since 1.6 */ public StringLookup base64EncoderStringLookup() { return StringLookupFactory.INSTANCE_BASE64_ENCODER; } /** * Returns the Base64DecoderStringLookup singleton instance to decode Base64 strings. *

* Using a {@link StringLookup} from the {@link StringLookupFactory}: *

* *
     * StringLookupFactory.INSTANCE.base64DecoderStringLookup().lookup("SGVsbG9Xb3JsZCE=");
     * 
*

* Using a {@link StringSubstitutor}: *

* *
     * StringSubstitutor.createInterpolator().replace("... ${base64Decoder:SGVsbG9Xb3JsZCE=} ..."));
     * 
*

* The above examples convert {@code "SGVsbG9Xb3JsZCE="} to {@code "HelloWorld!"}. *

* * @return The Base64DecoderStringLookup singleton instance. * @since 1.5 * @deprecated Use {@link #base64DecoderStringLookup()}. */ @Deprecated public StringLookup base64StringLookup() { return StringLookupFactory.INSTANCE_BASE64_DECODER; } /** * Returns a new function-based lookup where the request for a lookup is answered by applying the function with a lookup key. * * @param the function return type. * @param the function's second parameter type. * @param biFunction the function. * @return a new MapStringLookup. * @since 1.9 */ public BiStringLookup biFunctionStringLookup(final BiFunction biFunction) { return BiFunctionStringLookup.on(biFunction); } /** * Returns the ConstantStringLookup singleton instance to look up the value of a fully-qualified static final value. *

* Sometimes it is necessary in a configuration file to refer to a constant defined in a class. This can be done with this lookup implementation. Variable * names must be in the format {@code apackage.AClass.AFIELD}. The {@code lookup(String)} method will split the passed in string at the last dot, separating * the fully qualified class name and the name of the constant (i.e. static final) member field. Then the class is loaded and the field's * value is obtained using reflection. *

*

* Once retrieved values are cached for fast access. This class is thread-safe. It can be used as a standard (i.e. global) lookup object and serve multiple * clients concurrently. *

*

* Using a {@link StringLookup} from the {@link StringLookupFactory}: *

* *
     * StringLookupFactory.INSTANCE.constantStringLookup().lookup("java.awt.event.KeyEvent.VK_ESCAPE");
     * 
*

* Using a {@link StringSubstitutor}: *

* *
     * StringSubstitutor.createInterpolator().replace("... ${const:java.awt.event.KeyEvent.VK_ESCAPE} ..."));
     * 
*

* The above examples convert {@code java.awt.event.KeyEvent.VK_ESCAPE} to {@code "27"}. *

* * @return The ConstantStringLookup singleton instance. * @since 1.5 */ public StringLookup constantStringLookup() { return ConstantStringLookup.INSTANCE; } /** * Returns the DateStringLookup singleton instance to format the current date with the format given in the key in a format compatible with * {@link java.text.SimpleDateFormat}. *

* Using a {@link StringLookup} from the {@link StringLookupFactory}: *

* *
     * StringLookupFactory.INSTANCE.dateStringLookup().lookup("yyyy-MM-dd");
     * 
*

* Using a {@link StringSubstitutor}: *

* *
     * StringSubstitutor.createInterpolator().replace("... ${date:yyyy-MM-dd} ..."));
     * 
*

* The above examples convert {@code "yyyy-MM-dd"} to todays's date, for example, {@code "2019-08-04"}. *

* * @return The DateStringLookup singleton instance. */ public StringLookup dateStringLookup() { return DateStringLookup.INSTANCE; } /** * Returns the DnsStringLookup singleton instance where the lookup key is one of: *
    *
  • name: for the local host name, for example {@code EXAMPLE} but also {@code EXAMPLE.apache.org}.
  • *
  • canonical-name: for the local canonical host name, for example {@code EXAMPLE.apache.org}.
  • *
  • address: for the local host address, for example {@code 192.168.56.1}.
  • *
* *

* Using a {@link StringLookup} from the {@link StringLookupFactory}: *

* *
     * StringLookupFactory.INSTANCE.dnsStringLookup().lookup("address|apache.org");
     * 
*

* When used through a {@link StringSubstitutor}, this lookup must either be added programmatically (as below) or enabled as a default lookup using the * {@value #DEFAULT_STRING_LOOKUPS_PROPERTY} system property (see class documentation). *

* *
     * Map<String, StringLookup> lookupMap = new HashMap<>();
     * lookupMap.put("dns", StringLookupFactory.INSTANCE.dnsStringLookup());
     *
     * StringLookup variableResolver = StringLookupFactory.INSTANCE.interpolatorStringLookup(lookupMap, null, false);
     *
     * new StringSubstitutor(variableResolver).replace("... ${dns:address|apache.org} ...");
     * 
*

* The above examples convert {@code "address|apache.org"} to the IP address of {@code apache.org}. *

* * @return the DnsStringLookup singleton instance. * @since 1.8 */ public StringLookup dnsStringLookup() { return DnsStringLookup.INSTANCE; } /** * Returns the EnvironmentVariableStringLookup singleton instance where the lookup key is an environment variable name. *

* Using a {@link StringLookup} from the {@link StringLookupFactory}: *

* *
     * StringLookupFactory.INSTANCE.environmentVariableStringLookup().lookup("USER");
     * 
*

* Using a {@link StringSubstitutor}: *

* *
     * StringSubstitutor.createInterpolator().replace("... ${env:USER} ..."));
     * 
*

* The above examples convert (on Linux) {@code "USER"} to the current user name. On Windows 10, you would use {@code "USERNAME"} to the same effect. *

* * @return The EnvironmentVariableStringLookup singleton instance. */ public StringLookup environmentVariableStringLookup() { return StringLookupFactory.INSTANCE_ENVIRONMENT_VARIABLES; } /** * Returns a file StringLookup instance. *

* If this factory was built using {@link Builder#setFences(Path...)}, then the string lookup is fenced and will throw an {@link IllegalArgumentException} * if a lookup causes causes a path to resolve outside of these fences. Otherwise, the result is unfenced to preserved behavior from previous versions. *

* Using a fenced StringLookup *

* To use a fenced {@link StringLookup}, use {@link StringLookupFactory#builder()}: *

* *
     * // Make the fence the current directory
     * StringLookupFactory factory = StringLookupFactory.builder().setFences(Paths.get("")).get();
     * factory.fileStringLookup().lookup("UTF-8:com/domain/document.txt");
     *
     * // throws IllegalArgumentException
     * factory.fileStringLookup().lookup("UTF-8:/rootdir/foo/document.txt");
     *
     * // throws IllegalArgumentException
     * factory.fileStringLookup().lookup("UTF-8:../document.txt");
     * 
* * Using an unfenced StringLookup *

* To use an unfenced {@link StringLookup}, use {@link StringLookupFactory#INSTANCE}: *

* *
     * StringLookupFactory.INSTANCE.fileStringLookup().lookup("UTF-8:com/domain/document.properties");
     * 
* * Using a StringLookup with StringSubstitutor *

* To build a fenced StringSubstitutor, use: *

* *
     * // Make the fence the current directory
     * final StringLookupFactory factory = StringLookupFactory.builder().setFences(Paths.get("")).get();
     * final StringSubstitutor stringSubstitutor = new StringSubstitutor(factory.interpolatorStringLookup());
     * stringSubstitutor.replace("... ${file:UTF-8:com/domain/document.txt} ..."));
     *
     * // throws IllegalArgumentException
     * stringSubstitutor.replace("... ${file:UTF-8:/rootdir/foo/document.txt} ..."));
     * 
*

* Using an unfenced {@link StringSubstitutor}: *

* *
     * StringSubstitutor.createInterpolator().replace("... ${file:UTF-8:com/domain/document.txt} ..."));
     * 
*

* The above examples convert {@code "UTF-8:com/domain/document.txt"} to the contents of the file. *

* * @return a file StringLookup instance. * @since 1.5 */ public StringLookup fileStringLookup() { return fences != null ? fileStringLookup(fences) : FileStringLookup.INSTANCE; } /** * Returns a fenced file StringLookup instance. *

* To use a {@link StringLookup} fenced by the current directory, use: *

* *
     * StringLookupFactory.INSTANCE.fileStringLookup(Paths.get("")).lookup("UTF-8:com/domain/document.txt");
     *
     * // throws IllegalArgumentException
     * StringLookupFactory.INSTANCE.fileStringLookup(Paths.get("")).lookup("UTF-8:/rootdir/foo/document.txt");
     *
     * // throws IllegalArgumentException
     * StringLookupFactory.INSTANCE.fileStringLookup(Paths.get("")).lookup("UTF-8:../com/domain/document.txt");
     * 
*

* The above example converts {@code "UTF-8:com/domain/document.txt"} to the contents of the file. *

*

* {@link StringSubstitutor} methods like {@link StringSubstitutor#replace(String)} will throw a {@link IllegalArgumentException} when a file doesn't * resolves in a fence. *

* * @param fences The fences guarding Path resolution. * @return a file StringLookup instance. * @since 1.12.0 */ public StringLookup fileStringLookup(final Path... fences) { return new FileStringLookup(fences); } /** * Returns a new function-based lookup where the request for a lookup is answered by applying the function with a lookup key. * * @param the function return type. * @param function the function. * @return a new MapStringLookup. * @since 1.9 */ public StringLookup functionStringLookup(final Function function) { return FunctionStringLookup.on(function); } /** * Returns a {@link InterpolatorStringLookup} containing the configured {@link #addDefaultStringLookups(Map) default lookups}. See the class documentation * for details on how these defaults are configured. *

* Using a {@link StringLookup} from the {@link StringLookupFactory}: *

* *
     * StringLookupFactory.INSTANCE.interpolatorStringLookup().lookup("${sys:os.name}, ${env:USER}");
     * 
*

* Using a {@link StringSubstitutor}: *

* *
     * StringSubstitutor.createInterpolator().replace("... ${sys:os.name}, ${env:USER} ..."));
     * 
*

* The above examples convert {@code "${sys:os.name}, ${env:USER}"} to the OS name and Linux user name. *

* * @return the default {@link InterpolatorStringLookup}. */ public StringLookup interpolatorStringLookup() { return InterpolatorStringLookup.INSTANCE; } /** * Returns a new InterpolatorStringLookup. If {@code addDefaultLookups} is {@code true}, the configured {@link #addDefaultStringLookups(Map) default * lookups} are included in addition to the ones provided in {@code stringLookupMap}. (See the class documentation for details on how default lookups are * configured.) * * @param stringLookupMap the map of string lookups. * @param defaultStringLookup the default string lookup; this lookup is used when a variable cannot be resolved using the lookups in {@code stringLookupMap} * or the configured default lookups (if enabled) * @param addDefaultLookups whether to use default lookups as described above. * @return a new InterpolatorStringLookup. * @since 1.4 */ public StringLookup interpolatorStringLookup(final Map stringLookupMap, final StringLookup defaultStringLookup, final boolean addDefaultLookups) { return new InterpolatorStringLookup(stringLookupMap, defaultStringLookup, addDefaultLookups); } /** * Returns a new InterpolatorStringLookup using the given key-value pairs and the configured {@link #addDefaultStringLookups(Map) default lookups} to * resolve variables. (See the class documentation for details on how default lookups are configured.) * * @param the value type the default string lookup's map. * @param map the default map for string lookups. * @return a new InterpolatorStringLookup. */ public StringLookup interpolatorStringLookup(final Map map) { return new InterpolatorStringLookup(map); } /** * Returns a new InterpolatorStringLookup using the given lookup and the configured {@link #addDefaultStringLookups(Map) default lookups} to resolve * variables. (See the class documentation for details on how default lookups are configured.) * * @param defaultStringLookup the default string lookup. * @return a new InterpolatorStringLookup. */ public StringLookup interpolatorStringLookup(final StringLookup defaultStringLookup) { return new InterpolatorStringLookup(defaultStringLookup); } /** * Returns the JavaPlatformStringLookup singleton instance. Looks up keys related to Java: Java version, JRE version, VM version, and so on. *

* The lookup keys with examples are: *

*
    *
  • version: "Java version 1.8.0_181"
  • *
  • runtime: "Java(TM) SE Runtime Environment (build 1.8.0_181-b13) from Oracle Corporation"
  • *
  • vm: "Java HotSpot(TM) 64-Bit Server VM (build 25.181-b13, mixed mode)"
  • *
  • os: "Windows 10 10.0, architecture: amd64-64"
  • *
  • hardware: "processors: 4, architecture: amd64-64, instruction sets: amd64"
  • *
  • locale: "default locale: en_US, platform encoding: iso-8859-1"
  • *
* *

* Using a {@link StringLookup} from the {@link StringLookupFactory}: *

* *
     * StringLookupFactory.INSTANCE.javaPlatformStringLookup().lookup("version");
     * 
*

* Using a {@link StringSubstitutor}: *

* *
     * StringSubstitutor.createInterpolator().replace("... ${java:version} ..."));
     * 
*

* The above examples convert {@code "version"} to the current VM version, for example, {@code "Java version 1.8.0_181"}. *

* * @return The JavaPlatformStringLookup singleton instance. */ public StringLookup javaPlatformStringLookup() { return JavaPlatformStringLookup.INSTANCE; } /** * Returns the InetAddressStringLookup instance where the lookup key for {@link InetAddress#getLocalHost()} is one of: *
    *
  • name: for the local host name, for example {@code EXAMPLE}.
  • *
  • canonical-name: for the local canonical host name, for example {@code EXAMPLE.apache.org}.
  • *
  • address: for the local host address, for example {@code 192.168.56.1}.
  • *
* *

* Using a {@link StringLookup} from the {@link StringLookupFactory}: *

* *
     * StringLookupFactory.INSTANCE.localHostStringLookup().lookup("canonical-name");
     * 
*

* Using a {@link StringSubstitutor}: *

* *
     * StringSubstitutor.createInterpolator().replace("... ${localhost:canonical-name} ..."));
     * 
*

* The above examples convert {@code "canonical-name"} to the current host name, for example, {@code "EXAMPLE.apache.org"}. *

* * @return The InetAddressStringLookup singleton instance. */ public StringLookup localHostStringLookup() { return InetAddressStringLookup.LOCAL_HOST; } /** * Returns the InetAddressStringLookup instance where the lookup key for {@link InetAddress#getLoopbackAddress()} is one of: *
    *
  • name: for the local host name, for example {@code EXAMPLE}.
  • *
  • canonical-name: for the local canonical host name, for example {@code EXAMPLE.apache.org}.
  • *
  • address: for the local host address, for example {@code 192.168.56.1}.
  • *
* *

* Using a {@link StringLookup} from the {@link StringLookupFactory}: *

* *
     * StringLookupFactory.INSTANCE.loopbackAddressStringLookup().lookup("canonical-name");
     * 
*

* Using a {@link StringSubstitutor}: *

* *
     * StringSubstitutor.createInterpolator().replace("... ${loopbackAddress:canonical-name} ..."));
     * 
*

* The above examples convert {@code "canonical-name"} to the current host name, for example, {@code "EXAMPLE.apache.org"}. *

* * @return The InetAddressStringLookup singleton instance. */ public StringLookup loopbackAddressStringLookup() { return InetAddressStringLookup.LOOPACK_ADDRESS; } /** * Returns a new map-based lookup where the request for a lookup is answered with the value for that key. * * @param the map value type. * @param map the map. * @return a new MapStringLookup. */ public StringLookup mapStringLookup(final Map map) { return FunctionStringLookup.on(map); } /** * Returns the NullStringLookup singleton instance which always returns null. * * @return The NullStringLookup singleton instance. */ public StringLookup nullStringLookup() { return StringLookupFactory.INSTANCE_NULL; } /** * Returns a Properties StringLookup instance. *

* If this factory was built using {@link Builder#setFences(Path...)}, then the string lookup is fenced and will throw an {@link IllegalArgumentException} * if a lookup causes causes a path to resolve outside of these fences. Otherwise, the result is unfenced to preserved behavior from previous versions. *

*

* We looks up a value for the key in the format "DocumentPath::MyKey". *

*

* Note the use of "::" instead of ":" to allow for "C:" drive letters in paths. *

*

* For example: "com/domain/document.properties::MyKey". *

* Using a fenced StringLookup *

* To use a fenced {@link StringLookup}, use {@link StringLookupFactory#builder()}: *

* *
     * // Make the fence the current directory
     * StringLookupFactory factory = StringLookupFactory.builder().setFences(Paths.get("")).get();
     * factory.propertiesStringLookup().lookup("com/domain/document.properties::MyKey");
     *
     * // throws IllegalArgumentException
     * factory.propertiesStringLookup().lookup("/com/domain/document.properties::MyKey");
     *
     * // throws IllegalArgumentException
     * factory.propertiesStringLookup().lookup("../com/domain/document.properties::MyKey");
     * 
* * Using an unfenced StringLookup *

* To use an unfenced {@link StringLookup}, use {@link StringLookupFactory#INSTANCE}: *

* *
     * StringLookupFactory.INSTANCE.propertiesStringLookup().lookup("com/domain/document.properties::MyKey");
     * 
* * Using a StringLookup with StringSubstitutor *

* To build a fenced StringSubstitutor, use: *

* *
     * // Make the fence the current directory
     * final StringLookupFactory factory = StringLookupFactory.builder().setFences(Paths.get("")).get();
     * final StringSubstitutor stringSubstitutor = new StringSubstitutor(factory.interpolatorStringLookup());
     * stringSubstitutor.replace("... ${properties:com/domain/document.properties::MyKey} ..."));
     *
     * // throws IllegalArgumentException
     * stringSubstitutor.replace("... ${properties:/rootdir/foo/document.properties::MyKey} ..."));
     * 
*

* Using an unfenced {@link StringSubstitutor}: *

* *
     * StringSubstitutor.createInterpolator().replace("... ${properties:com/domain/document.properties::MyKey} ..."));
     * 
*

* The above examples convert {@code "com/domain/document.properties::MyKey"} to the key value in the properties file at the path * "com/domain/document.properties". *

* * @return a Properties StringLookup instance. * @since 1.5 */ public StringLookup propertiesStringLookup() { return fences != null ? propertiesStringLookup(fences) : PropertiesStringLookup.INSTANCE; } /** * Returns a fenced Properties StringLookup instance. *

* Looks up the value for the key in the format "DocumentPath::MyKey":. *

*

* Note the use of "::" instead of ":" to allow for "C:" drive letters in paths. *

*

* For example: "com/domain/document.properties::MyKey". *

*

* To use a {@link StringLookup} fenced by the current directory, use: *

* *
     * StringLookupFactory.INSTANCE.fileStringLookup(Paths.get("")).lookup("com/domain/document.properties::MyKey");
     *
     * // throws IllegalArgumentException
     * StringLookupFactory.INSTANCE.fileStringLookup(Paths.get("")).lookup("com/domain/document.properties::MyKey");
     *
     * // throws IllegalArgumentException
     * StringLookupFactory.INSTANCE.fileStringLookup(Paths.get("")).lookup("com/domain/document.properties::MyKey");
     * 
*

* The above example converts {@code "com/domain/document.properties::MyKey"} to the key value in the properties file at the path * "com/domain/document.properties". *

*

* {@link StringSubstitutor} methods like {@link StringSubstitutor#replace(String)} will throw a {@link IllegalArgumentException} when a file doesn't * resolves in a fence. *

* * @param fences The fences guarding Path resolution. * @return a Properties StringLookup instance. * @since 1.12.0 */ public StringLookup propertiesStringLookup(final Path... fences) { return new PropertiesStringLookup(fences); } /** * Returns the ResourceBundleStringLookup singleton instance. *

* Looks up the value for a given key in the format "BundleName:BundleKey". *

*

* For example: "com.domain.messages:MyKey". *

*

* Using a {@link StringLookup} from the {@link StringLookupFactory}: *

* *
     * StringLookupFactory.INSTANCE.resourceBundleStringLookup().lookup("com.domain.messages:MyKey");
     * 
*

* Using a {@link StringSubstitutor}: *

* *
     * StringSubstitutor.createInterpolator().replace("... ${resourceBundle:com.domain.messages:MyKey} ..."));
     * 
*

* The above examples convert {@code "com.domain.messages:MyKey"} to the key value in the resource bundle at {@code "com.domain.messages"}. *

* * @return The ResourceBundleStringLookup singleton instance. */ public StringLookup resourceBundleStringLookup() { return ResourceBundleStringLookup.INSTANCE; } /** * Returns a ResourceBundleStringLookup instance for the given bundle name. *

* Looks up the value for a given key in the format "MyKey". *

*

* For example: "MyKey". *

*

* Using a {@link StringLookup} from the {@link StringLookupFactory}: *

* *
     * StringLookupFactory.INSTANCE.resourceBundleStringLookup("com.domain.messages").lookup("MyKey");
     * 
*

* The above example converts {@code "MyKey"} to the key value in the resource bundle at {@code "com.domain.messages"}. *

* * @param bundleName Only lookup in this bundle. * @return a ResourceBundleStringLookup instance for the given bundle name. * @since 1.5 */ public StringLookup resourceBundleStringLookup(final String bundleName) { return new ResourceBundleStringLookup(bundleName); } /** * Returns the ScriptStringLookup singleton instance. NOTE: This lookup is not included as a {@link #addDefaultStringLookups(Map) default lookup} unless * explicitly enabled. See the class level documentation for details. *

* Looks up the value for the key in the format "ScriptEngineName:Script". *

*

* For example: "javascript:3 + 4". *

*

* Using a {@link StringLookup} from the {@link StringLookupFactory}: *

* *
     * StringLookupFactory.INSTANCE.scriptStringLookup().lookup("javascript:3 + 4");
     * 
*

* When used through a {@link StringSubstitutor}, this lookup must either be added programmatically (as below) or enabled as a default lookup using the * {@value #DEFAULT_STRING_LOOKUPS_PROPERTY} system property (see class documentation). *

* *
     * Map<String, StringLookup> lookupMap = new HashMap<>();
     * lookupMap.put("script", StringLookupFactory.INSTANCE.scriptStringLookup());
     *
     * StringLookup variableResolver = StringLookupFactory.INSTANCE.interpolatorStringLookup(lookupMap, null, false);
     *
     * String value = new StringSubstitutor(variableResolver).replace("${script:javascript:3 + 4}");
     * 
*

* The above examples convert {@code "javascript:3 + 4"} to {@code "7"}. *

* * @return The ScriptStringLookup singleton instance. * @since 1.5 */ public StringLookup scriptStringLookup() { return ScriptStringLookup.INSTANCE; } /** * Returns the SystemPropertyStringLookup singleton instance where the lookup key is a system property name. * *

* Using a {@link StringLookup} from the {@link StringLookupFactory}: *

* *
     * StringLookupFactory.INSTANCE.systemPropertyStringLookup().lookup("os.name");
     * 
*

* Using a {@link StringSubstitutor}: *

* *
     * StringSubstitutor.createInterpolator().replace("... ${sys:os.name} ..."));
     * 
*

* The above examples convert {@code "os.name"} to the operating system name. *

* * @return The SystemPropertyStringLookup singleton instance. */ public StringLookup systemPropertyStringLookup() { return StringLookupFactory.INSTANCE_SYSTEM_PROPERTIES; } /** * Returns the UrlDecoderStringLookup singleton instance. *

* Decodes URL Strings using the UTF-8 encoding. *

*

* For example: "Hello%20World%21" becomes "Hello World!". *

*

* Using a {@link StringLookup} from the {@link StringLookupFactory}: *

* *
     * StringLookupFactory.INSTANCE.urlDecoderStringLookup().lookup("Hello%20World%21");
     * 
*

* Using a {@link StringSubstitutor}: *

* *
     * StringSubstitutor.createInterpolator().replace("... ${urlDecoder:Hello%20World%21} ..."));
     * 
*

* The above examples convert {@code "Hello%20World%21"} to {@code "Hello World!"}. *

* * @return The UrlStringLookup singleton instance. * @since 1.6 */ public StringLookup urlDecoderStringLookup() { return UrlDecoderStringLookup.INSTANCE; } /** * Returns the UrlDecoderStringLookup singleton instance. *

* Decodes URL Strings using the UTF-8 encoding. *

*

* For example: "Hello World!" becomes "Hello+World%21". *

*

* Using a {@link StringLookup} from the {@link StringLookupFactory}: *

* *
     * StringLookupFactory.INSTANCE.urlEncoderStringLookup().lookup("Hello World!");
     * 
*

* Using a {@link StringSubstitutor}: *

* *
     * StringSubstitutor.createInterpolator().replace("... ${urlEncoder:Hello World!} ..."));
     * 
*

* The above examples convert {@code "Hello World!"} to {@code "Hello%20World%21"}. *

* * @return The UrlStringLookup singleton instance. * @since 1.6 */ public StringLookup urlEncoderStringLookup() { return UrlEncoderStringLookup.INSTANCE; } /** * Returns the UrlStringLookup singleton instance. This lookup is not included as a {@link #addDefaultStringLookups(Map) default lookup} unless explicitly * enabled. See the class level documentation for details. *

* Looks up the value for the key in the format "CharsetName:URL". *

*

* For example, using the HTTP scheme: "UTF-8:http://www.google.com" *

*

* For example, using the file scheme: "UTF-8:file:///C:/somehome/commons/commons-text/src/test/resources/document.properties" *

*

* Using a {@link StringLookup} from the {@link StringLookupFactory}: *

* *
     * StringLookupFactory.INSTANCE.urlStringLookup().lookup("UTF-8:https://www.apache.org");
     * 
*

* When used through a {@link StringSubstitutor}, this lookup must either be added programmatically (as below) or enabled as a default lookup using the * {@value #DEFAULT_STRING_LOOKUPS_PROPERTY} system property (see class documentation). *

* *
     * Map<String, StringLookup> lookupMap = new HashMap<>();
     * lookupMap.put("url", StringLookupFactory.INSTANCE.urlStringLookup());
     *
     * StringLookup variableResolver = StringLookupFactory.INSTANCE.interpolatorStringLookup(lookupMap, null, false);
     *
     * String value = new StringSubstitutor(variableResolver).replace("${url:UTF-8:https://www.apache.org}");
     * 
*

* The above examples convert {@code "UTF-8:https://www.apache.org"} to the contents of that page. *

* * @return The UrlStringLookup singleton instance. * @since 1.5 */ public StringLookup urlStringLookup() { return UrlStringLookup.INSTANCE; } /** * Returns the XmlDecoderStringLookup singleton instance. *

* Decodes strings according to the XML 1.0 specification. *

*

* For example: "&lt;element&gt;" becomes "<element>". *

*

* Using a {@link StringLookup} from the {@link StringLookupFactory}: *

* *
     * StringLookupFactory.INSTANCE.xmlDecoderStringLookup().lookup("&lt;element&gt;");
     * 
*

* Using a {@link StringSubstitutor}: *

* *
     * StringSubstitutor.createInterpolator().replace("... ${xmlDecoder:&lt;element&gt;} ..."));
     * 
*

* The above examples convert {@code "<element>"} to {@code ""}. *

* * @return The XmlDecoderStringLookup singleton instance. * @since 1.11.0 */ public StringLookup xmlDecoderStringLookup() { return XmlDecoderStringLookup.INSTANCE; } /** * Returns the XmlEncoderStringLookup singleton instance. *

* Encodes strings according to the XML 1.0 specification. *

*

* For example: "<element>" becomes "&lt;element&gt;". *

*

* Using a {@link StringLookup} from the {@link StringLookupFactory}: *

* *
     * StringLookupFactory.INSTANCE.xmlEncoderStringLookup().lookup("<element>");
     * 
*

* Using a {@link StringSubstitutor}: *

* *
     * StringSubstitutor.createInterpolator().replace("... ${xmlEncoder:<element>} ..."));
     * 
*

* The above examples convert {@code ""} to {@code "<element>"}. *

* * @return The XmlEncoderStringLookup singleton instance. * @since 1.11.0 */ public StringLookup xmlEncoderStringLookup() { return XmlEncoderStringLookup.INSTANCE; } /** * Returns an XML StringLookup instance. *

* If this factory was built using {@link Builder#setFences(Path...)}, then the string lookup is fenced and will throw an {@link IllegalArgumentException} * if a lookup causes causes a path to resolve outside of these fences. Otherwise, the result is unfenced to preserved behavior from previous versions. *

*

* We look up the value for the key in the format "DocumentPath:XPath". *

*

* For example: "com/domain/document.xml:/path/to/node". *

*

* Using a {@link StringLookup} from the {@link StringLookupFactory}: *

* *
     * StringLookupFactory.INSTANCE.xmlStringLookup().lookup("com/domain/document.xml:/path/to/node");
     * 
*

* Using a {@link StringSubstitutor}: *

* *
     * StringSubstitutor.createInterpolator().replace("... ${xml:com/domain/document.xml:/path/to/node} ..."));
     * 
*

* The above examples convert {@code "com/domain/document.xml:/path/to/node"} to the value of the XPath in the XML document. *

* * @return An XML StringLookup instance. * @since 1.5 */ public StringLookup xmlStringLookup() { return fences != null ? xmlStringLookup(XmlStringLookup.DEFAULT_FEATURES, fences) : XmlStringLookup.INSTANCE; } /** * Returns an XML StringLookup instance. *

* If this factory was built using {@link Builder#setFences(Path...)}, then the string lookup is fenced and will throw an {@link IllegalArgumentException} * if a lookup causes causes a path to resolve outside of these fences. Otherwise, the result is unfenced to preserved behavior from previous versions. *

*

* We look up the value for the key in the format "DocumentPath:XPath". *

*

* For example: "com/domain/document.xml:/path/to/node". *

*

* Using a {@link StringLookup} from the {@link StringLookupFactory}: *

* *
     * StringLookupFactory.INSTANCE.xmlStringLookup().lookup("com/domain/document.xml:/path/to/node");
     * 
*

* Using a {@link StringSubstitutor}: *

* *
     * StringSubstitutor.createInterpolator().replace("... ${xml:com/domain/document.xml:/path/to/node} ..."));
     * 
*

* The above examples convert {@code "com/domain/document.xml:/path/to/node"} to the value of the XPath in the XML document. *

* * @param xPathFactoryFeatures XPathFactory features to set. * @return An XML StringLookup instance. * @see XPathFactory#setFeature(String, boolean) * @since 1.11.0 */ public StringLookup xmlStringLookup(final Map xPathFactoryFeatures) { return xmlStringLookup(xPathFactoryFeatures, fences); } /** * Returns a fenced XML StringLookup instance. *

* If this factory was built using {@link Builder#setFences(Path...)}, then the string lookup is fenced and will throw an {@link IllegalArgumentException} * if a lookup causes causes a path to resolve outside of these fences. Otherwise, the result is unfenced to preserved behavior from previous versions. *

*

* We look up the value for the key in the format "DocumentPath:XPath". *

*

* For example: "com/domain/document.xml:/path/to/node". *

*

* Using a {@link StringLookup} from the {@link StringLookupFactory} fenced by the current directory ({@code Paths.get("")}): *

* *
     * StringLookupFactory.INSTANCE.xmlStringLookup(map, Pathe.get("")).lookup("com/domain/document.xml:/path/to/node");
     * 
*

* To use a {@link StringLookup} fenced by the current directory, use: *

* *
     * StringLookupFactory.INSTANCE.xmlStringLookup(Paths.get("")).lookup("com/domain/document.xml:/path/to/node");
     *
     * // throws IllegalArgumentException
     * StringLookupFactory.INSTANCE.xmlStringLookup(Paths.get("")).lookup("/rootdir/foo/document.xml:/path/to/node");
     *
     * // throws IllegalArgumentException
     * StringLookupFactory.INSTANCE.xmlStringLookup(Paths.get("")).lookup("../com/domain/document.xml:/path/to/node");
     * 
*

* The above examples convert {@code "com/domain/document.xml:/path/to/node"} to the value of the XPath in the XML document. *

*

* {@link StringSubstitutor} methods like {@link StringSubstitutor#replace(String)} will throw a {@link IllegalArgumentException} when a file doesn't * resolves in a fence. *

* * @param xPathFactoryFeatures XPathFactory features to set. * @param fences The fences guarding Path resolution. * @return An XML StringLookup instance. * @since 1.12.0 */ public StringLookup xmlStringLookup(final Map xPathFactoryFeatures, final Path... fences) { return new XmlStringLookup(xPathFactoryFeatures, fences); } }