Skip to content

Commit

Permalink
Make JsonValue serializable
Browse files Browse the repository at this point in the history
This enables storing JsonValues in the HTTP session on the server

Bug: Issue 8364
Change-Id: I3c43b27dc2b86f16060170b425b9754a8a5d3d54
  • Loading branch information
Artur- committed Apr 15, 2016
1 parent 7c574ab commit 510bfaf
Show file tree
Hide file tree
Showing 9 changed files with 235 additions and 8 deletions.
4 changes: 3 additions & 1 deletion elemental/src/elemental/json/JsonValue.java
Expand Up @@ -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.
Expand Down
22 changes: 20 additions & 2 deletions elemental/src/elemental/json/impl/JreJsonArray.java
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -162,4 +168,16 @@ public void traverse(elemental.json.impl.JsonVisitor visitor,
}
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());
}

}
20 changes: 19 additions & 1 deletion elemental/src/elemental/json/impl/JreJsonBoolean.java
Expand Up @@ -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;
Expand All @@ -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;
}
Expand Down Expand Up @@ -69,4 +76,15 @@ public void traverse(elemental.json.impl.JsonVisitor visitor, JsonContext ctx) {
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());
}

}
12 changes: 12 additions & 0 deletions elemental/src/elemental/json/impl/JreJsonNull.java
Expand Up @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -62,4 +69,9 @@ public void traverse(JsonVisitor visitor, elemental.json.impl.JsonContext ctx) {
public String toJson() {
return null;
}

private Object readResolve() throws ObjectStreamException {
return NULL_INSTANCE;
}

}
19 changes: 18 additions & 1 deletion elemental/src/elemental/json/impl/JreJsonNumber.java
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -74,4 +81,14 @@ public String toJson() {
}
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());
}
}
22 changes: 20 additions & 2 deletions elemental/src/elemental/json/impl/JreJsonObject.java
Expand Up @@ -15,13 +15,17 @@
*/
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;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import elemental.json.Json;
import elemental.json.JsonArray;
import elemental.json.JsonBoolean;
import elemental.json.JsonFactory;
Expand All @@ -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>();
Expand All @@ -51,8 +57,8 @@ private static List<String> stringifyOrder(String[] keys) {
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;
Expand Down Expand Up @@ -175,4 +181,16 @@ public void traverse(JsonVisitor visitor, JsonContext ctx) {
}
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());
}

}
20 changes: 19 additions & 1 deletion elemental/src/elemental/json/impl/JreJsonString.java
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -78,4 +85,15 @@ public void traverse(JsonVisitor visitor, JsonContext ctx) {
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());
}

}
10 changes: 10 additions & 0 deletions elemental/src/elemental/json/impl/JreJsonValue.java
Expand Up @@ -15,6 +15,10 @@
*/
package elemental.json.impl;

import java.io.IOException;
import java.io.ObjectInputStream;

import elemental.json.Json;
import elemental.json.JsonValue;

/**
Expand All @@ -28,4 +32,10 @@ public abstract class JreJsonValue implements JsonValue {
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);
}
}
114 changes: 114 additions & 0 deletions 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;
}

}

0 comments on commit 510bfaf

Please sign in to comment.