Author: rwhitcomb Date: Wed Apr 22 23:26:15 2015 New Revision: 1675517 URL: http://svn.apache.org/r1675517 Log: PIVOT-967: Fix the JSONSerializer to correctly deal with special characters inside string values (especially \r and others).
Add the ability to directly support java.util.Map values in an object passed to JSONSerializer.writeObject (by instantiating a MapAdapter around the java.util.Map object). Update the JSONSerializerTest to test these changes (both read and write). Update the "map.json" with test values. Modified: pivot/trunk/core/src/org/apache/pivot/json/JSONSerializer.java pivot/trunk/core/test/org/apache/pivot/json/test/JSONSerializerTest.java pivot/trunk/core/test/org/apache/pivot/json/test/map.json Modified: pivot/trunk/core/src/org/apache/pivot/json/JSONSerializer.java URL: http://svn.apache.org/viewvc/pivot/trunk/core/src/org/apache/pivot/json/JSONSerializer.java?rev=1675517&r1=1675516&r2=1675517&view=diff ============================================================================== --- pivot/trunk/core/src/org/apache/pivot/json/JSONSerializer.java (original) +++ pivot/trunk/core/src/org/apache/pivot/json/JSONSerializer.java Wed Apr 22 23:26:15 2015 @@ -40,6 +40,7 @@ import org.apache.pivot.collections.Hash import org.apache.pivot.collections.List; import org.apache.pivot.collections.Map; import org.apache.pivot.collections.Sequence; +import org.apache.pivot.collections.adapter.MapAdapter; import org.apache.pivot.io.EchoReader; import org.apache.pivot.io.EchoWriter; import org.apache.pivot.serialization.MacroReader; @@ -378,6 +379,8 @@ public class JSONSerializer implements S c = reader.read(); while (c != -1 && c != t) { + // The JSON spec says that control characters are not supported, + // so silently ignore them if (!Character.isISOControl(c)) { if (c == '\\') { c = reader.read(); @@ -875,6 +878,21 @@ public class JSONSerializer implements S break; } + case '\r': { + stringBuilder.append("\\r"); + break; + } + + case '\f': { + stringBuilder.append("\\f"); + break; + } + + case '\b': { + stringBuilder.append("\\b"); + break; + } + case '\\': case '\"': case '\'': { @@ -883,7 +901,10 @@ public class JSONSerializer implements S } default: { - if (charset.name().startsWith("UTF") || ci <= 0xFF) { + // For Unicode character sets if it is a control character, then use \\uXXXX notation + // and for other character sets if the value is an ASCII control character. + if ((charset.name().startsWith("UTF") && !Character.isISOControl(ci)) || + (ci > 0x1F && ci != 0x7F && ci <= 0xFF)) { stringBuilder.append(ci); } else { stringBuilder.append("\\u"); @@ -932,6 +953,8 @@ public class JSONSerializer implements S Map<String, Object> map; if (object instanceof Map<?, ?>) { map = (Map<String, Object>) object; + } else if (object instanceof java.util.Map<?, ?>) { + map = new MapAdapter<>((java.util.Map<String, Object>)object); } else { map = new BeanAdapter(object, true); } Modified: pivot/trunk/core/test/org/apache/pivot/json/test/JSONSerializerTest.java URL: http://svn.apache.org/viewvc/pivot/trunk/core/test/org/apache/pivot/json/test/JSONSerializerTest.java?rev=1675517&r1=1675516&r2=1675517&view=diff ============================================================================== --- pivot/trunk/core/test/org/apache/pivot/json/test/JSONSerializerTest.java (original) +++ pivot/trunk/core/test/org/apache/pivot/json/test/JSONSerializerTest.java Wed Apr 22 23:26:15 2015 @@ -139,6 +139,7 @@ public class JSONSerializerTest { assertEquals(JSON.get(o1, "e.g"), 5); assertEquals(JSON.get(o1, "i.a"), 200); assertEquals(JSON.get(o1, "i.c"), true); + assertEquals(JSON.get(o1, "m"), "Hello\r\n\tWorld!"); jsonSerializer.getJSONSerializerListeners().remove(jsonSerializerListener); Object o2 = jsonSerializer.readObject(getClass().getResourceAsStream("map.json")); @@ -147,6 +148,7 @@ public class JSONSerializerTest { assertEquals(JSON.get(o2, "k[2].b"), 200); assertEquals(JSON.get(o2, "k[2].c"), "300"); assertEquals(JSON.get(o2, "j"), 200); + assertEquals(JSON.get(o2, "n"), "This is a \"test\" of the 'quoting' in \\JSON\\"); assertTrue(o1.equals(o2)); @@ -157,18 +159,25 @@ public class JSONSerializerTest { } @Test - public void testJavaMap() { + public void testJavaMap() throws SerializationException { System.out.println("Test interaction with Standard java.util.Map"); java.util.HashMap<String, java.util.Map<String, String>> root = new java.util.HashMap<>(); java.util.HashMap<String, String> child = new java.util.HashMap<>(); child.put("name", "John Doe"); + child.put("address", "123 Main St.\r\nAnytown USA"); root.put("child", child); String childName = JSON.get(root, "child.name"); - System.out.println("JSON child.name = \"" + childName + "\""); + String childAddr = JSON.get(root, "child.address"); + System.out.println("JSON child.name = \"" + childName + "\", child.address = \"" + childAddr + "\""); assertEquals(childName, "John Doe"); + assertEquals(childAddr, "123 Main St.\r\nAnytown USA"); + + String serializedForm = JSONSerializer.toString(root); + System.out.println("Serialized form: \"" + serializedForm + "\""); + assertEquals(serializedForm, "{child: {address: \"123 Main St.\\r\\nAnytown USA\", name: \"John Doe\"}}"); } } Modified: pivot/trunk/core/test/org/apache/pivot/json/test/map.json URL: http://svn.apache.org/viewvc/pivot/trunk/core/test/org/apache/pivot/json/test/map.json?rev=1675517&r1=1675516&r2=1675517&view=diff ============================================================================== --- pivot/trunk/core/test/org/apache/pivot/json/test/map.json (original) +++ pivot/trunk/core/test/org/apache/pivot/json/test/map.json Wed Apr 22 23:26:15 2015 @@ -29,11 +29,13 @@ { ${A_B_C}, d: ["1", "2", "${THREE}"], e: {f: 4, g: 5, h: 6}, - "i": { a: ${TWO_HUNDRED}, b: "Goodbye", c: true}, + "i": { a: ${TWO_HUNDRED}, b: "Goodbye", c: true }, j: ${TWO_HUNDRED}, k: [ {a:1, b:2, c:"${THREE}"}, {a:1${ZERO}, b:${TWENTY}, c:"${THIRTY}"}, {a:1${ZERO}${ZERO}, b:${TWO_HUNDRED}, c:"${THREE_HUNDRED}"} - ] + ], + m: "Hello\r\n\tWorld!", + n: "This is a \"test\" of the \'quoting\' in \\JSON\\" }