Provide a setting to allow a client to skip the escaping of special HTML characters.

As well, remove the "/" from the list of special HTML characters since it is causing some incompatibilities.
This commit is contained in:
Joel Leitch 2008-12-28 23:05:22 +00:00
parent 1c87bd5993
commit 73d93e3322
11 changed files with 211 additions and 105 deletions

View File

@ -36,32 +36,35 @@ import java.util.Set;
*/ */
class Escaper { class Escaper {
static final char[] HEX_CHARS = { private static final char[] HEX_CHARS = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
}; };
private static final Set<Character> JS_ESCAPE_CHARS; private static final Set<Character> JS_ESCAPE_CHARS;
private static final Set<Character> HTML_ESCAPE_CHARS;
static { static {
Set<Character> tmpSet = new HashSet<Character>(); Set<Character> mandatoryEscapeSet = new HashSet<Character>();
tmpSet.add('\u0000'); mandatoryEscapeSet.add('"');
tmpSet.add('\r'); mandatoryEscapeSet.add('\\');
tmpSet.add('\n'); JS_ESCAPE_CHARS = Collections.unmodifiableSet(mandatoryEscapeSet);
tmpSet.add('\u2028');
tmpSet.add('\u2029'); Set<Character> htmlEscapeSet = new HashSet<Character>();
tmpSet.add('\u0085'); htmlEscapeSet.add('<');
tmpSet.add('\''); htmlEscapeSet.add('>');
tmpSet.add('"'); htmlEscapeSet.add('&');
tmpSet.add('<'); htmlEscapeSet.add('=');
tmpSet.add('>'); // htmlEscapeSet.add('/'); -- Removing slash for now since it causes some incompatibilities
tmpSet.add('&'); HTML_ESCAPE_CHARS = Collections.unmodifiableSet(htmlEscapeSet);
tmpSet.add('=');
tmpSet.add('/');
tmpSet.add('\\');
JS_ESCAPE_CHARS = Collections.unmodifiableSet(tmpSet);
} }
public static String escapeJsonString(CharSequence plainText) { private final boolean escapeHtmlCharacters;
Escaper(boolean escapeHtmlCharacters) {
this.escapeHtmlCharacters = escapeHtmlCharacters;
}
public String escapeJsonString(CharSequence plainText) {
StringBuffer escapedString = new StringBuffer(plainText.length() + 20); StringBuffer escapedString = new StringBuffer(plainText.length() + 20);
try { try {
escapeJsonString(plainText, escapedString); escapeJsonString(plainText, escapedString);
@ -71,9 +74,10 @@ class Escaper {
return escapedString.toString(); return escapedString.toString();
} }
private static void escapeJsonString(CharSequence plainText, StringBuffer out) throws IOException { private void escapeJsonString(CharSequence plainText, StringBuffer out) throws IOException {
int pos = 0; // Index just past the last char in plainText written to out. int pos = 0; // Index just past the last char in plainText written to out.
int len = plainText.length(); int len = plainText.length();
for (int charCount, i = 0; i < len; i += charCount) { for (int charCount, i = 0; i < len; i += charCount) {
int codePoint = Character.codePointAt(plainText, i); int codePoint = Character.codePointAt(plainText, i);
charCount = Character.charCount(codePoint); charCount = Character.charCount(codePoint);
@ -109,9 +113,6 @@ class Escaper {
case '"': case '"':
out.append('\\').append((char) codePoint); out.append('\\').append((char) codePoint);
break; break;
case '\'':
out.append((char) codePoint);
break;
default: default:
appendHexJavaScriptRepresentation(codePoint, out); appendHexJavaScriptRepresentation(codePoint, out);
break; break;
@ -120,6 +121,16 @@ class Escaper {
out.append(plainText, pos, len); out.append(plainText, pos, len);
} }
private boolean mustEscapeCharInJsString(int codepoint) {
if (!Character.isSupplementaryCodePoint(codepoint)) {
char c = (char) codepoint;
return JS_ESCAPE_CHARS.contains(c)
|| (escapeHtmlCharacters && HTML_ESCAPE_CHARS.contains(c));
} else {
return false;
}
}
private static boolean isControlCharacter(int codePoint) { private static boolean isControlCharacter(int codePoint) {
// JSON spec defines these code points as control characters, so they must be escaped // JSON spec defines these code points as control characters, so they must be escaped
return codePoint < 0x20 return codePoint < 0x20
@ -146,12 +157,4 @@ class Escaper {
.append(HEX_CHARS[(codePoint >>> 4) & 0xf]) .append(HEX_CHARS[(codePoint >>> 4) & 0xf])
.append(HEX_CHARS[codePoint & 0xf]); .append(HEX_CHARS[codePoint & 0xf]);
} }
private static boolean mustEscapeCharInJsString(int codepoint) {
if (!Character.isSupplementaryCodePoint(codepoint)) {
return JS_ESCAPE_CHARS.contains((char)codepoint);
} else {
return false;
}
}
} }

View File

@ -207,6 +207,31 @@ public final class GsonBuilder {
return this; return this;
} }
/**
* Configures Gson to output Json that fits in a page for pretty printing. This option only
* affects Json serialization.
*
* @param escapeHtmlChars true if specific HTML characters should be escaped
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
* @since 1.3
*/
public GsonBuilder setPrettyPrinting(boolean escapeHtmlChars) {
setFormatter(new JsonPrintFormatter(escapeHtmlChars));
return this;
}
/**
* Configures Gson to output Json in a compact format.
*
* @param escapeHtmlChars true if specific HTML characters should be escaped
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
* @since 1.3
*/
public GsonBuilder setCompactPrinting(boolean escapeHtmlChars) {
setFormatter(new JsonCompactFormatter(escapeHtmlChars));
return this;
}
/** /**
* Configures Gson with a new formatting strategy other than the default strategy. The default * Configures Gson with a new formatting strategy other than the default strategy. The default
* strategy is to provide a compact representation that eliminates all unneeded white-space. * strategy is to provide a compact representation that eliminates all unneeded white-space.

View File

@ -125,13 +125,23 @@ final class JsonCompactFormatter implements JsonFormatter {
} }
} }
private final boolean escapeHtmlChars;
JsonCompactFormatter() {
this(true);
}
JsonCompactFormatter(boolean escapeHtmlChars) {
this.escapeHtmlChars = escapeHtmlChars;
}
public void format(JsonElement root, Appendable writer, public void format(JsonElement root, Appendable writer,
boolean serializeNulls) throws IOException { boolean serializeNulls) throws IOException {
if (root == null) { if (root == null) {
return; return;
} }
JsonElementVisitor visitor = JsonElementVisitor visitor = new JsonEscapingVisitor(
new JsonEscapingVisitor(new FormattingVisitor(writer, serializeNulls)); new FormattingVisitor(writer, serializeNulls), escapeHtmlChars);
JsonTreeNavigator navigator = new JsonTreeNavigator(visitor, serializeNulls); JsonTreeNavigator navigator = new JsonTreeNavigator(visitor, serializeNulls);
navigator.navigate(root); navigator.navigate(root);
} }

View File

@ -25,14 +25,20 @@ import java.io.IOException;
* @author Joel Leitch * @author Joel Leitch
*/ */
class JsonEscapingVisitor extends DelegatingJsonElementVisitor { class JsonEscapingVisitor extends DelegatingJsonElementVisitor {
private final Escaper escaper;
/** /**
* Constructs a Visitor that will properly escape any JSON primitive values. * Constructs a Visitor that will properly escape any JSON primitive values.
* *
* @param delegate the JsonElementVisitor that this instance will use for delegation * @param delegate the JsonElementVisitor that this instance will use for delegation
*/ */
protected JsonEscapingVisitor(JsonElementVisitor delegate) { protected JsonEscapingVisitor(JsonElementVisitor delegate, boolean escapeHtmlChars) {
this(delegate, new Escaper(escapeHtmlChars));
}
protected JsonEscapingVisitor(JsonElementVisitor delegate, Escaper escaper) {
super(delegate); super(delegate);
this.escaper = escaper;
} }
@Override @Override
@ -55,7 +61,7 @@ class JsonEscapingVisitor extends DelegatingJsonElementVisitor {
private JsonPrimitive escapeJsonPrimitive(JsonPrimitive member) { private JsonPrimitive escapeJsonPrimitive(JsonPrimitive member) {
if (member.isString()) { if (member.isString()) {
String memberValue = member.getAsString(); String memberValue = member.getAsString();
String escapedValue = Escaper.escapeJsonString(memberValue); String escapedValue = escaper.escapeJsonString(memberValue);
if (!escapedValue.equals(memberValue)) { if (!escapedValue.equals(memberValue)) {
member.setValue(escapedValue); member.setValue(escapedValue);
} }

View File

@ -32,19 +32,26 @@ final class JsonPrintFormatter implements JsonFormatter {
private final int printMargin; private final int printMargin;
private final int indentationSize; private final int indentationSize;
private final int rightMargin; private final int rightMargin;
private final boolean escapeHtmlChars;
public static final int DEFAULT_PRINT_MARGIN = 80; public static final int DEFAULT_PRINT_MARGIN = 80;
public static final int DEFAULT_INDENTATION_SIZE = 2; public static final int DEFAULT_INDENTATION_SIZE = 2;
public static final int DEFAULT_RIGHT_MARGIN = 4; public static final int DEFAULT_RIGHT_MARGIN = 4;
public JsonPrintFormatter() { JsonPrintFormatter() {
this(DEFAULT_PRINT_MARGIN, DEFAULT_INDENTATION_SIZE, DEFAULT_RIGHT_MARGIN); this(true);
} }
public JsonPrintFormatter(int printMargin, int indentationSize, int rightMargin) { JsonPrintFormatter(boolean escapeHtmlChars) {
this(DEFAULT_PRINT_MARGIN, DEFAULT_INDENTATION_SIZE, DEFAULT_RIGHT_MARGIN, escapeHtmlChars);
}
JsonPrintFormatter(int printMargin, int indentationSize, int rightMargin,
boolean escapeHtmlChars) {
this.printMargin = printMargin; this.printMargin = printMargin;
this.indentationSize = indentationSize; this.indentationSize = indentationSize;
this.rightMargin = rightMargin; this.rightMargin = rightMargin;
this.escapeHtmlChars = escapeHtmlChars;
} }
private class JsonWriter { private class JsonWriter {
@ -234,8 +241,8 @@ final class JsonPrintFormatter implements JsonFormatter {
return; return;
} }
JsonWriter jsonWriter = new JsonWriter(writer); JsonWriter jsonWriter = new JsonWriter(writer);
JsonElementVisitor visitor = JsonElementVisitor visitor = new JsonEscapingVisitor(
new JsonEscapingVisitor(new PrintFormattingVisitor(jsonWriter, serializeNulls)); new PrintFormattingVisitor(jsonWriter, serializeNulls), escapeHtmlChars);
JsonTreeNavigator navigator = new JsonTreeNavigator(visitor, serializeNulls); JsonTreeNavigator navigator = new JsonTreeNavigator(visitor, serializeNulls);
navigator.navigate(root); navigator.navigate(root);
jsonWriter.finishLine(); jsonWriter.finishLine();

View File

@ -0,0 +1,12 @@
package com.google.gson;
public class TestCharacters {
public static void main(String[] args) {
System.out.println("\\b: " + Character.codePointAt("\b", 0));
System.out.println("\\r: " + Character.codePointAt("\r", 0));
System.out.println("\\n: " + Character.codePointAt("\n", 0));
System.out.println("\\t: " + Character.codePointAt("\t", 0));
System.out.println("': " + Character.codePointAt("'", 0));
}
}

View File

@ -25,52 +25,62 @@ import junit.framework.TestCase;
*/ */
public class EscaperTest extends TestCase { public class EscaperTest extends TestCase {
private Escaper escapeHtmlChar;
private Escaper noEscapeHtmlChar;
@Override
protected void setUp() throws Exception {
super.setUp();
escapeHtmlChar = new Escaper(true);
noEscapeHtmlChar = new Escaper(false);
}
public void testNoSpecialCharacters() { public void testNoSpecialCharacters() {
String value = "Testing123"; String value = "Testing123";
String escapedString = Escaper.escapeJsonString(value); String escapedString = escapeHtmlChar.escapeJsonString(value);
assertEquals(value, escapedString); assertEquals(value, escapedString);
} }
public void testNewlineEscaping() throws Exception { public void testNewlineEscaping() throws Exception {
String containsNewline = "123\n456"; String containsNewline = "123\n456";
String escapedString = Escaper.escapeJsonString(containsNewline); String escapedString = escapeHtmlChar.escapeJsonString(containsNewline);
assertEquals("123\\n456", escapedString); assertEquals("123\\n456", escapedString);
} }
public void testCarrageReturnEscaping() throws Exception { public void testCarrageReturnEscaping() throws Exception {
String containsCarrageReturn = "123\r456"; String containsCarrageReturn = "123\r456";
String escapedString = Escaper.escapeJsonString(containsCarrageReturn); String escapedString = escapeHtmlChar.escapeJsonString(containsCarrageReturn);
assertEquals("123\\r456", escapedString); assertEquals("123\\r456", escapedString);
} }
public void testTabEscaping() throws Exception { public void testTabEscaping() throws Exception {
String containsTab = "123\t456"; String containsTab = "123\t456";
String escapedString = Escaper.escapeJsonString(containsTab); String escapedString = escapeHtmlChar.escapeJsonString(containsTab);
assertEquals("123\\t456", escapedString); assertEquals("123\\t456", escapedString);
} }
public void testQuoteEscaping() throws Exception { public void testQuoteEscaping() throws Exception {
String containsQuote = "123\"456"; String containsQuote = "123\"456";
String escapedString = Escaper.escapeJsonString(containsQuote); String escapedString = escapeHtmlChar.escapeJsonString(containsQuote);
assertEquals("123\\\"456", escapedString); assertEquals("123\\\"456", escapedString);
} }
public void testLineSeparatorEscaping() throws Exception { public void testLineSeparatorEscaping() throws Exception {
String src = "123\u2028 456"; String src = "123\u2028 456";
String escapedString = Escaper.escapeJsonString(src); String escapedString = escapeHtmlChar.escapeJsonString(src);
assertEquals("123\\u2028 456", escapedString); assertEquals("123\\u2028 456", escapedString);
} }
public void testParagraphSeparatorEscaping() throws Exception { public void testParagraphSeparatorEscaping() throws Exception {
String src = "123\u2029 456"; String src = "123\u2029 456";
String escapedString = Escaper.escapeJsonString(src); String escapedString = escapeHtmlChar.escapeJsonString(src);
assertEquals("123\\u2029 456", escapedString); assertEquals("123\\u2029 456", escapedString);
} }
public void testControlCharBlockEscaping() throws Exception { public void testControlCharBlockEscaping() throws Exception {
for (char c = '\u007f'; c <= '\u009f'; ++c) { for (char c = '\u007f'; c <= '\u009f'; ++c) {
String src = "123 " + c + " 456"; String src = "123 " + c + " 456";
String escapedString = Escaper.escapeJsonString(src); String escapedString = escapeHtmlChar.escapeJsonString(src);
assertFalse(src.equals(escapedString)); assertFalse(src.equals(escapedString));
} }
} }
@ -79,8 +89,11 @@ public class EscaperTest extends TestCase {
String containsEquals = "123=456"; String containsEquals = "123=456";
int index = containsEquals.indexOf('='); int index = containsEquals.indexOf('=');
String unicodeValue = convertToUnicodeString(Character.codePointAt(containsEquals, index)); String unicodeValue = convertToUnicodeString(Character.codePointAt(containsEquals, index));
String escapedString = Escaper.escapeJsonString(containsEquals); String escapedString = escapeHtmlChar.escapeJsonString(containsEquals);
assertEquals("123" + unicodeValue + "456", escapedString); assertEquals("123" + unicodeValue + "456", escapedString);
escapedString = noEscapeHtmlChar.escapeJsonString(containsEquals);
assertEquals(containsEquals, escapedString);
} }
public void testGreaterThanAndLessThanEscaping() throws Exception { public void testGreaterThanAndLessThanEscaping() throws Exception {
@ -90,8 +103,11 @@ public class EscaperTest extends TestCase {
String gtAsUnicode = convertToUnicodeString(Character.codePointAt(containsLtGt, gtIndex)); String gtAsUnicode = convertToUnicodeString(Character.codePointAt(containsLtGt, gtIndex));
String ltAsUnicode = convertToUnicodeString(Character.codePointAt(containsLtGt, ltIndex)); String ltAsUnicode = convertToUnicodeString(Character.codePointAt(containsLtGt, ltIndex));
String escapedString = Escaper.escapeJsonString(containsLtGt); String escapedString = escapeHtmlChar.escapeJsonString(containsLtGt);
assertEquals("123" + gtAsUnicode + "456" + ltAsUnicode, escapedString); assertEquals("123" + gtAsUnicode + "456" + ltAsUnicode, escapedString);
escapedString = noEscapeHtmlChar.escapeJsonString(containsLtGt);
assertEquals(containsLtGt, escapedString);
} }
public void testAmpersandEscaping() throws Exception { public void testAmpersandEscaping() throws Exception {
@ -99,24 +115,30 @@ public class EscaperTest extends TestCase {
int ampIndex = containsAmp.indexOf('&'); int ampIndex = containsAmp.indexOf('&');
String ampAsUnicode = convertToUnicodeString(Character.codePointAt(containsAmp, ampIndex)); String ampAsUnicode = convertToUnicodeString(Character.codePointAt(containsAmp, ampIndex));
String escapedString = Escaper.escapeJsonString(containsAmp); String escapedString = escapeHtmlChar.escapeJsonString(containsAmp);
assertEquals("123" + ampAsUnicode + "456", escapedString); assertEquals("123" + ampAsUnicode + "456", escapedString);
escapedString = noEscapeHtmlChar.escapeJsonString(containsAmp);
assertEquals(containsAmp, escapedString);
char ampCharAsUnicode = '\u0026'; char ampCharAsUnicode = '\u0026';
String containsAmpUnicode = "123" + ampCharAsUnicode + "456"; String containsAmpUnicode = "123" + ampCharAsUnicode + "456";
escapedString = Escaper.escapeJsonString(containsAmpUnicode); escapedString = escapeHtmlChar.escapeJsonString(containsAmpUnicode);
assertEquals("123" + ampAsUnicode + "456", escapedString); assertEquals("123" + ampAsUnicode + "456", escapedString);
escapedString = noEscapeHtmlChar.escapeJsonString(containsAmpUnicode);
assertEquals(containsAmp, escapedString);
} }
public void testSlashEscaping() throws Exception { public void testSlashEscaping() throws Exception {
String containsSlash = "123\\456"; String containsSlash = "123\\456";
String escapedString = Escaper.escapeJsonString(containsSlash); String escapedString = escapeHtmlChar.escapeJsonString(containsSlash);
assertEquals("123\\\\456", escapedString); assertEquals("123\\\\456", escapedString);
} }
public void testSingleQuoteNotEscaped() throws Exception { public void testSingleQuoteNotEscaped() throws Exception {
String containsSingleQuote = "123'456"; String containsSingleQuote = "123'456";
String escapedString = Escaper.escapeJsonString(containsSingleQuote); String escapedString = escapeHtmlChar.escapeJsonString(containsSingleQuote);
assertEquals(containsSingleQuote, escapedString); assertEquals(containsSingleQuote, escapedString);
} }
@ -124,7 +146,7 @@ public class EscaperTest extends TestCase {
char unicodeChar = '\u2028'; char unicodeChar = '\u2028';
String unicodeString = "Testing" + unicodeChar; String unicodeString = "Testing" + unicodeChar;
String escapedString = Escaper.escapeJsonString(unicodeString); String escapedString = escapeHtmlChar.escapeJsonString(unicodeString);
assertFalse(unicodeString.equals(escapedString)); assertFalse(unicodeString.equals(escapedString));
assertEquals("Testing\\u2028", escapedString); assertEquals("Testing\\u2028", escapedString);
} }
@ -132,7 +154,7 @@ public class EscaperTest extends TestCase {
public void testUnicodeCharacterStringNoEscaping() throws Exception { public void testUnicodeCharacterStringNoEscaping() throws Exception {
String unicodeString = "\u0065\u0066"; String unicodeString = "\u0065\u0066";
String escapedString = Escaper.escapeJsonString(unicodeString); String escapedString = escapeHtmlChar.escapeJsonString(unicodeString);
assertEquals(unicodeString, escapedString); assertEquals(unicodeString, escapedString);
} }

View File

@ -60,7 +60,8 @@ public class FunctionalWithInternalDependenciesTest extends TestCase {
} }
public void testPrettyPrintList() { public void testPrettyPrintList() {
JsonFormatter formatter = new JsonPrintFormatter(PRINT_MARGIN, INDENTATION_SIZE, RIGHT_MARGIN); JsonFormatter formatter = new JsonPrintFormatter(
PRINT_MARGIN, INDENTATION_SIZE, RIGHT_MARGIN, true);
Gson gson = builder.setFormatter(formatter).create(); Gson gson = builder.setFormatter(formatter).create();
BagOfPrimitives b = new BagOfPrimitives(); BagOfPrimitives b = new BagOfPrimitives();
List<BagOfPrimitives> listOfB = new LinkedList<BagOfPrimitives>(); List<BagOfPrimitives> listOfB = new LinkedList<BagOfPrimitives>();
@ -74,7 +75,8 @@ public class FunctionalWithInternalDependenciesTest extends TestCase {
} }
public void testPrettyPrintArrayOfObjects() { public void testPrettyPrintArrayOfObjects() {
JsonFormatter formatter = new JsonPrintFormatter(PRINT_MARGIN, INDENTATION_SIZE, RIGHT_MARGIN); JsonFormatter formatter = new JsonPrintFormatter(
PRINT_MARGIN, INDENTATION_SIZE, RIGHT_MARGIN, true);
Gson gson = builder.setFormatter(formatter).create(); Gson gson = builder.setFormatter(formatter).create();
ArrayOfObjects target = new ArrayOfObjects(); ArrayOfObjects target = new ArrayOfObjects();
String json = gson.toJson(target); String json = gson.toJson(target);
@ -83,7 +85,8 @@ public class FunctionalWithInternalDependenciesTest extends TestCase {
} }
public void testPrettyPrintArrayOfPrimitives() { public void testPrettyPrintArrayOfPrimitives() {
JsonFormatter formatter = new JsonPrintFormatter(PRINT_MARGIN, INDENTATION_SIZE, RIGHT_MARGIN); JsonFormatter formatter = new JsonPrintFormatter(
PRINT_MARGIN, INDENTATION_SIZE, RIGHT_MARGIN, true);
Gson gson = builder.setFormatter(formatter).create(); Gson gson = builder.setFormatter(formatter).create();
int[] ints = new int[] { 1, 2, 3, 4, 5 }; int[] ints = new int[] { 1, 2, 3, 4, 5 };
String json = gson.toJson(ints); String json = gson.toJson(ints);
@ -91,7 +94,8 @@ public class FunctionalWithInternalDependenciesTest extends TestCase {
} }
public void testPrettyPrintArrayOfPrimitiveArrays() { public void testPrettyPrintArrayOfPrimitiveArrays() {
JsonFormatter formatter = new JsonPrintFormatter(PRINT_MARGIN, INDENTATION_SIZE, RIGHT_MARGIN); JsonFormatter formatter = new JsonPrintFormatter(
PRINT_MARGIN, INDENTATION_SIZE, RIGHT_MARGIN, true);
Gson gson = builder.setFormatter(formatter).create(); Gson gson = builder.setFormatter(formatter).create();
int[][] ints = new int[][] { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 }, { 9, 0 }, { 10 } }; int[][] ints = new int[][] { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 }, { 9, 0 }, { 10 } };
String json = gson.toJson(ints); String json = gson.toJson(ints);
@ -99,7 +103,8 @@ public class FunctionalWithInternalDependenciesTest extends TestCase {
} }
public void testPrettyPrintListOfPrimitiveArrays() { public void testPrettyPrintListOfPrimitiveArrays() {
JsonFormatter formatter = new JsonPrintFormatter(PRINT_MARGIN, INDENTATION_SIZE, RIGHT_MARGIN); JsonFormatter formatter = new JsonPrintFormatter(
PRINT_MARGIN, INDENTATION_SIZE, RIGHT_MARGIN, true);
Gson gson = builder.setFormatter(formatter).create(); Gson gson = builder.setFormatter(formatter).create();
List<Integer[]> list = Arrays.asList(new Integer[][] { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 }, List<Integer[]> list = Arrays.asList(new Integer[][] { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 },
{ 9, 0 }, { 10 } }); { 9, 0 }, { 10 } });
@ -108,7 +113,8 @@ public class FunctionalWithInternalDependenciesTest extends TestCase {
} }
public void testMultipleArrays() { public void testMultipleArrays() {
JsonFormatter formatter = new JsonPrintFormatter(PRINT_MARGIN, INDENTATION_SIZE, RIGHT_MARGIN); JsonFormatter formatter = new JsonPrintFormatter(
PRINT_MARGIN, INDENTATION_SIZE, RIGHT_MARGIN, true);
Gson gson = builder.setFormatter(formatter).create(); Gson gson = builder.setFormatter(formatter).create();
int[][][] ints = new int[][][] { { { 1 }, { 2 } } }; int[][][] ints = new int[][][] { { { 1 }, { 2 } } };
String json = gson.toJson(ints); String json = gson.toJson(ints);

View File

@ -26,12 +26,14 @@ import junit.framework.TestCase;
public class JsonEscapingVisitorTest extends TestCase { public class JsonEscapingVisitorTest extends TestCase {
private StubbedJsonElementVisitor stubVisitor; private StubbedJsonElementVisitor stubVisitor;
private JsonEscapingVisitor escapingVisitor; private JsonEscapingVisitor escapingVisitor;
private Escaper escaper;
@Override @Override
protected void setUp() throws Exception { protected void setUp() throws Exception {
super.setUp(); super.setUp();
stubVisitor = new StubbedJsonElementVisitor(); stubVisitor = new StubbedJsonElementVisitor();
escapingVisitor = new JsonEscapingVisitor(stubVisitor); escaper = new Escaper(true);
escapingVisitor = new JsonEscapingVisitor(stubVisitor, escaper);
} }
public void testNonStringPrimitiveVisitation() throws Exception { public void testNonStringPrimitiveVisitation() throws Exception {
@ -52,7 +54,7 @@ public class JsonEscapingVisitorTest extends TestCase {
String value = "Testing\"123"; String value = "Testing\"123";
JsonPrimitive primitive = new JsonPrimitive(value); JsonPrimitive primitive = new JsonPrimitive(value);
escapingVisitor.visitPrimitive(primitive); escapingVisitor.visitPrimitive(primitive);
assertEquals(Escaper.escapeJsonString(value), stubVisitor.primitiveReceived.getAsString()); assertEquals(escaper.escapeJsonString(value), stubVisitor.primitiveReceived.getAsString());
} }
public void testNonStringArrayVisitation() throws Exception { public void testNonStringArrayVisitation() throws Exception {
@ -79,7 +81,7 @@ public class JsonEscapingVisitorTest extends TestCase {
JsonArray array = new JsonArray(); JsonArray array = new JsonArray();
array.add(primitive); array.add(primitive);
escapingVisitor.visitArrayMember(array, primitive, true); escapingVisitor.visitArrayMember(array, primitive, true);
assertEquals(Escaper.escapeJsonString(value), stubVisitor.primitiveReceived.getAsString()); assertEquals(escaper.escapeJsonString(value), stubVisitor.primitiveReceived.getAsString());
} }
public void testNonStringFieldVisitation() throws Exception { public void testNonStringFieldVisitation() throws Exception {
@ -112,7 +114,7 @@ public class JsonEscapingVisitorTest extends TestCase {
object.addProperty(fieldName, value); object.addProperty(fieldName, value);
escapingVisitor.visitObjectMember(object, fieldName, primitive, true); escapingVisitor.visitObjectMember(object, fieldName, primitive, true);
assertEquals(Escaper.escapeJsonString(value), stubVisitor.primitiveReceived.getAsString()); assertEquals(escaper.escapeJsonString(value), stubVisitor.primitiveReceived.getAsString());
} }
private static class StubbedJsonElementVisitor implements JsonElementVisitor { private static class StubbedJsonElementVisitor implements JsonElementVisitor {

View File

@ -52,7 +52,7 @@ public class DefaultTypeAdaptersTest extends TestCase {
public void testUrlSerialization() throws Exception { public void testUrlSerialization() throws Exception {
String urlValue = "http://google.com/"; String urlValue = "http://google.com/";
URL url = new URL(urlValue); URL url = new URL(urlValue);
assertEquals("\"http:\\/\\/google.com\\/\"", gson.toJson(url)); assertEquals("\"http://google.com/\"", gson.toJson(url));
} }
public void testUrlDeserialization() { public void testUrlDeserialization() {
@ -60,6 +60,9 @@ public class DefaultTypeAdaptersTest extends TestCase {
String json = "'http:\\/\\/google.com\\/'"; String json = "'http:\\/\\/google.com\\/'";
URL target = gson.fromJson(json, URL.class); URL target = gson.fromJson(json, URL.class);
assertEquals(urlValue, target.toExternalForm()); assertEquals(urlValue, target.toExternalForm());
gson.fromJson('"' + urlValue + '"', URL.class);
assertEquals(urlValue, target.toExternalForm());
} }
public void testUrlNullSerialization() throws Exception { public void testUrlNullSerialization() throws Exception {
@ -80,7 +83,7 @@ public class DefaultTypeAdaptersTest extends TestCase {
public void testUriSerialization() throws Exception { public void testUriSerialization() throws Exception {
String uriValue = "http://google.com/"; String uriValue = "http://google.com/";
URI uri = new URI(uriValue); URI uri = new URI(uriValue);
assertEquals("\"http:\\/\\/google.com\\/\"", gson.toJson(uri)); assertEquals("\"http://google.com/\"", gson.toJson(uri));
} }
public void testUriDeserialization() { public void testUriDeserialization() {

View File

@ -547,4 +547,14 @@ public class PrimitiveTest extends TestCase {
value = gson.fromJson("\"25\"", long.class); value = gson.fromJson("\"25\"", long.class);
assertEquals(25, value); assertEquals(25, value);
} }
public void testHtmlCharacterSerialization() throws Exception {
String target = "<script>var a = 12;</script>";
String result = gson.toJson(target);
assertFalse(result.equals('"' + target + '"'));
gson = new GsonBuilder().setCompactPrinting(false).create();
result = gson.toJson(target);
assertTrue(result.equals('"' + target + '"'));
}
} }