Make JsonValue serializable
This enables storing JsonValues in the HTTP session on the server
Bug: Issue 8364
Change-Id: I3c43b27dc2b86f16060170b425b9754a8a5d3d54
diff --git a/elemental/src/elemental/json/JsonValue.java b/elemental/src/elemental/json/JsonValue.java
index f4f2154..c0de7ab 100644
--- a/elemental/src/elemental/json/JsonValue.java
+++ b/elemental/src/elemental/json/JsonValue.java
@@ -15,10 +15,12 @@
*/
package elemental.json;
+import java.io.Serializable;
+
/**
* Base interface for all Json values.
*/
-public interface JsonValue {
+public interface JsonValue extends Serializable {
/**
* Coerces underlying value to boolean according to the rules of Javascript coercion.
diff --git a/elemental/src/elemental/json/impl/JreJsonArray.java b/elemental/src/elemental/json/impl/JreJsonArray.java
index 5a6a240..c31ba33 100644
--- a/elemental/src/elemental/json/impl/JreJsonArray.java
+++ b/elemental/src/elemental/json/impl/JreJsonArray.java
@@ -15,9 +15,13 @@
*/
package elemental.json.impl;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;
+import elemental.json.Json;
import elemental.json.JsonArray;
import elemental.json.JsonBoolean;
import elemental.json.JsonFactory;
@@ -32,9 +36,11 @@
*/
public class JreJsonArray extends JreJsonValue implements JsonArray {
- private ArrayList<JsonValue> arrayValues = new ArrayList<JsonValue>();
+ private static final long serialVersionUID = 1L;
- private JsonFactory factory;
+ private transient ArrayList<JsonValue> arrayValues = new ArrayList<JsonValue>();
+
+ private transient JsonFactory factory;
public JreJsonArray(JsonFactory factory) {
this.factory = factory;
@@ -162,4 +168,16 @@
}
visitor.endVisit(this, ctx);
}
+
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
+ JreJsonArray instance = parseJson(stream);
+ this.factory = Json.instance();
+ this.arrayValues = instance.arrayValues;
+ }
+
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ stream.writeObject(toJson());
+ }
+
}
diff --git a/elemental/src/elemental/json/impl/JreJsonBoolean.java b/elemental/src/elemental/json/impl/JreJsonBoolean.java
index a947fd3..e48895f 100644
--- a/elemental/src/elemental/json/impl/JreJsonBoolean.java
+++ b/elemental/src/elemental/json/impl/JreJsonBoolean.java
@@ -15,6 +15,11 @@
*/
package elemental.json.impl;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import elemental.json.Json;
import elemental.json.JsonBoolean;
import elemental.json.JsonType;
import elemental.json.JsonValue;
@@ -24,7 +29,9 @@
*/
public class JreJsonBoolean extends JreJsonValue implements JsonBoolean {
- private boolean bool;
+ private static final long serialVersionUID = 1L;
+
+ private transient boolean bool;
public JreJsonBoolean(boolean bool) {
this.bool = bool;
}
@@ -69,4 +76,15 @@
public String toJson() throws IllegalStateException {
return String.valueOf(bool);
}
+
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
+ JreJsonBoolean instance = parseJson(stream);
+ this.bool = instance.bool;
+ }
+
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ stream.writeObject(toJson());
+ }
+
}
diff --git a/elemental/src/elemental/json/impl/JreJsonNull.java b/elemental/src/elemental/json/impl/JreJsonNull.java
index 25acab1..7336417 100644
--- a/elemental/src/elemental/json/impl/JreJsonNull.java
+++ b/elemental/src/elemental/json/impl/JreJsonNull.java
@@ -15,6 +15,11 @@
*/
package elemental.json.impl;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamException;
+
import elemental.json.JsonNull;
import elemental.json.JsonType;
import elemental.json.JsonValue;
@@ -24,6 +29,8 @@
*/
public class JreJsonNull extends JreJsonValue implements JsonNull {
+ private static final long serialVersionUID = 1L;
+
public static final JsonNull NULL_INSTANCE = new JreJsonNull();
@Override
@@ -62,4 +69,9 @@
public String toJson() {
return null;
}
+
+ private Object readResolve() throws ObjectStreamException {
+ return NULL_INSTANCE;
+ }
+
}
diff --git a/elemental/src/elemental/json/impl/JreJsonNumber.java b/elemental/src/elemental/json/impl/JreJsonNumber.java
index 4fb2842..26c6e61 100644
--- a/elemental/src/elemental/json/impl/JreJsonNumber.java
+++ b/elemental/src/elemental/json/impl/JreJsonNumber.java
@@ -15,6 +15,11 @@
*/
package elemental.json.impl;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import elemental.json.Json;
import elemental.json.JsonNumber;
import elemental.json.JsonType;
import elemental.json.JsonValue;
@@ -24,7 +29,9 @@
*/
public class JreJsonNumber extends JreJsonValue implements JsonNumber {
- private double number;
+ private static final long serialVersionUID = 1L;
+
+ private transient double number;
public JreJsonNumber(double number) {
this.number = number;
@@ -74,4 +81,14 @@
}
return toReturn;
}
+
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
+ JreJsonNumber instance = parseJson(stream);
+ this.number = instance.number;
+ }
+
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ stream.writeObject(toJson());
+ }
}
diff --git a/elemental/src/elemental/json/impl/JreJsonObject.java b/elemental/src/elemental/json/impl/JreJsonObject.java
index 992f9a0..732def2 100755
--- a/elemental/src/elemental/json/impl/JreJsonObject.java
+++ b/elemental/src/elemental/json/impl/JreJsonObject.java
@@ -15,6 +15,9 @@
*/
package elemental.json.impl;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -22,6 +25,7 @@
import java.util.List;
import java.util.Map;
+import elemental.json.Json;
import elemental.json.JsonArray;
import elemental.json.JsonBoolean;
import elemental.json.JsonFactory;
@@ -36,6 +40,8 @@
*/
public class JreJsonObject extends JreJsonValue implements JsonObject {
+ private static final long serialVersionUID = 1L;
+
private static List<String> stringifyOrder(String[] keys) {
List<String> toReturn = new ArrayList<String>();
List<String> nonNumeric = new ArrayList<String>();
@@ -51,8 +57,8 @@
return toReturn;
}
- private JsonFactory factory;
- private Map<String, JsonValue> map = new LinkedHashMap<String, JsonValue>();
+ private transient JsonFactory factory;
+ private transient Map<String, JsonValue> map = new LinkedHashMap<String, JsonValue>();
public JreJsonObject(JsonFactory factory) {
this.factory = factory;
@@ -175,4 +181,16 @@
}
visitor.endVisit(this, ctx);
}
+
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
+ JreJsonObject instance = parseJson(stream);
+ this.factory = Json.instance();
+ this.map = instance.map;
+ }
+
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ stream.writeObject(toJson());
+ }
+
}
diff --git a/elemental/src/elemental/json/impl/JreJsonString.java b/elemental/src/elemental/json/impl/JreJsonString.java
index f282245..690ea10 100644
--- a/elemental/src/elemental/json/impl/JreJsonString.java
+++ b/elemental/src/elemental/json/impl/JreJsonString.java
@@ -15,6 +15,11 @@
*/
package elemental.json.impl;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import elemental.json.Json;
import elemental.json.JsonString;
import elemental.json.JsonType;
import elemental.json.JsonValue;
@@ -24,7 +29,9 @@
*/
public class JreJsonString extends JreJsonValue implements JsonString {
- private String string;
+ private static final long serialVersionUID = 1L;
+
+ private transient String string;
public JreJsonString(String string) {
this.string = string;
@@ -78,4 +85,15 @@
public String toJson() throws IllegalStateException {
return JsonUtil.quote(getString());
}
+
+ private void readObject(ObjectInputStream stream) throws IOException,
+ ClassNotFoundException {
+ JreJsonString instance = parseJson(stream);
+ this.string = instance.string;
+ }
+
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ stream.writeObject(toJson());
+ }
+
}
diff --git a/elemental/src/elemental/json/impl/JreJsonValue.java b/elemental/src/elemental/json/impl/JreJsonValue.java
index 313f8fb..94eccca 100644
--- a/elemental/src/elemental/json/impl/JreJsonValue.java
+++ b/elemental/src/elemental/json/impl/JreJsonValue.java
@@ -15,6 +15,10 @@
*/
package elemental.json.impl;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+
+import elemental.json.Json;
import elemental.json.JsonValue;
/**
@@ -28,4 +32,10 @@
public Object toNative() {
return this;
}
+
+ protected static <T extends JsonValue> T parseJson(ObjectInputStream stream)
+ throws ClassNotFoundException, IOException {
+ String jsonString = (String) stream.readObject();
+ return Json.instance().parse(jsonString);
+ }
}
diff --git a/elemental/tests/elemental/json/impl/JreJsonSerialization.java b/elemental/tests/elemental/json/impl/JreJsonSerialization.java
new file mode 100644
index 0000000..a3097a7
--- /dev/null
+++ b/elemental/tests/elemental/json/impl/JreJsonSerialization.java
@@ -0,0 +1,114 @@
+package elemental.json.impl;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+
+import junit.framework.TestCase;
+import elemental.json.Json;
+import elemental.json.JsonArray;
+import elemental.json.JsonNull;
+import elemental.json.JsonObject;
+import elemental.json.JsonValue;
+
+public class JreJsonSerialization extends TestCase {
+
+ public void testSerializeNull() throws Exception {
+ JsonNull null1 = Json.createNull();
+ JsonNull null2 = Json.createNull();
+ JsonValue out = serializeDeserialize(null1);
+ assertJsonEquals(null1, out);
+ assertSame(null1, out);
+ assertSame(null2, out);
+ assertSame(JreJsonNull.NULL_INSTANCE, out);
+ }
+
+ public void testSerializeObject() throws Exception {
+ JsonObject foo = Json.createObject();
+ foo.put("true", true);
+ foo.put("string", "string");
+ foo.put("number", 1.25);
+
+ JsonObject subObject = Json.createObject();
+ subObject.put("false", false);
+ subObject.put("string2", "string2");
+ subObject.put("number", -151);
+
+ JsonArray subArray = Json.createArray();
+ subArray.set(0, true);
+ subArray.set(1, 1);
+ subArray.set(2, "2");
+
+ foo.put("object", subObject);
+ foo.put("array", subArray);
+ foo.put("null", Json.createNull());
+
+ assertJsonEqualsAfterSerialization(foo);
+ }
+
+ public void testSerializeArray() throws Exception {
+ JsonObject subObject = Json.createObject();
+ subObject.put("false", false);
+ subObject.put("string2", "string2");
+ subObject.put("number", -151);
+
+ JsonArray subArray = Json.createArray();
+ subArray.set(0, true);
+ subArray.set(1, 1);
+ subArray.set(2, "2");
+
+ JsonArray array = Json.createArray();
+ array.set(0, true);
+ array.set(1, false);
+ array.set(2, 2);
+ array.set(3, "3");
+ array.set(4, subObject);
+ array.set(5, subArray);
+
+ assertJsonEqualsAfterSerialization(array);
+ }
+
+ public void testSerializeBoolean() throws Exception {
+ assertJsonEqualsAfterSerialization(Json.create(true));
+ assertJsonEqualsAfterSerialization(Json.create(false));
+ }
+
+ public void testSerializeString() throws Exception {
+ assertJsonEqualsAfterSerialization(Json.create("foo"));
+ assertJsonEqualsAfterSerialization(Json.create(""));
+ }
+
+ public void testSerializeNumber() throws Exception {
+ assertJsonEqualsAfterSerialization(Json.create(0));
+ assertJsonEqualsAfterSerialization(Json.create(-1.213123123));
+ }
+
+ private <T extends Serializable & JsonValue> void assertJsonEqualsAfterSerialization(
+ T in) throws Exception {
+ T out = serializeDeserialize(in);
+ assertNotSame(in, out);
+ assertJsonEquals(in, out);
+ }
+
+ private void assertJsonEquals(JsonValue a, JsonValue b) {
+ assertEquals(a.toJson(), b.toJson());
+ }
+
+ @SuppressWarnings("unchecked")
+ public <T extends Serializable & JsonValue> T serializeDeserialize(
+ T originalJsonValue) throws Exception {
+ ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+ ObjectOutputStream out = new ObjectOutputStream(buffer);
+ out.writeObject(originalJsonValue);
+ out.close();
+
+ ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(
+ buffer.toByteArray()));
+ T processedJsonValue = (T) in.readObject();
+ in.close();
+ return processedJsonValue;
+ }
+
+}