/* * 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.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.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 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 list = new LinkedList(); list.add(0); list.add(1); list.add(2); list.add(3); Queue queue = new LinkedList(); queue.add(0L); queue.add(1L); queue.add(2L); queue.add(3L); Set set = new TreeSet(); set.add(0.1F); set.add(0.2F); set.add(0.3F); set.add(0.4F); SortedSet sortedSet = new TreeSet(); 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 static class ClassWithSubInterfacesOfCollection { private List list; private Queue queue; private Set set; private SortedSet sortedSet; ClassWithSubInterfacesOfCollection() { } public ClassWithSubInterfacesOfCollection(List list, Queue queue, Set set, SortedSet 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 children = new ArrayList(); } 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; } } }