This is an automated email from the ASF dual-hosted git repository. ggregory pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-text.git
The following commit(s) were added to refs/heads/master by this push: new 54098055 Add StringLookupFactory.xmlStringLookup(Map, Path...) and deprecated xmlStringLookup() and xmlStringLookup(Map) 54098055 is described below commit 540980552685b3ee95f9f376a9aa7a3970c5bb69 Author: Gary Gregory <garydgreg...@gmail.com> AuthorDate: Fri Apr 5 12:50:40 2024 -0400 Add StringLookupFactory.xmlStringLookup(Map, Path...) and deprecated xmlStringLookup() and xmlStringLookup(Map) --- src/changes/changes.xml | 1 + .../commons/text/lookup/StringLookupFactory.java | 251 +++++++++++---------- .../commons/text/lookup/XmlStringLookup.java | 13 +- .../commons/text/lookup/FileStringLookupTest.java | 11 +- .../text/lookup/PropertiesStringLookupTest.java | 3 +- .../commons/text/lookup/XmlStringLookupTest.java | 20 +- 6 files changed, 164 insertions(+), 135 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index ce772d7f..7c4228bb 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -49,6 +49,7 @@ The <action> type attribute can be add,update,fix,remove. <!-- ADD --> <action type="add" dev="ggregory" due-to="Gary Gregory">Add StringLookupFactory.fileStringLookup(Path...) and deprecated fileStringLookup().</action> <action type="add" dev="ggregory" due-to="Gary Gregory">Add StringLookupFactory.propertiesStringLookup(Path...) and deprecated propertiesStringLookup().</action> + <action type="add" dev="ggregory" due-to="Gary Gregory">Add StringLookupFactory.xmlStringLookup(Map, Path...) and deprecated xmlStringLookup() and xmlStringLookup(Map).</action> <!-- FIX --> <action issue="TEXT-232" type="fix" dev="ggregory" due-to="Arnout Engelen, Gary Gregory">WordUtils.containsAllWords​() may throw PatternSyntaxException.</action> <action issue="TEXT-175" type="fix" dev="ggregory" due-to="David Lavati, seanfabs, Gary Gregory, Bruno P. Kinoshita">Fix regression for determining whitespace in WordUtils #519.</action> diff --git a/src/main/java/org/apache/commons/text/lookup/StringLookupFactory.java b/src/main/java/org/apache/commons/text/lookup/StringLookupFactory.java index 51096ea1..52f9f3d2 100644 --- a/src/main/java/org/apache/commons/text/lookup/StringLookupFactory.java +++ b/src/main/java/org/apache/commons/text/lookup/StringLookupFactory.java @@ -47,19 +47,15 @@ import org.apache.commons.text.StringSubstitutor; * <li>{@link #interpolatorStringLookup(Map, StringLookup, boolean)}.</li> * </ul> * <p> - * 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)}. + * 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)}. * </p> * <table> * <caption>Default String Lookups</caption> @@ -221,8 +217,7 @@ import org.apache.commons.text.StringSubstitutor; public final class StringLookupFactory { /** - * Internal class used to construct the default {@link StringLookup} map used by - * {@link StringLookupFactory#addDefaultStringLookups(Map)}. + * Internal class used to construct the default {@link StringLookup} map used by {@link StringLookupFactory#addDefaultStringLookups(Map)}. */ static final class DefaultStringLookupsHolder { @@ -230,10 +225,11 @@ public final class StringLookupFactory { static final DefaultStringLookupsHolder INSTANCE = new DefaultStringLookupsHolder(System.getProperties()); /** - * Add 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. + * Add 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 + * @param map map to add to */ private static void addLookup(final DefaultStringLookup lookup, final Map<String, StringLookup> map) { map.put(toKey(lookup.getKey()), lookup.getStringLookup()); @@ -245,6 +241,7 @@ public final class StringLookupFactory { /** * Create the lookup map used when the user has requested no customization. + * * @return default lookup map */ private static Map<String, StringLookup> createDefaultStringLookups() { @@ -271,9 +268,9 @@ public final class StringLookupFactory { } /** - * 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. + * 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 */ @@ -296,18 +293,19 @@ public final class StringLookupFactory { /** * Constructs a new instance initialized with the given properties. + * * @param props initialization properties */ DefaultStringLookupsHolder(final Properties props) { - final Map<String, StringLookup> lookups = - props.containsKey(StringLookupFactory.DEFAULT_STRING_LOOKUPS_PROPERTY) - ? parseStringLookups(props.getProperty(StringLookupFactory.DEFAULT_STRING_LOOKUPS_PROPERTY)) - : createDefaultStringLookups(); + final Map<String, StringLookup> 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<String, StringLookup> getDefaultStringLookups() { @@ -315,6 +313,14 @@ public final class StringLookupFactory { } } + /** + * 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. */ @@ -341,7 +347,7 @@ public final class StringLookupFactory { * </p> */ static final FunctionStringLookup<String> INSTANCE_BASE64_DECODER = FunctionStringLookup - .on(key -> new String(Base64.getDecoder().decode(key), StandardCharsets.ISO_8859_1)); + .on(key -> new String(Base64.getDecoder().decode(key), StandardCharsets.ISO_8859_1)); /** * Encodes Base64 Strings. @@ -365,7 +371,7 @@ public final class StringLookupFactory { * Defines the singleton for this class. */ static final FunctionStringLookup<String> INSTANCE_BASE64_ENCODER = FunctionStringLookup - .on(key -> Base64.getEncoder().encodeToString(key.getBytes(StandardCharsets.ISO_8859_1))); + .on(key -> Base64.getEncoder().encodeToString(key.getBytes(StandardCharsets.ISO_8859_1))); /** * Looks up keys from environment variables. @@ -384,8 +390,7 @@ public final class StringLookupFactory { * StringSubstitutor.createInterpolator().replace("... ${env:USER} ...")); * </pre> * <p> - * 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. + * 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. * </p> */ static final FunctionStringLookup<String> INSTANCE_ENVIRONMENT_VARIABLES = FunctionStringLookup.on(System::getenv); @@ -533,16 +538,6 @@ public final class StringLookupFactory { */ public static final String KEY_XML_ENCODER = "xmlEncoder"; - /** - * 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"; - /** * Clears any static resources. * @@ -554,6 +549,7 @@ public final class StringLookupFactory { /** * 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 */ @@ -581,10 +577,9 @@ public final class StringLookupFactory { } /** - * 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. + * 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 @@ -679,11 +674,10 @@ public final class StringLookupFactory { } /** - * Returns a new function-based lookup where the request for a lookup is answered by applying the function with a - * lookup key. + * Returns a new function-based lookup where the request for a lookup is answered by applying the function with a lookup key. * - * @param <R> the function return type. - * @param <U> the function's second parameter type. + * @param <R> the function return type. + * @param <U> the function's second parameter type. * @param biFunction the function. * @return a new MapStringLookup. * @since 1.9 @@ -695,15 +689,14 @@ public final class StringLookupFactory { /** * Returns the ConstantStringLookup singleton instance to look up the value of a fully-qualified static final value. * <p> - * 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. <b>static final</b>) member field. Then the class is loaded and the - * field's value is obtained using reflection. + * 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. <b>static final</b>) member field. Then the class is loaded and the field's value is + * obtained using reflection. * </p> * <p> - * 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. + * 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. * </p> * <p> * Using a {@link StringLookup} from the {@link StringLookupFactory}: @@ -731,8 +724,8 @@ public final class StringLookupFactory { } /** - * 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}. + * 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}. * <p> * Using a {@link StringLookup} from the {@link StringLookupFactory}: * </p> @@ -773,9 +766,8 @@ public final class StringLookupFactory { * StringLookupFactory.INSTANCE.dnsStringLookup().lookup("address|apache.org"); * </pre> * <p> - * 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). + * 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). * </p> * * <pre> @@ -798,8 +790,7 @@ public final class StringLookupFactory { } /** - * Returns the EnvironmentVariableStringLookup singleton instance where the lookup key is an environment variable - * name. + * Returns the EnvironmentVariableStringLookup singleton instance where the lookup key is an environment variable name. * <p> * Using a {@link StringLookup} from the {@link StringLookupFactory}: * </p> @@ -815,8 +806,7 @@ public final class StringLookupFactory { * StringSubstitutor.createInterpolator().replace("... ${env:USER} ...")); * </pre> * <p> - * 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. + * 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. * </p> * * @return The EnvironmentVariableStringLookup singleton instance. @@ -889,10 +879,9 @@ public final class StringLookupFactory { } /** - * Returns a new function-based lookup where the request for a lookup is answered by applying the function with a - * lookup key. + * Returns a new function-based lookup where the request for a lookup is answered by applying the function with a lookup key. * - * @param <R> the function return type. + * @param <R> the function return type. * @param function the function. * @return a new MapStringLookup. * @since 1.9 @@ -902,9 +891,8 @@ public final class StringLookupFactory { } /** - * Returns a {@link InterpolatorStringLookup} containing the configured - * {@link #addDefaultStringLookups(Map) default lookups}. See the class documentation for - * details on how these defaults are configured. + * Returns a {@link InterpolatorStringLookup} containing the configured {@link #addDefaultStringLookups(Map) default lookups}. See the class documentation + * for details on how these defaults are configured. * <p> * Using a {@link StringLookup} from the {@link StringLookupFactory}: * </p> @@ -930,27 +918,25 @@ public final class StringLookupFactory { } /** - * 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.) + * 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. + * @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<String, StringLookup> stringLookupMap, - final StringLookup defaultStringLookup, final boolean addDefaultLookups) { + public StringLookup interpolatorStringLookup(final Map<String, StringLookup> 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.) + * 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 <V> the value type the default string lookup's map. * @param map the default map for string lookups. @@ -961,9 +947,8 @@ public final class StringLookupFactory { } /** - * 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.) + * 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. @@ -973,8 +958,7 @@ public final class StringLookupFactory { } /** - * Returns the JavaPlatformStringLookup singleton instance. Looks up keys related to Java: Java version, JRE - * version, VM version, and so on. + * Returns the JavaPlatformStringLookup singleton instance. Looks up keys related to Java: Java version, JRE version, VM version, and so on. * <p> * The lookup keys with examples are: * </p> @@ -1002,8 +986,7 @@ public final class StringLookupFactory { * StringSubstitutor.createInterpolator().replace("... ${java:version} ...")); * </pre> * <p> - * The above examples convert {@code "version"} to the current VM version, for example, - * {@code "Java version 1.8.0_181"}. + * The above examples convert {@code "version"} to the current VM version, for example, {@code "Java version 1.8.0_181"}. * </p> * * @return The JavaPlatformStringLookup singleton instance. @@ -1035,8 +1018,7 @@ public final class StringLookupFactory { * StringSubstitutor.createInterpolator().replace("... ${localhost:canonical-name} ...")); * </pre> * <p> - * The above examples convert {@code "canonical-name"} to the current host name, for example, - * {@code "EXAMPLE.apache.org"}. + * The above examples convert {@code "canonical-name"} to the current host name, for example, {@code "EXAMPLE.apache.org"}. * </p> * * @return The DateStringLookup singleton instance. @@ -1092,8 +1074,8 @@ public final class StringLookupFactory { * StringSubstitutor.createInterpolator().replace("... ${properties:com/domain/document.properties::MyKey} ...")); * </pre> * <p> - * 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". + * 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". * </p> * * @return The PropertiesStringLookup singleton instance. @@ -1135,8 +1117,8 @@ public final class StringLookupFactory { * stringSubstitutor.replace("... ${properties:com/domain/document.properties::MyKey} ...")); * </pre> * <p> - * 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". + * 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". * </p> * <p> * Methods {@link StringSubstitutor#replace(String)} will throw a {@link IllegalArgumentException} when a file doesn't resolves in a fence. @@ -1173,8 +1155,7 @@ public final class StringLookupFactory { * StringSubstitutor.createInterpolator().replace("... ${resourceBundle:com.domain.messages:MyKey} ...")); * </pre> * <p> - * The above examples convert {@code "com.domain.messages:MyKey"} to the key value in the resource bundle at - * {@code "com.domain.messages"}. + * The above examples convert {@code "com.domain.messages:MyKey"} to the key value in the resource bundle at {@code "com.domain.messages"}. * </p> * * @return The ResourceBundleStringLookup singleton instance. @@ -1199,8 +1180,7 @@ public final class StringLookupFactory { * StringLookupFactory.INSTANCE.resourceBundleStringLookup("com.domain.messages").lookup("MyKey"); * </pre> * <p> - * The above example converts {@code "MyKey"} to the key value in the resource bundle at - * {@code "com.domain.messages"}. + * The above example converts {@code "MyKey"} to the key value in the resource bundle at {@code "com.domain.messages"}. * </p> * * @param bundleName Only lookup in this bundle. @@ -1212,9 +1192,8 @@ public final class StringLookupFactory { } /** - * 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. + * 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. * <p> * Looks up the value for the key in the format "ScriptEngineName:Script". * </p> @@ -1229,9 +1208,8 @@ public final class StringLookupFactory { * StringLookupFactory.INSTANCE.scriptStringLookup().lookup("javascript:3 + 4"); * </pre> * <p> - * 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). + * 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). * </p> * * <pre> @@ -1347,9 +1325,8 @@ public final class StringLookupFactory { } /** - * 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. + * 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. * <p> * Looks up the value for the key in the format "CharsetName:URL". * </p> @@ -1357,8 +1334,7 @@ public final class StringLookupFactory { * For example, using the HTTP scheme: "UTF-8:http://www.google.com" * </p> * <p> - * For example, using the file scheme: - * "UTF-8:file:///C:/somehome/commons/commons-text/src/test/resources/document.properties" + * For example, using the file scheme: "UTF-8:file:///C:/somehome/commons/commons-text/src/test/resources/document.properties" * </p> * <p> * Using a {@link StringLookup} from the {@link StringLookupFactory}: @@ -1368,9 +1344,8 @@ public final class StringLookupFactory { * StringLookupFactory.INSTANCE.urlStringLookup().lookup("UTF-8:https://www.apache.org"); * </pre> * <p> - * 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). + * 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). * </p> * * <pre> @@ -1481,19 +1456,20 @@ public final class StringLookupFactory { * StringSubstitutor.createInterpolator().replace("... ${xml:com/domain/document.xml:/path/to/node} ...")); * </pre> * <p> - * The above examples convert {@code "com/domain/document.xml:/path/to/node"} to the value of the XPath in the XML - * document. + * The above examples convert {@code "com/domain/document.xml:/path/to/node"} to the value of the XPath in the XML document. * </p> * * @return The XmlStringLookup singleton instance. * @since 1.5 + * @deprecated Use {@link #xmlStringLookup(Map, Path...)}. */ + @Deprecated public StringLookup xmlStringLookup() { return XmlStringLookup.INSTANCE; } /** - * Returns the XmlStringLookup singleton instance. + * Returns a XmlStringLookup instance. * <p> * Looks up the value for the key in the format "DocumentPath:XPath". * </p> @@ -1515,16 +1491,55 @@ public final class StringLookupFactory { * StringSubstitutor.createInterpolator().replace("... ${xml:com/domain/document.xml:/path/to/node} ...")); * </pre> * <p> - * The above examples convert {@code "com/domain/document.xml:/path/to/node"} to the value of the XPath in the XML - * document. + * The above examples convert {@code "com/domain/document.xml:/path/to/node"} to the value of the XPath in the XML document. * </p> * * @param xPathFactoryFeatures XPathFactory features to set. * @return The XmlStringLookup singleton instance. * @see XPathFactory#setFeature(String, boolean) * @since 1.11.0 + * @deprecated Use {@link #xmlStringLookup(Map, Path...)}. */ + @Deprecated public StringLookup xmlStringLookup(final Map<String, Boolean> xPathFactoryFeatures) { return new XmlStringLookup(xPathFactoryFeatures); } + + /** + * Returns a fenced XmlStringLookup instance. + * <p> + * Looks up the value for the key in the format "DocumentPath:XPath". + * </p> + * <p> + * For example: "com/domain/document.xml:/path/to/node". + * </p> + * <p> + * Using a {@link StringLookup} from the {@link StringLookupFactory} fenced by the current directory ({@code Paths.get("")}): + * </p> + * + * <pre> + * StringLookupFactory.INSTANCE.xmlStringLookup(map, Pathe.get("")).lookup("com/domain/document.xml:/path/to/node"); + * </pre> + * <p> + * Using a {@link StringSubstitutor}: + * </p> + * + * <pre> + * StringSubstitutor stringSubstitutor = StringSubstitutor.createInterpolator(); + * final InterpolatorStringLookup stringLookup = (InterpolatorStringLookup) stringSubstitutor.getStringLookup(); + * stringLookup.getStringLookupMap().replace(StringLookupFactory.KEY_PROPERTIES, StringLookupFactory.INSTANCE.fileStringLookup(Paths.get(""))); + * stringSubstitutor.replace("... ${xml:com/domain/document.xml:/path/to/node} ...")); + * </pre> + * <p> + * The above examples convert {@code "com/domain/document.xml:/path/to/node"} to the value of the XPath in the XML document. + * </p> + * + * @param xPathFactoryFeatures XPathFactory features to set. + * @param fences The fences guarding Path resolution. + * @return The XmlStringLookup singleton instance. + * @since 1.12.0 + */ + public StringLookup xmlStringLookup(final Map<String, Boolean> xPathFactoryFeatures, final Path... fences) { + return new XmlStringLookup(xPathFactoryFeatures, fences); + } } diff --git a/src/main/java/org/apache/commons/text/lookup/XmlStringLookup.java b/src/main/java/org/apache/commons/text/lookup/XmlStringLookup.java index f3bdd0aa..27aada14 100644 --- a/src/main/java/org/apache/commons/text/lookup/XmlStringLookup.java +++ b/src/main/java/org/apache/commons/text/lookup/XmlStringLookup.java @@ -19,7 +19,7 @@ package org.apache.commons.text.lookup; import java.io.InputStream; import java.nio.file.Files; -import java.nio.file.Paths; +import java.nio.file.Path; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; @@ -42,12 +42,12 @@ import org.xml.sax.InputSource; * * @since 1.5 */ -final class XmlStringLookup extends AbstractStringLookup { +final class XmlStringLookup extends AbstractPathFencedLookup { /** * Defines default XPath factory features. */ - private static final Map<String, Boolean> DEFAULT_FEATURES; + static final Map<String, Boolean> DEFAULT_FEATURES; static { DEFAULT_FEATURES = new HashMap<>(1); @@ -57,7 +57,7 @@ final class XmlStringLookup extends AbstractStringLookup { /** * Defines the singleton for this class. */ - static final XmlStringLookup INSTANCE = new XmlStringLookup(DEFAULT_FEATURES); + static final XmlStringLookup INSTANCE = new XmlStringLookup(DEFAULT_FEATURES, (Path[]) null); /** * Defines XPath factory features. @@ -70,7 +70,8 @@ final class XmlStringLookup extends AbstractStringLookup { * @param xPathFactoryFeatures XPathFactory features to set. * @see XPathFactory#setFeature(String, boolean) */ - XmlStringLookup(final Map<String, Boolean> xPathFactoryFeatures) { + XmlStringLookup(final Map<String, Boolean> xPathFactoryFeatures, final Path... fences) { + super(fences); this.xPathFactoryFeatures = Objects.requireNonNull(xPathFactoryFeatures, "xPathFfactoryFeatures"); } @@ -96,7 +97,7 @@ final class XmlStringLookup extends AbstractStringLookup { } final String documentPath = keys[0]; final String xpath = StringUtils.substringAfter(key, SPLIT_CH); - try (InputStream inputStream = Files.newInputStream(Paths.get(documentPath))) { + try (InputStream inputStream = Files.newInputStream(getPath(documentPath))) { final XPathFactory factory = XPathFactory.newInstance(); for (final Entry<String, Boolean> p : xPathFactoryFeatures.entrySet()) { factory.setFeature(p.getKey(), p.getValue()); diff --git a/src/test/java/org/apache/commons/text/lookup/FileStringLookupTest.java b/src/test/java/org/apache/commons/text/lookup/FileStringLookupTest.java index c8467d3e..c9dd6742 100644 --- a/src/test/java/org/apache/commons/text/lookup/FileStringLookupTest.java +++ b/src/test/java/org/apache/commons/text/lookup/FileStringLookupTest.java @@ -33,6 +33,8 @@ import org.junit.jupiter.api.Test; */ public class FileStringLookupTest { + private static final Path CURRENT_PATH = Paths.get(StringUtils.EMPTY); + @Test public void testDefaultInstanceBadCharsetName() { assertThrows(IllegalArgumentException.class, @@ -78,8 +80,7 @@ public class FileStringLookupTest { public void testFenceBadDirPlusGoodOne() throws Exception { final byte[] expectedBytes = Files.readAllBytes(Paths.get("src/test/resources/org/apache/commons/text/document.properties")); final String expectedString = new String(expectedBytes, StandardCharsets.UTF_8); - final Path currentPath = Paths.get(StringUtils.EMPTY); - final FileStringLookup fileStringLookup = new FileStringLookup(Paths.get("dir does not exist at all"), currentPath); + final FileStringLookup fileStringLookup = new FileStringLookup(Paths.get("dir does not exist at all"), CURRENT_PATH); Assertions.assertEquals(expectedString, fileStringLookup.lookup("UTF-8:src/test/resources/org/apache/commons/text/document.properties")); assertThrows(IllegalArgumentException.class, () -> fileStringLookup.lookup("UTF-8:/src/test/resources/org/apache/commons/text/document.properties")); } @@ -88,8 +89,7 @@ public class FileStringLookupTest { public void testFenceCurrentDirOne() throws Exception { final byte[] expectedBytes = Files.readAllBytes(Paths.get("src/test/resources/org/apache/commons/text/document.properties")); final String expectedString = new String(expectedBytes, StandardCharsets.UTF_8); - final Path currentPath = Paths.get(StringUtils.EMPTY); - final FileStringLookup fileStringLookup = new FileStringLookup(currentPath); + final FileStringLookup fileStringLookup = new FileStringLookup(CURRENT_PATH); Assertions.assertEquals(expectedString, fileStringLookup.lookup("UTF-8:src/test/resources/org/apache/commons/text/document.properties")); assertThrows(IllegalArgumentException.class, () -> fileStringLookup.lookup("UTF-8:/src/test/resources/org/apache/commons/text/document.properties")); } @@ -98,8 +98,7 @@ public class FileStringLookupTest { public void testFenceCurrentDirPlusOne() throws Exception { final byte[] expectedBytes = Files.readAllBytes(Paths.get("src/test/resources/org/apache/commons/text/document.properties")); final String expectedString = new String(expectedBytes, StandardCharsets.UTF_8); - final Path currentPath = Paths.get(StringUtils.EMPTY); - final FileStringLookup fileStringLookup = new FileStringLookup(Paths.get("target"), currentPath); + final FileStringLookup fileStringLookup = new FileStringLookup(Paths.get("target"), CURRENT_PATH); Assertions.assertEquals(expectedString, fileStringLookup.lookup("UTF-8:src/test/resources/org/apache/commons/text/document.properties")); assertThrows(IllegalArgumentException.class, () -> fileStringLookup.lookup("UTF-8:/src/test/resources/org/apache/commons/text/document.properties")); } diff --git a/src/test/java/org/apache/commons/text/lookup/PropertiesStringLookupTest.java b/src/test/java/org/apache/commons/text/lookup/PropertiesStringLookupTest.java index 26aacf3f..a296c6d5 100644 --- a/src/test/java/org/apache/commons/text/lookup/PropertiesStringLookupTest.java +++ b/src/test/java/org/apache/commons/text/lookup/PropertiesStringLookupTest.java @@ -25,6 +25,7 @@ import java.nio.file.Paths; import java.util.HashMap; import java.util.Map; +import org.apache.commons.lang3.StringUtils; import org.apache.commons.text.StringSubstitutor; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -35,7 +36,7 @@ import org.junit.jupiter.api.Test; public class PropertiesStringLookupTest { private static final Path[] NULL_PATH_ARRAY = null; - private static final Path CURRENT_PATH = Paths.get(""); // NOT "."! + private static final Path CURRENT_PATH = Paths.get(StringUtils.EMPTY); // NOT "."! private static final String DOC_RELATIVE = "src/test/resources/org/apache/commons/text/document.properties"; private static final String DOC_ROOT = "/foo.txt"; private static final String KEY = "mykey"; diff --git a/src/test/java/org/apache/commons/text/lookup/XmlStringLookupTest.java b/src/test/java/org/apache/commons/text/lookup/XmlStringLookupTest.java index 12211597..04784970 100644 --- a/src/test/java/org/apache/commons/text/lookup/XmlStringLookupTest.java +++ b/src/test/java/org/apache/commons/text/lookup/XmlStringLookupTest.java @@ -24,10 +24,13 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.HashMap; import javax.xml.XMLConstants; +import org.apache.commons.lang3.StringUtils; import org.junit.jupiter.api.Test; /** @@ -35,12 +38,15 @@ import org.junit.jupiter.api.Test; */ public class XmlStringLookupTest { - private static final String DOC_PATH = "src/test/resources/org/apache/commons/text/document.xml"; + private static final Path CURRENT_PATH = Paths.get(StringUtils.EMPTY); // NOT "." + private static final Path ABSENT_PATH = Paths.get("does not exist at all"); + private static final String DOC_RELATIVE = "src/test/resources/org/apache/commons/text/document.xml"; + private static final String DOC_ROOT = "/document.xml"; static void assertLookup(final StringLookup xmlStringLookup) { assertNotNull(xmlStringLookup); assertTrue(xmlStringLookup instanceof XmlStringLookup); - assertEquals("Hello World!", xmlStringLookup.lookup(DOC_PATH + ":/root/path/to/node")); + assertEquals("Hello World!", xmlStringLookup.lookup(DOC_RELATIVE + ":/root/path/to/node")); assertNull(xmlStringLookup.lookup(null)); } @@ -51,13 +57,19 @@ public class XmlStringLookupTest { @Test public void testMissingXPath() { - assertThrows(IllegalArgumentException.class, () -> XmlStringLookup.INSTANCE.lookup(DOC_PATH + ":" + "!JUNK!")); + assertThrows(IllegalArgumentException.class, () -> XmlStringLookup.INSTANCE.lookup(DOC_RELATIVE + ":" + "!JUNK!")); } @Test public void testNoFeatures() { final String xpath = "/root/path/to/node"; - assertEquals("Hello World!", new XmlStringLookup(new HashMap<>()).lookup(DOC_PATH + ":" + xpath)); + assertEquals("Hello World!", new XmlStringLookup(new HashMap<>()).lookup(DOC_RELATIVE + ":" + xpath)); + assertEquals("Hello World!", new XmlStringLookup(new HashMap<>(), CURRENT_PATH).lookup(DOC_RELATIVE + ":" + xpath)); + assertEquals("Hello World!", new XmlStringLookup(new HashMap<>(), CURRENT_PATH, ABSENT_PATH).lookup(DOC_RELATIVE + ":" + xpath)); + assertEquals("Hello World!", new XmlStringLookup(new HashMap<>(), ABSENT_PATH, CURRENT_PATH).lookup(DOC_RELATIVE + ":" + xpath)); + assertThrows(IllegalArgumentException.class, () -> new XmlStringLookup(new HashMap<>(), ABSENT_PATH).lookup(DOC_ROOT + ":" + xpath)); + assertThrows(IllegalArgumentException.class, () -> new XmlStringLookup(new HashMap<>(), CURRENT_PATH).lookup(DOC_ROOT + ":" + xpath)); + assertThrows(IllegalArgumentException.class, () -> new XmlStringLookup(new HashMap<>(), ABSENT_PATH, CURRENT_PATH).lookup(DOC_ROOT + ":" + xpath)); } @Test