You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ni...@apache.org on 2011/01/09 04:17:25 UTC
svn commit: r1056876 - in /commons/proper/lang/branches/LANG_2_X/src:
main/java/org/apache/commons/lang/text/StrSubstitutor.java
test/java/org/apache/commons/lang/text/StrSubstitutorTest.java
Author: niallp
Date: Sun Jan 9 03:17:24 2011
New Revision: 1056876
URL: http://svn.apache.org/viewvc?rev=1056876&view=rev
Log:
Port LANG-482 to LANG 2.x Branch - Enhance StrSubstitutor to support substitution in variable names
Modified:
commons/proper/lang/branches/LANG_2_X/src/main/java/org/apache/commons/lang/text/StrSubstitutor.java
commons/proper/lang/branches/LANG_2_X/src/test/java/org/apache/commons/lang/text/StrSubstitutorTest.java
Modified: commons/proper/lang/branches/LANG_2_X/src/main/java/org/apache/commons/lang/text/StrSubstitutor.java
URL: http://svn.apache.org/viewvc/commons/proper/lang/branches/LANG_2_X/src/main/java/org/apache/commons/lang/text/StrSubstitutor.java?rev=1056876&r1=1056875&r2=1056876&view=diff
==============================================================================
--- commons/proper/lang/branches/LANG_2_X/src/main/java/org/apache/commons/lang/text/StrSubstitutor.java (original)
+++ commons/proper/lang/branches/LANG_2_X/src/main/java/org/apache/commons/lang/text/StrSubstitutor.java Sun Jan 9 03:17:24 2011
@@ -86,6 +86,16 @@ import java.util.Properties;
* <pre>
* The variable $${${name}} must be used.
* </pre>
+ * <p>
+ * In some complex scenarios you might even want to perform substitution in the
+ * names of variables, for instance
+ * <pre>
+ * ${jre-${java.specification.version}}
+ * </pre>
+ * <code>StrSubstitutor</code> supports this recursive substitution in variable
+ * names, but it has to be enabled explicitly by setting the
+ * {@link #setEnableSubstitutionInVariables(boolean) enableSubstitutionInVariables}
+ * property to <b>true</b>.
*
* @author Apache Software Foundation
* @author Oliver Heger
@@ -123,6 +133,10 @@ public class StrSubstitutor {
* Variable resolution is delegated to an implementor of VariableResolver.
*/
private StrLookup variableResolver;
+ /**
+ * The flag whether substitution in variable names is enabled.
+ */
+ private boolean enableSubstitutionInVariables;
//-----------------------------------------------------------------------
/**
@@ -564,7 +578,7 @@ public class StrSubstitutor {
StrMatcher prefixMatcher = getVariablePrefixMatcher();
StrMatcher suffixMatcher = getVariableSuffixMatcher();
char escape = getEscapeChar();
-
+
boolean top = (priorVariables == null);
boolean altered = false;
int lengthChange = 0;
@@ -572,7 +586,8 @@ public class StrSubstitutor {
int bufEnd = offset + length;
int pos = offset;
while (pos < bufEnd) {
- int startMatchLen = prefixMatcher.isMatch(chars, pos, offset, bufEnd);
+ int startMatchLen = prefixMatcher.isMatch(chars, pos, offset,
+ bufEnd);
if (startMatchLen == 0) {
pos++;
} else {
@@ -580,7 +595,7 @@ public class StrSubstitutor {
if (pos > offset && chars[pos - 1] == escape) {
// escaped
buf.deleteCharAt(pos - 1);
- chars = buf.buffer; // in case buffer was altered
+ chars = buf.buffer; // in case buffer was altered
lengthChange--;
altered = true;
bufEnd--;
@@ -589,45 +604,73 @@ public class StrSubstitutor {
int startPos = pos;
pos += startMatchLen;
int endMatchLen = 0;
+ int nestedVarCount = 0;
while (pos < bufEnd) {
- endMatchLen = suffixMatcher.isMatch(chars, pos, offset, bufEnd);
+ if (isEnableSubstitutionInVariables()
+ && (endMatchLen = prefixMatcher.isMatch(chars,
+ pos, offset, bufEnd)) != 0) {
+ // found a nested variable start
+ nestedVarCount++;
+ pos += endMatchLen;
+ continue;
+ }
+
+ endMatchLen = suffixMatcher.isMatch(chars, pos, offset,
+ bufEnd);
if (endMatchLen == 0) {
pos++;
} else {
// found variable end marker
- String varName = new String(chars, startPos + startMatchLen,
- pos - startPos - startMatchLen);
- pos += endMatchLen;
- int endPos = pos;
-
- // on the first call initialize priorVariables
- if (priorVariables == null) {
- priorVariables = new ArrayList();
- priorVariables.add(new String(chars, offset, length));
- }
-
- // handle cyclic substitution
- checkCyclicSubstitution(varName, priorVariables);
- priorVariables.add(varName);
-
- // resolve the variable
- String varValue = resolveVariable(varName, buf, startPos, endPos);
- if (varValue != null) {
- // recursive replace
- int varLen = varValue.length();
- buf.replace(startPos, endPos, varValue);
- altered = true;
- int change = substitute(buf, startPos, varLen, priorVariables);
- change = change + (varLen - (endPos - startPos));
- pos += change;
- bufEnd += change;
- lengthChange += change;
- chars = buf.buffer; // in case buffer was altered
+ if (nestedVarCount == 0) {
+ String varName = new String(chars, startPos
+ + startMatchLen, pos - startPos
+ - startMatchLen);
+ if (isEnableSubstitutionInVariables()) {
+ StrBuilder bufName = new StrBuilder(varName);
+ substitute(bufName, 0, bufName.length());
+ varName = bufName.toString();
+ }
+ pos += endMatchLen;
+ int endPos = pos;
+
+ // on the first call initialize priorVariables
+ if (priorVariables == null) {
+ priorVariables = new ArrayList();
+ priorVariables.add(new String(chars,
+ offset, length));
+ }
+
+ // handle cyclic substitution
+ checkCyclicSubstitution(varName, priorVariables);
+ priorVariables.add(varName);
+
+ // resolve the variable
+ String varValue = resolveVariable(varName, buf,
+ startPos, endPos);
+ if (varValue != null) {
+ // recursive replace
+ int varLen = varValue.length();
+ buf.replace(startPos, endPos, varValue);
+ altered = true;
+ int change = substitute(buf, startPos,
+ varLen, priorVariables);
+ change = change
+ + (varLen - (endPos - startPos));
+ pos += change;
+ bufEnd += change;
+ lengthChange += change;
+ chars = buf.buffer; // in case buffer was
+ // altered
+ }
+
+ // remove variable from the cyclic stack
+ priorVariables
+ .remove(priorVariables.size() - 1);
+ break;
+ } else {
+ nestedVarCount--;
+ pos += endMatchLen;
}
-
- // remove variable from the cyclic stack
- priorVariables.remove(priorVariables.size() - 1);
- break;
}
}
}
@@ -854,4 +897,29 @@ public class StrSubstitutor {
this.variableResolver = variableResolver;
}
+ // Substitution support in variable names
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a flag whether substitution is done in variable names.
+ *
+ * @return the substitution in variable names flag
+ * @since 2.6
+ */
+ public boolean isEnableSubstitutionInVariables() {
+ return enableSubstitutionInVariables;
+ }
+
+ /**
+ * Sets a flag whether substitution is done in variable names. If set to
+ * <b>true</b>, the names of variables can contain other variables which are
+ * processed first before the original variable is evaluated, e.g.
+ * <code>${jre-${java.version}}</code>. The default value is <b>false</b>.
+ *
+ * @param enableSubstitutionInVariables the new value of the flag
+ * @since 2.6
+ */
+ public void setEnableSubstitutionInVariables(
+ boolean enableSubstitutionInVariables) {
+ this.enableSubstitutionInVariables = enableSubstitutionInVariables;
+ }
}
Modified: commons/proper/lang/branches/LANG_2_X/src/test/java/org/apache/commons/lang/text/StrSubstitutorTest.java
URL: http://svn.apache.org/viewvc/commons/proper/lang/branches/LANG_2_X/src/test/java/org/apache/commons/lang/text/StrSubstitutorTest.java?rev=1056876&r1=1056875&r2=1056876&view=diff
==============================================================================
--- commons/proper/lang/branches/LANG_2_X/src/test/java/org/apache/commons/lang/text/StrSubstitutorTest.java (original)
+++ commons/proper/lang/branches/LANG_2_X/src/test/java/org/apache/commons/lang/text/StrSubstitutorTest.java Sun Jan 9 03:17:24 2011
@@ -254,6 +254,57 @@ public class StrSubstitutorTest extends
assertEquals("${animal} jumps", sub.replace("The ${animal} jumps over the ${target}.", 4, 15));
}
+ /**
+ * Tests whether a variable can be replaced in a variable name.
+ */
+ public void testReplaceInVariable() {
+ values.put("animal.1", "fox");
+ values.put("animal.2", "mouse");
+ values.put("species", "2");
+ StrSubstitutor sub = new StrSubstitutor(values);
+ sub.setEnableSubstitutionInVariables(true);
+ assertEquals(
+ "Wrong result (1)",
+ "The mouse jumps over the lazy dog.",
+ sub.replace("The ${animal.${species}} jumps over the ${target}."));
+ values.put("species", "1");
+ assertEquals(
+ "Wrong result (2)",
+ "The fox jumps over the lazy dog.",
+ sub.replace("The ${animal.${species}} jumps over the ${target}."));
+ }
+
+ /**
+ * Tests whether substitution in variable names is disabled per default.
+ */
+ public void testReplaceInVariableDisabled() {
+ values.put("animal.1", "fox");
+ values.put("animal.2", "mouse");
+ values.put("species", "2");
+ StrSubstitutor sub = new StrSubstitutor(values);
+ assertEquals(
+ "Wrong result",
+ "The ${animal.${species}} jumps over the lazy dog.",
+ sub.replace("The ${animal.${species}} jumps over the ${target}."));
+ }
+
+ /**
+ * Tests complex and recursive substitution in variable names.
+ */
+ public void testReplaceInVariableRecursive() {
+ values.put("animal.2", "brown fox");
+ values.put("animal.1", "white mouse");
+ values.put("color", "white");
+ values.put("species.white", "1");
+ values.put("species.brown", "2");
+ StrSubstitutor sub = new StrSubstitutor(values);
+ sub.setEnableSubstitutionInVariables(true);
+ assertEquals(
+ "Wrong result",
+ "The white mouse jumps over the lazy dog.",
+ sub.replace("The ${animal.${species.${color}}} jumps over the ${target}."));
+ }
+
//-----------------------------------------------------------------------
/**
* Tests protected.