520 lines
18 KiB
Java
520 lines
18 KiB
Java
/*
|
|
* Copyright (C) 2008 Google Inc.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package com.google.gson.functional;
|
|
|
|
import com.google.gson.Gson;
|
|
import com.google.gson.GsonBuilder;
|
|
import com.google.gson.InstanceCreator;
|
|
import com.google.gson.JsonParseException;
|
|
import com.google.gson.common.TestTypes.ArrayOfObjects;
|
|
import com.google.gson.common.TestTypes.BagOfPrimitiveWrappers;
|
|
import com.google.gson.common.TestTypes.BagOfPrimitives;
|
|
import com.google.gson.common.TestTypes.ClassOverridingEquals;
|
|
import com.google.gson.common.TestTypes.ClassWithArray;
|
|
import com.google.gson.common.TestTypes.ClassWithNoFields;
|
|
import com.google.gson.common.TestTypes.ClassWithObjects;
|
|
import com.google.gson.common.TestTypes.ClassWithTransientFields;
|
|
import com.google.gson.common.TestTypes.MyEnum;
|
|
import com.google.gson.common.TestTypes.Nested;
|
|
import com.google.gson.common.TestTypes.PrimitiveArray;
|
|
|
|
import junit.framework.TestCase;
|
|
|
|
import java.lang.reflect.Type;
|
|
import java.util.ArrayList;
|
|
import java.util.Collection;
|
|
import java.util.LinkedList;
|
|
import java.util.List;
|
|
import java.util.Queue;
|
|
import java.util.Set;
|
|
import java.util.SortedSet;
|
|
import java.util.TreeSet;
|
|
|
|
/**
|
|
* Functional tests for Json serialization and deserialization of regular classes.
|
|
*
|
|
* @author Inderjeet Singh
|
|
* @author Joel Leitch
|
|
*/
|
|
public class ObjectTest extends TestCase {
|
|
private Gson gson;
|
|
|
|
@Override
|
|
protected void setUp() throws Exception {
|
|
super.setUp();
|
|
gson = new Gson();
|
|
}
|
|
|
|
public void testJsonInSingleQuotesDeserialization() {
|
|
String json = "{'stringValue':'no message','intValue':10,'longValue':20}";
|
|
BagOfPrimitives target = gson.fromJson(json, BagOfPrimitives.class);
|
|
assertEquals("no message", target.stringValue);
|
|
assertEquals(10, target.intValue);
|
|
assertEquals(20, target.longValue);
|
|
}
|
|
|
|
public void testJsonInMixedQuotesDeserialization() {
|
|
String json = "{\"stringValue\":'no message','intValue':10,'longValue':20}";
|
|
BagOfPrimitives target = gson.fromJson(json, BagOfPrimitives.class);
|
|
assertEquals("no message", target.stringValue);
|
|
assertEquals(10, target.intValue);
|
|
assertEquals(20, target.longValue);
|
|
}
|
|
|
|
public void testBagOfPrimitivesSerialization() throws Exception {
|
|
BagOfPrimitives target = new BagOfPrimitives(10, 20, false, "stringValue");
|
|
assertEquals(target.getExpectedJson(), gson.toJson(target));
|
|
}
|
|
|
|
public void testBagOfPrimitivesDeserialization() throws Exception {
|
|
BagOfPrimitives src = new BagOfPrimitives(10, 20, false, "stringValue");
|
|
String json = src.getExpectedJson();
|
|
BagOfPrimitives target = gson.fromJson(json, BagOfPrimitives.class);
|
|
assertEquals(json, target.getExpectedJson());
|
|
}
|
|
|
|
public void testBagOfPrimitiveWrappersSerialization() throws Exception {
|
|
BagOfPrimitiveWrappers target = new BagOfPrimitiveWrappers(10L, 20, false);
|
|
assertEquals(target.getExpectedJson(), gson.toJson(target));
|
|
}
|
|
|
|
public void testBagOfPrimitiveWrappersDeserialization() throws Exception {
|
|
BagOfPrimitiveWrappers target = new BagOfPrimitiveWrappers(10L, 20, false);
|
|
String jsonString = target.getExpectedJson();
|
|
target = gson.fromJson(jsonString, BagOfPrimitiveWrappers.class);
|
|
assertEquals(jsonString, target.getExpectedJson());
|
|
}
|
|
|
|
public void testDirectedAcyclicGraphSerialization() throws Exception {
|
|
ContainsReferenceToSelfType a = new ContainsReferenceToSelfType();
|
|
ContainsReferenceToSelfType b = new ContainsReferenceToSelfType();
|
|
ContainsReferenceToSelfType c = new ContainsReferenceToSelfType();
|
|
a.children.add(b);
|
|
a.children.add(c);
|
|
b.children.add(c);
|
|
assertNotNull(gson.toJson(a));
|
|
}
|
|
|
|
public void testDirectedAcyclicGraphDeserialization() throws Exception {
|
|
String json = "{\"children\":[{\"children\":[{\"children\":[]}]},{\"children\":[]}]}";
|
|
ContainsReferenceToSelfType target = gson.fromJson(json, ContainsReferenceToSelfType.class);
|
|
assertNotNull(target);
|
|
assertEquals(2, target.children.size());
|
|
}
|
|
|
|
public void testClassWithTransientFieldsSerialization() throws Exception {
|
|
ClassWithTransientFields target = new ClassWithTransientFields(1L);
|
|
assertEquals(target.getExpectedJson(), gson.toJson(target));
|
|
}
|
|
|
|
public void testClassWithTransientFieldsDeserialization() throws Exception {
|
|
String json = "{\"longValue\":[1]}";
|
|
ClassWithTransientFields target = gson.fromJson(json, ClassWithTransientFields.class);
|
|
assertEquals(json, target.getExpectedJson());
|
|
}
|
|
|
|
public void testClassWithTransientFieldsDeserializationTransientFieldsPassedInJsonAreIgnored()
|
|
throws Exception {
|
|
String json = "{\"transientLongValue\":1,\"longValue\":[1]}";
|
|
ClassWithTransientFields target = gson.fromJson(json, ClassWithTransientFields.class);
|
|
assertFalse(target.transientLongValue != 1);
|
|
}
|
|
|
|
public void testClassWithNoFieldsSerialization() throws Exception {
|
|
assertEquals("{}", gson.toJson(new ClassWithNoFields()));
|
|
}
|
|
|
|
public void testClassWithNoFieldsDeserialization() throws Exception {
|
|
String json = "{}";
|
|
ClassWithNoFields target = gson.fromJson(json, ClassWithNoFields.class);
|
|
ClassWithNoFields expected = new ClassWithNoFields();
|
|
assertEquals(expected, target);
|
|
}
|
|
|
|
public void testNestedSerialization() throws Exception {
|
|
Nested target = new Nested(new BagOfPrimitives(10, 20, false, "stringValue"),
|
|
new BagOfPrimitives(30, 40, true, "stringValue"));
|
|
assertEquals(target.getExpectedJson(), gson.toJson(target));
|
|
}
|
|
|
|
public void testNestedDeserialization() throws Exception {
|
|
String json = "{\"primitive1\":{\"longValue\":10,\"intValue\":20,\"booleanValue\":false,"
|
|
+ "\"stringValue\":\"stringValue\"},\"primitive2\":{\"longValue\":30,\"intValue\":40,"
|
|
+ "\"booleanValue\":true,\"stringValue\":\"stringValue\"}}";
|
|
Nested target = gson.fromJson(json, Nested.class);
|
|
assertEquals(json, target.getExpectedJson());
|
|
}
|
|
|
|
public void testInheritenceSerialization() throws Exception {
|
|
SubTypeOfNested target = new SubTypeOfNested(new BagOfPrimitives(10, 20, false, "stringValue"),
|
|
new BagOfPrimitives(30, 40, true, "stringValue"));
|
|
assertEquals(target.getExpectedJson(), gson.toJson(target));
|
|
}
|
|
|
|
public void testInheritenceDeserialization() throws Exception {
|
|
String json = "{\"value\":5,\"primitive1\":{\"longValue\":10,\"intValue\":20,"
|
|
+ "\"booleanValue\":false,\"stringValue\":\"stringValue\"},\"primitive2\":"
|
|
+ "{\"longValue\":30,\"intValue\":40,\"booleanValue\":true,"
|
|
+ "\"stringValue\":\"stringValue\"}}";
|
|
SubTypeOfNested target = gson.fromJson(json, SubTypeOfNested.class);
|
|
assertEquals(json, target.getExpectedJson());
|
|
}
|
|
|
|
public void testNullSerialization() throws Exception {
|
|
assertEquals("", gson.toJson(null));
|
|
}
|
|
|
|
public void testNullDeserialization() throws Exception {
|
|
try {
|
|
gson.fromJson("", Object.class);
|
|
fail("Null strings should not be allowed");
|
|
} catch (JsonParseException expected) {
|
|
}
|
|
}
|
|
|
|
public void testNullFieldsSerialization() throws Exception {
|
|
Nested target = new Nested(new BagOfPrimitives(10, 20, false, "stringValue"), null);
|
|
assertEquals(target.getExpectedJson(), gson.toJson(target));
|
|
}
|
|
|
|
public void testNullFieldsDeserialization() throws Exception {
|
|
String json = "{\"primitive1\":{\"longValue\":10,\"intValue\":20,\"booleanValue\":false"
|
|
+ ",\"stringValue\":\"stringValue\"}}";
|
|
Nested target = gson.fromJson(json, Nested.class);
|
|
assertEquals(json, target.getExpectedJson());
|
|
}
|
|
|
|
public void testArrayOfObjectsSerialization() throws Exception {
|
|
ArrayOfObjects target = new ArrayOfObjects();
|
|
assertEquals(target.getExpectedJson(), gson.toJson(target));
|
|
}
|
|
|
|
public void testArrayOfObjectsDeserialization() throws Exception {
|
|
String json = new ArrayOfObjects().getExpectedJson();
|
|
ArrayOfObjects target = gson.fromJson(json, ArrayOfObjects.class);
|
|
assertEquals(json, target.getExpectedJson());
|
|
}
|
|
|
|
public void testArrayOfArraysSerialization() throws Exception {
|
|
ArrayOfArrays target = new ArrayOfArrays();
|
|
assertEquals(target.getExpectedJson(), gson.toJson(target));
|
|
}
|
|
|
|
public void testArrayOfArraysDeserialization() throws Exception {
|
|
String json = new ArrayOfArrays().getExpectedJson();
|
|
ArrayOfArrays target = gson.fromJson(json, ArrayOfArrays.class);
|
|
assertEquals(json, target.getExpectedJson());
|
|
}
|
|
|
|
public void testClassWithEnumFieldSerialization() throws Exception {
|
|
ClassWithEnumFields target = new ClassWithEnumFields();
|
|
assertEquals(target.getExpectedJson(), gson.toJson(target));
|
|
}
|
|
|
|
public void testClassWithEnumFieldDeserialization() throws Exception {
|
|
String json = new ClassWithEnumFields().getExpectedJson();
|
|
ClassWithEnumFields target = gson.fromJson(json, ClassWithEnumFields.class);
|
|
assertEquals(json, target.getExpectedJson());
|
|
}
|
|
|
|
public void testTopLevelEnumSerialization() throws Exception {
|
|
MyEnum target = MyEnum.VALUE1;
|
|
assertEquals(target.getExpectedJson(), gson.toJson(target));
|
|
}
|
|
|
|
public void testTopLevelEnumDeserialization() throws Exception {
|
|
String json = MyEnum.VALUE1.getExpectedJson();
|
|
MyEnum target = gson.fromJson(json, MyEnum.class);
|
|
assertEquals(json, target.getExpectedJson());
|
|
}
|
|
|
|
public void testSubInterfacesOfCollectionSerialization() throws Exception {
|
|
List<Integer> list = new LinkedList<Integer>();
|
|
list.add(0);
|
|
list.add(1);
|
|
list.add(2);
|
|
list.add(3);
|
|
Queue<Long> queue = new LinkedList<Long>();
|
|
queue.add(0L);
|
|
queue.add(1L);
|
|
queue.add(2L);
|
|
queue.add(3L);
|
|
Set<Float> set = new TreeSet<Float>();
|
|
set.add(0.1F);
|
|
set.add(0.2F);
|
|
set.add(0.3F);
|
|
set.add(0.4F);
|
|
SortedSet<Character> sortedSet = new TreeSet<Character>();
|
|
sortedSet.add('a');
|
|
sortedSet.add('b');
|
|
sortedSet.add('c');
|
|
sortedSet.add('d');
|
|
ClassWithSubInterfacesOfCollection target =
|
|
new ClassWithSubInterfacesOfCollection(list, queue, set, sortedSet);
|
|
assertEquals(target.getExpectedJson(), gson.toJson(target));
|
|
}
|
|
|
|
public void testSubInterfacesOfCollectionDeserialization() throws Exception {
|
|
String json = "{\"list\":[0,1,2,3],\"queue\":[0,1,2,3],\"set\":[0.1,0.2,0.3,0.4],"
|
|
+ "\"sortedSet\":[\"a\",\"b\",\"c\",\"d\"]"
|
|
// + ",\"navigableSet\":[\"abc\",\"def\",\"ghi\",\"jkl\"]"
|
|
+ "}";
|
|
ClassWithSubInterfacesOfCollection target = gson.fromJson(
|
|
json, ClassWithSubInterfacesOfCollection.class);
|
|
assertEquals(json, target.getExpectedJson());
|
|
}
|
|
|
|
/**
|
|
* Created in response to Issue 14: http://code.google.com/p/google-gson/issues/detail?id=14
|
|
*/
|
|
public void testNullArraysDeserialization() throws Exception {
|
|
String json = "{\"array\": null}";
|
|
ClassWithArray target = gson.fromJson(json, ClassWithArray.class);
|
|
assertNull(target.array);
|
|
}
|
|
|
|
/**
|
|
* Created in response to Issue 14: http://code.google.com/p/google-gson/issues/detail?id=14
|
|
*/
|
|
public void testNullObjectFieldsDeserialization() throws Exception {
|
|
String json = "{\"bag\": null}";
|
|
ClassWithObjects target = gson.fromJson(json, ClassWithObjects.class);
|
|
assertNull(target.bag);
|
|
}
|
|
|
|
public void testEmptyCollectionInAnObjectDeserialization() throws Exception {
|
|
String json = "{\"children\":[]}";
|
|
ContainsReferenceToSelfType target = gson.fromJson(json, ContainsReferenceToSelfType.class);
|
|
assertNotNull(target);
|
|
assertTrue(target.children.isEmpty());
|
|
}
|
|
|
|
public void testPrimitiveArrayInAnObjectDeserialization() throws Exception {
|
|
String json = "{\"longArray\":[0,1,2,3,4,5,6,7,8,9]}";
|
|
PrimitiveArray target = gson.fromJson(json, PrimitiveArray.class);
|
|
assertEquals(json, target.getExpectedJson());
|
|
}
|
|
|
|
/**
|
|
* Created in response to Issue 14: http://code.google.com/p/google-gson/issues/detail?id=14
|
|
*/
|
|
public void testNullPrimitiveFieldsDeserialization() throws Exception {
|
|
String json = "{\"longValue\":null}";
|
|
BagOfPrimitives target = gson.fromJson(json, BagOfPrimitives.class);
|
|
assertEquals(BagOfPrimitives.DEFAULT_VALUE, target.longValue);
|
|
}
|
|
|
|
public void testEmptyCollectionInAnObjectSerialization() throws Exception {
|
|
ContainsReferenceToSelfType target = new ContainsReferenceToSelfType();
|
|
assertEquals("{\"children\":[]}", gson.toJson(target));
|
|
}
|
|
|
|
public void testCircularSerialization() throws Exception {
|
|
ContainsReferenceToSelfType a = new ContainsReferenceToSelfType();
|
|
ContainsReferenceToSelfType b = new ContainsReferenceToSelfType();
|
|
a.children.add(b);
|
|
b.children.add(a);
|
|
try {
|
|
gson.toJson(a);
|
|
fail("Circular types should not get printed!");
|
|
} catch (IllegalStateException expected) { }
|
|
}
|
|
|
|
public void testSelfReferenceSerialization() throws Exception {
|
|
ClassOverridingEquals objA = new ClassOverridingEquals();
|
|
objA.ref = objA;
|
|
|
|
try {
|
|
gson.toJson(objA);
|
|
fail("Circular reference to self can not be serialized!");
|
|
} catch (IllegalStateException expected) { }
|
|
}
|
|
|
|
public void testPrivateNoArgConstructorDeserialization() throws Exception {
|
|
ClassWithPrivateNoArgsConstructor target =
|
|
gson.fromJson("{\"a\":20}", ClassWithPrivateNoArgsConstructor.class);
|
|
assertEquals(20, target.a);
|
|
}
|
|
|
|
public void testAnonymousLocalClassesSerialization() throws Exception {
|
|
assertEquals("", gson.toJson(new ClassWithNoFields() {
|
|
// empty anonymous class
|
|
}));
|
|
}
|
|
|
|
public void testPrimitiveArrayFieldSerialization() {
|
|
PrimitiveArray target = new PrimitiveArray(new long[] { 1L, 2L, 3L });
|
|
assertEquals(target.getExpectedJson(), gson.toJson(target));
|
|
}
|
|
|
|
public void testInnerClassSerialization() {
|
|
Parent p = new Parent();
|
|
Parent.Child c = p.new Child();
|
|
String json = gson.toJson(c);
|
|
assertTrue(json.contains("value2"));
|
|
assertFalse(json.contains("value1"));
|
|
}
|
|
|
|
public void testInnerClassDeserialization() {
|
|
final Parent p = new Parent();
|
|
Gson gson = new GsonBuilder().registerTypeAdapter(Parent.Child.class, new InstanceCreator<Parent.Child>() {
|
|
public Parent.Child createInstance(Type type) {
|
|
return p.new Child();
|
|
}
|
|
}).create();
|
|
String json = "{'value2':3}";
|
|
Parent.Child c = gson.fromJson(json, Parent.Child.class);
|
|
assertEquals(3, c.value2);
|
|
}
|
|
|
|
private static class Parent {
|
|
int value1 = 1;
|
|
private class Child {
|
|
int value2 = 2;
|
|
}
|
|
}
|
|
|
|
public static class ClassWithSubInterfacesOfCollection {
|
|
private List<Integer> list;
|
|
private Queue<Long> queue;
|
|
private Set<Float> set;
|
|
private SortedSet<Character> sortedSet;
|
|
|
|
ClassWithSubInterfacesOfCollection() {
|
|
}
|
|
|
|
public ClassWithSubInterfacesOfCollection(List<Integer> list, Queue<Long> queue, Set<Float> set,
|
|
SortedSet<Character> sortedSet) {
|
|
this.list = list;
|
|
this.queue = queue;
|
|
this.set = set;
|
|
this.sortedSet = sortedSet;
|
|
}
|
|
|
|
public String getExpectedJson() {
|
|
StringBuilder sb = new StringBuilder();
|
|
sb.append("{");
|
|
sb.append("\"list\":");
|
|
append(sb, list).append(",");
|
|
sb.append("\"queue\":");
|
|
append(sb, queue).append(",");
|
|
sb.append("\"set\":");
|
|
append(sb, set).append(",");
|
|
sb.append("\"sortedSet\":");
|
|
append(sb, sortedSet);
|
|
sb.append("}");
|
|
return sb.toString();
|
|
}
|
|
|
|
private StringBuilder append(StringBuilder sb, Collection<?> c) {
|
|
sb.append("[");
|
|
boolean first = true;
|
|
for (Object o : c) {
|
|
if (!first) {
|
|
sb.append(",");
|
|
} else {
|
|
first = false;
|
|
}
|
|
if (o instanceof String || o instanceof Character) {
|
|
sb.append('\"');
|
|
}
|
|
sb.append(o.toString());
|
|
if (o instanceof String || o instanceof Character) {
|
|
sb.append('\"');
|
|
}
|
|
}
|
|
sb.append("]");
|
|
return sb;
|
|
}
|
|
}
|
|
|
|
private static class ContainsReferenceToSelfType {
|
|
public Collection<ContainsReferenceToSelfType> children =
|
|
new ArrayList<ContainsReferenceToSelfType>();
|
|
}
|
|
|
|
private static class SubTypeOfNested extends Nested {
|
|
private final long value = 5;
|
|
|
|
public SubTypeOfNested() {
|
|
this(null, null);
|
|
}
|
|
|
|
public SubTypeOfNested(BagOfPrimitives primitive1, BagOfPrimitives primitive2) {
|
|
super(primitive1, primitive2);
|
|
}
|
|
|
|
@Override
|
|
public void appendFields(StringBuilder sb) {
|
|
sb.append("\"value\":").append(value).append(",");
|
|
super.appendFields(sb);
|
|
}
|
|
}
|
|
|
|
private static class ArrayOfArrays {
|
|
private final BagOfPrimitives[][] elements;
|
|
public ArrayOfArrays() {
|
|
elements = new BagOfPrimitives[3][2];
|
|
for (int i = 0; i < elements.length; ++i) {
|
|
BagOfPrimitives[] row = elements[i];
|
|
for (int j = 0; j < row.length; ++j) {
|
|
row[j] = new BagOfPrimitives(i+j, i*j, false, i+"_"+j);
|
|
}
|
|
}
|
|
}
|
|
public String getExpectedJson() {
|
|
StringBuilder sb = new StringBuilder("{\"elements\":[");
|
|
boolean first = true;
|
|
for (BagOfPrimitives[] row : elements) {
|
|
if (first) {
|
|
first = false;
|
|
} else {
|
|
sb.append(",");
|
|
}
|
|
boolean firstOfRow = true;
|
|
sb.append("[");
|
|
for (BagOfPrimitives element : row) {
|
|
if (firstOfRow) {
|
|
firstOfRow = false;
|
|
} else {
|
|
sb.append(",");
|
|
}
|
|
sb.append(element.getExpectedJson());
|
|
}
|
|
sb.append("]");
|
|
}
|
|
sb.append("]}");
|
|
return sb.toString();
|
|
}
|
|
}
|
|
|
|
private static class ClassWithEnumFields {
|
|
private final MyEnum value1 = MyEnum.VALUE1;
|
|
private final MyEnum value2 = MyEnum.VALUE2;
|
|
public String getExpectedJson() {
|
|
return "{\"value1\":\"" + value1 + "\",\"value2\":\"" + value2 + "\"}";
|
|
}
|
|
}
|
|
|
|
private static class ClassWithPrivateNoArgsConstructor {
|
|
public int a;
|
|
private ClassWithPrivateNoArgsConstructor() {
|
|
a = 10;
|
|
}
|
|
}
|
|
}
|