This is an automated email from the ASF dual-hosted git repository.
jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git
The following commit(s) were added to refs/heads/master by this push:
new 80b8200 Tests.
80b8200 is described below
commit 80b8200ec3a02498e51425d8654be629e3777285
Author: JamesBognar <[email protected]>
AuthorDate: Fri Jul 6 17:46:27 2018 -0400
Tests.
---
.../juneau/httppart/OpenApiPartParserTest.java | 30 ++++
.../juneau/httppart/OpenApiPartSerializerTest.java | 77 +++++----
.../org/apache/juneau/utils/StringUtilsTest.java | 59 +++----
.../org/apache/juneau/http/HeaderStringArray.java | 2 +-
.../juneau/httppart/OpenApiPartSerializer.java | 4 +-
.../java/org/apache/juneau/internal/AsciiSet.java | 13 ++
.../org/apache/juneau/internal/StringUtils.java | 177 +++++++++++++++------
.../org/apache/juneau/svl/VarResolverSession.java | 14 +-
8 files changed, 254 insertions(+), 122 deletions(-)
diff --git
a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/OpenApiPartParserTest.java
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/OpenApiPartParserTest.java
index 6ab32fa..f3fb701 100644
---
a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/OpenApiPartParserTest.java
+++
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/OpenApiPartParserTest.java
@@ -364,6 +364,36 @@ public class OpenApiPartParserTest {
assertObjectEquals("['C3-[\\'foo\\',\\'bar\\']','C3-[\\'baz\\']']", p.parse(s,
"foo,bar|baz", List.class, C3.class));
}
+ @Test
+ public void c12a_stringType_nullKeyword_plain() throws Exception {
+ HttpPartSchema s = schema("string").build();
+ assertEquals("null", p.parse(s, "null", String.class));
+ }
+
+ @Test
+ public void c12b_stringType_nullKeyword_plain_2d() throws Exception {
+ HttpPartSchema s =
schema("array").items(schema("string")).build();
+ assertObjectEquals("['null']", p.parse(s, "null",
String[].class));
+ assertObjectEquals("[null]", p.parse(s, "@(null)",
String[].class));
+ }
+
+ @Test
+ public void c12c_stringType_nullKeyword_uon() throws Exception {
+ HttpPartSchema s = schema("string","uon").build();
+ assertEquals(null, p.parse(s, "null", String.class));
+ assertEquals("null", p.parse(s, "'null'", String.class));
+ }
+
+ @Test
+ public void c12d_stringType_nullKeyword_uon_2d() throws Exception {
+ HttpPartSchema s =
schema("array").items(schema("string","uon")).build();
+ assertObjectEquals("[null,'x']", p.parse(s, "null,x",
String[].class));
+ assertObjectEquals("[null]", p.parse(s, "null",
String[].class));
+ assertObjectEquals("[null]", p.parse(s, "@(null)",
String[].class));
+ assertObjectEquals("['null']", p.parse(s, "'null'",
String[].class));
+ assertObjectEquals("['null']", p.parse(s, "@('null')",
String[].class));
+ }
+
//-----------------------------------------------------------------------------------------------------------------
// type = array
//-----------------------------------------------------------------------------------------------------------------
diff --git
a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/OpenApiPartSerializerTest.java
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/OpenApiPartSerializerTest.java
index 840f561..ee43059 100644
---
a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/OpenApiPartSerializerTest.java
+++
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/OpenApiPartSerializerTest.java
@@ -339,25 +339,27 @@ public class OpenApiPartSerializerTest {
@Test
public void d01_arrayType_collectionFormatCsv() throws Exception {
HttpPartSchema ps =
schema("array").collectionFormat("csv").build();
- assertEquals("foo,bar", s.serialize(ps, new
String[]{"foo","bar"}));
- assertEquals("foo,bar", s.serialize(ps, new
Object[]{"foo","bar"}));
- assertEquals("D-foo,D-bar", s.serialize(ps, new D[]{new
D("foo"),new D("bar")}));
- assertEquals("foo,bar", s.serialize(ps,
AList.create("foo","bar")));
- assertEquals("foo,bar", s.serialize(ps,
AList.<Object>create("foo","bar")));
- assertEquals("D-foo,D-bar", s.serialize(ps, AList.create(new
D("foo"),new D("bar"))));
- assertEquals("foo,bar", s.serialize(ps, new
ObjectList().append("foo","bar")));
+ assertEquals("foo,bar,null", s.serialize(ps, new
String[]{"foo","bar",null}));
+ assertEquals("foo,bar,null", s.serialize(ps, new
Object[]{"foo","bar",null}));
+ assertEquals("D-foo,D-bar,null", s.serialize(ps, new D[]{new
D("foo"),new D("bar"),null}));
+ assertEquals("foo,bar,null", s.serialize(ps,
AList.create("foo","bar",null)));
+ assertEquals("foo,bar,null", s.serialize(ps,
AList.<Object>create("foo","bar",null)));
+ assertEquals("D-foo,D-bar,null", s.serialize(ps,
AList.create(new D("foo"),new D("bar"),null)));
+ assertEquals("foo,bar,null", s.serialize(ps, new
ObjectList().append("foo","bar",null)));
+
+ assertEquals("foo\\,bar,null", s.serialize(ps, new
String[]{"foo,bar",null}));
}
@Test
public void d02_arrayType_collectionFormatPipes() throws Exception {
HttpPartSchema ps =
schema("array").collectionFormat("pipes").build();
- assertEquals("foo|bar", s.serialize(ps, new
String[]{"foo","bar"}));
- assertEquals("foo|bar", s.serialize(ps, new
Object[]{"foo","bar"}));
- assertEquals("D-foo|D-bar", s.serialize(ps, new D[]{new
D("foo"),new D("bar")}));
- assertEquals("foo|bar", s.serialize(ps,
AList.create("foo","bar")));
- assertEquals("foo|bar", s.serialize(ps,
AList.<Object>create("foo","bar")));
- assertEquals("D-foo|D-bar", s.serialize(ps, AList.create(new
D("foo"),new D("bar"))));
- assertEquals("foo|bar", s.serialize(ps, new
ObjectList().append("foo","bar")));
+ assertEquals("foo|bar|null", s.serialize(ps, new
String[]{"foo","bar",null}));
+ assertEquals("foo|bar|null", s.serialize(ps, new
Object[]{"foo","bar",null}));
+ assertEquals("D-foo|D-bar|null", s.serialize(ps, new D[]{new
D("foo"),new D("bar"),null}));
+ assertEquals("foo|bar|null", s.serialize(ps,
AList.create("foo","bar",null)));
+ assertEquals("foo|bar|null", s.serialize(ps,
AList.<Object>create("foo","bar",null)));
+ assertEquals("D-foo|D-bar|null", s.serialize(ps,
AList.create(new D("foo"),new D("bar"),null)));
+ assertEquals("foo|bar|null", s.serialize(ps, new
ObjectList().append("foo","bar",null)));
}
@Test
@@ -477,7 +479,7 @@ public class OpenApiPartSerializerTest {
public void e02_booleanType_2d() throws Exception {
HttpPartSchema ps =
schema("array").items(schema("boolean")).build();
assertEquals("true,true", s.serialize(ps, new
boolean[]{true,true}));
- assertEquals("true,true", s.serialize(ps, new
Boolean[]{true,true}));
+ assertEquals("true,null", s.serialize(ps, new
Boolean[]{true,null}));
assertEquals("true,true", s.serialize(ps,
AList.create(true,true)));
assertEquals("true,true", s.serialize(ps, new
String[]{"true","true"}));
assertEquals("true,true", s.serialize(ps,
AList.create("true","true")));
@@ -488,30 +490,27 @@ public class OpenApiPartSerializerTest {
assertEquals("true,true", s.serialize(ps, new E2(true,true)));
}
- // @Test
-// public void e03_booleanType_3d() throws Exception {
-// HttpPartSchema ps =
schema("array").collectionFormat("pipes").items(schema("array").items(schema("boolean"))).build();
-// assertEquals("[[true,true],[false]]", s.serialize(ps,
"true,true|false", boolean[][].class));
-// assertEquals("[[true,true],[false]]", s.serialize(ps,
"true,true|false", List.class, boolean[].class));
-// assertEquals("[[true,true],[false]]", s.serialize(ps,
"true,true|false", Boolean[][].class));
-// assertEquals("[[true,true],[false]]", s.serialize(ps,
"true,true|false", List.class, Boolean[].class));
-// assertEquals("[[true,true],[false]]", s.serialize(ps,
"true,true|false", List.class, List.class, Boolean.class));
-// assertEquals("[['true','true'],['false']]", s.serialize(ps,
"true,true|false", String[][].class));
-// assertEquals("[['true','true'],['false']]", s.serialize(ps,
"true,true|false", List.class, List.class, String.class));
-// assertEquals("[['true','true'],['false']]", s.serialize(ps,
"true,true|false", List.class, String[].class));
-// assertEquals("[[true,true],[false]]", s.serialize(ps,
"true,true|false", Object[][].class));
-// assertEquals("[[true,true],[false]]", s.serialize(ps,
"true,true|false", List.class, List.class, Object.class));
-// assertEquals("[[true,true],[false]]", s.serialize(ps,
"true,true|false", List.class, Object[].class));
-// assertEquals("[['E1-true','E1-true'],['E1-false']]",
s.serialize(ps, "true,true|false", E1[][].class));
-// assertEquals("[['E1-true','E1-true'],['E1-false']]",
s.serialize(ps, "true,true|false", List.class, List.class, E1.class));
-// assertEquals("[['E1-true','E1-true'],['E1-false']]",
s.serialize(ps, "true,true|false", List.class, E1[].class));
-// assertEquals("['E2-[true,true]','E2-[false]']", s.serialize(ps,
"true,true|false", E2[].class));
-// assertEquals("['E2-[true,true]','E2-[false]']", s.serialize(ps,
"true,true|false", List.class, E2.class));
-//
-// assertEquals("[[true,true],[false]]", s.serialize(ps,
"True,true|false", boolean[][].class));
-// assertEquals("[[true,true],[false]]", s.serialize(ps,
"TRUE,true|false", boolean[][].class));
-// }
-//
+ @Test
+ public void e03_booleanType_3d() throws Exception {
+ HttpPartSchema ps =
schema("array").collectionFormat("pipes").items(schema("array").items(schema("boolean"))).build();
+ assertEquals("true,true|false", s.serialize(ps, new
boolean[][]{{true,true},{false}}));
+ assertEquals("true,true|false", s.serialize(ps,
AList.create(new boolean[]{true,true},new boolean[]{false})));
+ assertEquals("true,true|false,null", s.serialize(ps, new
Boolean[][]{{true,true},{false,null}}));
+ assertEquals("true,true|false,null", s.serialize(ps,
AList.create(new Boolean[]{true,true},new Boolean[]{false,null})));
+ assertEquals("true,true|false,null", s.serialize(ps,
AList.create(AList.create(true,true),AList.create(false,null))));
+ assertEquals("true,true|false,null", s.serialize(ps, new
String[][]{{"true","true"},{"false",null}}));
+ assertEquals("true,true|false,null", s.serialize(ps,
AList.create(AList.create("true","true"),AList.create("false",null))));
+ assertEquals("true,true|false,null", s.serialize(ps,
AList.create(new String[]{"true","true"},new String[]{"false",null})));
+ assertEquals("true,true|false,null", s.serialize(ps, new
Object[][]{{true,true},{false,null}}));
+ assertEquals("true,true|false,null", s.serialize(ps,
AList.create(AList.create((Object)true,(Object)true),AList.create((Object)false,null))));
+ assertEquals("true,true|false,null", s.serialize(ps,
AList.create(new Object[]{true,true},new Object[]{false,null})));
+ assertEquals("true,true|false,null", s.serialize(ps, new
E1[][]{{new E1(true),new E1(true)},{new E1(false),new E1(null)}}));
+ assertEquals("true,true|false,null", s.serialize(ps,
AList.create(AList.create(new E1(true),new E1(true)), AList.create(new
E1(false),new E1(null)))));
+ assertEquals("true,true|false,null", s.serialize(ps,
AList.create(new E1[]{new E1(true),new E1(true)},new E1[]{new E1(false),new
E1(null)})));
+ assertEquals("true,true|false,null", s.serialize(ps, new
E2[]{new E2(true,true),new E2(false,null)}));
+ assertEquals("true,true|false,null", s.serialize(ps,
AList.create(new E2(true,true),new E2(false,null))));
+ }
+
//
//-----------------------------------------------------------------------------------------------------------------
// // type = integer
//
//-----------------------------------------------------------------------------------------------------------------
diff --git
a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/utils/StringUtilsTest.java
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/utils/StringUtilsTest.java
index 0e7086a..657f4a7 100755
---
a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/utils/StringUtilsTest.java
+++
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/utils/StringUtilsTest.java
@@ -21,6 +21,7 @@ import java.util.*;
import java.util.concurrent.atomic.*;
import org.apache.juneau.*;
+import org.apache.juneau.internal.*;
import org.apache.juneau.json.*;
import org.apache.juneau.parser.*;
import org.apache.juneau.serializer.*;
@@ -464,8 +465,10 @@ public class StringUtilsTest {
assertEquals("1,2", join(Arrays.asList(new Integer[]{1,2}),
","));
assertNull(join((Object[])null, ','));
- assertEquals("1", join(new Object[]{1}, ','));
- assertEquals("1,2", join(new Object[]{1,2}, ','));
+ assertEquals("x,y,z", join(new Object[]{"x,y","z"}, ','));
+
+ assertNull(joine((Object[])null, ','));
+ assertEquals("x\\,y,z", joine(new Object[]{"x,y","z"}, ','));
assertNull(join((int[])null, ','));
assertEquals("1", join(new int[]{1}, ','));
@@ -474,6 +477,9 @@ public class StringUtilsTest {
assertNull(join((Collection<?>)null, ','));
assertEquals("1", join(Arrays.asList(new Integer[]{1}), ','));
assertEquals("1,2", join(Arrays.asList(new Integer[]{1,2}),
','));
+
+ assertNull(joine((Collection<?>)null, ','));
+ assertEquals("x\\,y,z", joine(Arrays.asList(new
String[]{"x,y","z"}), ','));
}
//====================================================================================================
@@ -555,25 +561,22 @@ public class StringUtilsTest {
//====================================================================================================
@Test
public void testUnescapeChars() throws Exception {
- char[] toEscape = {'\\',',','|'};
- char escape = '\\';
+ AsciiSet escape = AsciiSet.create("\\,|");
- assertNull(unEscapeChars(null, toEscape, escape));
- assertEquals("xxx", unEscapeChars("xxx", new char[0], escape));
- assertEquals("xxx", unEscapeChars("xxx", null, escape));
- assertEquals("xxx", unEscapeChars("xxx", toEscape, (char)0));
+ assertNull(unEscapeChars(null, escape));
+ assertEquals("xxx", unEscapeChars("xxx", escape));
- assertEquals("xxx", unEscapeChars("xxx", toEscape, escape));
- assertEquals("x,xx", unEscapeChars("x\\,xx", toEscape, escape));
- assertEquals("x\\xx", unEscapeChars("x\\xx", toEscape, escape));
- assertEquals("x\\,xx", unEscapeChars("x\\\\,xx", toEscape,
escape));
- assertEquals("x\\,xx", unEscapeChars("x\\\\\\,xx", toEscape,
escape));
- assertEquals("\\", unEscapeChars("\\", toEscape, escape));
- assertEquals(",", unEscapeChars("\\,", toEscape, escape));
- assertEquals("|", unEscapeChars("\\|", toEscape, escape));
+ assertEquals("xxx", unEscapeChars("xxx", escape));
+ assertEquals("x,xx", unEscapeChars("x\\,xx", escape));
+ assertEquals("x\\xx", unEscapeChars("x\\xx", escape));
+ assertEquals("x\\,xx", unEscapeChars("x\\\\,xx", escape));
+ assertEquals("x\\,xx", unEscapeChars("x\\\\\\,xx", escape));
+ assertEquals("\\", unEscapeChars("\\", escape));
+ assertEquals(",", unEscapeChars("\\,", escape));
+ assertEquals("|", unEscapeChars("\\|", escape));
- toEscape = new char[] {',','|'};
- assertEquals("x\\\\xx", unEscapeChars("x\\\\xx", toEscape,
escape));
+ escape = AsciiSet.create(",|");
+ assertEquals("x\\\\xx", unEscapeChars("x\\\\xx", escape));
}
//====================================================================================================
@@ -735,16 +738,16 @@ public class StringUtilsTest {
//====================================================================================================
@Test
public void testSplitMap() {
- assertObjectEquals("{a:'1'}", splitMap("a=1", ',', '=', true));
- assertObjectEquals("{a:'1',b:'2'}", splitMap("a=1,b=2", ',',
'=', true));
- assertObjectEquals("{a:'1',b:'2'}", splitMap(" a = 1 , b = 2 ",
',', '=', true));
- assertObjectEquals("{' a ':' 1 ',' b ':' 2 '}", splitMap(" a =
1 , b = 2 ", ',', '=', false));
- assertObjectEquals("{a:''}", splitMap("a", ',', '=', true));
- assertObjectEquals("{a:'',b:''}", splitMap("a,b", ',', '=',
true));
- assertObjectEquals("{a:'1',b:''}", splitMap("a=1,b", ',', '=',
true));
- assertObjectEquals("{a:'',b:'1'}", splitMap("a,b=1", ',', '=',
true));
- assertObjectEquals("{'a=':'1'}", splitMap("a\\==1", ',', '=',
true));
- assertObjectEquals("{'a\\\\':'1'}", splitMap("a\\\\=1", ',',
'=', true));
+ assertObjectEquals("{a:'1'}", splitMap("a=1", true));
+ assertObjectEquals("{a:'1',b:'2'}", splitMap("a=1,b=2", true));
+ assertObjectEquals("{a:'1',b:'2'}", splitMap(" a = 1 , b = 2 ",
true));
+ assertObjectEquals("{' a ':' 1 ',' b ':' 2 '}", splitMap(" a =
1 , b = 2 ", false));
+ assertObjectEquals("{a:''}", splitMap("a", true));
+ assertObjectEquals("{a:'',b:''}", splitMap("a,b", true));
+ assertObjectEquals("{a:'1',b:''}", splitMap("a=1,b", true));
+ assertObjectEquals("{a:'',b:'1'}", splitMap("a,b=1", true));
+ assertObjectEquals("{'a=':'1'}", splitMap("a\\==1", true));
+ assertObjectEquals("{'a\\\\':'1'}", splitMap("a\\\\=1", true));
}
//====================================================================================================
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/HeaderStringArray.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/HeaderStringArray.java
index 58edeb4..cd2777f 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/HeaderStringArray.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/HeaderStringArray.java
@@ -50,7 +50,7 @@ public class HeaderStringArray {
* @return This header as a simple string.
*/
public String asString() {
- return StringUtils.join(value, ',');
+ return StringUtils.joine(value, ',');
}
/**
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/OpenApiPartSerializer.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/OpenApiPartSerializer.java
index 29f6e97..5c7a688 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/OpenApiPartSerializer.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/OpenApiPartSerializer.java
@@ -190,7 +190,7 @@ public class OpenApiPartSerializer extends
UonPartSerializer {
HttpPartSchema.CollectionFormat cf =
schema.getCollectionFormat();
if (cf == PIPES)
- out = join(l, '|');
+ out = joine(l, '|');
else if (cf == SSV)
out = join(l, ' ');
else if (cf == TSV)
@@ -198,7 +198,7 @@ public class OpenApiPartSerializer extends
UonPartSerializer {
else if (cf == HttpPartSchema.CollectionFormat.UON)
out = super.serialize(partType, null, l);
else
- out = join(l, ',');
+ out = joine(l, ',');
} else if (t == BOOLEAN || t == INTEGER || t == NUMBER) {
out = value == null ? "null" : value.toString();
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/AsciiSet.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/AsciiSet.java
index ebdf79d..7014b99 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/AsciiSet.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/AsciiSet.java
@@ -106,6 +106,19 @@ public final class AsciiSet {
}
/**
+ * Adds a set of characters to this set.
+ *
+ * @param chars The characters to keep in this store.
+ * @return This object (for method chaining).
+ */
+ public Builder chars(char...chars) {
+ for (int i = 0; i < chars.length; i++)
+ if (chars[i] < 128)
+ store[chars[i]] = true;
+ return this;
+ }
+
+ /**
* Create a new {@link AsciiSet} object with the contents of
this builder.
*
* @return A new {link AsciiSet} object.
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/StringUtils.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/StringUtils.java
index 452fccf..40f620a 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/StringUtils.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/StringUtils.java
@@ -22,6 +22,7 @@ import java.nio.*;
import java.nio.charset.*;
import java.text.*;
import java.util.*;
+import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.util.regex.*;
@@ -428,6 +429,29 @@ public final class StringUtils {
}
/**
+ * Same as {@link #join(Object[], char)} except escapes the delimiter
character if found in the tokens.
+ *
+ * @param tokens The tokens to join.
+ * @param d The delimiter.
+ * @return The delimited string. If <code>tokens</code> is
<jk>null</jk>, returns <jk>null</jk>.
+ */
+ public static String joine(Object[] tokens, char d) {
+ if (tokens == null)
+ return null;
+ return joine(tokens, d, new StringBuilder()).toString();
+ }
+
+ private static AsciiSet getEscapeSet(char c) {
+ AsciiSet s = ESCAPE_SETS.get(c);
+ if (s == null) {
+ s = AsciiSet.create().chars(c, '\\').build();
+ ESCAPE_SETS.put(c, s);
+ }
+ return s;
+ }
+ static Map<Character,AsciiSet> ESCAPE_SETS = new ConcurrentHashMap<>();
+
+ /**
* Join the specified tokens into a delimited string and writes the
output to the specified string builder.
*
* @param tokens The tokens to join.
@@ -447,6 +471,26 @@ public final class StringUtils {
}
/**
+ * Same as {@link #join(Object[], char, StringBuilder)} but escapes the
delimiter character if found in the tokens.
+ *
+ * @param tokens The tokens to join.
+ * @param d The delimiter.
+ * @param sb The string builder to append the response to.
+ * @return The same string builder passed in as <code>sb</code>.
+ */
+ public static StringBuilder joine(Object[] tokens, char d,
StringBuilder sb) {
+ if (tokens == null)
+ return sb;
+ AsciiSet as = getEscapeSet(d);
+ for (int i = 0; i < tokens.length; i++) {
+ if (i > 0)
+ sb.append(d);
+ sb.append(escapeChars(asString(tokens[i]), as));
+ }
+ return sb;
+ }
+
+ /**
* Join the specified tokens into a delimited string.
*
* @param tokens The tokens to join.
@@ -485,6 +529,26 @@ public final class StringUtils {
}
/**
+ * Same as {@link #join(Collection, char)} but escapes the delimiter if
found in the tokens.
+ *
+ * @param tokens The tokens to join.
+ * @param d The delimiter.
+ * @return The delimited string. If <code>tokens</code> is
<jk>null</jk>, returns <jk>null</jk>.
+ */
+ public static String joine(Collection<?> tokens, char d) {
+ if (tokens == null)
+ return null;
+ AsciiSet as = getEscapeSet(d);
+ StringBuilder sb = new StringBuilder();
+ for (Iterator<?> iter = tokens.iterator(); iter.hasNext();) {
+ sb.append(escapeChars(asString(iter.next()), as));
+ if (iter.hasNext())
+ sb.append(d);
+ }
+ return sb.toString();
+ }
+
+ /**
* Joins tokens with newlines.
*
* @param tokens The tokens to concatenate.
@@ -541,7 +605,7 @@ public final class StringUtils {
*/
public static String[] split(String s, char c, int limit) {
- char[] unEscapeChars = new char[]{'\\', c};
+ AsciiSet escapeChars = getEscapeSet(c);
if (s == null)
return null;
@@ -558,7 +622,7 @@ public final class StringUtils {
if (sArray[i] == '\\') escapeCount++;
else if (sArray[i]==c && escapeCount % 2 == 0) {
String s2 = new String(sArray, x1, i-x1);
- String s3 = unEscapeChars(s2, unEscapeChars);
+ String s3 = unEscapeChars(s2, escapeChars);
l.add(s3.trim());
limit--;
x1 = i+1;
@@ -566,7 +630,7 @@ public final class StringUtils {
if (sArray[i] != '\\') escapeCount = 0;
}
String s2 = new String(sArray, x1, sArray.length-x1);
- String s3 = unEscapeChars(s2, unEscapeChars);
+ String s3 = unEscapeChars(s2, escapeChars);
l.add(s3.trim());
return l.toArray(new String[l.size()]);
@@ -603,14 +667,10 @@ public final class StringUtils {
* </p>
*
* @param s The string to split.
- * @param delim The delimiter between the key-value pairs.
- * @param eq The delimiter between the key and value.
* @param trim Trim strings after parsing.
* @return The parsed map. Never <jk>null</jk>.
*/
- public static Map<String,String> splitMap(String s, char delim, char
eq, boolean trim) {
-
- char[] unEscapeChars = new char[]{'\\', delim, eq};
+ public static Map<String,String> splitMap(String s, boolean trim) {
if (s == null)
return null;
@@ -629,33 +689,33 @@ public final class StringUtils {
int x1 = 0, escapeCount = 0;
String key = null;
for (int i = 0; i < sArray.length + 1; i++) {
- char c = i == sArray.length ? delim : sArray[i];
+ char c = i == sArray.length ? ',' : sArray[i];
if (c == '\\')
escapeCount++;
if (escapeCount % 2 == 0) {
if (state == S1) {
- if (c == eq) {
+ if (c == '=') {
key = s.substring(x1, i);
if (trim)
key = trim(key);
- key = unEscapeChars(key,
unEscapeChars);
+ key = unEscapeChars(key,
MAP_ESCAPE_SET);
state = S2;
x1 = i+1;
- } else if (c == delim) {
+ } else if (c == ',') {
key = s.substring(x1, i);
if (trim)
key = trim(key);
- key = unEscapeChars(key,
unEscapeChars);
+ key = unEscapeChars(key,
MAP_ESCAPE_SET);
m.put(key, "");
state = S1;
x1 = i+1;
}
} else if (state == S2) {
- if (c == delim) {
+ if (c == ',') {
String val = s.substring(x1, i);
if (trim)
val = trim(val);
- val = unEscapeChars(val,
unEscapeChars);
+ val = unEscapeChars(val,
MAP_ESCAPE_SET);
m.put(key, val);
key = null;
x1 = i+1;
@@ -669,6 +729,8 @@ public final class StringUtils {
return m;
}
+ private static final AsciiSet MAP_ESCAPE_SET = AsciiSet.create(",=\\");
+
/**
* Returns <jk>true</jk> if the specified string contains any of the
specified characters.
*
@@ -710,7 +772,6 @@ public final class StringUtils {
* <br>An empty string results in an empty array.
*/
public static String[] splitQuoted(String s) {
- char[] unEscapeChars = new char[]{'\\', '\'', '"'};
if (s == null)
return null;
@@ -757,7 +818,7 @@ public final class StringUtils {
if (c == (state == S2 ? '\'' : '"')) {
String s2 = s.substring(mark,
i);
if (needsUnescape)
- s2 = unEscapeChars(s2,
unEscapeChars, '\\');
+ s2 = unEscapeChars(s2,
QUOTE_ESCAPE_SET);
l.add(s2);
state = S1;
isInEscape = needsUnescape =
false;
@@ -779,6 +840,8 @@ public final class StringUtils {
return l.toArray(new String[l.size()]);
}
+ private static final AsciiSet QUOTE_ESCAPE_SET =
AsciiSet.create("\"'\\");
+
/**
* Returns <jk>true</jk> if specified string is <jk>null</jk> or empty.
*
@@ -848,47 +911,65 @@ public final class StringUtils {
}
/**
- * Removes escape characters (\) from the specified characters.
+ * Removes escape characters from the specified characters.
*
* @param s The string to remove escape characters from.
- * @param toEscape The characters escaped.
+ * @param escaped The characters escaped.
* @return A new string if characters were removed, or the same string
if not or if the input was <jk>null</jk>.
*/
- public static String unEscapeChars(String s, char[] toEscape) {
- return unEscapeChars(s, toEscape, '\\');
- }
+ public static String unEscapeChars(String s, AsciiSet escaped) {
+ if (s == null || s.length() == 0)
+ return s;
+ int count = 0;
+ for (int i = 0; i < s.length(); i++)
+ if (escaped.contains(s.charAt(i)))
+ count++;
+ if (count == 0)
+ return s;
+ StringBuffer sb = new StringBuffer(s.length()-count);
+ for (int i = 0; i < s.length(); i++) {
+ char c = s.charAt(i);
- /**
- * Removes escape characters (specified by escapeChar) from the
specified characters.
- *
- * @param s The string to remove escape characters from.
- * @param toEscape The characters escaped.
- * @param escapeChar The escape character.
- * @return A new string if characters were removed, or the same string
if not or if the input was <jk>null</jk>.
- */
- public static String unEscapeChars(String s, char[] toEscape, char
escapeChar) {
- if (s == null) return null;
- if (s.length() == 0 || toEscape == null || toEscape.length == 0
|| escapeChar == 0) return s;
- StringBuffer sb = new StringBuffer(s.length());
- char[] sArray = s.toCharArray();
- for (int i = 0; i < sArray.length; i++) {
- char c = sArray[i];
-
- if (c == escapeChar) {
- if (i+1 != sArray.length) {
- char c2 = sArray[i+1];
- boolean isOneOf = false;
- for (int j = 0; j < toEscape.length &&
! isOneOf; j++)
- isOneOf = (c2 == toEscape[j]);
- if (isOneOf) {
+ if (c == '\\') {
+ if (i+1 != s.length()) {
+ char c2 = s.charAt(i+1);
+ if (escaped.contains(c2)) {
i++;
- } else if (c2 == escapeChar) {
- sb.append(escapeChar);
+ } else if (c2 == '\\') {
+ sb.append('\\');
i++;
}
}
}
- sb.append(sArray[i]);
+ sb.append(s.charAt(i));
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Escapes the specified characters in the string.
+ *
+ * @param s The string with characters to escape.
+ * @param escaped The characters to escape.
+ * @return The string with characters escaped, or the same string if no
escapable characters were found.
+ */
+ public static String escapeChars(String s, AsciiSet escaped) {
+ if (s == null || s.length() == 0)
+ return s;
+
+ int count = 0;
+ for (int i = 0; i < s.length(); i++)
+ if (escaped.contains(s.charAt(i)))
+ count++;
+ if (count == 0)
+ return s;
+
+ StringBuffer sb = new StringBuffer(s.length() + count);
+ for (int i = 0; i < s.length(); i++) {
+ char c = s.charAt(i);
+ if (escaped.contains(c))
+ sb.append('\\');
+ sb.append(c);
}
return sb.toString();
}
diff --git
a/juneau-core/juneau-svl/src/main/java/org/apache/juneau/svl/VarResolverSession.java
b/juneau-core/juneau-svl/src/main/java/org/apache/juneau/svl/VarResolverSession.java
index b386e85..fb8c6f0 100644
---
a/juneau-core/juneau-svl/src/main/java/org/apache/juneau/svl/VarResolverSession.java
+++
b/juneau-core/juneau-svl/src/main/java/org/apache/juneau/svl/VarResolverSession.java
@@ -18,6 +18,8 @@ import java.io.*;
import java.lang.reflect.*;
import java.util.*;
+import org.apache.juneau.internal.*;
+
/**
* A var resolver session that combines a {@link VarResolver} with one or more
session objects.
*
@@ -306,7 +308,7 @@ public class VarResolverSession {
state = S3;
} else if (c < 'A' || c > 'z' || (c > 'Z' && c
< 'a')) { // False trigger "$X "
if (hasInnerEscapes)
-
out.append(unEscapeChars(s.substring(x, i+1), new char[]{'\\','{'}));
+
out.append(unEscapeChars(s.substring(x, i+1), AS1));
else
out.append(s, x, i+1);
x = i + 1;
@@ -330,7 +332,7 @@ public class VarResolverSession {
Var r = getVar(varType);
if (r == null) {
if (hasInnerEscapes)
-
out.append(unEscapeChars(s.substring(x2, i+1), new char[]{'\\','$','{','}'}));
+
out.append(unEscapeChars(s.substring(x2, i+1), AS2));
else
out.append(s,
x2, i+1);
x = i+1;
@@ -364,12 +366,16 @@ public class VarResolverSession {
if (isInEscape)
out.append('\\');
else if (state == S2)
- out.append('$').append(unEscapeChars(s.substring(x+1),
new char[]{'{', '\\'}));
+ out.append('$').append(unEscapeChars(s.substring(x+1),
AS1));
else if (state == S3)
-
out.append('$').append(varType).append('{').append(unEscapeChars(s.substring(x+1),
new char[]{'\\','$','{','}'}));
+
out.append('$').append(varType).append('{').append(unEscapeChars(s.substring(x+1),
AS2));
return out;
}
+ private static final AsciiSet
+ AS1 = AsciiSet.create("\\{"),
+ AS2 = AsciiSet.create("\\${}")
+ ;
/**
* Returns the session object with the specified name.