google-gson/0000775000175000017500000000000012207114637012633 5ustar ebourgebourggoogle-gson/LICENSE0000664000175000017500000002645211551141143013642 0ustar ebourgebourgGoogle Gson Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2008-2011 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. google-gson/README0000664000175000017500000000060111053601477013511 0ustar ebourgebourgGson is a Java library that can be used to convert a Java object into its JSON representation. It can also be used to convert a JSON string into an equivalent Java object. Gson can work with arbitrary Java objects including pre-existing objects that you do not have source-code of. Complete Gson documentation is available at its project page http://code.google.com/p/google-gson google-gson/pom.xml0000664000175000017500000001756512144256347014173 0ustar ebourgebourg 4.0.0 com.google.code.gson gson jar 2.2.4 2008 Gson org.sonatype.oss oss-parent 7 http://code.google.com/p/google-gson/ Google Gson library UTF-8 The Apache Software License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.txt repo scm:svn:http://google-gson.googlecode.com/svn/tags/gson-2.2.4 scm:svn:https://google-gson.googlecode.com/svn/tags/gson-2.2.4 http://google-gson.googlecode.com/svn/tags/gson-2.2.4 Google Code Issue Tracking http://code.google.com/p/google-gson/issues/list Google, Inc. http://www.google.com junit junit 3.8.2 test release-sign-artifacts performRelease true org.apache.maven.plugins maven-gpg-plugin 1.4 sign-artifacts verify sign package org.apache.maven.plugins maven-compiler-plugin 3.1 1.5 1.5 org.apache.maven.plugins maven-jar-plugin 2.4 package jar false J2SE-1.5 ${project.version} http://code.google.com/p/google-gson/ Google Gson Project ${project.name} ${project.description} . 2 com.google.gson org.apache.maven.plugins maven-source-plugin 2.2.1 attach-sources verify jar com.google.gson;version="${project.version}" com.google.gson.source 2 ${project.version} org.apache.maven.plugins maven-javadoc-plugin 2.9 attach-javadocs jar com.google.gson com.google.gson.internal:com.google.gson.internal.bind http://docs.oracle.com/javase/1.5.0/docs/api/ true protected org.apache.maven.plugins maven-eclipse-plugin 2.9 true true ../eclipse-ws/ file:///${basedir}/../lib/gson-formatting-styles.xml org.apache.maven.plugins maven-release-plugin -DenableCiProfile=true https://google-gson.googlecode.com/svn/tags maven-assembly-plugin 2.4 assembly-descriptor.xml google-gson-${project.version} target/dist target/assembly/work Inderjeet Singh Trymph Inc. Joel Leitch Google Inc. Jesse Wilson Square Inc. google-gson/Gson 2.1 notes.txt0000664000175000017500000000045411663107727015706 0ustar ebourgebourgDropped support for GsonBuilder.registerTypeHierarchyAdapter+InstanceCreator Relax registerTypeHierarchyAdapter order Gson 2.0 failed if you registered Manager then Employee would fail Gson 2.1 it isn't a problem com.google.gson.functional.TypeHierarchyAdapterTest#testRegisterSubTypeFirstNotAllowedgoogle-gson/src/0000775000175000017500000000000012207114635013420 5ustar ebourgebourggoogle-gson/src/metric/0000775000175000017500000000000012207114635014703 5ustar ebourgebourggoogle-gson/src/metric/java/0000775000175000017500000000000012207114635015624 5ustar ebourgebourggoogle-gson/src/metric/java/com/0000775000175000017500000000000012207114635016402 5ustar ebourgebourggoogle-gson/src/metric/java/com/google/0000775000175000017500000000000012207114635017656 5ustar ebourgebourggoogle-gson/src/metric/java/com/google/gson/0000775000175000017500000000000012207114635020624 5ustar ebourgebourggoogle-gson/src/test/0000775000175000017500000000000012207114634014376 5ustar ebourgebourggoogle-gson/src/test/java/0000775000175000017500000000000012207114634015317 5ustar ebourgebourggoogle-gson/src/test/java/com/0000775000175000017500000000000012207114634016075 5ustar ebourgebourggoogle-gson/src/test/java/com/google/0000775000175000017500000000000012207114634017351 5ustar ebourgebourggoogle-gson/src/test/java/com/google/gson/0000775000175000017500000000000012207114635020320 5ustar ebourgebourggoogle-gson/src/test/java/com/google/gson/PrimitiveTypeAdapter.java0000664000175000017500000000504611633056630025305 0ustar ebourgebourg/* * 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; import com.google.gson.internal.Primitives; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * Handles type conversion from some object to some primitive (or primitive * wrapper instance). * * @author Joel Leitch */ final class PrimitiveTypeAdapter { @SuppressWarnings("unchecked") public T adaptType(Object from, Class to) { Class aClass = Primitives.wrap(to); if (Primitives.isWrapperType(aClass)) { if (aClass == Character.class) { String value = from.toString(); if (value.length() == 1) { return (T) (Character) from.toString().charAt(0); } throw new JsonParseException("The value: " + value + " contains more than a character."); } try { Constructor constructor = aClass.getConstructor(String.class); return (T) constructor.newInstance(from.toString()); } catch (NoSuchMethodException e) { throw new JsonParseException(e); } catch (IllegalAccessException e) { throw new JsonParseException(e); } catch (InvocationTargetException e) { throw new JsonParseException(e); } catch (InstantiationException e) { throw new JsonParseException(e); } } else if (Enum.class.isAssignableFrom(to)) { // Case where the type being adapted to is an Enum // We will try to convert from.toString() to the enum try { Method valuesMethod = to.getMethod("valueOf", String.class); return (T) valuesMethod.invoke(null, from.toString()); } catch (NoSuchMethodException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e); } } else { throw new JsonParseException("Can not adapt type " + from.getClass() + " to " + to); } } } google-gson/src/test/java/com/google/gson/ExposeAnnotationExclusionStrategyTest.java0000664000175000017500000000564511662650451030755 0ustar ebourgebourg/* * Copyright (C) 2011 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; import com.google.gson.annotations.Expose; import com.google.gson.internal.Excluder; import junit.framework.TestCase; import java.lang.reflect.Field; /** * Unit tests for GsonBuilder.REQUIRE_EXPOSE_DESERIALIZE. * * @author Joel Leitch */ public class ExposeAnnotationExclusionStrategyTest extends TestCase { private Excluder excluder = Excluder.DEFAULT.excludeFieldsWithoutExposeAnnotation(); public void testNeverSkipClasses() throws Exception { assertFalse(excluder.excludeClass(MockObject.class, true)); assertFalse(excluder.excludeClass(MockObject.class, false)); } public void testSkipNonAnnotatedFields() throws Exception { Field f = createFieldAttributes("hiddenField"); assertTrue(excluder.excludeField(f, true)); assertTrue(excluder.excludeField(f, false)); } public void testSkipExplicitlySkippedFields() throws Exception { Field f = createFieldAttributes("explicitlyHiddenField"); assertTrue(excluder.excludeField(f, true)); assertTrue(excluder.excludeField(f, false)); } public void testNeverSkipExposedAnnotatedFields() throws Exception { Field f = createFieldAttributes("exposedField"); assertFalse(excluder.excludeField(f, true)); assertFalse(excluder.excludeField(f, false)); } public void testNeverSkipExplicitlyExposedAnnotatedFields() throws Exception { Field f = createFieldAttributes("explicitlyExposedField"); assertFalse(excluder.excludeField(f, true)); assertFalse(excluder.excludeField(f, false)); } public void testDifferentSerializeAndDeserializeField() throws Exception { Field f = createFieldAttributes("explicitlyDifferentModeField"); assertFalse(excluder.excludeField(f, true)); assertTrue(excluder.excludeField(f, false)); } private static Field createFieldAttributes(String fieldName) throws Exception { return MockObject.class.getField(fieldName); } @SuppressWarnings("unused") private static class MockObject { @Expose public final int exposedField = 0; @Expose(serialize=true, deserialize=true) public final int explicitlyExposedField = 0; @Expose(serialize=false, deserialize=false) public final int explicitlyHiddenField = 0; @Expose(serialize=true, deserialize=false) public final int explicitlyDifferentModeField = 0; public final int hiddenField = 0; } } google-gson/src/test/java/com/google/gson/JsonObjectTest.java0000664000175000017500000001210012035434745024063 0ustar ebourgebourg/* * 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; import com.google.gson.common.MoreAsserts; import junit.framework.TestCase; /** * Unit test for the {@link JsonObject} class. * * @author Joel Leitch */ public class JsonObjectTest extends TestCase { public void testAddingAndRemovingObjectProperties() throws Exception { JsonObject jsonObj = new JsonObject(); String propertyName = "property"; assertFalse(jsonObj.has(propertyName)); assertNull(jsonObj.get(propertyName)); JsonPrimitive value = new JsonPrimitive("blah"); jsonObj.add(propertyName, value); assertEquals(value, jsonObj.get(propertyName)); JsonElement removedElement = jsonObj.remove(propertyName); assertEquals(value, removedElement); assertFalse(jsonObj.has(propertyName)); assertNull(jsonObj.get(propertyName)); } public void testAddingNullPropertyValue() throws Exception { String propertyName = "property"; JsonObject jsonObj = new JsonObject(); jsonObj.add(propertyName, null); assertTrue(jsonObj.has(propertyName)); JsonElement jsonElement = jsonObj.get(propertyName); assertNotNull(jsonElement); assertTrue(jsonElement.isJsonNull()); } public void testAddingNullOrEmptyPropertyName() throws Exception { JsonObject jsonObj = new JsonObject(); try { jsonObj.add(null, JsonNull.INSTANCE); fail("Should not allow null property names."); } catch (NullPointerException expected) { } jsonObj.add("", JsonNull.INSTANCE); jsonObj.add(" \t", JsonNull.INSTANCE); } public void testAddingBooleanProperties() throws Exception { String propertyName = "property"; JsonObject jsonObj = new JsonObject(); jsonObj.addProperty(propertyName, true); assertTrue(jsonObj.has(propertyName)); JsonElement jsonElement = jsonObj.get(propertyName); assertNotNull(jsonElement); assertTrue(jsonElement.getAsBoolean()); } public void testAddingStringProperties() throws Exception { String propertyName = "property"; String value = "blah"; JsonObject jsonObj = new JsonObject(); jsonObj.addProperty(propertyName, value); assertTrue(jsonObj.has(propertyName)); JsonElement jsonElement = jsonObj.get(propertyName); assertNotNull(jsonElement); assertEquals(value, jsonElement.getAsString()); } public void testAddingCharacterProperties() throws Exception { String propertyName = "property"; char value = 'a'; JsonObject jsonObj = new JsonObject(); jsonObj.addProperty(propertyName, value); assertTrue(jsonObj.has(propertyName)); JsonElement jsonElement = jsonObj.get(propertyName); assertNotNull(jsonElement); assertEquals(String.valueOf(value), jsonElement.getAsString()); assertEquals(value, jsonElement.getAsCharacter()); } /** * From bug report http://code.google.com/p/google-gson/issues/detail?id=182 */ public void testPropertyWithQuotes() { JsonObject jsonObj = new JsonObject(); jsonObj.add("a\"b", new JsonPrimitive("c\"d")); String json = new Gson().toJson(jsonObj); assertEquals("{\"a\\\"b\":\"c\\\"d\"}", json); } /** * From issue 227. */ public void testWritePropertyWithEmptyStringName() { JsonObject jsonObj = new JsonObject(); jsonObj.add("", new JsonPrimitive(true)); assertEquals("{\"\":true}", new Gson().toJson(jsonObj)); } public void testReadPropertyWithEmptyStringName() { JsonObject jsonObj = new JsonParser().parse("{\"\":true}").getAsJsonObject(); assertEquals(true, jsonObj.get("").getAsBoolean()); } public void testEqualsOnEmptyObject() { MoreAsserts.assertEqualsAndHashCode(new JsonObject(), new JsonObject()); } public void testEqualsNonEmptyObject() { JsonObject a = new JsonObject(); JsonObject b = new JsonObject(); assertEquals(a, a); a.add("foo", new JsonObject()); assertFalse(a.equals(b)); assertFalse(b.equals(a)); b.add("foo", new JsonObject()); MoreAsserts.assertEqualsAndHashCode(a, b); a.add("bar", new JsonObject()); assertFalse(a.equals(b)); assertFalse(b.equals(a)); b.add("bar", JsonNull.INSTANCE); assertFalse(a.equals(b)); assertFalse(b.equals(a)); } public void testDeepCopy() { JsonObject original = new JsonObject(); JsonArray firstEntry = new JsonArray(); original.add("key", firstEntry); JsonObject copy = original.deepCopy(); firstEntry.add(new JsonPrimitive("z")); assertEquals(1, original.get("key").getAsJsonArray().size()); assertEquals(0, copy.get("key").getAsJsonArray().size()); } } google-gson/src/test/java/com/google/gson/intercept/0000775000175000017500000000000012207114634022314 5ustar ebourgebourggoogle-gson/src/test/java/com/google/gson/JsonParserTest.java0000664000175000017500000001012012035434745024111 0ustar ebourgebourg/* * Copyright (C) 2009 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; import java.io.CharArrayReader; import java.io.CharArrayWriter; import java.io.StringReader; import junit.framework.TestCase; import com.google.gson.common.TestTypes.BagOfPrimitives; import com.google.gson.internal.Streams; import com.google.gson.stream.JsonReader; /** * Unit test for {@link JsonParser} * * @author Inderjeet Singh */ public class JsonParserTest extends TestCase { private JsonParser parser; @Override protected void setUp() throws Exception { super.setUp(); parser = new JsonParser(); } public void testParseInvalidJson() { try { parser.parse("[[]"); fail(); } catch (JsonSyntaxException expected) { } } public void testParseUnquotedStringArrayFails() { JsonElement element = parser.parse("[a,b,c]"); assertEquals("a", element.getAsJsonArray().get(0).getAsString()); assertEquals("b", element.getAsJsonArray().get(1).getAsString()); assertEquals("c", element.getAsJsonArray().get(2).getAsString()); assertEquals(3, element.getAsJsonArray().size()); } public void testParseString() { String json = "{a:10,b:'c'}"; JsonElement e = parser.parse(json); assertTrue(e.isJsonObject()); assertEquals(10, e.getAsJsonObject().get("a").getAsInt()); assertEquals("c", e.getAsJsonObject().get("b").getAsString()); } public void testParseEmptyString() { JsonElement e = parser.parse("\" \""); assertTrue(e.isJsonPrimitive()); assertEquals(" ", e.getAsString()); } public void testParseEmptyWhitespaceInput() { JsonElement e = parser.parse(" "); assertTrue(e.isJsonNull()); } public void testParseUnquotedSingleWordStringFails() { assertEquals("Test", parser.parse("Test").getAsString()); } public void testParseUnquotedMultiWordStringFails() { String unquotedSentence = "Test is a test..blah blah"; try { parser.parse(unquotedSentence); fail(); } catch (JsonSyntaxException expected) { } } public void testParseMixedArray() { String json = "[{},13,\"stringValue\"]"; JsonElement e = parser.parse(json); assertTrue(e.isJsonArray()); JsonArray array = e.getAsJsonArray(); assertEquals("{}", array.get(0).toString()); assertEquals(13, array.get(1).getAsInt()); assertEquals("stringValue", array.get(2).getAsString()); } public void testParseReader() { StringReader reader = new StringReader("{a:10,b:'c'}"); JsonElement e = parser.parse(reader); assertTrue(e.isJsonObject()); assertEquals(10, e.getAsJsonObject().get("a").getAsInt()); assertEquals("c", e.getAsJsonObject().get("b").getAsString()); } public void testReadWriteTwoObjects() throws Exception { Gson gson = new Gson(); CharArrayWriter writer = new CharArrayWriter(); BagOfPrimitives expectedOne = new BagOfPrimitives(1, 1, true, "one"); writer.write(gson.toJson(expectedOne).toCharArray()); BagOfPrimitives expectedTwo = new BagOfPrimitives(2, 2, false, "two"); writer.write(gson.toJson(expectedTwo).toCharArray()); CharArrayReader reader = new CharArrayReader(writer.toCharArray()); JsonReader parser = new JsonReader(reader); parser.setLenient(true); JsonElement element1 = Streams.parse(parser); JsonElement element2 = Streams.parse(parser); BagOfPrimitives actualOne = gson.fromJson(element1, BagOfPrimitives.class); assertEquals("one", actualOne.stringValue); BagOfPrimitives actualTwo = gson.fromJson(element2, BagOfPrimitives.class); assertEquals("two", actualTwo.stringValue); } } google-gson/src/test/java/com/google/gson/InnerClassExclusionStrategyTest.java0000664000175000017500000000345611662650451027516 0ustar ebourgebourg/* * 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; import com.google.gson.internal.Excluder; import java.lang.reflect.Field; import junit.framework.TestCase; /** * Unit test for GsonBuilder.EXCLUDE_INNER_CLASSES. * * @author Joel Leitch */ public class InnerClassExclusionStrategyTest extends TestCase { public InnerClass innerClass = new InnerClass(); public StaticNestedClass staticNestedClass = new StaticNestedClass(); private Excluder excluder = Excluder.DEFAULT.disableInnerClassSerialization(); public void testExcludeInnerClassObject() throws Exception { Class clazz = innerClass.getClass(); assertTrue(excluder.excludeClass(clazz, true)); } public void testExcludeInnerClassField() throws Exception { Field f = getClass().getField("innerClass"); assertTrue(excluder.excludeField(f, true)); } public void testIncludeStaticNestedClassObject() throws Exception { Class clazz = staticNestedClass.getClass(); assertFalse(excluder.excludeClass(clazz, true)); } public void testIncludeStaticNestedClassField() throws Exception { Field f = getClass().getField("staticNestedClass"); assertFalse(excluder.excludeField(f, true)); } class InnerClass { } static class StaticNestedClass { } } google-gson/src/test/java/com/google/gson/MixedStreamTest.java0000664000175000017500000001632111651170612024247 0ustar ebourgebourg/* * Copyright (C) 2010 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; import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; import java.io.IOException; import java.io.StringReader; import java.io.StringWriter; import java.lang.reflect.Type; import java.util.Arrays; import java.util.List; import junit.framework.TestCase; public final class MixedStreamTest extends TestCase { private static final Car BLUE_MUSTANG = new Car("mustang", 0x0000FF); private static final Car BLACK_BMW = new Car("bmw", 0x000000); private static final Car RED_MIATA = new Car("miata", 0xFF0000); private static final String CARS_JSON = "[\n" + " {\n" + " \"name\": \"mustang\",\n" + " \"color\": 255\n" + " },\n" + " {\n" + " \"name\": \"bmw\",\n" + " \"color\": 0\n" + " },\n" + " {\n" + " \"name\": \"miata\",\n" + " \"color\": 16711680\n" + " }\n" + "]"; public void testWriteMixedStreamed() throws IOException { Gson gson = new Gson(); StringWriter stringWriter = new StringWriter(); JsonWriter jsonWriter = new JsonWriter(stringWriter); jsonWriter.beginArray(); jsonWriter.setIndent(" "); gson.toJson(BLUE_MUSTANG, Car.class, jsonWriter); gson.toJson(BLACK_BMW, Car.class, jsonWriter); gson.toJson(RED_MIATA, Car.class, jsonWriter); jsonWriter.endArray(); assertEquals(CARS_JSON, stringWriter.toString()); } public void testReadMixedStreamed() throws IOException { Gson gson = new Gson(); StringReader stringReader = new StringReader(CARS_JSON); JsonReader jsonReader = new JsonReader(stringReader); jsonReader.beginArray(); assertEquals(BLUE_MUSTANG, gson.fromJson(jsonReader, Car.class)); assertEquals(BLACK_BMW, gson.fromJson(jsonReader, Car.class)); assertEquals(RED_MIATA, gson.fromJson(jsonReader, Car.class)); jsonReader.endArray(); } public void testReaderDoesNotMutateState() throws IOException { Gson gson = new Gson(); JsonReader jsonReader = new JsonReader(new StringReader(CARS_JSON)); jsonReader.beginArray(); jsonReader.setLenient(false); gson.fromJson(jsonReader, Car.class); assertFalse(jsonReader.isLenient()); jsonReader.setLenient(true); gson.fromJson(jsonReader, Car.class); assertTrue(jsonReader.isLenient()); } public void testWriteDoesNotMutateState() throws IOException { Gson gson = new Gson(); JsonWriter jsonWriter = new JsonWriter(new StringWriter()); jsonWriter.beginArray(); jsonWriter.setHtmlSafe(true); jsonWriter.setLenient(true); gson.toJson(BLUE_MUSTANG, Car.class, jsonWriter); assertTrue(jsonWriter.isHtmlSafe()); assertTrue(jsonWriter.isLenient()); jsonWriter.setHtmlSafe(false); jsonWriter.setLenient(false); gson.toJson(BLUE_MUSTANG, Car.class, jsonWriter); assertFalse(jsonWriter.isHtmlSafe()); assertFalse(jsonWriter.isLenient()); } public void testReadInvalidState() throws IOException { Gson gson = new Gson(); JsonReader jsonReader = new JsonReader(new StringReader(CARS_JSON)); jsonReader.beginArray(); jsonReader.beginObject(); try { gson.fromJson(jsonReader, String.class); fail(); } catch (JsonParseException expected) { } } public void testReadClosed() throws IOException { Gson gson = new Gson(); JsonReader jsonReader = new JsonReader(new StringReader(CARS_JSON)); jsonReader.close(); try { gson.fromJson(jsonReader, new TypeToken>() {}.getType()); fail(); } catch (JsonParseException expected) { } } public void testWriteInvalidState() throws IOException { Gson gson = new Gson(); JsonWriter jsonWriter = new JsonWriter(new StringWriter()); jsonWriter.beginObject(); try { gson.toJson(BLUE_MUSTANG, Car.class, jsonWriter); fail(); } catch (IllegalStateException expected) { } } public void testWriteClosed() throws IOException { Gson gson = new Gson(); JsonWriter jsonWriter = new JsonWriter(new StringWriter()); jsonWriter.beginArray(); jsonWriter.endArray(); jsonWriter.close(); try { gson.toJson(BLUE_MUSTANG, Car.class, jsonWriter); fail(); } catch (IllegalStateException expected) { } } public void testWriteNulls() { Gson gson = new Gson(); try { gson.toJson(new JsonPrimitive("hello"), (JsonWriter) null); fail(); } catch (NullPointerException expected) { } StringWriter stringWriter = new StringWriter(); gson.toJson(null, new JsonWriter(stringWriter)); assertEquals("null", stringWriter.toString()); } public void testReadNulls() { Gson gson = new Gson(); try { gson.fromJson((JsonReader) null, Integer.class); fail(); } catch (NullPointerException expected) { } try { gson.fromJson(new JsonReader(new StringReader("true")), null); fail(); } catch (NullPointerException expected) { } } public void testWriteHtmlSafe() { List contents = Arrays.asList("<", ">", "&", "=", "'"); Type type = new TypeToken>() {}.getType(); StringWriter writer = new StringWriter(); new Gson().toJson(contents, type, new JsonWriter(writer)); assertEquals("[\"\\u003c\",\"\\u003e\",\"\\u0026\",\"\\u003d\",\"\\u0027\"]", writer.toString()); writer = new StringWriter(); new GsonBuilder().disableHtmlEscaping().create() .toJson(contents, type, new JsonWriter(writer)); assertEquals("[\"<\",\">\",\"&\",\"=\",\"'\"]", writer.toString()); } public void testWriteLenient() { List doubles = Arrays.asList(Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, -0.0d, 0.5d, 0.0d); Type type = new TypeToken>() {}.getType(); StringWriter writer = new StringWriter(); JsonWriter jsonWriter = new JsonWriter(writer); new GsonBuilder().serializeSpecialFloatingPointValues().create() .toJson(doubles, type, jsonWriter); assertEquals("[NaN,-Infinity,Infinity,-0.0,0.5,0.0]", writer.toString()); try { new Gson().toJson(doubles, type, new JsonWriter(new StringWriter())); fail(); } catch (IllegalArgumentException expected) { } } static final class Car { String name; int color; Car(String name, int color) { this.name = name; this.color = color; } // used by Gson Car() {} @Override public int hashCode() { return name.hashCode() ^ color; } @Override public boolean equals(Object o) { return o instanceof Car && ((Car) o).name.equals(name) && ((Car) o).color == color; } } } google-gson/src/test/java/com/google/gson/DefaultInetAddressTypeAdapterTest.java0000664000175000017500000000256611512710124027702 0ustar ebourgebourg/* * Copyright (C) 2011 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; import java.net.InetAddress; import junit.framework.TestCase; /** * Unit tests for the default serializer/deserializer for the {@code InetAddress} type. * * @author Joel Leitch */ public class DefaultInetAddressTypeAdapterTest extends TestCase { private Gson gson; @Override protected void setUp() throws Exception { super.setUp(); gson = new Gson(); } public void testInetAddressSerializationAndDeserialization() throws Exception { InetAddress localhost = InetAddress.getLocalHost(); String localInetAddress = gson.toJson(localhost); assertEquals("\"" + localhost.getHostAddress() + "\"", localInetAddress); InetAddress value = gson.fromJson(localInetAddress, InetAddress.class); assertEquals(localhost, value); } } google-gson/src/test/java/com/google/gson/JsonNullTest.java0000664000175000017500000000244012132064744023571 0ustar ebourgebourg/* * Copyright (C) 2011 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; import com.google.gson.common.MoreAsserts; import junit.framework.TestCase; /** * @author Jesse Wilson */ public final class JsonNullTest extends TestCase { @SuppressWarnings("deprecation") public void testEqualsAndHashcode() { MoreAsserts.assertEqualsAndHashCode(new JsonNull(), new JsonNull()); MoreAsserts.assertEqualsAndHashCode(new JsonNull(), JsonNull.INSTANCE); MoreAsserts.assertEqualsAndHashCode(JsonNull.INSTANCE, JsonNull.INSTANCE); } public void testDeepCopy() { @SuppressWarnings("deprecation") JsonNull a = new JsonNull(); assertSame(JsonNull.INSTANCE, a.deepCopy()); assertSame(JsonNull.INSTANCE, JsonNull.INSTANCE.deepCopy()); } } google-gson/src/test/java/com/google/gson/MockExclusionStrategy.java0000664000175000017500000000223611546442367025507 0ustar ebourgebourg/* * 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; /** * This is a configurable {@link ExclusionStrategy} that can be used for * unit testing. * * @author Joel Leitch */ final class MockExclusionStrategy implements ExclusionStrategy { private final boolean skipClass; private final boolean skipField; public MockExclusionStrategy(boolean skipClass, boolean skipField) { this.skipClass = skipClass; this.skipField = skipField; } public boolean shouldSkipField(FieldAttributes f) { return skipField; } public boolean shouldSkipClass(Class clazz) { return skipClass; } } google-gson/src/test/java/com/google/gson/CommentsTest.java0000664000175000017500000000241511435665115023620 0ustar ebourgebourg/* * Copyright (C) 2010 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; import com.google.gson.reflect.TypeToken; import java.util.Arrays; import java.util.List; import junit.framework.TestCase; /** * @author Jesse Wilson */ public final class CommentsTest extends TestCase { /** * Test for issue 212. */ public void testParseComments() { String json = "[\n" + " // this is a comment\n" + " \"a\",\n" + " /* this is another comment */\n" + " \"b\",\n" + " # this is yet another comment\n" + " \"c\"\n" + "]"; List abc = new Gson().fromJson(json, new TypeToken>() {}.getType()); assertEquals(Arrays.asList("a", "b", "c"), abc); } } google-gson/src/test/java/com/google/gson/JsonPrimitiveTest.java0000664000175000017500000002204312014561057024626 0ustar ebourgebourg/* * 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; import com.google.gson.common.MoreAsserts; import junit.framework.TestCase; import java.math.BigDecimal; import java.math.BigInteger; /** * Unit test for the {@link JsonPrimitive} class. * * @author Joel Leitch */ public class JsonPrimitiveTest extends TestCase { public void testBoolean() throws Exception { JsonPrimitive json = new JsonPrimitive(Boolean.TRUE); assertTrue(json.isBoolean()); assertTrue(json.getAsBoolean()); // Extra support for booleans json = new JsonPrimitive(1); assertFalse(json.getAsBoolean()); json = new JsonPrimitive("1"); assertFalse(json.getAsBoolean()); json = new JsonPrimitive("true"); assertTrue(json.getAsBoolean()); json = new JsonPrimitive("TrUe"); assertTrue(json.getAsBoolean()); json = new JsonPrimitive("1.3"); assertFalse(json.getAsBoolean()); } public void testParsingStringAsBoolean() throws Exception { JsonPrimitive json = new JsonPrimitive("true"); assertFalse(json.isBoolean()); assertTrue(json.getAsBoolean()); } public void testParsingStringAsNumber() throws Exception { JsonPrimitive json = new JsonPrimitive("1"); assertFalse(json.isNumber()); assertEquals(1D, json.getAsDouble(), 0.00001); assertEquals(1F, json.getAsFloat(), 0.00001); assertEquals(1, json.getAsInt()); assertEquals(1L, json.getAsLong()); assertEquals((short) 1, json.getAsShort()); assertEquals((byte) 1, json.getAsByte()); assertEquals(new BigInteger("1"), json.getAsBigInteger()); assertEquals(new BigDecimal("1"), json.getAsBigDecimal()); } public void testStringsAndChar() throws Exception { JsonPrimitive json = new JsonPrimitive("abc"); assertTrue(json.isString()); assertEquals('a', json.getAsCharacter()); assertEquals("abc", json.getAsString()); json = new JsonPrimitive('z'); assertTrue(json.isString()); assertEquals('z', json.getAsCharacter()); assertEquals("z", json.getAsString()); } public void testExponential() throws Exception { JsonPrimitive json = new JsonPrimitive("1E+7"); assertEquals(new BigDecimal("1E+7"), json.getAsBigDecimal()); assertEquals(new Double("1E+7"), json.getAsDouble(), 0.00001); assertEquals(new Float("1E+7"), json.getAsDouble(), 0.00001); try { json.getAsInt(); fail("Integers can not handle exponents like this."); } catch (NumberFormatException expected) { } } public void testByteEqualsShort() { JsonPrimitive p1 = new JsonPrimitive(new Byte((byte)10)); JsonPrimitive p2 = new JsonPrimitive(new Short((short)10)); assertEquals(p1, p2); assertEquals(p1.hashCode(), p2.hashCode()); } public void testByteEqualsInteger() { JsonPrimitive p1 = new JsonPrimitive(new Byte((byte)10)); JsonPrimitive p2 = new JsonPrimitive(new Integer(10)); assertEquals(p1, p2); assertEquals(p1.hashCode(), p2.hashCode()); } public void testByteEqualsLong() { JsonPrimitive p1 = new JsonPrimitive(new Byte((byte)10)); JsonPrimitive p2 = new JsonPrimitive(new Long(10L)); assertEquals(p1, p2); assertEquals(p1.hashCode(), p2.hashCode()); } public void testByteEqualsBigInteger() { JsonPrimitive p1 = new JsonPrimitive(new Byte((byte)10)); JsonPrimitive p2 = new JsonPrimitive(new BigInteger("10")); assertEquals(p1, p2); assertEquals(p1.hashCode(), p2.hashCode()); } public void testShortEqualsInteger() { JsonPrimitive p1 = new JsonPrimitive(new Short((short)10)); JsonPrimitive p2 = new JsonPrimitive(new Integer(10)); assertEquals(p1, p2); assertEquals(p1.hashCode(), p2.hashCode()); } public void testShortEqualsLong() { JsonPrimitive p1 = new JsonPrimitive(new Short((short)10)); JsonPrimitive p2 = new JsonPrimitive(new Long(10)); assertEquals(p1, p2); assertEquals(p1.hashCode(), p2.hashCode()); } public void testShortEqualsBigInteger() { JsonPrimitive p1 = new JsonPrimitive(new Short((short)10)); JsonPrimitive p2 = new JsonPrimitive(new BigInteger("10")); assertEquals(p1, p2); assertEquals(p1.hashCode(), p2.hashCode()); } public void testIntegerEqualsLong() { JsonPrimitive p1 = new JsonPrimitive(new Integer(10)); JsonPrimitive p2 = new JsonPrimitive(new Long(10L)); assertEquals(p1, p2); assertEquals(p1.hashCode(), p2.hashCode()); } public void testIntegerEqualsBigInteger() { JsonPrimitive p1 = new JsonPrimitive(new Integer(10)); JsonPrimitive p2 = new JsonPrimitive(new BigInteger("10")); assertEquals(p1, p2); assertEquals(p1.hashCode(), p2.hashCode()); } public void testLongEqualsBigInteger() { JsonPrimitive p1 = new JsonPrimitive(new Long(10L)); JsonPrimitive p2 = new JsonPrimitive(new BigInteger("10")); assertEquals(p1, p2); assertEquals(p1.hashCode(), p2.hashCode()); } public void testFloatEqualsDouble() { JsonPrimitive p1 = new JsonPrimitive(new Float(10.25F)); JsonPrimitive p2 = new JsonPrimitive(new Double(10.25D)); assertEquals(p1, p2); assertEquals(p1.hashCode(), p2.hashCode()); } public void testFloatEqualsBigDecimal() { JsonPrimitive p1 = new JsonPrimitive(new Float(10.25F)); JsonPrimitive p2 = new JsonPrimitive(new BigDecimal("10.25")); assertEquals(p1, p2); assertEquals(p1.hashCode(), p2.hashCode()); } public void testDoubleEqualsBigDecimal() { JsonPrimitive p1 = new JsonPrimitive(new Double(10.25D)); JsonPrimitive p2 = new JsonPrimitive(new BigDecimal("10.25")); assertEquals(p1, p2); assertEquals(p1.hashCode(), p2.hashCode()); } public void testValidJsonOnToString() throws Exception { JsonPrimitive json = new JsonPrimitive("Some\nEscaped\nValue"); assertEquals("\"Some\\nEscaped\\nValue\"", json.toString()); json = new JsonPrimitive(new BigDecimal("1.333")); assertEquals("1.333", json.toString()); } public void testEquals() { MoreAsserts.assertEqualsAndHashCode(new JsonPrimitive("A"), new JsonPrimitive("A")); MoreAsserts.assertEqualsAndHashCode(new JsonPrimitive(true), new JsonPrimitive(true)); MoreAsserts.assertEqualsAndHashCode(new JsonPrimitive(5L), new JsonPrimitive(5L)); MoreAsserts.assertEqualsAndHashCode(new JsonPrimitive('a'), new JsonPrimitive('a')); MoreAsserts.assertEqualsAndHashCode(new JsonPrimitive(Float.NaN), new JsonPrimitive(Float.NaN)); MoreAsserts.assertEqualsAndHashCode(new JsonPrimitive(Float.NEGATIVE_INFINITY), new JsonPrimitive(Float.NEGATIVE_INFINITY)); MoreAsserts.assertEqualsAndHashCode(new JsonPrimitive(Float.POSITIVE_INFINITY), new JsonPrimitive(Float.POSITIVE_INFINITY)); MoreAsserts.assertEqualsAndHashCode(new JsonPrimitive(Double.NaN), new JsonPrimitive(Double.NaN)); MoreAsserts.assertEqualsAndHashCode(new JsonPrimitive(Double.NEGATIVE_INFINITY), new JsonPrimitive(Double.NEGATIVE_INFINITY)); MoreAsserts.assertEqualsAndHashCode(new JsonPrimitive(Double.POSITIVE_INFINITY), new JsonPrimitive(Double.POSITIVE_INFINITY)); assertFalse(new JsonPrimitive("a").equals(new JsonPrimitive("b"))); assertFalse(new JsonPrimitive(true).equals(new JsonPrimitive(false))); assertFalse(new JsonPrimitive(0).equals(new JsonPrimitive(1))); } public void testEqualsAcrossTypes() { MoreAsserts.assertEqualsAndHashCode(new JsonPrimitive("a"), new JsonPrimitive('a')); MoreAsserts.assertEqualsAndHashCode(new JsonPrimitive(new BigInteger("0")), new JsonPrimitive(0)); MoreAsserts.assertEqualsAndHashCode(new JsonPrimitive(0), new JsonPrimitive(0L)); MoreAsserts.assertEqualsAndHashCode(new JsonPrimitive(new BigInteger("0")), new JsonPrimitive(0)); MoreAsserts.assertEqualsAndHashCode(new JsonPrimitive(Float.NaN), new JsonPrimitive(Double.NaN)); } public void testEqualsIntegerAndBigInteger() { JsonPrimitive a = new JsonPrimitive(5L); JsonPrimitive b = new JsonPrimitive(new BigInteger("18446744073709551621")); // 2^64 + 5 // Ideally, the following assertion should have failed but the price is too much to pay // assertFalse(a + " equals " + b, a.equals(b)); assertTrue(a + " equals " + b, a.equals(b)); } public void testEqualsDoesNotEquateStringAndNonStringTypes() { assertFalse(new JsonPrimitive("true").equals(new JsonPrimitive(true))); assertFalse(new JsonPrimitive("0").equals(new JsonPrimitive(0))); assertFalse(new JsonPrimitive("NaN").equals(new JsonPrimitive(Float.NaN))); } public void testDeepCopy() { JsonPrimitive a = new JsonPrimitive("a"); assertSame(a, a.deepCopy()); // Primitives are immutable! } } google-gson/src/test/java/com/google/gson/GsonTypeAdapterTest.java0000664000175000017500000001265412043527451025106 0ustar ebourgebourg/* * 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; import java.lang.reflect.Type; import java.math.BigInteger; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import junit.framework.TestCase; /** * Contains numerous tests involving registered type converters with a Gson instance. * * @author Inderjeet Singh * @author Joel Leitch */ public class GsonTypeAdapterTest extends TestCase { private Gson gson; @Override protected void setUp() throws Exception { super.setUp(); gson = new GsonBuilder() .registerTypeAdapter(AtomicLong.class, new ExceptionTypeAdapter()) .registerTypeAdapter(AtomicInteger.class, new AtomicIntegerTypeAdapter()) .create(); } public void testDefaultTypeAdapterThrowsParseException() throws Exception { try { gson.fromJson("{\"abc\":123}", BigInteger.class); fail("Should have thrown a JsonParseException"); } catch (JsonParseException expected) { } } public void testTypeAdapterThrowsException() throws Exception { try { gson.toJson(new AtomicLong(0)); fail("Type Adapter should have thrown an exception"); } catch (IllegalStateException expected) { } try { gson.fromJson("123", AtomicLong.class); fail("Type Adapter should have thrown an exception"); } catch (JsonParseException expected) { } } public void testTypeAdapterProperlyConvertsTypes() throws Exception { int intialValue = 1; AtomicInteger atomicInt = new AtomicInteger(intialValue); String json = gson.toJson(atomicInt); assertEquals(intialValue + 1, Integer.parseInt(json)); atomicInt = gson.fromJson(json, AtomicInteger.class); assertEquals(intialValue, atomicInt.get()); } public void testTypeAdapterDoesNotAffectNonAdaptedTypes() throws Exception { String expected = "blah"; String actual = gson.toJson(expected); assertEquals("\"" + expected + "\"", actual); actual = gson.fromJson(actual, String.class); assertEquals(expected, actual); } private static class ExceptionTypeAdapter implements JsonSerializer, JsonDeserializer { public JsonElement serialize( AtomicLong src, Type typeOfSrc, JsonSerializationContext context) { throw new IllegalStateException(); } public AtomicLong deserialize( JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { throw new IllegalStateException(); } } private static class AtomicIntegerTypeAdapter implements JsonSerializer, JsonDeserializer { public JsonElement serialize(AtomicInteger src, Type typeOfSrc, JsonSerializationContext context) { return new JsonPrimitive(src.incrementAndGet()); } public AtomicInteger deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { int intValue = json.getAsInt(); return new AtomicInteger(--intValue); } } static abstract class Abstract { String a; } static class Concrete extends Abstract { String b; } // https://groups.google.com/d/topic/google-gson/EBmOCa8kJPE/discussion public void testDeserializerForAbstractClass() { Concrete instance = new Concrete(); instance.a = "android"; instance.b = "beep"; assertSerialized("{\"a\":\"android\"}", Abstract.class, true, true, instance); assertSerialized("{\"a\":\"android\"}", Abstract.class, true, false, instance); assertSerialized("{\"a\":\"android\"}", Abstract.class, false, true, instance); assertSerialized("{\"a\":\"android\"}", Abstract.class, false, false, instance); assertSerialized("{\"b\":\"beep\",\"a\":\"android\"}", Concrete.class, true, true, instance); assertSerialized("{\"b\":\"beep\",\"a\":\"android\"}", Concrete.class, true, false, instance); assertSerialized("{\"b\":\"beep\",\"a\":\"android\"}", Concrete.class, false, true, instance); assertSerialized("{\"b\":\"beep\",\"a\":\"android\"}", Concrete.class, false, false, instance); } private void assertSerialized(String expected, Class instanceType, boolean registerAbstractDeserializer, boolean registerAbstractHierarchyDeserializer, Object instance) { JsonDeserializer deserializer = new JsonDeserializer() { public Abstract deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { throw new AssertionError(); } }; GsonBuilder builder = new GsonBuilder(); if (registerAbstractDeserializer) { builder.registerTypeAdapter(Abstract.class, deserializer); } if (registerAbstractHierarchyDeserializer) { builder.registerTypeHierarchyAdapter(Abstract.class, deserializer); } Gson gson = builder.create(); assertEquals(expected, gson.toJson(instance, instanceType)); } } google-gson/src/test/java/com/google/gson/metrics/0000775000175000017500000000000012207114635021766 5ustar ebourgebourggoogle-gson/src/test/java/com/google/gson/metrics/PerformanceTest.java0000664000175000017500000002477611433073202025744 0ustar ebourgebourg/* * 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.metrics; import com.google.gson.Gson; import com.google.gson.JsonParseException; import com.google.gson.annotations.Expose; import com.google.gson.reflect.TypeToken; import junit.framework.TestCase; import java.io.StringWriter; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Tests to measure performance for Gson. All tests in this file will be disabled in code. To run * them remove disabled_ prefix from the tests and run them. * * @author Inderjeet Singh * @author Joel Leitch */ public class PerformanceTest extends TestCase { private static final int COLLECTION_SIZE = 5000; private static final int NUM_ITERATIONS = 100; private Gson gson; @Override protected void setUp() throws Exception { super.setUp(); gson = new Gson(); } public void testDummy() { // This is here to prevent Junit for complaining when we disable all tests. } public void disabled_testStringDeserialization() { StringBuilder sb = new StringBuilder(8096); sb.append("Error Yippie"); while (true) { try { String stackTrace = sb.toString(); sb.append(stackTrace); String json = "{\"message\":\"Error message.\"," + "\"stackTrace\":\"" + stackTrace + "\"}"; parseLongJson(json); System.out.println("Gson could handle a string of size: " + stackTrace.length()); } catch (JsonParseException expected) { break; } } } private void parseLongJson(String json) throws JsonParseException { ExceptionHolder target = gson.fromJson(json, ExceptionHolder.class); assertTrue(target.message.contains("Error")); assertTrue(target.stackTrace.contains("Yippie")); } private static class ExceptionHolder { public final String message; public final String stackTrace; // For use by Gson @SuppressWarnings("unused") private ExceptionHolder() { this("", ""); } public ExceptionHolder(String message, String stackTrace) { this.message = message; this.stackTrace = stackTrace; } } @SuppressWarnings("unused") private static class CollectionEntry { final String name; final String value; // For use by Gson private CollectionEntry() { this(null, null); } CollectionEntry(String name, String value) { this.name = name; this.value = value; } } /** * Created in response to http://code.google.com/p/google-gson/issues/detail?id=96 */ public void disabled_testLargeCollectionSerialization() { int count = 1400000; List list = new ArrayList(count); for (int i = 0; i < count; ++i) { list.add(new CollectionEntry("name"+i,"value"+i)); } gson.toJson(list); } /** * Created in response to http://code.google.com/p/google-gson/issues/detail?id=96 */ public void disabled_testLargeCollectionDeserialization() { StringBuilder sb = new StringBuilder(); int count = 87000; boolean first = true; sb.append('['); for (int i = 0; i < count; ++i) { if (first) { first = false; } else { sb.append(','); } sb.append("{name:'name").append(i).append("',value:'value").append(i).append("'}"); } sb.append(']'); String json = sb.toString(); Type collectionType = new TypeToken>(){}.getType(); List list = gson.fromJson(json, collectionType); assertEquals(count, list.size()); } /** * Created in response to http://code.google.com/p/google-gson/issues/detail?id=96 */ // Last I tested, Gson was able to serialize upto 14MB byte array public void disabled_testByteArraySerialization() { for (int size = 4145152; true; size += 1036288) { byte[] ba = new byte[size]; for (int i = 0; i < size; ++i) { ba[i] = 0x05; } gson.toJson(ba); System.out.printf("Gson could serialize a byte array of size: %d\n", size); } } /** * Created in response to http://code.google.com/p/google-gson/issues/detail?id=96 */ // Last I tested, Gson was able to deserialize a byte array of 11MB public void disable_testByteArrayDeserialization() { for (int numElements = 10639296; true; numElements += 16384) { StringBuilder sb = new StringBuilder(numElements*2); sb.append("["); boolean first = true; for (int i = 0; i < numElements; ++i) { if (first) { first = false; } else { sb.append(","); } sb.append("5"); } sb.append("]"); String json = sb.toString(); byte[] ba = gson.fromJson(json, byte[].class); System.out.printf("Gson could deserialize a byte array of size: %d\n", ba.length); } } // The tests to measure serialization and deserialization performance of Gson // Based on the discussion at // http://groups.google.com/group/google-gson/browse_thread/thread/7a50b17a390dfaeb // Test results: 10/19/2009 // Serialize classes avg time: 60 ms // Deserialized classes avg time: 70 ms // Serialize exposed classes avg time: 159 ms // Deserialized exposed classes avg time: 173 ms public void disabled_testSerializeClasses() { ClassWithList c = new ClassWithList("str"); for (int i = 0; i < COLLECTION_SIZE; ++i) { c.list.add(new ClassWithField("element-" + i)); } StringWriter w = new StringWriter(); long t1 = System.currentTimeMillis(); for (int i = 0; i < NUM_ITERATIONS; ++i) { gson.toJson(c, w); } long t2 = System.currentTimeMillis(); long avg = (t2 - t1) / NUM_ITERATIONS; System.out.printf("Serialize classes avg time: %d ms\n", avg); } public void disabled_testDeserializeClasses() { String json = buildJsonForClassWithList(); ClassWithList[] target = new ClassWithList[NUM_ITERATIONS]; long t1 = System.currentTimeMillis(); for (int i = 0; i < NUM_ITERATIONS; ++i) { target[i] = gson.fromJson(json, ClassWithList.class); } long t2 = System.currentTimeMillis(); long avg = (t2 - t1) / NUM_ITERATIONS; System.out.printf("Deserialize classes avg time: %d ms\n", avg); } public void disable_testLargeObjectSerializationAndDeserialization() { Map largeObject = new HashMap(); for (long l = 0; l < 100000; l++) { largeObject.put("field" + l, l); } long t1 = System.currentTimeMillis(); String json = gson.toJson(largeObject); long t2 = System.currentTimeMillis(); System.out.printf("Large object serialized in: %d ms\n", (t2 - t1)); t1 = System.currentTimeMillis(); gson.fromJson(json, new TypeToken>() {}.getType()); t2 = System.currentTimeMillis(); System.out.printf("Large object deserialized in: %d ms\n", (t2 - t1)); } public void disabled_testSerializeExposedClasses() { ClassWithListOfObjects c1 = new ClassWithListOfObjects("str"); for (int i1 = 0; i1 < COLLECTION_SIZE; ++i1) { c1.list.add(new ClassWithExposedField("element-" + i1)); } ClassWithListOfObjects c = c1; StringWriter w = new StringWriter(); long t1 = System.currentTimeMillis(); for (int i = 0; i < NUM_ITERATIONS; ++i) { gson.toJson(c, w); } long t2 = System.currentTimeMillis(); long avg = (t2 - t1) / NUM_ITERATIONS; System.out.printf("Serialize exposed classes avg time: %d ms\n", avg); } public void disabled_testDeserializeExposedClasses() { String json = buildJsonForClassWithList(); ClassWithListOfObjects[] target = new ClassWithListOfObjects[NUM_ITERATIONS]; long t1 = System.currentTimeMillis(); for (int i = 0; i < NUM_ITERATIONS; ++i) { target[i] = gson.fromJson(json, ClassWithListOfObjects.class); } long t2 = System.currentTimeMillis(); long avg = (t2 - t1) / NUM_ITERATIONS; System.out.printf("Deserialize exposed classes avg time: %d ms\n", avg); } public void disabled_testLargeGsonMapRoundTrip() throws Exception { Map original = new HashMap(); for (long i = 0; i < 1000000; i++) { original.put(i, i + 1); } Gson gson = new Gson(); String json = gson.toJson(original); Type longToLong = new TypeToken>(){}.getType(); gson.fromJson(json, longToLong); } private String buildJsonForClassWithList() { StringBuilder sb = new StringBuilder("{"); sb.append("field:").append("'str',"); sb.append("list:["); boolean first = true; for (int i = 0; i < COLLECTION_SIZE; ++i) { if (first) { first = false; } else { sb.append(","); } sb.append("{field:'element-" + i + "'}"); } sb.append("]"); sb.append("}"); String json = sb.toString(); return json; } @SuppressWarnings("unused") private static final class ClassWithList { final String field; final List list = new ArrayList(COLLECTION_SIZE); ClassWithList() { this(null); } ClassWithList(String field) { this.field = field; } } @SuppressWarnings("unused") private static final class ClassWithField { final String field; ClassWithField() { this(""); } public ClassWithField(String field) { this.field = field; } } @SuppressWarnings("unused") private static final class ClassWithListOfObjects { @Expose final String field; @Expose final List list = new ArrayList(COLLECTION_SIZE); ClassWithListOfObjects() { this(null); } ClassWithListOfObjects(String field) { this.field = field; } } @SuppressWarnings("unused") private static final class ClassWithExposedField { @Expose final String field; ClassWithExposedField() { this(""); } ClassWithExposedField(String field) { this.field = field; } } } google-gson/src/test/java/com/google/gson/JavaSerializationTest.java0000664000175000017500000000547412012734422025450 0ustar ebourgebourg/* * Copyright (C) 2012 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; import com.google.gson.reflect.TypeToken; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import junit.framework.TestCase; /** * Check that Gson doesn't return non-serializable data types. * * @author Jesse Wilson */ public final class JavaSerializationTest extends TestCase { private final Gson gson = new Gson(); public void testMapIsSerializable() throws Exception { Type type = new TypeToken>() {}.getType(); Map map = gson.fromJson("{\"b\":1,\"c\":2,\"a\":3}", type); Map serialized = serializedCopy(map); assertEquals(map, serialized); // Also check that the iteration order is retained. assertEquals(Arrays.asList("b", "c", "a"), new ArrayList(serialized.keySet())); } public void testListIsSerializable() throws Exception { Type type = new TypeToken>() {}.getType(); List list = gson.fromJson("[\"a\",\"b\",\"c\"]", type); List serialized = serializedCopy(list); assertEquals(list, serialized); } public void testNumberIsSerializable() throws Exception { Type type = new TypeToken>() {}.getType(); List list = gson.fromJson("[1,3.14,6.673e-11]", type); List serialized = serializedCopy(list); assertEquals(1.0, serialized.get(0).doubleValue()); assertEquals(3.14, serialized.get(1).doubleValue()); assertEquals(6.673e-11, serialized.get(2).doubleValue()); } @SuppressWarnings("unchecked") // Serialization promises to return the same type. private T serializedCopy(T object) throws IOException, ClassNotFoundException { ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(bytesOut); out.writeObject(object); out.close(); ByteArrayInputStream bytesIn = new ByteArrayInputStream(bytesOut.toByteArray()); ObjectInputStream in = new ObjectInputStream(bytesIn); return (T) in.readObject(); } } google-gson/src/test/java/com/google/gson/ParameterizedTypeFixtures.java0000664000175000017500000001343611662261616026370 0ustar ebourgebourg/* * 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; import com.google.gson.internal.$Gson$Types; import com.google.gson.internal.Primitives; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; /** * This class contains some test fixtures for Parameterized types. These classes should ideally * belong either in the common or functional package, but they are placed here because they need * access to package protected elements of com.google.gson. * * @author Inderjeet Singh * @author Joel Leitch */ public class ParameterizedTypeFixtures { public static class MyParameterizedType { public final T value; public MyParameterizedType(T value) { this.value = value; } public T getValue() { return value; } public String getExpectedJson() { String valueAsJson = getExpectedJson(value); return String.format("{\"value\":%s}", valueAsJson); } private String getExpectedJson(Object obj) { Class clazz = obj.getClass(); if (Primitives.isWrapperType(Primitives.wrap(clazz))) { return obj.toString(); } else if (obj.getClass().equals(String.class)) { return "\"" + obj.toString() + "\""; } else { // Try invoking a getExpectedJson() method if it exists try { Method method = clazz.getMethod("getExpectedJson"); Object results = method.invoke(obj); return (String) results; } catch (SecurityException e) { throw new RuntimeException(e); } catch (NoSuchMethodException e) { throw new RuntimeException(e); } catch (IllegalArgumentException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e); } } } @Override public int hashCode() { return value == null ? 0 : value.hashCode(); } @SuppressWarnings("unchecked") @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } MyParameterizedType other = (MyParameterizedType) obj; if (value == null) { if (other.value != null) { return false; } } else if (!value.equals(other.value)) { return false; } return true; } } public static class MyParameterizedTypeInstanceCreator implements InstanceCreator>{ private final T instanceOfT; /** * Caution the specified instance is reused by the instance creator for each call. * This means that the fields of the same objects will be overwritten by Gson. * This is usually fine in tests since there we deserialize just once, but quite * dangerous in practice. * * @param instanceOfT */ public MyParameterizedTypeInstanceCreator(T instanceOfT) { this.instanceOfT = instanceOfT; } public MyParameterizedType createInstance(Type type) { return new MyParameterizedType(instanceOfT); } } public static class MyParameterizedTypeAdapter implements JsonSerializer>, JsonDeserializer> { @SuppressWarnings("unchecked") public static String getExpectedJson(MyParameterizedType obj) { Class clazz = (Class) obj.value.getClass(); boolean addQuotes = !clazz.isArray() && !Primitives.unwrap(clazz).isPrimitive(); StringBuilder sb = new StringBuilder("{\""); sb.append(obj.value.getClass().getSimpleName()).append("\":"); if (addQuotes) { sb.append("\""); } sb.append(obj.value.toString()); if (addQuotes) { sb.append("\""); } sb.append("}"); return sb.toString(); } public JsonElement serialize(MyParameterizedType src, Type classOfSrc, JsonSerializationContext context) { JsonObject json = new JsonObject(); T value = src.getValue(); json.add(value.getClass().getSimpleName(), context.serialize(value)); return json; } @SuppressWarnings("unchecked") public MyParameterizedType deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { Type genericClass = ((ParameterizedType) typeOfT).getActualTypeArguments()[0]; Class rawType = $Gson$Types.getRawType(genericClass); String className = rawType.getSimpleName(); JsonElement jsonElement = json.getAsJsonObject().get(className); T value; if (genericClass == Integer.class) { value = (T) Integer.valueOf(jsonElement.getAsInt()); } else if (genericClass == String.class) { value = (T) jsonElement.getAsString(); } else { value = (T) jsonElement; } if (Primitives.isPrimitive(genericClass)) { PrimitiveTypeAdapter typeAdapter = new PrimitiveTypeAdapter(); value = (T) typeAdapter.adaptType(value, rawType); } return new MyParameterizedType(value); } } } google-gson/src/test/java/com/google/gson/common/0000775000175000017500000000000012207114634021607 5ustar ebourgebourggoogle-gson/src/test/java/com/google/gson/common/TestTypes.java0000664000175000017500000002701111616630610024417 0ustar ebourgebourg/* * 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.common; import java.lang.reflect.Type; import java.util.Collection; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; import com.google.gson.JsonPrimitive; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; import com.google.gson.annotations.SerializedName; /** * Types used for testing JSON serialization and deserialization * * @author Inderjeet Singh * @author Joel Leitch */ public class TestTypes { public static class Base { public static final String BASE_NAME = Base.class.getSimpleName(); public static final String BASE_FIELD_KEY = "baseName"; public static final String SERIALIZER_KEY = "serializerName"; public String baseName = BASE_NAME; public String serializerName; } public static class Sub extends Base { public static final String SUB_NAME = Sub.class.getSimpleName(); public static final String SUB_FIELD_KEY = "subName"; public final String subName = SUB_NAME; } public static class ClassWithBaseField { public static final String FIELD_KEY = "base"; public final Base base; public ClassWithBaseField(Base base) { this.base = base; } } public static class ClassWithBaseArrayField { public static final String FIELD_KEY = "base"; public final Base[] base; public ClassWithBaseArrayField(Base[] base) { this.base = base; } } public static class ClassWithBaseCollectionField { public static final String FIELD_KEY = "base"; public final Collection base; public ClassWithBaseCollectionField(Collection base) { this.base = base; } } public static class BaseSerializer implements JsonSerializer { public static final String NAME = BaseSerializer.class.getSimpleName(); public JsonElement serialize(Base src, Type typeOfSrc, JsonSerializationContext context) { JsonObject obj = new JsonObject(); obj.addProperty(Base.SERIALIZER_KEY, NAME); return obj; } } public static class SubSerializer implements JsonSerializer { public static final String NAME = SubSerializer.class.getSimpleName(); public JsonElement serialize(Sub src, Type typeOfSrc, JsonSerializationContext context) { JsonObject obj = new JsonObject(); obj.addProperty(Base.SERIALIZER_KEY, NAME); return obj; } } public static class StringWrapper { public final String someConstantStringInstanceField; public StringWrapper(String value) { someConstantStringInstanceField = value; } } public static class BagOfPrimitives { public static final long DEFAULT_VALUE = 0; public long longValue; public int intValue; public boolean booleanValue; public String stringValue; public BagOfPrimitives() { this(DEFAULT_VALUE, 0, false, ""); } public BagOfPrimitives(long longValue, int intValue, boolean booleanValue, String stringValue) { this.longValue = longValue; this.intValue = intValue; this.booleanValue = booleanValue; this.stringValue = stringValue; } public int getIntValue() { return intValue; } public String getExpectedJson() { StringBuilder sb = new StringBuilder(); sb.append("{"); sb.append("\"longValue\":").append(longValue).append(","); sb.append("\"intValue\":").append(intValue).append(","); sb.append("\"booleanValue\":").append(booleanValue).append(","); sb.append("\"stringValue\":\"").append(stringValue).append("\""); sb.append("}"); return sb.toString(); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (booleanValue ? 1231 : 1237); result = prime * result + intValue; result = prime * result + (int) (longValue ^ (longValue >>> 32)); result = prime * result + ((stringValue == null) ? 0 : stringValue.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; BagOfPrimitives other = (BagOfPrimitives) obj; if (booleanValue != other.booleanValue) return false; if (intValue != other.intValue) return false; if (longValue != other.longValue) return false; if (stringValue == null) { if (other.stringValue != null) return false; } else if (!stringValue.equals(other.stringValue)) return false; return true; } @Override public String toString() { return String.format("(longValue=%d,intValue=%d,booleanValue=%b,stringValue=%s)", longValue, intValue, booleanValue, stringValue); } } public static class BagOfPrimitiveWrappers { private final Long longValue; private final Integer intValue; private final Boolean booleanValue; public BagOfPrimitiveWrappers(Long longValue, Integer intValue, Boolean booleanValue) { this.longValue = longValue; this.intValue = intValue; this.booleanValue = booleanValue; } public String getExpectedJson() { StringBuilder sb = new StringBuilder(); sb.append("{"); sb.append("\"longValue\":").append(longValue).append(","); sb.append("\"intValue\":").append(intValue).append(","); sb.append("\"booleanValue\":").append(booleanValue); sb.append("}"); return sb.toString(); } } public static class PrimitiveArray { private final long[] longArray; public PrimitiveArray() { this(new long[0]); } public PrimitiveArray(long[] longArray) { this.longArray = longArray; } public String getExpectedJson() { StringBuilder sb = new StringBuilder(); sb.append("{\"longArray\":["); boolean first = true; for (long l : longArray) { if (!first) { sb.append(","); } else { first = false; } sb.append(l); } sb.append("]}"); return sb.toString(); } } public static class ClassWithNoFields { // Nothing here.. . @Override public boolean equals(Object other) { return other.getClass() == ClassWithNoFields.class; } } public static class Nested { private final BagOfPrimitives primitive1; private final BagOfPrimitives primitive2; public Nested() { this(null, null); } public Nested(BagOfPrimitives primitive1, BagOfPrimitives primitive2) { this.primitive1 = primitive1; this.primitive2 = primitive2; } public String getExpectedJson() { StringBuilder sb = new StringBuilder(); sb.append("{"); appendFields(sb); sb.append("}"); return sb.toString(); } public void appendFields(StringBuilder sb) { if (primitive1 != null) { sb.append("\"primitive1\":").append(primitive1.getExpectedJson()); } if (primitive1 != null && primitive2 != null) { sb.append(","); } if (primitive2 != null) { sb.append("\"primitive2\":").append(primitive2.getExpectedJson()); } } } public static class ClassWithTransientFields { public transient T transientT; public final transient long transientLongValue; private final long[] longValue; public ClassWithTransientFields() { this(0L); } public ClassWithTransientFields(long value) { longValue = new long[] { value }; transientLongValue = value + 1; } public String getExpectedJson() { StringBuilder sb = new StringBuilder(); sb.append("{"); sb.append("\"longValue\":[").append(longValue[0]).append("]"); sb.append("}"); return sb.toString(); } } public static class ClassWithCustomTypeConverter { private final BagOfPrimitives bag; private final int value; public ClassWithCustomTypeConverter() { this(new BagOfPrimitives(), 10); } public ClassWithCustomTypeConverter(int value) { this(new BagOfPrimitives(value, value, false, ""), value); } public ClassWithCustomTypeConverter(BagOfPrimitives bag, int value) { this.bag = bag; this.value = value; } public BagOfPrimitives getBag() { return bag; } public String getExpectedJson() { return "{\"url\":\"" + bag.getExpectedJson() + "\",\"value\":" + value + "}"; } public int getValue() { return value; } } public static class ArrayOfObjects { private final BagOfPrimitives[] elements; public ArrayOfObjects() { elements = new BagOfPrimitives[3]; for (int i = 0; i < elements.length; ++i) { elements[i] = new BagOfPrimitives(i, i+2, false, "i"+i); } } public String getExpectedJson() { StringBuilder sb = new StringBuilder("{\"elements\":["); boolean first = true; for (BagOfPrimitives element : elements) { if (first) { first = false; } else { sb.append(","); } sb.append(element.getExpectedJson()); } sb.append("]}"); return sb.toString(); } } public static class ClassOverridingEquals { public ClassOverridingEquals ref; public String getExpectedJson() { if (ref == null) { return "{}"; } return "{\"ref\":" + ref.getExpectedJson() + "}"; } @Override public boolean equals(Object obj) { return true; } @Override public int hashCode() { return 1; } } public static class ClassWithArray { public final Object[] array; public ClassWithArray() { array = null; } public ClassWithArray(Object[] array) { this.array = array; } } public static class ClassWithObjects { public final BagOfPrimitives bag; public ClassWithObjects() { this(new BagOfPrimitives()); } public ClassWithObjects(BagOfPrimitives bag) { this.bag = bag; } } public static class ClassWithSerializedNameFields { @SerializedName("fooBar") public final int f; @SerializedName("Another Foo") public final int g; public ClassWithSerializedNameFields() { this(1, 4); } public ClassWithSerializedNameFields(int f, int g) { this.f = f; this.g = g; } public String getExpectedJson() { return '{' + "\"fooBar\":" + f + ",\"Another Foo\":" + g + '}'; } } public static class CrazyLongTypeAdapter implements JsonSerializer, JsonDeserializer { public static final long DIFFERENCE = 5L; public JsonElement serialize(Long src, Type typeOfSrc, JsonSerializationContext context) { return new JsonPrimitive(src + DIFFERENCE); } public Long deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { return json.getAsLong() - DIFFERENCE; } } }google-gson/src/test/java/com/google/gson/common/MoreAsserts.java0000664000175000017500000000423111526342534024726 0ustar ebourgebourg/* * 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.common; import junit.framework.Assert; import java.util.Collection; /** * Handy asserts that we wish were present in {@link Assert} * so that we didn't have to write them. * * @author Inderjeet Singh */ public class MoreAsserts { public static void assertEquals(int[] expected, int[] target) { if (expected == null) { Assert.assertNull(target); } Assert.assertEquals(expected.length, target.length); for (int i = 0; i < expected.length; ++i) { Assert.assertEquals(expected[i], target[i]); } } public static void assertEquals(Integer[] expected, Integer[] target) { if (expected == null) { Assert.assertNull(target); } Assert.assertEquals(expected.length, target.length); for (int i = 0; i < expected.length; ++i) { Assert.assertEquals(expected[i], target[i]); } } /** * Asserts that the specified {@code value} is not present in {@code collection} * @param collection the collection to look into * @param value the value that needs to be checked for presence */ public static void assertContains(Collection collection, T value) { for (T entry : collection) { if (entry.equals(value)) { return; } } Assert.fail(value + " not present in " + collection); } public static void assertEqualsAndHashCode(Object a, Object b) { Assert.assertTrue(a.equals(b)); Assert.assertTrue(b.equals(a)); Assert.assertEquals(a.hashCode(), b.hashCode()); Assert.assertFalse(a.equals(null)); Assert.assertFalse(a.equals(new Object())); } } google-gson/src/test/java/com/google/gson/DefaultDateTypeAdapterTest.java0000664000175000017500000001533311672547662026374 0ustar ebourgebourg/* * 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; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; import java.util.TimeZone; import junit.framework.TestCase; /** * A simple unit test for the {@link DefaultDateTypeAdapter} class. * * @author Joel Leitch */ public class DefaultDateTypeAdapterTest extends TestCase { public void testFormattingInEnUs() { assertFormattingAlwaysEmitsUsLocale(Locale.US); } public void testFormattingInFr() { assertFormattingAlwaysEmitsUsLocale(Locale.FRANCE); } private void assertFormattingAlwaysEmitsUsLocale(Locale locale) { TimeZone defaultTimeZone = TimeZone.getDefault(); TimeZone.setDefault(TimeZone.getTimeZone("UTC")); Locale defaultLocale = Locale.getDefault(); Locale.setDefault(locale); try { assertFormatted("Jan 1, 1970 12:00:00 AM", new DefaultDateTypeAdapter()); assertFormatted("1/1/70", new DefaultDateTypeAdapter(DateFormat.SHORT)); assertFormatted("Jan 1, 1970", new DefaultDateTypeAdapter(DateFormat.MEDIUM)); assertFormatted("January 1, 1970", new DefaultDateTypeAdapter(DateFormat.LONG)); assertFormatted("1/1/70 12:00 AM", new DefaultDateTypeAdapter(DateFormat.SHORT, DateFormat.SHORT)); assertFormatted("Jan 1, 1970 12:00:00 AM", new DefaultDateTypeAdapter(DateFormat.MEDIUM, DateFormat.MEDIUM)); assertFormatted("January 1, 1970 12:00:00 AM UTC", new DefaultDateTypeAdapter(DateFormat.LONG, DateFormat.LONG)); assertFormatted("Thursday, January 1, 1970 12:00:00 AM UTC", new DefaultDateTypeAdapter(DateFormat.FULL, DateFormat.FULL)); } finally { TimeZone.setDefault(defaultTimeZone); Locale.setDefault(defaultLocale); } } public void testParsingDatesFormattedWithSystemLocale() { TimeZone defaultTimeZone = TimeZone.getDefault(); TimeZone.setDefault(TimeZone.getTimeZone("UTC")); Locale defaultLocale = Locale.getDefault(); Locale.setDefault(Locale.FRANCE); try { assertParsed("1 janv. 1970 00:00:00", new DefaultDateTypeAdapter()); assertParsed("01/01/70", new DefaultDateTypeAdapter(DateFormat.SHORT)); assertParsed("1 janv. 1970", new DefaultDateTypeAdapter(DateFormat.MEDIUM)); assertParsed("1 janvier 1970", new DefaultDateTypeAdapter(DateFormat.LONG)); assertParsed("01/01/70 00:00", new DefaultDateTypeAdapter(DateFormat.SHORT, DateFormat.SHORT)); assertParsed("1 janv. 1970 00:00:00", new DefaultDateTypeAdapter(DateFormat.MEDIUM, DateFormat.MEDIUM)); assertParsed("1 janvier 1970 00:00:00 UTC", new DefaultDateTypeAdapter(DateFormat.LONG, DateFormat.LONG)); assertParsed("jeudi 1 janvier 1970 00 h 00 UTC", new DefaultDateTypeAdapter(DateFormat.FULL, DateFormat.FULL)); } finally { TimeZone.setDefault(defaultTimeZone); Locale.setDefault(defaultLocale); } } public void testParsingDatesFormattedWithUsLocale() { TimeZone defaultTimeZone = TimeZone.getDefault(); TimeZone.setDefault(TimeZone.getTimeZone("UTC")); Locale defaultLocale = Locale.getDefault(); Locale.setDefault(Locale.US); try { assertParsed("Jan 1, 1970 0:00:00 AM", new DefaultDateTypeAdapter()); assertParsed("1/1/70", new DefaultDateTypeAdapter(DateFormat.SHORT)); assertParsed("Jan 1, 1970", new DefaultDateTypeAdapter(DateFormat.MEDIUM)); assertParsed("January 1, 1970", new DefaultDateTypeAdapter(DateFormat.LONG)); assertParsed("1/1/70 0:00 AM", new DefaultDateTypeAdapter(DateFormat.SHORT, DateFormat.SHORT)); assertParsed("Jan 1, 1970 0:00:00 AM", new DefaultDateTypeAdapter(DateFormat.MEDIUM, DateFormat.MEDIUM)); assertParsed("January 1, 1970 0:00:00 AM UTC", new DefaultDateTypeAdapter(DateFormat.LONG, DateFormat.LONG)); assertParsed("Thursday, January 1, 1970 0:00:00 AM UTC", new DefaultDateTypeAdapter(DateFormat.FULL, DateFormat.FULL)); } finally { TimeZone.setDefault(defaultTimeZone); Locale.setDefault(defaultLocale); } } public void testFormatUsesDefaultTimezone() { TimeZone defaultTimeZone = TimeZone.getDefault(); TimeZone.setDefault(TimeZone.getTimeZone("America/Los_Angeles")); Locale defaultLocale = Locale.getDefault(); Locale.setDefault(Locale.US); try { assertFormatted("Dec 31, 1969 4:00:00 PM", new DefaultDateTypeAdapter()); assertParsed("Dec 31, 1969 4:00:00 PM", new DefaultDateTypeAdapter()); } finally { TimeZone.setDefault(defaultTimeZone); Locale.setDefault(defaultLocale); } } public void testDateSerialization() throws Exception { int dateStyle = DateFormat.LONG; DefaultDateTypeAdapter dateTypeAdapter = new DefaultDateTypeAdapter(dateStyle); DateFormat formatter = DateFormat.getDateInstance(dateStyle, Locale.US); Date currentDate = new Date(); String dateString = dateTypeAdapter.serialize(currentDate, Date.class, null).getAsString(); assertEquals(formatter.format(currentDate), dateString); } public void testDatePattern() throws Exception { String pattern = "yyyy-MM-dd"; DefaultDateTypeAdapter dateTypeAdapter = new DefaultDateTypeAdapter(pattern); DateFormat formatter = new SimpleDateFormat(pattern); Date currentDate = new Date(); String dateString = dateTypeAdapter.serialize(currentDate, Date.class, null).getAsString(); assertEquals(formatter.format(currentDate), dateString); } public void testInvalidDatePattern() throws Exception { try { new DefaultDateTypeAdapter("I am a bad Date pattern...."); fail("Invalid date pattern should fail."); } catch (IllegalArgumentException expected) { } } private void assertFormatted(String formatted, DefaultDateTypeAdapter adapter) { assertEquals(formatted, adapter.serialize(new Date(0), Date.class, null).getAsString()); } private void assertParsed(String date, DefaultDateTypeAdapter adapter) { assertEquals(date, new Date(0), adapter.deserialize(new JsonPrimitive(date), Date.class, null)); assertEquals("ISO 8601", new Date(0), adapter.deserialize( new JsonPrimitive("1970-01-01T00:00:00Z"), Date.class, null)); } } google-gson/src/test/java/com/google/gson/ParameterizedTypeTest.java0000664000175000017500000000360411546731521025470 0ustar ebourgebourg/* * 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; import com.google.gson.internal.$Gson$Types; import com.google.gson.reflect.TypeToken; import junit.framework.TestCase; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.List; /** * Unit tests for {@code ParamterizedType}s created by the {@link $Gson$Types} class. * * @author Inderjeet Singh * @author Joel Leitch */ public class ParameterizedTypeTest extends TestCase { private ParameterizedType ourType; @Override protected void setUp() throws Exception { super.setUp(); ourType = $Gson$Types.newParameterizedTypeWithOwner(null, List.class, String.class); } public void testOurTypeFunctionality() throws Exception { Type parameterizedType = new TypeToken>() {}.getType(); assertNull(ourType.getOwnerType()); assertEquals(String.class, ourType.getActualTypeArguments()[0]); assertEquals(List.class, ourType.getRawType()); assertEquals(parameterizedType, ourType); assertEquals(parameterizedType.hashCode(), ourType.hashCode()); } public void testNotEquals() throws Exception { Type differentParameterizedType = new TypeToken>() {}.getType(); assertFalse(differentParameterizedType.equals(ourType)); assertFalse(ourType.equals(differentParameterizedType)); } } google-gson/src/test/java/com/google/gson/ObjectTypeAdapterTest.java0000664000175000017500000000420611727141145025400 0ustar ebourgebourg/* * Copyright (C) 2011 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; import java.util.Arrays; import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; import junit.framework.TestCase; public final class ObjectTypeAdapterTest extends TestCase { private final Gson gson = new GsonBuilder().create(); private final TypeAdapter adapter = gson.getAdapter(Object.class); public void testDeserialize() throws Exception { Map map = (Map) adapter.fromJson("{\"a\":5,\"b\":[1,2,null],\"c\":{\"x\":\"y\"}}"); assertEquals(5.0, map.get("a")); assertEquals(Arrays.asList(1.0, 2.0, null), map.get("b")); assertEquals(Collections.singletonMap("x", "y"), map.get("c")); assertEquals(3, map.size()); } public void testSerialize() throws Exception { Object object = new RuntimeType(); assertEquals("{'a':5,'b':[1,2,null]}", adapter.toJson(object).replace("\"", "'")); } public void testSerializeNullValue() throws Exception { Map map = new LinkedHashMap(); map.put("a", null); assertEquals("{'a':null}", adapter.toJson(map).replace('"', '\'')); } public void testDeserializeNullValue() throws Exception { Map map = new LinkedHashMap(); map.put("a", null); assertEquals(map, adapter.fromJson("{\"a\":null}")); } public void testSerializeObject() throws Exception { assertEquals("{}", adapter.toJson(new Object())); } @SuppressWarnings("unused") private class RuntimeType { Object a = 5; Object b = Arrays.asList(1, 2, null); } } google-gson/src/test/java/com/google/gson/LongSerializationPolicyTest.java0000664000175000017500000000434211647725126026655 0ustar ebourgebourg/* * Copyright (C) 2009 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; import junit.framework.TestCase; /** * Unit test for the {@link LongSerializationPolicy} class. * * @author Inderjeet Singh * @author Joel Leitch */ public class LongSerializationPolicyTest extends TestCase { public void testDefaultLongSerialization() throws Exception { JsonElement element = LongSerializationPolicy.DEFAULT.serialize(1556L); assertTrue(element.isJsonPrimitive()); JsonPrimitive jsonPrimitive = element.getAsJsonPrimitive(); assertFalse(jsonPrimitive.isString()); assertTrue(jsonPrimitive.isNumber()); assertEquals(1556L, element.getAsLong()); } public void testDefaultLongSerializationIntegration() { Gson gson = new GsonBuilder() .setLongSerializationPolicy(LongSerializationPolicy.DEFAULT) .create(); assertEquals("[1]", gson.toJson(new long[] { 1L }, long[].class)); assertEquals("[1]", gson.toJson(new Long[] { 1L }, Long[].class)); } public void testStringLongSerialization() throws Exception { JsonElement element = LongSerializationPolicy.STRING.serialize(1556L); assertTrue(element.isJsonPrimitive()); JsonPrimitive jsonPrimitive = element.getAsJsonPrimitive(); assertFalse(jsonPrimitive.isNumber()); assertTrue(jsonPrimitive.isString()); assertEquals("1556", element.getAsString()); } public void testStringLongSerializationIntegration() { Gson gson = new GsonBuilder() .setLongSerializationPolicy(LongSerializationPolicy.STRING) .create(); assertEquals("[\"1\"]", gson.toJson(new long[] { 1L }, long[].class)); assertEquals("[\"1\"]", gson.toJson(new Long[] { 1L }, Long[].class)); } } google-gson/src/test/java/com/google/gson/DefaultMapJsonSerializerTest.java0000664000175000017500000000431711633056630026740 0ustar ebourgebourg/* * 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; import com.google.gson.reflect.TypeToken; import java.lang.reflect.Type; import java.util.HashMap; import java.util.Map; import junit.framework.TestCase; /** * Unit test for the default JSON map serialization object located in the * {@link DefaultTypeAdapters} class. * * @author Joel Leitch */ public class DefaultMapJsonSerializerTest extends TestCase { private Gson gson = new Gson(); public void testEmptyMapNoTypeSerialization() { Map emptyMap = new HashMap(); JsonElement element = gson.toJsonTree(emptyMap, emptyMap.getClass()); assertTrue(element instanceof JsonObject); JsonObject emptyMapJsonObject = (JsonObject) element; assertTrue(emptyMapJsonObject.entrySet().isEmpty()); } public void testEmptyMapSerialization() { Type mapType = new TypeToken>() { }.getType(); Map emptyMap = new HashMap(); JsonElement element = gson.toJsonTree(emptyMap, mapType); assertTrue(element instanceof JsonObject); JsonObject emptyMapJsonObject = (JsonObject) element; assertTrue(emptyMapJsonObject.entrySet().isEmpty()); } public void testNonEmptyMapSerialization() { Type mapType = new TypeToken>() { }.getType(); Map myMap = new HashMap(); String key = "key1"; myMap.put(key, "value1"); Gson gson = new Gson(); JsonElement element = gson.toJsonTree(myMap, mapType); assertTrue(element.isJsonObject()); JsonObject mapJsonObject = element.getAsJsonObject(); assertTrue(mapJsonObject.has(key)); } } google-gson/src/test/java/com/google/gson/functional/0000775000175000017500000000000012207114635022462 5ustar ebourgebourggoogle-gson/src/test/java/com/google/gson/functional/ArrayTest.java0000664000175000017500000002170411642100264025242 0ustar ebourgebourg/* * 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.JsonParseException; import com.google.gson.common.MoreAsserts; import com.google.gson.common.TestTypes.BagOfPrimitives; import com.google.gson.common.TestTypes.ClassWithObjects; import com.google.gson.reflect.TypeToken; import junit.framework.TestCase; import java.lang.reflect.Type; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Collection; /** * Functional tests for Json serialization and deserialization of arrays. * * @author Inderjeet Singh * @author Joel Leitch */ public class ArrayTest extends TestCase { private Gson gson; @Override protected void setUp() throws Exception { super.setUp(); gson = new Gson(); } public void testTopLevelArrayOfIntsSerialization() { int[] target = {1, 2, 3, 4, 5, 6, 7, 8, 9}; assertEquals("[1,2,3,4,5,6,7,8,9]", gson.toJson(target)); } public void testTopLevelArrayOfIntsDeserialization() { int[] expected = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; int[] actual = gson.fromJson("[1,2,3,4,5,6,7,8,9]", int[].class); MoreAsserts.assertEquals(expected, actual); } public void testInvalidArrayDeserialization() { String json = "[1, 2 3, 4, 5]"; try { gson.fromJson(json, int[].class); fail("Gson should not deserialize array elements with missing ,"); } catch (JsonParseException expected) { } } public void testEmptyArraySerialization() { int[] target = {}; assertEquals("[]", gson.toJson(target)); } public void testEmptyArrayDeserialization() { int[] actualObject = gson.fromJson("[]", int[].class); assertTrue(actualObject.length == 0); Integer[] actualObject2 = gson.fromJson("[]", Integer[].class); assertTrue(actualObject2.length == 0); actualObject = gson.fromJson("[ ]", int[].class); assertTrue(actualObject.length == 0); } public void testNullsInArraySerialization() { String[] array = {"foo", null, "bar"}; String expected = "[\"foo\",null,\"bar\"]"; String json = gson.toJson(array); assertEquals(expected, json); } public void testNullsInArrayDeserialization() { String json = "[\"foo\",null,\"bar\"]"; String[] expected = {"foo", null, "bar"}; String[] target = gson.fromJson(json, expected.getClass()); for (int i = 0; i < expected.length; ++i) { assertEquals(expected[i], target[i]); } } public void testSingleNullInArraySerialization() { BagOfPrimitives[] array = new BagOfPrimitives[1]; array[0] = null; String json = gson.toJson(array); assertEquals("[null]", json); } public void testSingleNullInArrayDeserialization() { BagOfPrimitives[] array = gson.fromJson("[null]", BagOfPrimitives[].class); assertNull(array[0]); } public void testNullsInArrayWithSerializeNullPropertySetSerialization() { gson = new GsonBuilder().serializeNulls().create(); String[] array = {"foo", null, "bar"}; String expected = "[\"foo\",null,\"bar\"]"; String json = gson.toJson(array); assertEquals(expected, json); } public void testArrayOfStringsSerialization() { String[] target = {"Hello", "World"}; assertEquals("[\"Hello\",\"World\"]", gson.toJson(target)); } public void testArrayOfStringsDeserialization() { String json = "[\"Hello\",\"World\"]"; String[] target = gson.fromJson(json, String[].class); assertEquals("Hello", target[0]); assertEquals("World", target[1]); } public void testSingleStringArraySerialization() throws Exception { String[] s = { "hello" }; String output = gson.toJson(s); assertEquals("[\"hello\"]", output); } public void testSingleStringArrayDeserialization() throws Exception { String json = "[\"hello\"]"; String[] arrayType = gson.fromJson(json, String[].class); assertEquals(1, arrayType.length); assertEquals("hello", arrayType[0]); } @SuppressWarnings("unchecked") public void testArrayOfCollectionSerialization() throws Exception { StringBuilder sb = new StringBuilder("["); int arraySize = 3; Type typeToSerialize = new TypeToken[]>() {}.getType(); Collection[] arrayOfCollection = new ArrayList[arraySize]; for (int i = 0; i < arraySize; ++i) { int startValue = (3 * i) + 1; sb.append('[').append(startValue).append(',').append(startValue + 1).append(']'); ArrayList tmpList = new ArrayList(); tmpList.add(startValue); tmpList.add(startValue + 1); arrayOfCollection[i] = tmpList; if (i < arraySize - 1) { sb.append(','); } } sb.append(']'); String json = gson.toJson(arrayOfCollection, typeToSerialize); assertEquals(sb.toString(), json); } public void testArrayOfCollectionDeserialization() throws Exception { String json = "[[1,2],[3,4]]"; Type type = new TypeToken[]>() {}.getType(); Collection[] target = gson.fromJson(json, type); assertEquals(2, target.length); MoreAsserts.assertEquals(new Integer[] { 1, 2 }, target[0].toArray(new Integer[0])); MoreAsserts.assertEquals(new Integer[] { 3, 4 }, target[1].toArray(new Integer[0])); } public void testArrayOfPrimitivesAsObjectsSerialization() throws Exception { Object[] objs = new Object[] {1, "abc", 0.3f, 5L}; String json = gson.toJson(objs); assertTrue(json.contains("abc")); assertTrue(json.contains("0.3")); assertTrue(json.contains("5")); } public void testArrayOfPrimitivesAsObjectsDeserialization() throws Exception { String json = "[1,'abc',0.3,1.1,5]"; Object[] objs = gson.fromJson(json, Object[].class); assertEquals(1, ((Number)objs[0]).intValue()); assertEquals("abc", objs[1]); assertEquals(0.3, ((Number)objs[2]).doubleValue()); assertEquals(new BigDecimal("1.1"), new BigDecimal(objs[3].toString())); assertEquals(5, ((Number)objs[4]).shortValue()); } public void testObjectArrayWithNonPrimitivesSerialization() throws Exception { ClassWithObjects classWithObjects = new ClassWithObjects(); BagOfPrimitives bagOfPrimitives = new BagOfPrimitives(); String classWithObjectsJson = gson.toJson(classWithObjects); String bagOfPrimitivesJson = gson.toJson(bagOfPrimitives); Object[] objects = new Object[] { classWithObjects, bagOfPrimitives }; String json = gson.toJson(objects); assertTrue(json.contains(classWithObjectsJson)); assertTrue(json.contains(bagOfPrimitivesJson)); } public void testArrayOfNullSerialization() { Object[] array = new Object[] {null}; String json = gson.toJson(array); assertEquals("[null]", json); } public void testArrayOfNullDeserialization() { String[] values = gson.fromJson("[null]", String[].class); assertNull(values[0]); } /** * Regression tests for Issue 272 */ public void testMultidimenstionalArraysSerialization() { String[][] items = new String[][]{ {"3m Co", "71.72", "0.02", "0.03", "4/2 12:00am", "Manufacturing"}, {"Alcoa Inc", "29.01", "0.42", "1.47", "4/1 12:00am", "Manufacturing"} }; String json = gson.toJson(items); assertTrue(json.contains("[[\"3m Co")); assertTrue(json.contains("Manufacturing\"]]")); } public void testMultiDimenstionalObjectArraysSerialization() { Object[][] array = new Object[][] { new Object[] { 1, 2 } }; assertEquals("[[1,2]]", gson.toJson(array)); } /** * Regression test for Issue 205 */ public void testMixingTypesInObjectArraySerialization() { Object[] array = new Object[] { 1, 2, new Object[] { "one", "two", 3 } }; assertEquals("[1,2,[\"one\",\"two\",3]]", gson.toJson(array)); } /** * Regression tests for Issue 272 */ public void testMultidimenstionalArraysDeserialization() { String json = "[['3m Co','71.72','0.02','0.03','4/2 12:00am','Manufacturing']," + "['Alcoa Inc','29.01','0.42','1.47','4/1 12:00am','Manufacturing']]"; String[][] items = gson.fromJson(json, String[][].class); assertEquals("3m Co", items[0][0]); assertEquals("Manufacturing", items[1][5]); } /** http://code.google.com/p/google-gson/issues/detail?id=342 */ public void testArrayElementsAreArrays() { Object[] stringArrays = { new String[] {"test1", "test2"}, new String[] {"test3", "test4"} }; assertEquals("[[\"test1\",\"test2\"],[\"test3\",\"test4\"]]", new Gson().toJson(stringArrays)); } } google-gson/src/test/java/com/google/gson/functional/RawSerializationTest.java0000664000175000017500000000633111601440621027451 0ustar ebourgebourg/* * Copyright (C) 2010 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 java.util.Arrays; import java.util.Collection; import junit.framework.TestCase; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; /** * Unit tests to validate serialization of parameterized types without explicit types * * @author Inderjeet Singh */ public class RawSerializationTest extends TestCase { private Gson gson; @Override protected void setUp() throws Exception { super.setUp(); gson = new Gson(); } public void testCollectionOfPrimitives() { Collection ints = Arrays.asList(1, 2, 3, 4, 5); String json = gson.toJson(ints); assertEquals("[1,2,3,4,5]", json); } public void testCollectionOfObjects() { Collection foos = Arrays.asList(new Foo(1), new Foo(2)); String json = gson.toJson(foos); assertEquals("[{\"b\":1},{\"b\":2}]", json); } public void testParameterizedObject() { Bar bar = new Bar(new Foo(1)); String expectedJson = "{\"t\":{\"b\":1}}"; // Ensure that serialization works without specifying the type explicitly String json = gson.toJson(bar); assertEquals(expectedJson, json); // Ensure that serialization also works when the type is specified explicitly json = gson.toJson(bar, new TypeToken>(){}.getType()); assertEquals(expectedJson, json); } public void testTwoLevelParameterizedObject() { Bar> bar = new Bar>(new Bar(new Foo(1))); String expectedJson = "{\"t\":{\"t\":{\"b\":1}}}"; // Ensure that serialization works without specifying the type explicitly String json = gson.toJson(bar); assertEquals(expectedJson, json); // Ensure that serialization also works when the type is specified explicitly json = gson.toJson(bar, new TypeToken>>(){}.getType()); assertEquals(expectedJson, json); } public void testThreeLevelParameterizedObject() { Bar>> bar = new Bar>>(new Bar>(new Bar(new Foo(1)))); String expectedJson = "{\"t\":{\"t\":{\"t\":{\"b\":1}}}}"; // Ensure that serialization works without specifying the type explicitly String json = gson.toJson(bar); assertEquals(expectedJson, json); // Ensure that serialization also works when the type is specified explicitly json = gson.toJson(bar, new TypeToken>>>(){}.getType()); assertEquals(expectedJson, json); } private static class Foo { @SuppressWarnings("unused") int b; Foo(int b) { this.b = b; } } private static class Bar { @SuppressWarnings("unused") T t; Bar(T t) { this.t = t; } } } google-gson/src/test/java/com/google/gson/functional/EscapingTest.java0000664000175000017500000000661611470335201025722 0ustar ebourgebourg/* * 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.common.TestTypes.BagOfPrimitives; import java.util.ArrayList; import java.util.List; import junit.framework.TestCase; /** * Performs some functional test involving JSON output escaping. * * @author Inderjeet Singh * @author Joel Leitch */ public class EscapingTest extends TestCase { private Gson gson; @Override protected void setUp() throws Exception { super.setUp(); gson = new Gson(); } public void testEscapingQuotesInStringArray() throws Exception { String[] valueWithQuotes = { "beforeQuote\"afterQuote" }; String jsonRepresentation = gson.toJson(valueWithQuotes); String[] target = gson.fromJson(jsonRepresentation, String[].class); assertEquals(1, target.length); assertEquals(valueWithQuotes[0], target[0]); } public void testEscapeAllHtmlCharacters() { List strings = new ArrayList(); strings.add("<"); strings.add(">"); strings.add("="); strings.add("&"); strings.add("'"); strings.add("\""); assertEquals("[\"\\u003c\",\"\\u003e\",\"\\u003d\",\"\\u0026\",\"\\u0027\",\"\\\"\"]", gson.toJson(strings)); } public void testEscapingObjectFields() throws Exception { BagOfPrimitives objWithPrimitives = new BagOfPrimitives(1L, 1, true, "test with\" "; String result = gson.toJson(target); assertFalse(result.equals('"' + target + '"')); gson = new GsonBuilder().disableHtmlEscaping().create(); result = gson.toJson(target); assertTrue(result.equals('"' + target + '"')); } public void testDeserializePrimitiveWrapperAsObjectField() { String json = "{i:10}"; ClassWithIntegerField target = gson.fromJson(json, ClassWithIntegerField.class); assertEquals(10, target.i.intValue()); } private static class ClassWithIntegerField { Integer i; } public void testPrimitiveClassLiteral() { assertEquals(1, gson.fromJson("1", int.class).intValue()); assertEquals(1, gson.fromJson(new StringReader("1"), int.class).intValue()); assertEquals(1, gson.fromJson(new JsonPrimitive(1), int.class).intValue()); } public void testDeserializeJsonObjectAsLongPrimitive() { try { gson.fromJson("{'abc':1}", long.class); fail(); } catch (JsonSyntaxException expected) {} } public void testDeserializeJsonArrayAsLongWrapper() { try { gson.fromJson("[1,2,3]", Long.class); fail(); } catch (JsonSyntaxException expected) {} } public void testDeserializeJsonArrayAsInt() { try { gson.fromJson("[1, 2, 3, 4]", int.class); fail(); } catch (JsonSyntaxException expected) {} } public void testDeserializeJsonObjectAsInteger() { try { gson.fromJson("{}", Integer.class); fail(); } catch (JsonSyntaxException expected) {} } public void testDeserializeJsonObjectAsShortPrimitive() { try { gson.fromJson("{'abc':1}", short.class); fail(); } catch (JsonSyntaxException expected) {} } public void testDeserializeJsonArrayAsShortWrapper() { try { gson.fromJson("['a','b']", Short.class); fail(); } catch (JsonSyntaxException expected) {} } public void testDeserializeJsonArrayAsDoublePrimitive() { try { gson.fromJson("[1,2]", double.class); fail(); } catch (JsonSyntaxException expected) {} } public void testDeserializeJsonObjectAsDoubleWrapper() { try { gson.fromJson("{'abc':1}", Double.class); fail(); } catch (JsonSyntaxException expected) {} } public void testDeserializeJsonObjectAsFloatPrimitive() { try { gson.fromJson("{'abc':1}", float.class); fail(); } catch (JsonSyntaxException expected) {} } public void testDeserializeJsonArrayAsFloatWrapper() { try { gson.fromJson("[1,2,3]", Float.class); fail(); } catch (JsonSyntaxException expected) {} } public void testDeserializeJsonObjectAsBytePrimitive() { try { gson.fromJson("{'abc':1}", byte.class); fail(); } catch (JsonSyntaxException expected) {} } public void testDeserializeJsonArrayAsByteWrapper() { try { gson.fromJson("[1,2,3,4]", Byte.class); fail(); } catch (JsonSyntaxException expected) {} } public void testDeserializeJsonObjectAsBooleanPrimitive() { try { gson.fromJson("{'abc':1}", boolean.class); fail(); } catch (JsonSyntaxException expected) {} } public void testDeserializeJsonArrayAsBooleanWrapper() { try { gson.fromJson("[1,2,3,4]", Boolean.class); fail(); } catch (JsonSyntaxException expected) {} } public void testDeserializeJsonArrayAsBigDecimal() { try { gson.fromJson("[1,2,3,4]", BigDecimal.class); fail(); } catch (JsonSyntaxException expected) {} } public void testDeserializeJsonObjectAsBigDecimal() { try { gson.fromJson("{'a':1}", BigDecimal.class); fail(); } catch (JsonSyntaxException expected) {} } public void testDeserializeJsonArrayAsBigInteger() { try { gson.fromJson("[1,2,3,4]", BigInteger.class); fail(); } catch (JsonSyntaxException expected) {} } public void testDeserializeJsonObjectAsBigInteger() { try { gson.fromJson("{'c':2}", BigInteger.class); fail(); } catch (JsonSyntaxException expected) {} } public void testDeserializeJsonArrayAsNumber() { try { gson.fromJson("[1,2,3,4]", Number.class); fail(); } catch (JsonSyntaxException expected) {} } public void testDeserializeJsonObjectAsNumber() { try { gson.fromJson("{'c':2}", Number.class); fail(); } catch (JsonSyntaxException expected) {} } public void testDeserializingDecimalPointValueZeroSucceeds() { assertEquals(1, (int) gson.fromJson("1.0", Integer.class)); } public void testDeserializingNonZeroDecimalPointValuesAsIntegerFails() { try { gson.fromJson("1.02", Byte.class); fail(); } catch (JsonSyntaxException expected) { } try { gson.fromJson("1.02", Short.class); fail(); } catch (JsonSyntaxException expected) { } try { gson.fromJson("1.02", Integer.class); fail(); } catch (JsonSyntaxException expected) { } try { gson.fromJson("1.02", Long.class); fail(); } catch (JsonSyntaxException expected) { } } public void testDeserializingBigDecimalAsIntegerFails() { try { gson.fromJson("-122.08e-213", Integer.class); fail(); } catch (JsonSyntaxException expected) { } } public void testDeserializingBigIntegerAsInteger() { try { gson.fromJson("12121211243123245845384534687435634558945453489543985435", Integer.class); fail(); } catch (JsonSyntaxException expected) { } } public void testDeserializingBigIntegerAsLong() { try { gson.fromJson("12121211243123245845384534687435634558945453489543985435", Long.class); fail(); } catch (JsonSyntaxException expected) { } } public void testValueVeryCloseToZeroIsZero() { assertEquals(0, (byte) gson.fromJson("-122.08e-2132", byte.class)); assertEquals(0, (short) gson.fromJson("-122.08e-2132", short.class)); assertEquals(0, (int) gson.fromJson("-122.08e-2132", int.class)); assertEquals(0, (long) gson.fromJson("-122.08e-2132", long.class)); assertEquals(-0.0f, gson.fromJson("-122.08e-2132", float.class)); assertEquals(-0.0, gson.fromJson("-122.08e-2132", double.class)); assertEquals(0.0f, gson.fromJson("122.08e-2132", float.class)); assertEquals(0.0, gson.fromJson("122.08e-2132", double.class)); } public void testDeserializingBigDecimalAsFloat() { String json = "-122.08e-2132332"; float actual = gson.fromJson(json, float.class); assertEquals(-0.0f, actual); } public void testDeserializingBigDecimalAsDouble() { String json = "-122.08e-2132332"; double actual = gson.fromJson(json, double.class); assertEquals(-0.0d, actual); } public void testDeserializingBigDecimalAsBigIntegerFails() { try { gson.fromJson("-122.08e-213", BigInteger.class); fail(); } catch (JsonSyntaxException expected) { } } public void testDeserializingBigIntegerAsBigDecimal() { BigDecimal actual = gson.fromJson("12121211243123245845384534687435634558945453489543985435", BigDecimal.class); assertEquals("12121211243123245845384534687435634558945453489543985435", actual.toPlainString()); } public void testStringsAsBooleans() { String json = "['true', 'false', 'TRUE', 'yes', '1']"; assertEquals(Arrays.asList(true, false, true, false, false), gson.>fromJson(json, new TypeToken>() {}.getType())); } } google-gson/src/test/java/com/google/gson/functional/DefaultTypeAdaptersTest.java0000664000175000017500000006464612103754523030120 0ustar ebourgebourg/* * 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 java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.Type; import java.math.BigDecimal; import java.math.BigInteger; import java.net.InetAddress; import java.net.URI; import java.net.URL; import java.sql.Time; import java.sql.Timestamp; import java.text.DateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Properties; import java.util.Set; import java.util.TimeZone; import java.util.TreeSet; import java.util.UUID; import junit.framework.TestCase; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonArray; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonNull; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; import com.google.gson.JsonPrimitive; import com.google.gson.TypeAdapter; import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; /** * Functional test for Json serialization and deserialization for common classes for which default * support is provided in Gson. The tests for Map types are available in {@link MapTest}. * * @author Inderjeet Singh * @author Joel Leitch */ public class DefaultTypeAdaptersTest extends TestCase { private Gson gson; private TimeZone oldTimeZone; @Override protected void setUp() throws Exception { super.setUp(); this.oldTimeZone = TimeZone.getDefault(); TimeZone.setDefault(TimeZone.getTimeZone("America/Los_Angeles")); Locale.setDefault(Locale.US); gson = new Gson(); } @Override protected void tearDown() throws Exception { TimeZone.setDefault(oldTimeZone); super.tearDown(); } public void testClassSerialization() { try { gson.toJson(String.class); } catch (UnsupportedOperationException expected) {} // Override with a custom type adapter for class. gson = new GsonBuilder().registerTypeAdapter(Class.class, new MyClassTypeAdapter()).create(); assertEquals("\"java.lang.String\"", gson.toJson(String.class)); } public void testClassDeserialization() { try { gson.fromJson("String.class", String.class.getClass()); } catch (UnsupportedOperationException expected) {} // Override with a custom type adapter for class. gson = new GsonBuilder().registerTypeAdapter(Class.class, new MyClassTypeAdapter()).create(); assertEquals(String.class, gson.fromJson("java.lang.String", Class.class)); } public void testUrlSerialization() throws Exception { String urlValue = "http://google.com/"; URL url = new URL(urlValue); assertEquals("\"http://google.com/\"", gson.toJson(url)); } public void testUrlDeserialization() { String urlValue = "http://google.com/"; String json = "'http:\\/\\/google.com\\/'"; URL target = gson.fromJson(json, URL.class); assertEquals(urlValue, target.toExternalForm()); gson.fromJson('"' + urlValue + '"', URL.class); assertEquals(urlValue, target.toExternalForm()); } public void testUrlNullSerialization() throws Exception { ClassWithUrlField target = new ClassWithUrlField(); assertEquals("{}", gson.toJson(target)); } public void testUrlNullDeserialization() { String json = "{}"; ClassWithUrlField target = gson.fromJson(json, ClassWithUrlField.class); assertNull(target.url); } private static class ClassWithUrlField { URL url; } public void testUriSerialization() throws Exception { String uriValue = "http://google.com/"; URI uri = new URI(uriValue); assertEquals("\"http://google.com/\"", gson.toJson(uri)); } public void testUriDeserialization() { String uriValue = "http://google.com/"; String json = '"' + uriValue + '"'; URI target = gson.fromJson(json, URI.class); assertEquals(uriValue, target.toASCIIString()); } public void testNullSerialization() throws Exception { testNullSerializationAndDeserialization(Boolean.class); testNullSerializationAndDeserialization(Byte.class); testNullSerializationAndDeserialization(Short.class); testNullSerializationAndDeserialization(Integer.class); testNullSerializationAndDeserialization(Long.class); testNullSerializationAndDeserialization(Double.class); testNullSerializationAndDeserialization(Float.class); testNullSerializationAndDeserialization(Number.class); testNullSerializationAndDeserialization(Character.class); testNullSerializationAndDeserialization(String.class); testNullSerializationAndDeserialization(StringBuilder.class); testNullSerializationAndDeserialization(StringBuffer.class); testNullSerializationAndDeserialization(BigDecimal.class); testNullSerializationAndDeserialization(BigInteger.class); testNullSerializationAndDeserialization(TreeSet.class); testNullSerializationAndDeserialization(ArrayList.class); testNullSerializationAndDeserialization(HashSet.class); testNullSerializationAndDeserialization(Properties.class); testNullSerializationAndDeserialization(URL.class); testNullSerializationAndDeserialization(URI.class); testNullSerializationAndDeserialization(UUID.class); testNullSerializationAndDeserialization(Locale.class); testNullSerializationAndDeserialization(InetAddress.class); testNullSerializationAndDeserialization(BitSet.class); testNullSerializationAndDeserialization(Date.class); testNullSerializationAndDeserialization(GregorianCalendar.class); testNullSerializationAndDeserialization(Calendar.class); testNullSerializationAndDeserialization(Time.class); testNullSerializationAndDeserialization(Timestamp.class); testNullSerializationAndDeserialization(java.sql.Date.class); testNullSerializationAndDeserialization(Enum.class); testNullSerializationAndDeserialization(Class.class); } private void testNullSerializationAndDeserialization(Class c) { assertEquals("null", gson.toJson(null, c)); assertEquals(null, gson.fromJson("null", c)); } public void testUuidSerialization() throws Exception { String uuidValue = "c237bec1-19ef-4858-a98e-521cf0aad4c0"; UUID uuid = UUID.fromString(uuidValue); assertEquals('"' + uuidValue + '"', gson.toJson(uuid)); } public void testUuidDeserialization() { String uuidValue = "c237bec1-19ef-4858-a98e-521cf0aad4c0"; String json = '"' + uuidValue + '"'; UUID target = gson.fromJson(json, UUID.class); assertEquals(uuidValue, target.toString()); } public void testLocaleSerializationWithLanguage() { Locale target = new Locale("en"); assertEquals("\"en\"", gson.toJson(target)); } public void testLocaleDeserializationWithLanguage() { String json = "\"en\""; Locale locale = gson.fromJson(json, Locale.class); assertEquals("en", locale.getLanguage()); } public void testLocaleSerializationWithLanguageCountry() { Locale target = Locale.CANADA_FRENCH; assertEquals("\"fr_CA\"", gson.toJson(target)); } public void testLocaleDeserializationWithLanguageCountry() { String json = "\"fr_CA\""; Locale locale = gson.fromJson(json, Locale.class); assertEquals(Locale.CANADA_FRENCH, locale); } public void testLocaleSerializationWithLanguageCountryVariant() { Locale target = new Locale("de", "DE", "EURO"); String json = gson.toJson(target); assertEquals("\"de_DE_EURO\"", json); } public void testLocaleDeserializationWithLanguageCountryVariant() { String json = "\"de_DE_EURO\""; Locale locale = gson.fromJson(json, Locale.class); assertEquals("de", locale.getLanguage()); assertEquals("DE", locale.getCountry()); assertEquals("EURO", locale.getVariant()); } public void testBigDecimalFieldSerialization() { ClassWithBigDecimal target = new ClassWithBigDecimal("-122.01e-21"); String json = gson.toJson(target); String actual = json.substring(json.indexOf(':') + 1, json.indexOf('}')); assertEquals(target.value, new BigDecimal(actual)); } public void testBigDecimalFieldDeserialization() { ClassWithBigDecimal expected = new ClassWithBigDecimal("-122.01e-21"); String json = expected.getExpectedJson(); ClassWithBigDecimal actual = gson.fromJson(json, ClassWithBigDecimal.class); assertEquals(expected.value, actual.value); } public void testBadValueForBigDecimalDeserialization() { try { gson.fromJson("{\"value\"=1.5e-1.0031}", ClassWithBigDecimal.class); fail("Exponent of a BigDecimal must be an integer value."); } catch (JsonParseException expected) { } } public void testBigIntegerFieldSerialization() { ClassWithBigInteger target = new ClassWithBigInteger("23232323215323234234324324324324324324"); String json = gson.toJson(target); assertEquals(target.getExpectedJson(), json); } public void testBigIntegerFieldDeserialization() { ClassWithBigInteger expected = new ClassWithBigInteger("879697697697697697697697697697697697"); String json = expected.getExpectedJson(); ClassWithBigInteger actual = gson.fromJson(json, ClassWithBigInteger.class); assertEquals(expected.value, actual.value); } public void testOverrideBigIntegerTypeAdapter() throws Exception { gson = new GsonBuilder() .registerTypeAdapter(BigInteger.class, new NumberAsStringAdapter(BigInteger.class)) .create(); assertEquals("\"123\"", gson.toJson(new BigInteger("123"), BigInteger.class)); assertEquals(new BigInteger("123"), gson.fromJson("\"123\"", BigInteger.class)); } public void testOverrideBigDecimalTypeAdapter() throws Exception { gson = new GsonBuilder() .registerTypeAdapter(BigDecimal.class, new NumberAsStringAdapter(BigDecimal.class)) .create(); assertEquals("\"1.1\"", gson.toJson(new BigDecimal("1.1"), BigDecimal.class)); assertEquals(new BigDecimal("1.1"), gson.fromJson("\"1.1\"", BigDecimal.class)); } public void testSetSerialization() throws Exception { Gson gson = new Gson(); HashSet s = new HashSet(); s.add("blah"); String json = gson.toJson(s); assertEquals("[\"blah\"]", json); json = gson.toJson(s, Set.class); assertEquals("[\"blah\"]", json); } public void testBitSetSerialization() throws Exception { Gson gson = new Gson(); BitSet bits = new BitSet(); bits.set(1); bits.set(3, 6); bits.set(9); String json = gson.toJson(bits); assertEquals("[0,1,0,1,1,1,0,0,0,1]", json); } public void testBitSetDeserialization() throws Exception { BitSet expected = new BitSet(); expected.set(0); expected.set(2, 6); expected.set(8); Gson gson = new Gson(); String json = gson.toJson(expected); assertEquals(expected, gson.fromJson(json, BitSet.class)); json = "[1,0,1,1,1,1,0,0,1,0,0,0]"; assertEquals(expected, gson.fromJson(json, BitSet.class)); json = "[\"1\",\"0\",\"1\",\"1\",\"1\",\"1\",\"0\",\"0\",\"1\"]"; assertEquals(expected, gson.fromJson(json, BitSet.class)); json = "[true,false,true,true,true,true,false,false,true,false,false]"; assertEquals(expected, gson.fromJson(json, BitSet.class)); } public void testDefaultDateSerialization() { Date now = new Date(1315806903103L); String json = gson.toJson(now); assertEquals("\"Sep 11, 2011 10:55:03 PM\"", json); } public void testDefaultDateDeserialization() { String json = "'Dec 13, 2009 07:18:02 AM'"; Date extracted = gson.fromJson(json, Date.class); assertEqualsDate(extracted, 2009, 11, 13); assertEqualsTime(extracted, 7, 18, 2); } // Date can not directly be compared with another instance since the deserialization loses the // millisecond portion. @SuppressWarnings("deprecation") private void assertEqualsDate(Date date, int year, int month, int day) { assertEquals(year-1900, date.getYear()); assertEquals(month, date.getMonth()); assertEquals(day, date.getDate()); } @SuppressWarnings("deprecation") private void assertEqualsTime(Date date, int hours, int minutes, int seconds) { assertEquals(hours, date.getHours()); assertEquals(minutes, date.getMinutes()); assertEquals(seconds, date.getSeconds()); } public void testDefaultJavaSqlDateSerialization() { java.sql.Date instant = new java.sql.Date(1259875082000L); String json = gson.toJson(instant); assertEquals("\"Dec 3, 2009\"", json); } public void testDefaultJavaSqlDateDeserialization() { String json = "'Dec 3, 2009'"; java.sql.Date extracted = gson.fromJson(json, java.sql.Date.class); assertEqualsDate(extracted, 2009, 11, 3); } public void testDefaultJavaSqlTimestampSerialization() { Timestamp now = new java.sql.Timestamp(1259875082000L); String json = gson.toJson(now); assertEquals("\"Dec 3, 2009 1:18:02 PM\"", json); } public void testDefaultJavaSqlTimestampDeserialization() { String json = "'Dec 3, 2009 1:18:02 PM'"; Timestamp extracted = gson.fromJson(json, Timestamp.class); assertEqualsDate(extracted, 2009, 11, 3); assertEqualsTime(extracted, 13, 18, 2); } public void testDefaultJavaSqlTimeSerialization() { Time now = new Time(1259875082000L); String json = gson.toJson(now); assertEquals("\"01:18:02 PM\"", json); } public void testDefaultJavaSqlTimeDeserialization() { String json = "'1:18:02 PM'"; Time extracted = gson.fromJson(json, Time.class); assertEqualsTime(extracted, 13, 18, 2); } public void testDefaultDateSerializationUsingBuilder() throws Exception { Gson gson = new GsonBuilder().create(); Date now = new Date(1315806903103L); String json = gson.toJson(now); assertEquals("\"Sep 11, 2011 10:55:03 PM\"", json); } public void testDefaultDateDeserializationUsingBuilder() throws Exception { Gson gson = new GsonBuilder().create(); Date now = new Date(1315806903103L); String json = gson.toJson(now); Date extracted = gson.fromJson(json, Date.class); assertEquals(now.toString(), extracted.toString()); } public void testDefaultCalendarSerialization() throws Exception { Gson gson = new GsonBuilder().create(); String json = gson.toJson(Calendar.getInstance()); assertTrue(json.contains("year")); assertTrue(json.contains("month")); assertTrue(json.contains("dayOfMonth")); assertTrue(json.contains("hourOfDay")); assertTrue(json.contains("minute")); assertTrue(json.contains("second")); } public void testDefaultCalendarDeserialization() throws Exception { Gson gson = new GsonBuilder().create(); String json = "{year:2009,month:2,dayOfMonth:11,hourOfDay:14,minute:29,second:23}"; Calendar cal = gson.fromJson(json, Calendar.class); assertEquals(2009, cal.get(Calendar.YEAR)); assertEquals(2, cal.get(Calendar.MONTH)); assertEquals(11, cal.get(Calendar.DAY_OF_MONTH)); assertEquals(14, cal.get(Calendar.HOUR_OF_DAY)); assertEquals(29, cal.get(Calendar.MINUTE)); assertEquals(23, cal.get(Calendar.SECOND)); } public void testDefaultGregorianCalendarSerialization() throws Exception { Gson gson = new GsonBuilder().create(); GregorianCalendar cal = new GregorianCalendar(); String json = gson.toJson(cal); assertTrue(json.contains("year")); assertTrue(json.contains("month")); assertTrue(json.contains("dayOfMonth")); assertTrue(json.contains("hourOfDay")); assertTrue(json.contains("minute")); assertTrue(json.contains("second")); } public void testDefaultGregorianCalendarDeserialization() throws Exception { Gson gson = new GsonBuilder().create(); String json = "{year:2009,month:2,dayOfMonth:11,hourOfDay:14,minute:29,second:23}"; GregorianCalendar cal = gson.fromJson(json, GregorianCalendar.class); assertEquals(2009, cal.get(Calendar.YEAR)); assertEquals(2, cal.get(Calendar.MONTH)); assertEquals(11, cal.get(Calendar.DAY_OF_MONTH)); assertEquals(14, cal.get(Calendar.HOUR_OF_DAY)); assertEquals(29, cal.get(Calendar.MINUTE)); assertEquals(23, cal.get(Calendar.SECOND)); } public void testDateSerializationWithPattern() throws Exception { String pattern = "yyyy-MM-dd"; Gson gson = new GsonBuilder().setDateFormat(DateFormat.FULL).setDateFormat(pattern).create(); Date now = new Date(1315806903103L); String json = gson.toJson(now); assertEquals("\"2011-09-11\"", json); } @SuppressWarnings("deprecation") public void testDateDeserializationWithPattern() throws Exception { String pattern = "yyyy-MM-dd"; Gson gson = new GsonBuilder().setDateFormat(DateFormat.FULL).setDateFormat(pattern).create(); Date now = new Date(1315806903103L); String json = gson.toJson(now); Date extracted = gson.fromJson(json, Date.class); assertEquals(now.getYear(), extracted.getYear()); assertEquals(now.getMonth(), extracted.getMonth()); assertEquals(now.getDay(), extracted.getDay()); } public void testDateSerializationWithPatternNotOverridenByTypeAdapter() throws Exception { String pattern = "yyyy-MM-dd"; Gson gson = new GsonBuilder() .setDateFormat(pattern) .registerTypeAdapter(Date.class, new JsonDeserializer() { public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { return new Date(1315806903103L); } }) .create(); Date now = new Date(1315806903103L); String json = gson.toJson(now); assertEquals("\"2011-09-11\"", json); } // http://code.google.com/p/google-gson/issues/detail?id=230 public void testDateSerializationInCollection() throws Exception { Type listOfDates = new TypeToken>() {}.getType(); TimeZone defaultTimeZone = TimeZone.getDefault(); TimeZone.setDefault(TimeZone.getTimeZone("UTC")); Locale defaultLocale = Locale.getDefault(); Locale.setDefault(Locale.US); try { Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd").create(); List dates = Arrays.asList(new Date(0)); String json = gson.toJson(dates, listOfDates); assertEquals("[\"1970-01-01\"]", json); assertEquals(0L, gson.>fromJson("[\"1970-01-01\"]", listOfDates).get(0).getTime()); } finally { TimeZone.setDefault(defaultTimeZone); Locale.setDefault(defaultLocale); } } // http://code.google.com/p/google-gson/issues/detail?id=230 public void testTimestampSerialization() throws Exception { TimeZone defaultTimeZone = TimeZone.getDefault(); TimeZone.setDefault(TimeZone.getTimeZone("UTC")); Locale defaultLocale = Locale.getDefault(); Locale.setDefault(Locale.US); try { Timestamp timestamp = new Timestamp(0L); Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd").create(); String json = gson.toJson(timestamp, Timestamp.class); assertEquals("\"1970-01-01\"", json); assertEquals(0, gson.fromJson("\"1970-01-01\"", Timestamp.class).getTime()); } finally { TimeZone.setDefault(defaultTimeZone); Locale.setDefault(defaultLocale); } } // http://code.google.com/p/google-gson/issues/detail?id=230 public void testSqlDateSerialization() throws Exception { TimeZone defaultTimeZone = TimeZone.getDefault(); TimeZone.setDefault(TimeZone.getTimeZone("UTC")); Locale defaultLocale = Locale.getDefault(); Locale.setDefault(Locale.US); try { java.sql.Date sqlDate = new java.sql.Date(0L); Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd").create(); String json = gson.toJson(sqlDate, Timestamp.class); assertEquals("\"1970-01-01\"", json); assertEquals(0, gson.fromJson("\"1970-01-01\"", java.sql.Date.class).getTime()); } finally { TimeZone.setDefault(defaultTimeZone); Locale.setDefault(defaultLocale); } } public void testJsonPrimitiveSerialization() { assertEquals("5", gson.toJson(new JsonPrimitive(5), JsonElement.class)); assertEquals("true", gson.toJson(new JsonPrimitive(true), JsonElement.class)); assertEquals("\"foo\"", gson.toJson(new JsonPrimitive("foo"), JsonElement.class)); assertEquals("\"a\"", gson.toJson(new JsonPrimitive('a'), JsonElement.class)); } public void testJsonPrimitiveDeserialization() { assertEquals(new JsonPrimitive(5), gson.fromJson("5", JsonElement.class)); assertEquals(new JsonPrimitive(5), gson.fromJson("5", JsonPrimitive.class)); assertEquals(new JsonPrimitive(true), gson.fromJson("true", JsonElement.class)); assertEquals(new JsonPrimitive(true), gson.fromJson("true", JsonPrimitive.class)); assertEquals(new JsonPrimitive("foo"), gson.fromJson("\"foo\"", JsonElement.class)); assertEquals(new JsonPrimitive("foo"), gson.fromJson("\"foo\"", JsonPrimitive.class)); assertEquals(new JsonPrimitive('a'), gson.fromJson("\"a\"", JsonElement.class)); assertEquals(new JsonPrimitive('a'), gson.fromJson("\"a\"", JsonPrimitive.class)); } public void testJsonNullSerialization() { assertEquals("null", gson.toJson(JsonNull.INSTANCE, JsonElement.class)); assertEquals("null", gson.toJson(JsonNull.INSTANCE, JsonNull.class)); } public void testNullJsonElementSerialization() { assertEquals("null", gson.toJson(null, JsonElement.class)); assertEquals("null", gson.toJson(null, JsonNull.class)); } public void testJsonArraySerialization() { JsonArray array = new JsonArray(); array.add(new JsonPrimitive(1)); array.add(new JsonPrimitive(2)); array.add(new JsonPrimitive(3)); assertEquals("[1,2,3]", gson.toJson(array, JsonElement.class)); } public void testJsonArrayDeserialization() { JsonArray array = new JsonArray(); array.add(new JsonPrimitive(1)); array.add(new JsonPrimitive(2)); array.add(new JsonPrimitive(3)); String json = "[1,2,3]"; assertEquals(array, gson.fromJson(json, JsonElement.class)); assertEquals(array, gson.fromJson(json, JsonArray.class)); } public void testJsonObjectSerialization() { JsonObject object = new JsonObject(); object.add("foo", new JsonPrimitive(1)); object.add("bar", new JsonPrimitive(2)); assertEquals("{\"foo\":1,\"bar\":2}", gson.toJson(object, JsonElement.class)); } public void testJsonObjectDeserialization() { JsonObject object = new JsonObject(); object.add("foo", new JsonPrimitive(1)); object.add("bar", new JsonPrimitive(2)); String json = "{\"foo\":1,\"bar\":2}"; JsonElement actual = gson.fromJson(json, JsonElement.class); assertEquals(object, actual); JsonObject actualObj = gson.fromJson(json, JsonObject.class); assertEquals(object, actualObj); } public void testJsonNullDeserialization() { assertEquals(JsonNull.INSTANCE, gson.fromJson("null", JsonElement.class)); assertEquals(JsonNull.INSTANCE, gson.fromJson("null", JsonNull.class)); } private static class ClassWithBigDecimal { BigDecimal value; ClassWithBigDecimal(String value) { this.value = new BigDecimal(value); } String getExpectedJson() { return "{\"value\":" + value.toEngineeringString() + "}"; } } private static class ClassWithBigInteger { BigInteger value; ClassWithBigInteger(String value) { this.value = new BigInteger(value); } String getExpectedJson() { return "{\"value\":" + value + "}"; } } public void testPropertiesSerialization() { Properties props = new Properties(); props.setProperty("foo", "bar"); String json = gson.toJson(props); String expected = "{\"foo\":\"bar\"}"; assertEquals(expected, json); } public void testPropertiesDeserialization() { String json = "{foo:'bar'}"; Properties props = gson.fromJson(json, Properties.class); assertEquals("bar", props.getProperty("foo")); } public void testTreeSetSerialization() { TreeSet treeSet = new TreeSet(); treeSet.add("Value1"); String json = gson.toJson(treeSet); assertEquals("[\"Value1\"]", json); } public void testTreeSetDeserialization() { String json = "['Value1']"; Type type = new TypeToken>() {}.getType(); TreeSet treeSet = gson.fromJson(json, type); assertTrue(treeSet.contains("Value1")); } public void testStringBuilderSerialization() { StringBuilder sb = new StringBuilder("abc"); String json = gson.toJson(sb); assertEquals("\"abc\"", json); } public void testStringBuilderDeserialization() { StringBuilder sb = gson.fromJson("'abc'", StringBuilder.class); assertEquals("abc", sb.toString()); } public void testStringBufferSerialization() { StringBuffer sb = new StringBuffer("abc"); String json = gson.toJson(sb); assertEquals("\"abc\"", json); } public void testStringBufferDeserialization() { StringBuffer sb = gson.fromJson("'abc'", StringBuffer.class); assertEquals("abc", sb.toString()); } @SuppressWarnings("rawtypes") private static class MyClassTypeAdapter extends TypeAdapter { @Override public void write(JsonWriter out, Class value) throws IOException { out.value(value.getName()); } @Override public Class read(JsonReader in) throws IOException { String className = in.nextString(); try { return Class.forName(className); } catch (ClassNotFoundException e) { throw new IOException(e); } } } static class NumberAsStringAdapter extends TypeAdapter { private final Constructor constructor; NumberAsStringAdapter(Class type) throws Exception { this.constructor = type.getConstructor(String.class); } @Override public void write(JsonWriter out, Number value) throws IOException { out.value(value.toString()); } @Override public Number read(JsonReader in) throws IOException { try { return constructor.newInstance(in.nextString()); } catch (Exception e) { throw new AssertionError(e); } } } } google-gson/src/test/java/com/google/gson/functional/CustomTypeAdaptersTest.java0000664000175000017500000004103712006314117027764 0ustar ebourgebourg/* * 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.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; import com.google.gson.JsonPrimitive; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; import com.google.gson.common.TestTypes.BagOfPrimitives; import com.google.gson.common.TestTypes.ClassWithCustomTypeConverter; import com.google.gson.reflect.TypeToken; import java.util.Date; import junit.framework.TestCase; import java.lang.reflect.Type; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; /** * Functional tests for the support of custom serializer and deserializers. * * @author Inderjeet Singh * @author Joel Leitch */ public class CustomTypeAdaptersTest extends TestCase { private GsonBuilder builder; @Override protected void setUp() throws Exception { super.setUp(); builder = new GsonBuilder(); } public void testCustomSerializers() { Gson gson = builder.registerTypeAdapter( ClassWithCustomTypeConverter.class, new JsonSerializer() { public JsonElement serialize(ClassWithCustomTypeConverter src, Type typeOfSrc, JsonSerializationContext context) { JsonObject json = new JsonObject(); json.addProperty("bag", 5); json.addProperty("value", 25); return json; } }).create(); ClassWithCustomTypeConverter target = new ClassWithCustomTypeConverter(); assertEquals("{\"bag\":5,\"value\":25}", gson.toJson(target)); } public void testCustomDeserializers() { Gson gson = new GsonBuilder().registerTypeAdapter( ClassWithCustomTypeConverter.class, new JsonDeserializer() { public ClassWithCustomTypeConverter deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) { JsonObject jsonObject = json.getAsJsonObject(); int value = jsonObject.get("bag").getAsInt(); return new ClassWithCustomTypeConverter(new BagOfPrimitives(value, value, false, ""), value); } }).create(); String json = "{\"bag\":5,\"value\":25}"; ClassWithCustomTypeConverter target = gson.fromJson(json, ClassWithCustomTypeConverter.class); assertEquals(5, target.getBag().getIntValue()); } public void disable_testCustomSerializersOfSelf() { Gson gson = createGsonObjectWithFooTypeAdapter(); Gson basicGson = new Gson(); Foo newFooObject = new Foo(1, 2L); String jsonFromCustomSerializer = gson.toJson(newFooObject); String jsonFromGson = basicGson.toJson(newFooObject); assertEquals(jsonFromGson, jsonFromCustomSerializer); } public void disable_testCustomDeserializersOfSelf() { Gson gson = createGsonObjectWithFooTypeAdapter(); Gson basicGson = new Gson(); Foo expectedFoo = new Foo(1, 2L); String json = basicGson.toJson(expectedFoo); Foo newFooObject = gson.fromJson(json, Foo.class); assertEquals(expectedFoo.key, newFooObject.key); assertEquals(expectedFoo.value, newFooObject.value); } public void testCustomNestedSerializers() { Gson gson = new GsonBuilder().registerTypeAdapter( BagOfPrimitives.class, new JsonSerializer() { public JsonElement serialize(BagOfPrimitives src, Type typeOfSrc, JsonSerializationContext context) { return new JsonPrimitive(6); } }).create(); ClassWithCustomTypeConverter target = new ClassWithCustomTypeConverter(); assertEquals("{\"bag\":6,\"value\":10}", gson.toJson(target)); } public void testCustomNestedDeserializers() { Gson gson = new GsonBuilder().registerTypeAdapter( BagOfPrimitives.class, new JsonDeserializer() { public BagOfPrimitives deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { int value = json.getAsInt(); return new BagOfPrimitives(value, value, false, ""); } }).create(); String json = "{\"bag\":7,\"value\":25}"; ClassWithCustomTypeConverter target = gson.fromJson(json, ClassWithCustomTypeConverter.class); assertEquals(7, target.getBag().getIntValue()); } public void testCustomTypeAdapterDoesNotAppliesToSubClasses() { Gson gson = new GsonBuilder().registerTypeAdapter(Base.class, new JsonSerializer () { public JsonElement serialize(Base src, Type typeOfSrc, JsonSerializationContext context) { JsonObject json = new JsonObject(); json.addProperty("value", src.baseValue); return json; } }).create(); Base b = new Base(); String json = gson.toJson(b); assertTrue(json.contains("value")); b = new Derived(); json = gson.toJson(b); assertTrue(json.contains("derivedValue")); } public void testCustomTypeAdapterAppliesToSubClassesSerializedAsBaseClass() { Gson gson = new GsonBuilder().registerTypeAdapter(Base.class, new JsonSerializer () { public JsonElement serialize(Base src, Type typeOfSrc, JsonSerializationContext context) { JsonObject json = new JsonObject(); json.addProperty("value", src.baseValue); return json; } }).create(); Base b = new Base(); String json = gson.toJson(b); assertTrue(json.contains("value")); b = new Derived(); json = gson.toJson(b, Base.class); assertTrue(json.contains("value")); assertFalse(json.contains("derivedValue")); } private static class Base { int baseValue = 2; } private static class Derived extends Base { @SuppressWarnings("unused") int derivedValue = 3; } private Gson createGsonObjectWithFooTypeAdapter() { return new GsonBuilder().registerTypeAdapter(Foo.class, new FooTypeAdapter()).create(); } public static class Foo { private final int key; private final long value; public Foo() { this(0, 0L); } public Foo(int key, long value) { this.key = key; this.value = value; } } public static class FooTypeAdapter implements JsonSerializer, JsonDeserializer { public Foo deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { return context.deserialize(json, typeOfT); } public JsonElement serialize(Foo src, Type typeOfSrc, JsonSerializationContext context) { return context.serialize(src, typeOfSrc); } } public void testCustomSerializerInvokedForPrimitives() { Gson gson = new GsonBuilder() .registerTypeAdapter(boolean.class, new JsonSerializer() { public JsonElement serialize(Boolean s, Type t, JsonSerializationContext c) { return new JsonPrimitive(s ? 1 : 0); } }) .create(); assertEquals("1", gson.toJson(true, boolean.class)); assertEquals("true", gson.toJson(true, Boolean.class)); } @SuppressWarnings("rawtypes") public void testCustomDeserializerInvokedForPrimitives() { Gson gson = new GsonBuilder() .registerTypeAdapter(boolean.class, new JsonDeserializer() { public Object deserialize(JsonElement json, Type t, JsonDeserializationContext context) { return json.getAsInt() != 0; } }) .create(); assertEquals(Boolean.TRUE, gson.fromJson("1", boolean.class)); assertEquals(Boolean.TRUE, gson.fromJson("true", Boolean.class)); } public void testCustomByteArraySerializer() { Gson gson = new GsonBuilder().registerTypeAdapter(byte[].class, new JsonSerializer() { public JsonElement serialize(byte[] src, Type typeOfSrc, JsonSerializationContext context) { StringBuilder sb = new StringBuilder(src.length); for (byte b : src) { sb.append(b); } return new JsonPrimitive(sb.toString()); } }).create(); byte[] data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; String json = gson.toJson(data); assertEquals("\"0123456789\"", json); } public void testCustomByteArrayDeserializerAndInstanceCreator() { GsonBuilder gsonBuilder = new GsonBuilder().registerTypeAdapter(byte[].class, new JsonDeserializer() { public byte[] deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { String str = json.getAsString(); byte[] data = new byte[str.length()]; for (int i = 0; i < data.length; ++i) { data[i] = Byte.parseByte(""+str.charAt(i)); } return data; } }); Gson gson = gsonBuilder.create(); String json = "'0123456789'"; byte[] actual = gson.fromJson(json, byte[].class); byte[] expected = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; for (int i = 0; i < actual.length; ++i) { assertEquals(expected[i], actual[i]); } } private static class StringHolder { String part1; String part2; public StringHolder(String string) { String[] parts = string.split(":"); part1 = parts[0]; part2 = parts[1]; } public StringHolder(String part1, String part2) { this.part1 = part1; this.part2 = part2; } } private static class StringHolderTypeAdapter implements JsonSerializer, JsonDeserializer, InstanceCreator { public StringHolder createInstance(Type type) { //Fill up with objects that will be thrown away return new StringHolder("unknown:thing"); } public StringHolder deserialize(JsonElement src, Type type, JsonDeserializationContext context) { return new StringHolder(src.getAsString()); } public JsonElement serialize(StringHolder src, Type typeOfSrc, JsonSerializationContext context) { String contents = src.part1 + ':' + src.part2; return new JsonPrimitive(contents); } } // Test created from Issue 70 public void testCustomAdapterInvokedForCollectionElementSerializationWithType() { Gson gson = new GsonBuilder() .registerTypeAdapter(StringHolder.class, new StringHolderTypeAdapter()) .create(); Type setType = new TypeToken>() {}.getType(); StringHolder holder = new StringHolder("Jacob", "Tomaw"); Set setOfHolders = new HashSet(); setOfHolders.add(holder); String json = gson.toJson(setOfHolders, setType); assertTrue(json.contains("Jacob:Tomaw")); } // Test created from Issue 70 public void testCustomAdapterInvokedForCollectionElementSerialization() { Gson gson = new GsonBuilder() .registerTypeAdapter(StringHolder.class, new StringHolderTypeAdapter()) .create(); StringHolder holder = new StringHolder("Jacob", "Tomaw"); Set setOfHolders = new HashSet(); setOfHolders.add(holder); String json = gson.toJson(setOfHolders); assertTrue(json.contains("Jacob:Tomaw")); } // Test created from Issue 70 public void testCustomAdapterInvokedForCollectionElementDeserialization() { Gson gson = new GsonBuilder() .registerTypeAdapter(StringHolder.class, new StringHolderTypeAdapter()) .create(); Type setType = new TypeToken>() {}.getType(); Set setOfHolders = gson.fromJson("['Jacob:Tomaw']", setType); assertEquals(1, setOfHolders.size()); StringHolder foo = setOfHolders.iterator().next(); assertEquals("Jacob", foo.part1); assertEquals("Tomaw", foo.part2); } // Test created from Issue 70 public void testCustomAdapterInvokedForMapElementSerializationWithType() { Gson gson = new GsonBuilder() .registerTypeAdapter(StringHolder.class, new StringHolderTypeAdapter()) .create(); Type mapType = new TypeToken>() {}.getType(); StringHolder holder = new StringHolder("Jacob", "Tomaw"); Map mapOfHolders = new HashMap(); mapOfHolders.put("foo", holder); String json = gson.toJson(mapOfHolders, mapType); assertTrue(json.contains("\"foo\":\"Jacob:Tomaw\"")); } // Test created from Issue 70 public void testCustomAdapterInvokedForMapElementSerialization() { Gson gson = new GsonBuilder() .registerTypeAdapter(StringHolder.class, new StringHolderTypeAdapter()) .create(); StringHolder holder = new StringHolder("Jacob", "Tomaw"); Map mapOfHolders = new HashMap(); mapOfHolders.put("foo", holder); String json = gson.toJson(mapOfHolders); assertTrue(json.contains("\"foo\":\"Jacob:Tomaw\"")); } // Test created from Issue 70 public void testCustomAdapterInvokedForMapElementDeserialization() { Gson gson = new GsonBuilder() .registerTypeAdapter(StringHolder.class, new StringHolderTypeAdapter()) .create(); Type mapType = new TypeToken>() {}.getType(); Map mapOfFoo = gson.fromJson("{'foo':'Jacob:Tomaw'}", mapType); assertEquals(1, mapOfFoo.size()); StringHolder foo = mapOfFoo.get("foo"); assertEquals("Jacob", foo.part1); assertEquals("Tomaw", foo.part2); } public void testEnsureCustomSerializerNotInvokedForNullValues() { Gson gson = new GsonBuilder() .registerTypeAdapter(DataHolder.class, new DataHolderSerializer()) .create(); DataHolderWrapper target = new DataHolderWrapper(new DataHolder("abc")); String json = gson.toJson(target); assertEquals("{\"wrappedData\":{\"myData\":\"abc\"}}", json); } public void testEnsureCustomDeserializerNotInvokedForNullValues() { Gson gson = new GsonBuilder() .registerTypeAdapter(DataHolder.class, new DataHolderDeserializer()) .create(); String json = "{wrappedData:null}"; DataHolderWrapper actual = gson.fromJson(json, DataHolderWrapper.class); assertNull(actual.wrappedData); } // Test created from Issue 352 public void testRegisterHierarchyAdapterForDate() { Gson gson = new GsonBuilder() .registerTypeHierarchyAdapter(Date.class, new DateTypeAdapter()) .create(); assertEquals("0", gson.toJson(new Date(0))); assertEquals("0", gson.toJson(new java.sql.Date(0))); assertEquals(new Date(0), gson.fromJson("0", Date.class)); assertEquals(new java.sql.Date(0), gson.fromJson("0", java.sql.Date.class)); } private static class DataHolder { final String data; public DataHolder(String data) { this.data = data; } } private static class DataHolderWrapper { final DataHolder wrappedData; public DataHolderWrapper(DataHolder data) { this.wrappedData = data; } } private static class DataHolderSerializer implements JsonSerializer { public JsonElement serialize(DataHolder src, Type typeOfSrc, JsonSerializationContext context) { JsonObject obj = new JsonObject(); obj.addProperty("myData", src.data); return obj; } } private static class DataHolderDeserializer implements JsonDeserializer { public DataHolder deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { JsonObject jsonObj = json.getAsJsonObject(); JsonElement jsonElement = jsonObj.get("data"); if (jsonElement == null || jsonElement.isJsonNull()) { return new DataHolder(null); } return new DataHolder(jsonElement.getAsString()); } } private static class DateTypeAdapter implements JsonSerializer, JsonDeserializer { public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { return typeOfT == Date.class ? new Date(json.getAsLong()) : new java.sql.Date(json.getAsLong()); } public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) { return new JsonPrimitive(src.getTime()); } } } google-gson/src/test/java/com/google/gson/functional/ParameterizedTypesTest.java0000664000175000017500000004457211662261616030030 0ustar ebourgebourg/* * 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.ParameterizedTypeFixtures.MyParameterizedType; import com.google.gson.ParameterizedTypeFixtures.MyParameterizedTypeAdapter; import com.google.gson.ParameterizedTypeFixtures.MyParameterizedTypeInstanceCreator; import com.google.gson.common.TestTypes.BagOfPrimitives; import com.google.gson.reflect.TypeToken; import junit.framework.TestCase; import java.io.Reader; import java.io.Serializable; import java.io.StringReader; import java.io.StringWriter; import java.io.Writer; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * Functional tests for the serialization and deserialization of parameterized types in Gson. * * @author Inderjeet Singh * @author Joel Leitch */ public class ParameterizedTypesTest extends TestCase { private Gson gson; @Override protected void setUp() throws Exception { super.setUp(); gson = new Gson(); } public void testParameterizedTypesSerialization() throws Exception { MyParameterizedType src = new MyParameterizedType(10); Type typeOfSrc = new TypeToken>() {}.getType(); String json = gson.toJson(src, typeOfSrc); assertEquals(src.getExpectedJson(), json); } public void testParameterizedTypeDeserialization() throws Exception { BagOfPrimitives bag = new BagOfPrimitives(); MyParameterizedType expected = new MyParameterizedType(bag); Type expectedType = new TypeToken>() {}.getType(); BagOfPrimitives bagDefaultInstance = new BagOfPrimitives(); Gson gson = new GsonBuilder().registerTypeAdapter( expectedType, new MyParameterizedTypeInstanceCreator(bagDefaultInstance)) .create(); String json = expected.getExpectedJson(); MyParameterizedType actual = gson.fromJson(json, expectedType); assertEquals(expected, actual); } public void testTypesWithMultipleParametersSerialization() throws Exception { MultiParameters src = new MultiParameters(10, 1.0F, 2.1D, "abc", new BagOfPrimitives()); Type typeOfSrc = new TypeToken>() {}.getType(); String json = gson.toJson(src, typeOfSrc); String expected = "{\"a\":10,\"b\":1.0,\"c\":2.1,\"d\":\"abc\"," + "\"e\":{\"longValue\":0,\"intValue\":0,\"booleanValue\":false,\"stringValue\":\"\"}}"; assertEquals(expected, json); } public void testTypesWithMultipleParametersDeserialization() throws Exception { Type typeOfTarget = new TypeToken>() {}.getType(); String json = "{\"a\":10,\"b\":1.0,\"c\":2.1,\"d\":\"abc\"," + "\"e\":{\"longValue\":0,\"intValue\":0,\"booleanValue\":false,\"stringValue\":\"\"}}"; MultiParameters target = gson.fromJson(json, typeOfTarget); MultiParameters expected = new MultiParameters(10, 1.0F, 2.1D, "abc", new BagOfPrimitives()); assertEquals(expected, target); } public void testParameterizedTypeWithCustomSerializer() { Type ptIntegerType = new TypeToken>() {}.getType(); Type ptStringType = new TypeToken>() {}.getType(); Gson gson = new GsonBuilder() .registerTypeAdapter(ptIntegerType, new MyParameterizedTypeAdapter()) .registerTypeAdapter(ptStringType, new MyParameterizedTypeAdapter()) .create(); MyParameterizedType intTarget = new MyParameterizedType(10); String json = gson.toJson(intTarget, ptIntegerType); assertEquals(MyParameterizedTypeAdapter.getExpectedJson(intTarget), json); MyParameterizedType stringTarget = new MyParameterizedType("abc"); json = gson.toJson(stringTarget, ptStringType); assertEquals(MyParameterizedTypeAdapter.getExpectedJson(stringTarget), json); } public void testParameterizedTypesWithCustomDeserializer() { Type ptIntegerType = new TypeToken>() {}.getType(); Type ptStringType = new TypeToken>() {}.getType(); Gson gson = new GsonBuilder().registerTypeAdapter( ptIntegerType, new MyParameterizedTypeAdapter()) .registerTypeAdapter(ptStringType, new MyParameterizedTypeAdapter()) .registerTypeAdapter(ptStringType, new MyParameterizedTypeInstanceCreator("")) .registerTypeAdapter(ptIntegerType, new MyParameterizedTypeInstanceCreator(new Integer(0))) .create(); MyParameterizedType src = new MyParameterizedType(10); String json = MyParameterizedTypeAdapter.getExpectedJson(src); MyParameterizedType intTarget = gson.fromJson(json, ptIntegerType); assertEquals(10, intTarget.value.intValue()); MyParameterizedType srcStr = new MyParameterizedType("abc"); json = MyParameterizedTypeAdapter.getExpectedJson(srcStr); MyParameterizedType stringTarget = gson.fromJson(json, ptStringType); assertEquals("abc", stringTarget.value); } public void testParameterizedTypesWithWriterSerialization() throws Exception { Writer writer = new StringWriter(); MyParameterizedType src = new MyParameterizedType(10); Type typeOfSrc = new TypeToken>() {}.getType(); gson.toJson(src, typeOfSrc, writer); assertEquals(src.getExpectedJson(), writer.toString()); } public void testParameterizedTypeWithReaderDeserialization() throws Exception { BagOfPrimitives bag = new BagOfPrimitives(); MyParameterizedType expected = new MyParameterizedType(bag); Type expectedType = new TypeToken>() {}.getType(); BagOfPrimitives bagDefaultInstance = new BagOfPrimitives(); Gson gson = new GsonBuilder().registerTypeAdapter( expectedType, new MyParameterizedTypeInstanceCreator(bagDefaultInstance)) .create(); Reader json = new StringReader(expected.getExpectedJson()); MyParameterizedType actual = gson.fromJson(json, expectedType); assertEquals(expected, actual); } @SuppressWarnings("unchecked") public void testVariableTypeFieldsAndGenericArraysSerialization() throws Exception { Integer obj = 0; Integer[] array = { 1, 2, 3 }; List list = new ArrayList(); list.add(4); list.add(5); List[] arrayOfLists = new List[] { list, list }; Type typeOfSrc = new TypeToken>() {}.getType(); ObjectWithTypeVariables objToSerialize = new ObjectWithTypeVariables(obj, array, list, arrayOfLists, list, arrayOfLists); String json = gson.toJson(objToSerialize, typeOfSrc); assertEquals(objToSerialize.getExpectedJson(), json); } @SuppressWarnings("unchecked") public void testVariableTypeFieldsAndGenericArraysDeserialization() throws Exception { Integer obj = 0; Integer[] array = { 1, 2, 3 }; List list = new ArrayList(); list.add(4); list.add(5); List[] arrayOfLists = new List[] { list, list }; Type typeOfSrc = new TypeToken>() {}.getType(); ObjectWithTypeVariables objToSerialize = new ObjectWithTypeVariables(obj, array, list, arrayOfLists, list, arrayOfLists); String json = gson.toJson(objToSerialize, typeOfSrc); ObjectWithTypeVariables objAfterDeserialization = gson.fromJson(json, typeOfSrc); assertEquals(objAfterDeserialization.getExpectedJson(), json); } public void testVariableTypeDeserialization() throws Exception { Type typeOfSrc = new TypeToken>() {}.getType(); ObjectWithTypeVariables objToSerialize = new ObjectWithTypeVariables(0, null, null, null, null, null); String json = gson.toJson(objToSerialize, typeOfSrc); ObjectWithTypeVariables objAfterDeserialization = gson.fromJson(json, typeOfSrc); assertEquals(objAfterDeserialization.getExpectedJson(), json); } public void testVariableTypeArrayDeserialization() throws Exception { Integer[] array = { 1, 2, 3 }; Type typeOfSrc = new TypeToken>() {}.getType(); ObjectWithTypeVariables objToSerialize = new ObjectWithTypeVariables(null, array, null, null, null, null); String json = gson.toJson(objToSerialize, typeOfSrc); ObjectWithTypeVariables objAfterDeserialization = gson.fromJson(json, typeOfSrc); assertEquals(objAfterDeserialization.getExpectedJson(), json); } public void testParameterizedTypeWithVariableTypeDeserialization() throws Exception { List list = new ArrayList(); list.add(4); list.add(5); Type typeOfSrc = new TypeToken>() {}.getType(); ObjectWithTypeVariables objToSerialize = new ObjectWithTypeVariables(null, null, list, null, null, null); String json = gson.toJson(objToSerialize, typeOfSrc); ObjectWithTypeVariables objAfterDeserialization = gson.fromJson(json, typeOfSrc); assertEquals(objAfterDeserialization.getExpectedJson(), json); } @SuppressWarnings("unchecked") public void testParameterizedTypeGenericArraysSerialization() throws Exception { List list = new ArrayList(); list.add(1); list.add(2); List[] arrayOfLists = new List[] { list, list }; Type typeOfSrc = new TypeToken>() {}.getType(); ObjectWithTypeVariables objToSerialize = new ObjectWithTypeVariables(null, null, null, arrayOfLists, null, null); String json = gson.toJson(objToSerialize, typeOfSrc); assertEquals("{\"arrayOfListOfTypeParameters\":[[1,2],[1,2]]}", json); } @SuppressWarnings("unchecked") public void testParameterizedTypeGenericArraysDeserialization() throws Exception { List list = new ArrayList(); list.add(1); list.add(2); List[] arrayOfLists = new List[] { list, list }; Type typeOfSrc = new TypeToken>() {}.getType(); ObjectWithTypeVariables objToSerialize = new ObjectWithTypeVariables(null, null, null, arrayOfLists, null, null); String json = gson.toJson(objToSerialize, typeOfSrc); ObjectWithTypeVariables objAfterDeserialization = gson.fromJson(json, typeOfSrc); assertEquals(objAfterDeserialization.getExpectedJson(), json); } /** * An test object that has fields that are type variables. * * @param Enforce T to be a string to make writing the "toExpectedJson" method easier. */ private static class ObjectWithTypeVariables { private final T typeParameterObj; private final T[] typeParameterArray; private final List listOfTypeParameters; private final List[] arrayOfListOfTypeParameters; private final List listOfWildcardTypeParameters; private final List[] arrayOfListOfWildcardTypeParameters; // For use by Gson @SuppressWarnings("unused") private ObjectWithTypeVariables() { this(null, null, null, null, null, null); } public ObjectWithTypeVariables(T obj, T[] array, List list, List[] arrayOfList, List wildcardList, List[] arrayOfWildcardList) { this.typeParameterObj = obj; this.typeParameterArray = array; this.listOfTypeParameters = list; this.arrayOfListOfTypeParameters = arrayOfList; this.listOfWildcardTypeParameters = wildcardList; this.arrayOfListOfWildcardTypeParameters = arrayOfWildcardList; } public String getExpectedJson() { StringBuilder sb = new StringBuilder().append("{"); boolean needsComma = false; if (typeParameterObj != null) { sb.append("\"typeParameterObj\":").append(toString(typeParameterObj)); needsComma = true; } if (typeParameterArray != null) { if (needsComma) { sb.append(','); } sb.append("\"typeParameterArray\":["); appendObjectsToBuilder(sb, Arrays.asList(typeParameterArray)); sb.append(']'); needsComma = true; } if (listOfTypeParameters != null) { if (needsComma) { sb.append(','); } sb.append("\"listOfTypeParameters\":["); appendObjectsToBuilder(sb, listOfTypeParameters); sb.append(']'); needsComma = true; } if (arrayOfListOfTypeParameters != null) { if (needsComma) { sb.append(','); } sb.append("\"arrayOfListOfTypeParameters\":["); appendObjectsToBuilder(sb, arrayOfListOfTypeParameters); sb.append(']'); needsComma = true; } if (listOfWildcardTypeParameters != null) { if (needsComma) { sb.append(','); } sb.append("\"listOfWildcardTypeParameters\":["); appendObjectsToBuilder(sb, listOfWildcardTypeParameters); sb.append(']'); needsComma = true; } if (arrayOfListOfWildcardTypeParameters != null) { if (needsComma) { sb.append(','); } sb.append("\"arrayOfListOfWildcardTypeParameters\":["); appendObjectsToBuilder(sb, arrayOfListOfWildcardTypeParameters); sb.append(']'); needsComma = true; } sb.append('}'); return sb.toString(); } private void appendObjectsToBuilder(StringBuilder sb, Iterable iterable) { boolean isFirst = true; for (T obj : iterable) { if (!isFirst) { sb.append(','); } isFirst = false; sb.append(toString(obj)); } } private void appendObjectsToBuilder(StringBuilder sb, List[] arrayOfList) { boolean isFirst = true; for (List list : arrayOfList) { if (!isFirst) { sb.append(','); } isFirst = false; if (list != null) { sb.append('['); appendObjectsToBuilder(sb, list); sb.append(']'); } else { sb.append("null"); } } } public String toString(T obj) { return obj.toString(); } } private static class MultiParameters { A a; B b; C c; D d; E e; // For use by Gson @SuppressWarnings("unused") private MultiParameters() { } MultiParameters(A a, B b, C c, D d, E e) { super(); this.a = a; this.b = b; this.c = c; this.d = d; this.e = e; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((a == null) ? 0 : a.hashCode()); result = prime * result + ((b == null) ? 0 : b.hashCode()); result = prime * result + ((c == null) ? 0 : c.hashCode()); result = prime * result + ((d == null) ? 0 : d.hashCode()); result = prime * result + ((e == null) ? 0 : e.hashCode()); return result; } @Override @SuppressWarnings("unchecked") public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } MultiParameters other = (MultiParameters) obj; if (a == null) { if (other.a != null) { return false; } } else if (!a.equals(other.a)) { return false; } if (b == null) { if (other.b != null) { return false; } } else if (!b.equals(other.b)) { return false; } if (c == null) { if (other.c != null) { return false; } } else if (!c.equals(other.c)) { return false; } if (d == null) { if (other.d != null) { return false; } } else if (!d.equals(other.d)) { return false; } if (e == null) { if (other.e != null) { return false; } } else if (!e.equals(other.e)) { return false; } return true; } } // Begin: tests to reproduce issue 103 private static class Quantity { @SuppressWarnings("unused") int q = 10; } private static class MyQuantity extends Quantity { @SuppressWarnings("unused") int q2 = 20; } private interface Measurable { } private interface Field { } private interface Immutable { } public static final class Amount implements Measurable, Field>, Serializable, Immutable { private static final long serialVersionUID = -7560491093120970437L; int value = 30; } public void testDeepParameterizedTypeSerialization() { Amount amount = new Amount(); String json = gson.toJson(amount); assertTrue(json.contains("value")); assertTrue(json.contains("30")); } public void testDeepParameterizedTypeDeserialization() { String json = "{value:30}"; Type type = new TypeToken>() {}.getType(); Amount amount = gson.fromJson(json, type); assertEquals(30, amount.value); } // End: tests to reproduce issue 103 } google-gson/src/test/java/com/google/gson/functional/CircularReferenceTest.java0000664000175000017500000001032111640673703027553 0ustar ebourgebourg/* * 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 java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collection; import junit.framework.TestCase; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; import com.google.gson.common.TestTypes.ClassOverridingEquals; /** * Functional tests related to circular reference detection and error reporting. * * @author Inderjeet Singh * @author Joel Leitch */ public class CircularReferenceTest extends TestCase { private Gson gson; @Override protected void setUp() throws Exception { super.setUp(); gson = new Gson(); } 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 (StackOverflowError 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 (StackOverflowError expected) { } } public void testSelfReferenceArrayFieldSerialization() throws Exception { ClassWithSelfReferenceArray objA = new ClassWithSelfReferenceArray(); objA.children = new ClassWithSelfReferenceArray[]{objA}; try { gson.toJson(objA); fail("Circular reference to self can not be serialized!"); } catch (StackOverflowError expected) { } } public void testSelfReferenceCustomHandlerSerialization() throws Exception { ClassWithSelfReference obj = new ClassWithSelfReference(); obj.child = obj; Gson gson = new GsonBuilder().registerTypeAdapter(ClassWithSelfReference.class, new JsonSerializer() { public JsonElement serialize(ClassWithSelfReference src, Type typeOfSrc, JsonSerializationContext context) { JsonObject obj = new JsonObject(); obj.addProperty("property", "value"); obj.add("child", context.serialize(src.child)); return obj; } }).create(); try { gson.toJson(obj); fail("Circular reference to self can not be serialized!"); } catch (StackOverflowError expected) { } } 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()); } private static class ContainsReferenceToSelfType { Collection children = new ArrayList(); } private static class ClassWithSelfReference { ClassWithSelfReference child; } private static class ClassWithSelfReferenceArray { @SuppressWarnings("unused") ClassWithSelfReferenceArray[] children; } } google-gson/src/test/java/com/google/gson/functional/TreeTypeAdaptersTest.java0000664000175000017500000001305011663140617027415 0ustar ebourgebourg/* * Copyright (C) 2011 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 java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import junit.framework.TestCase; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonParseException; import com.google.gson.JsonPrimitive; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; import com.google.gson.reflect.TypeToken; /** * Collection of functional tests for DOM tree based type adapters. */ public class TreeTypeAdaptersTest extends TestCase { private static final Id STUDENT1_ID = new Id("5", Student.class); private static final Id STUDENT2_ID = new Id("6", Student.class); private static final Student STUDENT1 = new Student(STUDENT1_ID, "first"); private static final Student STUDENT2 = new Student(STUDENT2_ID, "second"); private static final Type TYPE_COURSE_HISTORY = new TypeToken>(){}.getType(); private static final Id> COURSE_ID = new Id>("10", TYPE_COURSE_HISTORY); private Gson gson; private Course course; @Override protected void setUp() { gson = new GsonBuilder() .registerTypeAdapter(Id.class, new IdTreeTypeAdapter()) .create(); course = new Course(COURSE_ID, 4, new Assignment(null, null), createList(STUDENT1, STUDENT2)); } public void testSerializeId() { String json = gson.toJson(course, TYPE_COURSE_HISTORY); assertTrue(json.contains(String.valueOf(COURSE_ID.getValue()))); assertTrue(json.contains(String.valueOf(STUDENT1_ID.getValue()))); assertTrue(json.contains(String.valueOf(STUDENT2_ID.getValue()))); } public void testDeserializeId() { String json = "{courseId:1,students:[{id:1,name:'first'},{id:6,name:'second'}]," + "numAssignments:4,assignment:{}}"; Course target = gson.fromJson(json, TYPE_COURSE_HISTORY); assertEquals("1", target.getStudents().get(0).id.getValue()); assertEquals("6", target.getStudents().get(1).id.getValue()); assertEquals("1", target.getId().getValue()); } private static final class Id { final String value; @SuppressWarnings("unused") final Type typeOfId; private Id(String value, Type typeOfId) { this.value = value; this.typeOfId = typeOfId; } public String getValue() { return value; } } private static final class IdTreeTypeAdapter implements JsonSerializer>, JsonDeserializer> { @SuppressWarnings("rawtypes") public Id deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { if (!(typeOfT instanceof ParameterizedType)) { throw new JsonParseException("Id of unknown type: " + typeOfT); } ParameterizedType parameterizedType = (ParameterizedType) typeOfT; // Since Id takes only one TypeVariable, the actual type corresponding to the first // TypeVariable is the Type we are looking for Type typeOfId = parameterizedType.getActualTypeArguments()[0]; return new Id(json.getAsString(), typeOfId); } public JsonElement serialize(Id src, Type typeOfSrc, JsonSerializationContext context) { return new JsonPrimitive(src.getValue()); } } @SuppressWarnings("unused") private static class Student { Id id; String name; private Student() { this(null, null); } public Student(Id id, String name) { this.id = id; this.name = name; } } @SuppressWarnings("unused") private static class Course { final List students; private final Id> courseId; private final int numAssignments; private final Assignment assignment; private Course() { this(null, 0, null, new ArrayList()); } public Course(Id> courseId, int numAssignments, Assignment assignment, List players) { this.courseId = courseId; this.numAssignments = numAssignments; this.assignment = assignment; this.students = players; } public Id> getId() { return courseId; } List getStudents() { return students; } } @SuppressWarnings("unused") private static class Assignment { private final Id> id; private final T data; private Assignment() { this(null, null); } public Assignment(Id> id, T data) { this.id = id; this.data = data; } } @SuppressWarnings("unused") private static class HistoryCourse { int numClasses; } private static List createList(T ...items) { return Arrays.asList(items); } } google-gson/src/test/java/com/google/gson/functional/ObjectTest.java0000664000175000017500000004264012132065234025376 0ustar ebourgebourg/* * 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.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; 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.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.Nested; import com.google.gson.common.TestTypes.PrimitiveArray; import com.google.gson.reflect.TypeToken; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.TimeZone; import junit.framework.TestCase; /** * Functional tests for Json serialization and deserialization of regular classes. * * @author Inderjeet Singh * @author Joel Leitch */ public class ObjectTest extends TestCase { private Gson gson; private TimeZone oldTimeZone = TimeZone.getDefault(); @Override protected void setUp() throws Exception { super.setUp(); gson = new Gson(); TimeZone.setDefault(TimeZone.getTimeZone("America/Los_Angeles")); Locale.setDefault(Locale.US); } @Override protected void tearDown() throws Exception { TimeZone.setDefault(oldTimeZone); super.tearDown(); } 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 testClassWithTransientFieldsSerialization() throws Exception { ClassWithTransientFields target = new ClassWithTransientFields(1L); assertEquals(target.getExpectedJson(), gson.toJson(target)); } @SuppressWarnings("rawtypes") public void testClassWithTransientFieldsDeserialization() throws Exception { String json = "{\"longValue\":[1]}"; ClassWithTransientFields target = gson.fromJson(json, ClassWithTransientFields.class); assertEquals(json, target.getExpectedJson()); } @SuppressWarnings("rawtypes") 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 testNullSerialization() throws Exception { assertEquals("null", gson.toJson(null)); } public void testEmptyStringDeserialization() throws Exception { Object object = gson.fromJson("", Object.class); assertNull(object); } public void testTruncatedDeserialization() { try { gson.fromJson("[\"a\", \"b\",", new TypeToken>() {}.getType()); fail(); } catch (JsonParseException expected) { } } public void testNullDeserialization() throws Exception { String myNullObject = null; Object object = gson.fromJson(myNullObject, Object.class); assertNull(object); } 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 testArrayOfObjectsAsFields() throws Exception { ClassWithObjects classWithObjects = new ClassWithObjects(); BagOfPrimitives bagOfPrimitives = new BagOfPrimitives(); String stringValue = "someStringValueInArray"; String classWithObjectsJson = gson.toJson(classWithObjects); String bagOfPrimitivesJson = gson.toJson(bagOfPrimitives); ClassWithArray classWithArray = new ClassWithArray( new Object[] { stringValue, classWithObjects, bagOfPrimitives }); String json = gson.toJson(classWithArray); assertTrue(json.contains(classWithObjectsJson)); assertTrue(json.contains(bagOfPrimitivesJson)); assertTrue(json.contains("\"" + stringValue + "\"")); } /** * 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\":[]}"; ClassWithCollectionField target = gson.fromJson(json, ClassWithCollectionField.class); assertNotNull(target); assertTrue(target.children.isEmpty()); } private static class ClassWithCollectionField { Collection children = new ArrayList(); } 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 { ClassWithCollectionField target = new ClassWithCollectionField(); assertEquals("{\"children\":[]}", gson.toJson(target)); } public void testPrivateNoArgConstructorDeserialization() throws Exception { ClassWithPrivateNoArgsConstructor target = gson.fromJson("{\"a\":20}", ClassWithPrivateNoArgsConstructor.class); assertEquals(20, target.a); } public void testAnonymousLocalClassesSerialization() throws Exception { assertEquals("null", gson.toJson(new ClassWithNoFields() { // empty anonymous class })); } public void testAnonymousLocalClassesCustomSerialization() throws Exception { gson = new GsonBuilder() .registerTypeHierarchyAdapter(ClassWithNoFields.class, new JsonSerializer() { public JsonElement serialize( ClassWithNoFields src, Type typeOfSrc, JsonSerializationContext context) { return new JsonObject(); } }).create(); assertEquals("null", 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)); } /** * Tests that a class field with type Object can be serialized properly. * See issue 54 */ public void testClassWithObjectFieldSerialization() { ClassWithObjectField obj = new ClassWithObjectField(); obj.member = "abc"; String json = gson.toJson(obj); assertTrue(json.contains("abc")); } private static class ClassWithObjectField { @SuppressWarnings("unused") Object member; } 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() { 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 { @SuppressWarnings("unused") int value1 = 1; private class Child { int value2 = 2; } } 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 ClassWithPrivateNoArgsConstructor { public int a; private ClassWithPrivateNoArgsConstructor() { a = 10; } } /** * In response to Issue 41 http://code.google.com/p/google-gson/issues/detail?id=41 */ public void testObjectFieldNamesWithoutQuotesDeserialization() { String json = "{longValue:1,'booleanValue':true,\"stringValue\":'bar'}"; BagOfPrimitives bag = gson.fromJson(json, BagOfPrimitives.class); assertEquals(1, bag.longValue); assertTrue(bag.booleanValue); assertEquals("bar", bag.stringValue); } public void testStringFieldWithNumberValueDeserialization() { String json = "{\"stringValue\":1}"; BagOfPrimitives bag = gson.fromJson(json, BagOfPrimitives.class); assertEquals("1", bag.stringValue); json = "{\"stringValue\":1.5E+6}"; bag = gson.fromJson(json, BagOfPrimitives.class); assertEquals("1.5E+6", bag.stringValue); json = "{\"stringValue\":true}"; bag = gson.fromJson(json, BagOfPrimitives.class); assertEquals("true", bag.stringValue); } /** * Created to reproduce issue 140 */ public void testStringFieldWithEmptyValueSerialization() { ClassWithEmptyStringFields target = new ClassWithEmptyStringFields(); target.a = "5794749"; String json = gson.toJson(target); assertTrue(json.contains("\"a\":\"5794749\"")); assertTrue(json.contains("\"b\":\"\"")); assertTrue(json.contains("\"c\":\"\"")); } /** * Created to reproduce issue 140 */ public void testStringFieldWithEmptyValueDeserialization() { String json = "{a:\"5794749\",b:\"\",c:\"\"}"; ClassWithEmptyStringFields target = gson.fromJson(json, ClassWithEmptyStringFields.class); assertEquals("5794749", target.a); assertEquals("", target.b); assertEquals("", target.c); } private static class ClassWithEmptyStringFields { String a = ""; String b = ""; String c = ""; } public void testJsonObjectSerialization() { Gson gson = new GsonBuilder().serializeNulls().create(); JsonObject obj = new JsonObject(); String json = gson.toJson(obj); assertEquals("{}", json); } /** * Test for issue 215. */ public void testSingletonLists() { Gson gson = new Gson(); Product product = new Product(); assertEquals("{\"attributes\":[],\"departments\":[]}", gson.toJson(product)); gson.fromJson(gson.toJson(product), Product.class); product.departments.add(new Department()); assertEquals("{\"attributes\":[],\"departments\":[{\"name\":\"abc\",\"code\":\"123\"}]}", gson.toJson(product)); gson.fromJson(gson.toJson(product), Product.class); product.attributes.add("456"); assertEquals("{\"attributes\":[\"456\"],\"departments\":[{\"name\":\"abc\",\"code\":\"123\"}]}", gson.toJson(product)); gson.fromJson(gson.toJson(product), Product.class); } // http://code.google.com/p/google-gson/issues/detail?id=270 public void testDateAsMapObjectField() { HasObjectMap a = new HasObjectMap(); a.map.put("date", new Date(0)); assertEquals("{\"map\":{\"date\":\"Dec 31, 1969 4:00:00 PM\"}}", gson.toJson(a)); } public class HasObjectMap { Map map = new HashMap(); } static final class Department { public String name = "abc"; public String code = "123"; } static final class Product { private List attributes = new ArrayList(); private List departments = new ArrayList(); } } google-gson/src/test/java/com/google/gson/functional/CustomDeserializerTest.java0000664000175000017500000001527511632330615030013 0ustar ebourgebourg/* * 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.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; import com.google.gson.common.TestTypes.Base; import com.google.gson.common.TestTypes.ClassWithBaseField; import junit.framework.TestCase; import java.lang.reflect.Type; /** * Functional Test exercising custom deserialization only. When test applies to both * serialization and deserialization then add it to CustomTypeAdapterTest. * * @author Joel Leitch */ public class CustomDeserializerTest extends TestCase { private static final String DEFAULT_VALUE = "test123"; private static final String SUFFIX = "blah"; private Gson gson; @Override protected void setUp() throws Exception { super.setUp(); gson = new GsonBuilder().registerTypeAdapter(DataHolder.class, new DataHolderDeserializer()).create(); } public void testDefaultConstructorNotCalledOnObject() throws Exception { DataHolder data = new DataHolder(DEFAULT_VALUE); String json = gson.toJson(data); DataHolder actual = gson.fromJson(json, DataHolder.class); assertEquals(DEFAULT_VALUE + SUFFIX, actual.getData()); } public void testDefaultConstructorNotCalledOnField() throws Exception { DataHolderWrapper dataWrapper = new DataHolderWrapper(new DataHolder(DEFAULT_VALUE)); String json = gson.toJson(dataWrapper); DataHolderWrapper actual = gson.fromJson(json, DataHolderWrapper.class); assertEquals(DEFAULT_VALUE + SUFFIX, actual.getWrappedData().getData()); } private static class DataHolder { private final String data; // For use by Gson @SuppressWarnings("unused") private DataHolder() { throw new IllegalStateException(); } public DataHolder(String data) { this.data = data; } public String getData() { return data; } } private static class DataHolderWrapper { private final DataHolder wrappedData; // For use by Gson @SuppressWarnings("unused") private DataHolderWrapper() { this(new DataHolder(DEFAULT_VALUE)); } public DataHolderWrapper(DataHolder data) { this.wrappedData = data; } public DataHolder getWrappedData() { return wrappedData; } } private static class DataHolderDeserializer implements JsonDeserializer { public DataHolder deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { JsonObject jsonObj = json.getAsJsonObject(); String dataString = jsonObj.get("data").getAsString(); return new DataHolder(dataString + SUFFIX); } } public void testJsonTypeFieldBasedDeserialization() { String json = "{field1:'abc',field2:'def',__type__:'SUB_TYPE1'}"; Gson gson = new GsonBuilder().registerTypeAdapter(MyBase.class, new JsonDeserializer() { public MyBase deserialize(JsonElement json, Type pojoType, JsonDeserializationContext context) throws JsonParseException { String type = json.getAsJsonObject().get(MyBase.TYPE_ACCESS).getAsString(); return context.deserialize(json, SubTypes.valueOf(type).getSubclass()); } }).create(); SubType1 target = (SubType1) gson.fromJson(json, MyBase.class); assertEquals("abc", target.field1); } private static class MyBase { static final String TYPE_ACCESS = "__type__"; } private enum SubTypes { SUB_TYPE1(SubType1.class), SUB_TYPE2(SubType2.class); private final Type subClass; private SubTypes(Type subClass) { this.subClass = subClass; } public Type getSubclass() { return subClass; } } private static class SubType1 extends MyBase { String field1; } private static class SubType2 extends MyBase { @SuppressWarnings("unused") String field2; } public void testCustomDeserializerReturnsNullForTopLevelObject() { Gson gson = new GsonBuilder() .registerTypeAdapter(Base.class, new JsonDeserializer() { public Base deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { return null; } }).create(); String json = "{baseName:'Base',subName:'SubRevised'}"; Base target = gson.fromJson(json, Base.class); assertNull(target); } public void testCustomDeserializerReturnsNull() { Gson gson = new GsonBuilder() .registerTypeAdapter(Base.class, new JsonDeserializer() { public Base deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { return null; } }).create(); String json = "{base:{baseName:'Base',subName:'SubRevised'}}"; ClassWithBaseField target = gson.fromJson(json, ClassWithBaseField.class); assertNull(target.base); } public void testCustomDeserializerReturnsNullForArrayElements() { Gson gson = new GsonBuilder() .registerTypeAdapter(Base.class, new JsonDeserializer() { public Base deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { return null; } }).create(); String json = "[{baseName:'Base'},{baseName:'Base'}]"; Base[] target = gson.fromJson(json, Base[].class); assertNull(target[0]); assertNull(target[1]); } public void testCustomDeserializerReturnsNullForArrayElementsForArrayField() { Gson gson = new GsonBuilder() .registerTypeAdapter(Base.class, new JsonDeserializer() { public Base deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { return null; } }).create(); String json = "{bases:[{baseName:'Base'},{baseName:'Base'}]}"; ClassWithBaseArray target = gson.fromJson(json, ClassWithBaseArray.class); assertNull(target.bases[0]); assertNull(target.bases[1]); } private static class ClassWithBaseArray { Base[] bases; } } google-gson/src/test/java/com/google/gson/functional/InheritanceTest.java0000664000175000017500000002206212042051114026405 0ustar ebourgebourg/* * Copyright (C) 2009 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.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.common.TestTypes.BagOfPrimitives; import com.google.gson.common.TestTypes.Base; import com.google.gson.common.TestTypes.ClassWithBaseArrayField; import com.google.gson.common.TestTypes.ClassWithBaseCollectionField; import com.google.gson.common.TestTypes.ClassWithBaseField; import com.google.gson.common.TestTypes.Nested; import com.google.gson.common.TestTypes.Sub; 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 classes with * inheritance hierarchies. * * @author Inderjeet Singh * @author Joel Leitch */ public class InheritanceTest extends TestCase { private Gson gson; @Override protected void setUp() throws Exception { super.setUp(); gson = new Gson(); } public void testSubClassSerialization() 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 testSubClassDeserialization() 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 testClassWithBaseFieldSerialization() { ClassWithBaseField sub = new ClassWithBaseField(new Sub()); JsonObject json = (JsonObject) gson.toJsonTree(sub); JsonElement base = json.getAsJsonObject().get(ClassWithBaseField.FIELD_KEY); assertEquals(Sub.SUB_NAME, base.getAsJsonObject().get(Sub.SUB_FIELD_KEY).getAsString()); } public void testClassWithBaseArrayFieldSerialization() { Base[] baseClasses = new Base[]{ new Sub(), new Sub()}; ClassWithBaseArrayField sub = new ClassWithBaseArrayField(baseClasses); JsonObject json = gson.toJsonTree(sub).getAsJsonObject(); JsonArray bases = json.get(ClassWithBaseArrayField.FIELD_KEY).getAsJsonArray(); for (JsonElement element : bases) { assertEquals(Sub.SUB_NAME, element.getAsJsonObject().get(Sub.SUB_FIELD_KEY).getAsString()); } } public void testClassWithBaseCollectionFieldSerialization() { Collection baseClasses = new ArrayList(); baseClasses.add(new Sub()); baseClasses.add(new Sub()); ClassWithBaseCollectionField sub = new ClassWithBaseCollectionField(baseClasses); JsonObject json = gson.toJsonTree(sub).getAsJsonObject(); JsonArray bases = json.get(ClassWithBaseArrayField.FIELD_KEY).getAsJsonArray(); for (JsonElement element : bases) { assertEquals(Sub.SUB_NAME, element.getAsJsonObject().get(Sub.SUB_FIELD_KEY).getAsString()); } } public void testBaseSerializedAsSub() { Base base = new Sub(); JsonObject json = gson.toJsonTree(base).getAsJsonObject(); assertEquals(Sub.SUB_NAME, json.get(Sub.SUB_FIELD_KEY).getAsString()); } public void testBaseSerializedAsSubForToJsonMethod() { Base base = new Sub(); String json = gson.toJson(base); assertTrue(json.contains(Sub.SUB_NAME)); } public void testBaseSerializedAsBaseWhenSpecifiedWithExplicitType() { Base base = new Sub(); JsonObject json = gson.toJsonTree(base, Base.class).getAsJsonObject(); assertEquals(Base.BASE_NAME, json.get(Base.BASE_FIELD_KEY).getAsString()); assertNull(json.get(Sub.SUB_FIELD_KEY)); } public void testBaseSerializedAsBaseWhenSpecifiedWithExplicitTypeForToJsonMethod() { Base base = new Sub(); String json = gson.toJson(base, Base.class); assertTrue(json.contains(Base.BASE_NAME)); assertFalse(json.contains(Sub.SUB_FIELD_KEY)); } public void testBaseSerializedAsSubWhenSpecifiedWithExplicitType() { Base base = new Sub(); JsonObject json = gson.toJsonTree(base, Sub.class).getAsJsonObject(); assertEquals(Sub.SUB_NAME, json.get(Sub.SUB_FIELD_KEY).getAsString()); } public void testBaseSerializedAsSubWhenSpecifiedWithExplicitTypeForToJsonMethod() { Base base = new Sub(); String json = gson.toJson(base, Sub.class); assertTrue(json.contains(Sub.SUB_NAME)); } private static class SubTypeOfNested extends Nested { private final long value = 5; public SubTypeOfNested(BagOfPrimitives primitive1, BagOfPrimitives primitive2) { super(primitive1, primitive2); } @Override public void appendFields(StringBuilder sb) { sb.append("\"value\":").append(value).append(","); super.appendFields(sb); } } 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\"]" + "}"; ClassWithSubInterfacesOfCollection target = gson.fromJson(json, ClassWithSubInterfacesOfCollection.class); assertTrue(target.listContains(0, 1, 2, 3)); assertTrue(target.queueContains(0, 1, 2, 3)); assertTrue(target.setContains(0.1F, 0.2F, 0.3F, 0.4F)); assertTrue(target.sortedSetContains('a', 'b', 'c', 'd')); } private static class ClassWithSubInterfacesOfCollection { private List list; private Queue queue; private Set set; private SortedSet sortedSet; public ClassWithSubInterfacesOfCollection(List list, Queue queue, Set set, SortedSet sortedSet) { this.list = list; this.queue = queue; this.set = set; this.sortedSet = sortedSet; } boolean listContains(int... values) { for (int value : values) { if (!list.contains(value)) { return false; } } return true; } boolean queueContains(long... values) { for (long value : values) { if (!queue.contains(value)) { return false; } } return true; } boolean setContains(float... values) { for (float value : values) { if (!set.contains(value)) { return false; } } return true; } boolean sortedSetContains(char... values) { for (char value : values) { if (!sortedSet.contains(value)) { return false; } } return true; } 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; } } } google-gson/src/test/java/com/google/gson/functional/CustomSerializerTest.java0000664000175000017500000001020311263655066027476 0ustar ebourgebourg/* * Copyright (C) 2009 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.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; import com.google.gson.common.TestTypes.Base; import com.google.gson.common.TestTypes.BaseSerializer; import com.google.gson.common.TestTypes.ClassWithBaseArrayField; import com.google.gson.common.TestTypes.ClassWithBaseField; import com.google.gson.common.TestTypes.Sub; import com.google.gson.common.TestTypes.SubSerializer; import junit.framework.TestCase; import java.lang.reflect.Type; /** * Functional Test exercising custom serialization only. When test applies to both * serialization and deserialization then add it to CustomTypeAdapterTest. * * @author Inderjeet Singh */ public class CustomSerializerTest extends TestCase { public void testBaseClassSerializerInvokedForBaseClassFields() { Gson gson = new GsonBuilder() .registerTypeAdapter(Base.class, new BaseSerializer()) .registerTypeAdapter(Sub.class, new SubSerializer()) .create(); ClassWithBaseField target = new ClassWithBaseField(new Base()); JsonObject json = (JsonObject) gson.toJsonTree(target); JsonObject base = json.get("base").getAsJsonObject(); assertEquals(BaseSerializer.NAME, base.get(Base.SERIALIZER_KEY).getAsString()); } public void testSubClassSerializerInvokedForBaseClassFieldsHoldingSubClassInstances() { Gson gson = new GsonBuilder() .registerTypeAdapter(Base.class, new BaseSerializer()) .registerTypeAdapter(Sub.class, new SubSerializer()) .create(); ClassWithBaseField target = new ClassWithBaseField(new Sub()); JsonObject json = (JsonObject) gson.toJsonTree(target); JsonObject base = json.get("base").getAsJsonObject(); assertEquals(SubSerializer.NAME, base.get(Base.SERIALIZER_KEY).getAsString()); } public void testSubClassSerializerInvokedForBaseClassFieldsHoldingArrayOfSubClassInstances() { Gson gson = new GsonBuilder() .registerTypeAdapter(Base.class, new BaseSerializer()) .registerTypeAdapter(Sub.class, new SubSerializer()) .create(); ClassWithBaseArrayField target = new ClassWithBaseArrayField(new Base[] {new Sub(), new Sub()}); JsonObject json = (JsonObject) gson.toJsonTree(target); JsonArray array = json.get("base").getAsJsonArray(); for (JsonElement element : array) { JsonElement serializerKey = element.getAsJsonObject().get(Base.SERIALIZER_KEY); assertEquals(SubSerializer.NAME, serializerKey.getAsString()); } } public void testBaseClassSerializerInvokedForBaseClassFieldsHoldingSubClassInstances() { Gson gson = new GsonBuilder() .registerTypeAdapter(Base.class, new BaseSerializer()) .create(); ClassWithBaseField target = new ClassWithBaseField(new Sub()); JsonObject json = (JsonObject) gson.toJsonTree(target); JsonObject base = json.get("base").getAsJsonObject(); assertEquals(BaseSerializer.NAME, base.get(Base.SERIALIZER_KEY).getAsString()); } public void testSerializerReturnsNull() { Gson gson = new GsonBuilder() .registerTypeAdapter(Base.class, new JsonSerializer() { public JsonElement serialize(Base src, Type typeOfSrc, JsonSerializationContext context) { return null; } }) .create(); JsonElement json = gson.toJsonTree(new Base()); assertTrue(json.isJsonNull()); } } google-gson/src/test/java/com/google/gson/functional/VersioningTest.java0000664000175000017500000001250311641373623026316 0ustar ebourgebourg/* * 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.annotations.Since; import com.google.gson.annotations.Until; import com.google.gson.common.TestTypes.BagOfPrimitives; import junit.framework.TestCase; /** * Functional tests for versioning support in Gson. * * @author Inderjeet Singh * @author Joel Leitch */ public class VersioningTest extends TestCase { private static final int A = 0; private static final int B = 1; private static final int C = 2; private static final int D = 3; private GsonBuilder builder; @Override protected void setUp() throws Exception { super.setUp(); builder = new GsonBuilder(); } public void testVersionedUntilSerialization() { Version1 target = new Version1(); Gson gson = builder.setVersion(1.29).create(); String json = gson.toJson(target); assertTrue(json.contains("\"a\":" + A)); gson = builder.setVersion(1.3).create(); json = gson.toJson(target); assertFalse(json.contains("\"a\":" + A)); } public void testVersionedUntilDeserialization() { Gson gson = builder.setVersion(1.3).create(); String json = "{\"a\":3,\"b\":4,\"c\":5}"; Version1 version1 = gson.fromJson(json, Version1.class); assertEquals(A, version1.a); } public void testVersionedClassesSerialization() { Gson gson = builder.setVersion(1.0).create(); String json1 = gson.toJson(new Version1()); String json2 = gson.toJson(new Version1_1()); assertEquals(json1, json2); } public void testVersionedClassesDeserialization() { Gson gson = builder.setVersion(1.0).create(); String json = "{\"a\":3,\"b\":4,\"c\":5}"; Version1 version1 = gson.fromJson(json, Version1.class); assertEquals(3, version1.a); assertEquals(4, version1.b); Version1_1 version1_1 = gson.fromJson(json, Version1_1.class); assertEquals(3, version1_1.a); assertEquals(4, version1_1.b); assertEquals(C, version1_1.c); } public void testIgnoreLaterVersionClassSerialization() { Gson gson = builder.setVersion(1.0).create(); assertEquals("null", gson.toJson(new Version1_2())); } public void testIgnoreLaterVersionClassDeserialization() { Gson gson = builder.setVersion(1.0).create(); String json = "{\"a\":3,\"b\":4,\"c\":5,\"d\":6}"; Version1_2 version1_2 = gson.fromJson(json, Version1_2.class); // Since the class is versioned to be after 1.0, we expect null // This is the new behavior in Gson 2.0 assertNull(version1_2); } public void testVersionedGsonWithUnversionedClassesSerialization() { Gson gson = builder.setVersion(1.0).create(); BagOfPrimitives target = new BagOfPrimitives(10, 20, false, "stringValue"); assertEquals(target.getExpectedJson(), gson.toJson(target)); } public void testVersionedGsonWithUnversionedClassesDeserialization() { Gson gson = builder.setVersion(1.0).create(); String json = "{\"longValue\":10,\"intValue\":20,\"booleanValue\":false}"; BagOfPrimitives expected = new BagOfPrimitives(); expected.longValue = 10; expected.intValue = 20; expected.booleanValue = false; BagOfPrimitives actual = gson.fromJson(json, BagOfPrimitives.class); assertEquals(expected, actual); } public void testVersionedGsonMixingSinceAndUntilSerialization() { Gson gson = builder.setVersion(1.0).create(); SinceUntilMixing target = new SinceUntilMixing(); String json = gson.toJson(target); assertFalse(json.contains("\"b\":" + B)); gson = builder.setVersion(1.2).create(); json = gson.toJson(target); assertTrue(json.contains("\"b\":" + B)); gson = builder.setVersion(1.3).create(); json = gson.toJson(target); assertFalse(json.contains("\"b\":" + B)); } public void testVersionedGsonMixingSinceAndUntilDeserialization() { String json = "{\"a\":5,\"b\":6}"; Gson gson = builder.setVersion(1.0).create(); SinceUntilMixing result = gson.fromJson(json, SinceUntilMixing.class); assertEquals(5, result.a); assertEquals(B, result.b); gson = builder.setVersion(1.2).create(); result = gson.fromJson(json, SinceUntilMixing.class); assertEquals(5, result.a); assertEquals(6, result.b); gson = builder.setVersion(1.3).create(); result = gson.fromJson(json, SinceUntilMixing.class); assertEquals(5, result.a); assertEquals(B, result.b); } private static class Version1 { @Until(1.3) int a = A; @Since(1.0) int b = B; } private static class Version1_1 extends Version1 { @Since(1.1) int c = C; } @Since(1.2) private static class Version1_2 extends Version1_1 { @SuppressWarnings("unused") int d = D; } private static class SinceUntilMixing { int a = A; @Since(1.1) @Until(1.3) int b = B; } } google-gson/src/test/java/com/google/gson/functional/FieldNamingTest.java0000664000175000017500000000667611662356307026371 0ustar ebourgebourg/* * Copyright (C) 2011 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 static com.google.gson.FieldNamingPolicy.IDENTITY; import static com.google.gson.FieldNamingPolicy.LOWER_CASE_WITH_DASHES; import static com.google.gson.FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES; import static com.google.gson.FieldNamingPolicy.UPPER_CAMEL_CASE; import static com.google.gson.FieldNamingPolicy.UPPER_CAMEL_CASE_WITH_SPACES; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.annotations.SerializedName; import junit.framework.TestCase; public final class FieldNamingTest extends TestCase { public void testIdentity() { Gson gson = new GsonBuilder().setFieldNamingPolicy(IDENTITY).create(); assertEquals("{'lowerCamel':1,'UpperCamel':2,'_lowerCamelLeadingUnderscore':3," + "'_UpperCamelLeadingUnderscore':4,'lower_words':5,'UPPER_WORDS':6," + "'annotatedName':7}", gson.toJson(new TestNames()).replace('\"', '\'')); } public void testUpperCamelCase() { Gson gson = new GsonBuilder().setFieldNamingPolicy(UPPER_CAMEL_CASE).create(); assertEquals("{'LowerCamel':1,'UpperCamel':2,'_LowerCamelLeadingUnderscore':3," + "'_UpperCamelLeadingUnderscore':4,'Lower_words':5,'UPPER_WORDS':6," + "'annotatedName':7}", gson.toJson(new TestNames()).replace('\"', '\'')); } public void testUpperCamelCaseWithSpaces() { Gson gson = new GsonBuilder().setFieldNamingPolicy(UPPER_CAMEL_CASE_WITH_SPACES).create(); assertEquals("{'Lower Camel':1,'Upper Camel':2,'_Lower Camel Leading Underscore':3," + "'_ Upper Camel Leading Underscore':4,'Lower_words':5,'U P P E R_ W O R D S':6," + "'annotatedName':7}", gson.toJson(new TestNames()).replace('\"', '\'')); } public void testLowerCaseWithUnderscores() { Gson gson = new GsonBuilder().setFieldNamingPolicy(LOWER_CASE_WITH_UNDERSCORES).create(); assertEquals("{'lower_camel':1,'upper_camel':2,'_lower_camel_leading_underscore':3," + "'__upper_camel_leading_underscore':4,'lower_words':5,'u_p_p_e_r__w_o_r_d_s':6," + "'annotatedName':7}", gson.toJson(new TestNames()).replace('\"', '\'')); } public void testLowerCaseWithDashes() { Gson gson = new GsonBuilder().setFieldNamingPolicy(LOWER_CASE_WITH_DASHES).create(); assertEquals("{'lower-camel':1,'upper-camel':2,'_lower-camel-leading-underscore':3," + "'_-upper-camel-leading-underscore':4,'lower_words':5,'u-p-p-e-r_-w-o-r-d-s':6," + "'annotatedName':7}", gson.toJson(new TestNames()).replace('\"', '\'')); } @SuppressWarnings("unused") // fields are used reflectively private static class TestNames { int lowerCamel = 1; int UpperCamel = 2; int _lowerCamelLeadingUnderscore = 3; int _UpperCamelLeadingUnderscore = 4; int lower_words = 5; int UPPER_WORDS = 6; @SerializedName("annotatedName") int annotated = 7; } } google-gson/src/test/java/com/google/gson/functional/DelegateTypeAdapterTest.java0000664000175000017500000000562311774402546030061 0ustar ebourgebourg/* * Copyright (C) 2012 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 java.io.IOException; import java.util.ArrayList; import java.util.List; import junit.framework.TestCase; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.TypeAdapter; import com.google.gson.TypeAdapterFactory; import com.google.gson.common.TestTypes.BagOfPrimitives; import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; /** * Functional tests for {@link Gson#getDelegateAdapter(TypeAdapterFactory, TypeToken)} method. * * @author Inderjeet Singh */ public class DelegateTypeAdapterTest extends TestCase { private StatsTypeAdapterFactory stats; private Gson gson; protected void setUp() throws Exception { super.setUp(); stats = new StatsTypeAdapterFactory(); gson = new GsonBuilder() .registerTypeAdapterFactory(stats) .create(); } public void testDelegateInvoked() { List bags = new ArrayList(); for (int i = 0; i < 10; ++i) { bags.add(new BagOfPrimitives(i, i, i % 2 == 0, String.valueOf(i))); } String json = gson.toJson(bags); bags = gson.fromJson(json, new TypeToken>(){}.getType()); // 11: 1 list object, and 10 entries. stats invoked on all 5 fields assertEquals(51, stats.numReads); assertEquals(51, stats.numWrites); } public void testDelegateInvokedOnStrings() { String[] bags = {"1", "2", "3", "4"}; String json = gson.toJson(bags); bags = gson.fromJson(json, String[].class); // 1 array object with 4 elements. assertEquals(5, stats.numReads); assertEquals(5, stats.numWrites); } private static class StatsTypeAdapterFactory implements TypeAdapterFactory { public int numReads = 0; public int numWrites = 0; public TypeAdapter create(Gson gson, TypeToken type) { final TypeAdapter delegate = gson.getDelegateAdapter(this, type); return new TypeAdapter() { @Override public void write(JsonWriter out, T value) throws IOException { ++numWrites; delegate.write(out, value); } @Override public T read(JsonReader in) throws IOException { ++numReads; return delegate.read(in); } }; } } } google-gson/src/test/java/com/google/gson/functional/SecurityTest.java0000664000175000017500000000610211160755073025777 0ustar ebourgebourg/* * 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.common.TestTypes.BagOfPrimitives; import junit.framework.TestCase; /** * Tests for security-related aspects of Gson * * @author Inderjeet Singh */ public class SecurityTest extends TestCase { /** * Keep this in sync with Gson.JSON_NON_EXECUTABLE_PREFIX */ private static final String JSON_NON_EXECUTABLE_PREFIX = ")]}'\n"; private GsonBuilder gsonBuilder; @Override protected void setUp() throws Exception { super.setUp(); gsonBuilder = new GsonBuilder(); } public void testNonExecutableJsonSerialization() { Gson gson = gsonBuilder.generateNonExecutableJson().create(); String json = gson.toJson(new BagOfPrimitives()); assertTrue(json.startsWith(JSON_NON_EXECUTABLE_PREFIX)); } public void testNonExecutableJsonDeserialization() { String json = JSON_NON_EXECUTABLE_PREFIX + "{longValue:1}"; Gson gson = gsonBuilder.create(); BagOfPrimitives target = gson.fromJson(json, BagOfPrimitives.class); assertEquals(1, target.longValue); } public void testJsonWithNonExectuableTokenSerialization() { Gson gson = gsonBuilder.generateNonExecutableJson().create(); String json = gson.toJson(JSON_NON_EXECUTABLE_PREFIX); assertTrue(json.contains(")]}'\n")); } /** * Gson should be able to deserialize a stream with non-exectuable token even if it is created * without {@link GsonBuilder#generateNonExecutableJson()}. */ public void testJsonWithNonExectuableTokenWithRegularGsonDeserialization() { Gson gson = gsonBuilder.create(); String json = JSON_NON_EXECUTABLE_PREFIX + "{stringValue:')]}\\u0027\\n'}"; BagOfPrimitives target = gson.fromJson(json, BagOfPrimitives.class); assertEquals(")]}'\n", target.stringValue); } /** * Gson should be able to deserialize a stream with non-exectuable token if it is created * with {@link GsonBuilder#generateNonExecutableJson()}. */ public void testJsonWithNonExectuableTokenWithConfiguredGsonDeserialization() { // Gson should be able to deserialize a stream with non-exectuable token even if it is created Gson gson = gsonBuilder.generateNonExecutableJson().create(); String json = JSON_NON_EXECUTABLE_PREFIX + "{intValue:2,stringValue:')]}\\u0027\\n'}"; BagOfPrimitives target = gson.fromJson(json, BagOfPrimitives.class); assertEquals(")]}'\n", target.stringValue); assertEquals(2, target.intValue); } } google-gson/src/test/java/com/google/gson/functional/PrimitiveCharacterTest.java0000664000175000017500000000304411634562040027753 0ustar ebourgebourg/* * 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 junit.framework.TestCase; import com.google.gson.Gson; /** * Functional tests for Java Character values. * * @author Inderjeet Singh * @author Joel Leitch */ public class PrimitiveCharacterTest extends TestCase { private Gson gson; @Override protected void setUp() throws Exception { super.setUp(); gson = new Gson(); } public void testPrimitiveCharacterAutoboxedSerialization() { assertEquals("\"A\"", gson.toJson('A')); assertEquals("\"A\"", gson.toJson('A', char.class)); assertEquals("\"A\"", gson.toJson('A', Character.class)); } public void testPrimitiveCharacterAutoboxedDeserialization() { char expected = 'a'; char actual = gson.fromJson("a", char.class); assertEquals(expected, actual); actual = gson.fromJson("\"a\"", char.class); assertEquals(expected, actual); actual = gson.fromJson("a", Character.class); assertEquals(expected, actual); } } google-gson/src/test/java/com/google/gson/functional/MapAsArrayTypeAdapterTest.java0000664000175000017500000001205011633316725030334 0ustar ebourgebourg/* * Copyright (C) 2010 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.JsonSyntaxException; import com.google.gson.reflect.TypeToken; import java.lang.reflect.Type; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import junit.framework.TestCase; public class MapAsArrayTypeAdapterTest extends TestCase { public void testSerializeComplexMapWithTypeAdapter() { Type type = new TypeToken>() {}.getType(); Gson gson = new GsonBuilder() .enableComplexMapKeySerialization() .create(); Map original = new LinkedHashMap(); original.put(new Point(5, 5), "a"); original.put(new Point(8, 8), "b"); String json = gson.toJson(original, type); assertEquals("[[{\"x\":5,\"y\":5},\"a\"],[{\"x\":8,\"y\":8},\"b\"]]", json); assertEquals(original, gson.>fromJson(json, type)); // test that registering a type adapter for one map doesn't interfere with others Map otherMap = new LinkedHashMap(); otherMap.put("t", true); otherMap.put("f", false); assertEquals("{\"t\":true,\"f\":false}", gson.toJson(otherMap, Map.class)); assertEquals("{\"t\":true,\"f\":false}", gson.toJson(otherMap, new TypeToken>() {}.getType())); assertEquals(otherMap, gson.fromJson("{\"t\":true,\"f\":false}", new TypeToken>() {}.getType())); } public void disabled_testTwoTypesCollapseToOneSerialize() { Gson gson = new GsonBuilder() .enableComplexMapKeySerialization() .create(); Map original = new LinkedHashMap(); original.put(new Double(1.0), "a"); original.put(new Float(1.0), "b"); try { gson.toJson(original, new TypeToken>() {}.getType()); fail(); // we no longer hash keys at serialization time } catch (JsonSyntaxException expected) { } } public void testTwoTypesCollapseToOneDeserialize() { Gson gson = new GsonBuilder() .enableComplexMapKeySerialization() .create(); String s = "[[\"1.00\",\"a\"],[\"1.0\",\"b\"]]"; try { gson.fromJson(s, new TypeToken>() {}.getType()); fail(); } catch (JsonSyntaxException expected) { } } public void testMultipleEnableComplexKeyRegistrationHasNoEffect() throws Exception { Type type = new TypeToken>() {}.getType(); Gson gson = new GsonBuilder() .enableComplexMapKeySerialization() .enableComplexMapKeySerialization() .create(); Map original = new LinkedHashMap(); original.put(new Point(6, 5), "abc"); original.put(new Point(1, 8), "def"); String json = gson.toJson(original, type); assertEquals("[[{\"x\":6,\"y\":5},\"abc\"],[{\"x\":1,\"y\":8},\"def\"]]", json); assertEquals(original, gson.>fromJson(json, type)); } public void testMapWithTypeVariableSerialization() { Gson gson = new GsonBuilder().enableComplexMapKeySerialization().create(); PointWithProperty map = new PointWithProperty(); map.map.put(new Point(2, 3), new Point(4, 5)); Type type = new TypeToken>(){}.getType(); String json = gson.toJson(map, type); assertEquals("{\"map\":[[{\"x\":2,\"y\":3},{\"x\":4,\"y\":5}]]}", json); } public void testMapWithTypeVariableDeserialization() { Gson gson = new GsonBuilder().enableComplexMapKeySerialization().create(); String json = "{map:[[{x:2,y:3},{x:4,y:5}]]}"; Type type = new TypeToken>(){}.getType(); PointWithProperty map = gson.fromJson(json, type); Point key = map.map.keySet().iterator().next(); Point value = map.map.values().iterator().next(); assertEquals(new Point(2, 3), key); assertEquals(new Point(4, 5), value); } static class Point { int x; int y; Point(int x, int y) { this.x = x; this.y = y; } Point() {} @Override public boolean equals(Object o) { return o instanceof Point && ((Point) o).x == x && ((Point) o).y == y; } @Override public int hashCode() { return x * 37 + y; } @Override public String toString() { return "(" + x + "," + y + ")"; } } static class PointWithProperty { Map map = new HashMap(); } } google-gson/src/test/java/com/google/gson/functional/JsonTreeTest.java0000664000175000017500000000566611651074324025735 0ustar ebourgebourgpackage com.google.gson.functional; import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; import com.google.gson.common.TestTypes.BagOfPrimitives; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import junit.framework.TestCase; /** * Functional tests for {@link Gson#toJsonTree(Object)} and * {@link Gson#toJsonTree(Object, java.lang.reflect.Type)} * * @author Inderjeet Singh * @author Joel Leitch */ public class JsonTreeTest extends TestCase { private Gson gson; @Override protected void setUp() throws Exception { super.setUp(); gson = new Gson(); } public void testToJsonTree() { BagOfPrimitives bag = new BagOfPrimitives(10L, 5, false, "foo"); JsonElement json = gson.toJsonTree(bag); assertTrue(json.isJsonObject()); JsonObject obj = json.getAsJsonObject(); Set> children = obj.entrySet(); assertEquals(4, children.size()); assertContains(obj, new JsonPrimitive(10L)); assertContains(obj, new JsonPrimitive(5)); assertContains(obj, new JsonPrimitive(false)); assertContains(obj, new JsonPrimitive("foo")); } public void testToJsonTreeObjectType() { SubTypeOfBagOfPrimitives bag = new SubTypeOfBagOfPrimitives(10L, 5, false, "foo", 1.4F); JsonElement json = gson.toJsonTree(bag, BagOfPrimitives.class); assertTrue(json.isJsonObject()); JsonObject obj = json.getAsJsonObject(); Set> children = obj.entrySet(); assertEquals(4, children.size()); assertContains(obj, new JsonPrimitive(10L)); assertContains(obj, new JsonPrimitive(5)); assertContains(obj, new JsonPrimitive(false)); assertContains(obj, new JsonPrimitive("foo")); } public void testJsonTreeToString() { SubTypeOfBagOfPrimitives bag = new SubTypeOfBagOfPrimitives(10L, 5, false, "foo", 1.4F); String json1 = gson.toJson(bag); JsonElement jsonElement = gson.toJsonTree(bag, SubTypeOfBagOfPrimitives.class); String json2 = gson.toJson(jsonElement); assertEquals(json1, json2); } public void testJsonTreeNull() { BagOfPrimitives bag = new BagOfPrimitives(10L, 5, false, null); JsonObject jsonElement = (JsonObject) gson.toJsonTree(bag, BagOfPrimitives.class); assertFalse(jsonElement.has("stringValue")); } private void assertContains(JsonObject json, JsonPrimitive child) { for (Map.Entry entry : json.entrySet()) { JsonElement node = entry.getValue(); if (node.isJsonPrimitive()) { if (node.getAsJsonPrimitive().equals(child)) { return; } } } fail(); } private static class SubTypeOfBagOfPrimitives extends BagOfPrimitives { @SuppressWarnings("unused") float f = 1.2F; public SubTypeOfBagOfPrimitives(long l, int i, boolean b, String string, float f) { super(l, i, b, string); this.f = f; } } } google-gson/src/test/java/com/google/gson/functional/TypeVariableTest.java0000664000175000017500000000743211515662212026562 0ustar ebourgebourg/* * Copyright (C) 2010 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.reflect.TypeToken; import java.lang.reflect.Type; import java.util.Arrays; import junit.framework.TestCase; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Functional test for Gson serialization and deserialization of * classes with type variables. * * @author Joel Leitch */ public class TypeVariableTest extends TestCase { public void testAdvancedTypeVariables() throws Exception { Gson gson = new Gson(); Bar bar1 = new Bar("someString", 1, true); ArrayList arrayList = new ArrayList(); arrayList.add(1); arrayList.add(2); arrayList.add(3); bar1.map.put("key1", arrayList); bar1.map.put("key2", new ArrayList()); String json = gson.toJson(bar1); Bar bar2 = gson.fromJson(json, Bar.class); assertEquals(bar1, bar2); } public void testTypeVariablesViaTypeParameter() throws Exception { Gson gson = new Gson(); Foo original = new Foo("e", 5, false); original.map.put("f", Arrays.asList(6, 7)); Type type = new TypeToken>() {}.getType(); String json = gson.toJson(original, type); assertEquals("{\"someSField\":\"e\",\"someTField\":5,\"map\":{\"f\":[6,7]},\"redField\":false}", json); assertEquals(original, gson.>fromJson(json, type)); } public void testBasicTypeVariables() throws Exception { Gson gson = new Gson(); Blue blue1 = new Blue(true); String json = gson.toJson(blue1); Blue blue2 = gson.fromJson(json, Blue.class); assertEquals(blue1, blue2); } public static class Blue extends Red { public Blue() { super(false); } public Blue(boolean value) { super(value); } // Technically, we should implement hashcode too @Override public boolean equals(Object o) { if (!(o instanceof Blue)) { return false; } Blue blue = (Blue) o; return redField.equals(blue.redField); } } public static class Red { protected S redField; public Red() {} public Red(S redField) { this.redField = redField; } } public static class Foo extends Red { private S someSField; private T someTField; public final Map> map = new HashMap>(); public Foo() {} public Foo(S sValue, T tValue, Boolean redField) { super(redField); this.someSField = sValue; this.someTField = tValue; } // Technically, we should implement hashcode too @Override @SuppressWarnings("unchecked") public boolean equals(Object o) { if (!(o instanceof Foo)) { return false; } Foo realFoo = (Foo) o; return redField.equals(realFoo.redField) && someTField.equals(realFoo.someTField) && someSField.equals(realFoo.someSField) && map.equals(realFoo.map); } } public static class Bar extends Foo { public Bar() { this("", 0, false); } public Bar(String s, Integer i, boolean b) { super(s, i, b); } } } google-gson/src/test/java/com/google/gson/functional/ConcurrencyTest.java0000775000175000017500000001013111256473076026470 0ustar ebourgebourg/* * 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 java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicBoolean; import junit.framework.TestCase; import com.google.gson.Gson; /** * Tests for ensuring Gson thread-safety. * * @author Inderjeet Singh * @author Joel Leitch */ public class ConcurrencyTest extends TestCase { private Gson gson; @Override protected void setUp() throws Exception { super.setUp(); gson = new Gson(); } /** * Source-code based on * http://groups.google.com/group/google-gson/browse_thread/thread/563bb51ee2495081 */ public void testSingleThreadSerialization() { MyObject myObj = new MyObject(); for (int i = 0; i < 10; i++) { gson.toJson(myObj); } } /** * Source-code based on * http://groups.google.com/group/google-gson/browse_thread/thread/563bb51ee2495081 */ public void testSingleThreadDeserialization() { for (int i = 0; i < 10; i++) { gson.fromJson("{'a':'hello','b':'world','i':1}", MyObject.class); } } /** * Source-code based on * http://groups.google.com/group/google-gson/browse_thread/thread/563bb51ee2495081 */ public void testMultiThreadSerialization() throws InterruptedException { final CountDownLatch startLatch = new CountDownLatch(1); final CountDownLatch finishedLatch = new CountDownLatch(10); final AtomicBoolean failed = new AtomicBoolean(false); ExecutorService executor = Executors.newFixedThreadPool(10); for (int taskCount = 0; taskCount < 10; taskCount++) { executor.execute(new Runnable() { public void run() { MyObject myObj = new MyObject(); try { startLatch.await(); for (int i = 0; i < 10; i++) { gson.toJson(myObj); } } catch (Throwable t) { failed.set(true); } finally { finishedLatch.countDown(); } } }); } startLatch.countDown(); finishedLatch.await(); assertFalse(failed.get()); } /** * Source-code based on * http://groups.google.com/group/google-gson/browse_thread/thread/563bb51ee2495081 */ public void testMultiThreadDeserialization() throws InterruptedException { final CountDownLatch startLatch = new CountDownLatch(1); final CountDownLatch finishedLatch = new CountDownLatch(10); final AtomicBoolean failed = new AtomicBoolean(false); ExecutorService executor = Executors.newFixedThreadPool(10); for (int taskCount = 0; taskCount < 10; taskCount++) { executor.execute(new Runnable() { public void run() { try { startLatch.await(); for (int i = 0; i < 10; i++) { gson.fromJson("{'a':'hello','b':'world','i':1}", MyObject.class); } } catch (Throwable t) { failed.set(true); } finally { finishedLatch.countDown(); } } }); } startLatch.countDown(); finishedLatch.await(); assertFalse(failed.get()); } @SuppressWarnings("unused") private static class MyObject { String a; String b; int i; MyObject() { this("hello", "world", 42); } public MyObject(String a, String b, int i) { this.a = a; this.b = b; this.i = i; } } } google-gson/src/test/java/com/google/gson/functional/EnumTest.java0000664000175000017500000001526612127371465025112 0ustar ebourgebourg/* * 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.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonParseException; import com.google.gson.JsonPrimitive; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; import com.google.gson.annotations.SerializedName; import com.google.gson.common.MoreAsserts; import com.google.gson.reflect.TypeToken; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collection; import java.util.EnumSet; import java.util.Set; import junit.framework.TestCase; /** * Functional tests for Java 5.0 enums. * * @author Inderjeet Singh * @author Joel Leitch */ public class EnumTest extends TestCase { private Gson gson; @Override protected void setUp() throws Exception { super.setUp(); gson = new Gson(); } public void testTopLevelEnumSerialization() throws Exception { String result = gson.toJson(MyEnum.VALUE1); assertEquals('"' + MyEnum.VALUE1.toString() + '"', result); } public void testTopLevelEnumDeserialization() throws Exception { MyEnum result = gson.fromJson('"' + MyEnum.VALUE1.toString() + '"', MyEnum.class); assertEquals(MyEnum.VALUE1, result); } public void testCollectionOfEnumsSerialization() { Type type = new TypeToken>() {}.getType(); Collection target = new ArrayList(); target.add(MyEnum.VALUE1); target.add(MyEnum.VALUE2); String expectedJson = "[\"VALUE1\",\"VALUE2\"]"; String actualJson = gson.toJson(target); assertEquals(expectedJson, actualJson); actualJson = gson.toJson(target, type); assertEquals(expectedJson, actualJson); } public void testCollectionOfEnumsDeserialization() { Type type = new TypeToken>() {}.getType(); String json = "[\"VALUE1\",\"VALUE2\"]"; Collection target = gson.fromJson(json, type); MoreAsserts.assertContains(target, MyEnum.VALUE1); MoreAsserts.assertContains(target, MyEnum.VALUE2); } public void testClassWithEnumFieldSerialization() throws Exception { ClassWithEnumFields target = new ClassWithEnumFields(); assertEquals(target.getExpectedJson(), gson.toJson(target)); } public void testClassWithEnumFieldDeserialization() throws Exception { String json = "{value1:'VALUE1',value2:'VALUE2'}"; ClassWithEnumFields target = gson.fromJson(json, ClassWithEnumFields.class); assertEquals(MyEnum.VALUE1,target.value1); assertEquals(MyEnum.VALUE2,target.value2); } private static enum MyEnum { VALUE1, VALUE2 } private static class ClassWithEnumFields { private final MyEnum value1 = MyEnum.VALUE1; private final MyEnum value2 = MyEnum.VALUE2; public String getExpectedJson() { return "{\"value1\":\"" + value1 + "\",\"value2\":\"" + value2 + "\"}"; } } /** * Test for issue 226. */ public void testEnumSubclass() { assertFalse(Roshambo.class == Roshambo.ROCK.getClass()); assertEquals("\"ROCK\"", gson.toJson(Roshambo.ROCK)); assertEquals("[\"ROCK\",\"PAPER\",\"SCISSORS\"]", gson.toJson(EnumSet.allOf(Roshambo.class))); assertEquals(Roshambo.ROCK, gson.fromJson("\"ROCK\"", Roshambo.class)); assertEquals(EnumSet.allOf(Roshambo.class), gson.fromJson("[\"ROCK\",\"PAPER\",\"SCISSORS\"]", new TypeToken>() {}.getType())); } public void testEnumSubclassWithRegisteredTypeAdapter() { gson = new GsonBuilder() .registerTypeHierarchyAdapter(Roshambo.class, new MyEnumTypeAdapter()) .create(); assertFalse(Roshambo.class == Roshambo.ROCK.getClass()); assertEquals("\"123ROCK\"", gson.toJson(Roshambo.ROCK)); assertEquals("[\"123ROCK\",\"123PAPER\",\"123SCISSORS\"]", gson.toJson(EnumSet.allOf(Roshambo.class))); assertEquals(Roshambo.ROCK, gson.fromJson("\"123ROCK\"", Roshambo.class)); assertEquals(EnumSet.allOf(Roshambo.class), gson.fromJson("[\"123ROCK\",\"123PAPER\",\"123SCISSORS\"]", new TypeToken>() {}.getType())); } public void testEnumSubclassAsParameterizedType() { Collection list = new ArrayList(); list.add(Roshambo.ROCK); list.add(Roshambo.PAPER); String json = gson.toJson(list); assertEquals("[\"ROCK\",\"PAPER\"]", json); Type collectionType = new TypeToken>() {}.getType(); Collection actualJsonList = gson.fromJson(json, collectionType); MoreAsserts.assertContains(actualJsonList, Roshambo.ROCK); MoreAsserts.assertContains(actualJsonList, Roshambo.PAPER); } public void testEnumCaseMapping() { assertEquals(Gender.MALE, gson.fromJson("\"boy\"", Gender.class)); assertEquals("\"boy\"", gson.toJson(Gender.MALE, Gender.class)); } public void testEnumSet() { EnumSet foo = EnumSet.of(Roshambo.ROCK, Roshambo.PAPER); String json = gson.toJson(foo); Type type = new TypeToken>() {}.getType(); EnumSet bar = gson.fromJson(json, type); assertTrue(bar.contains(Roshambo.ROCK)); assertTrue(bar.contains(Roshambo.PAPER)); assertFalse(bar.contains(Roshambo.SCISSORS)); } public enum Roshambo { ROCK { @Override Roshambo defeats() { return SCISSORS; } }, PAPER { @Override Roshambo defeats() { return ROCK; } }, SCISSORS { @Override Roshambo defeats() { return PAPER; } }; abstract Roshambo defeats(); } private static class MyEnumTypeAdapter implements JsonSerializer, JsonDeserializer { public JsonElement serialize(Roshambo src, Type typeOfSrc, JsonSerializationContext context) { return new JsonPrimitive("123" + src.name()); } public Roshambo deserialize(JsonElement json, Type classOfT, JsonDeserializationContext context) throws JsonParseException { return Roshambo.valueOf(json.getAsString().substring(3)); } } public enum Gender { @SerializedName("boy") MALE, @SerializedName("girl") FEMALE } } google-gson/src/test/java/com/google/gson/functional/MoreSpecificTypeSerializationTest.java0000664000175000017500000001325511553656747032165 0ustar ebourgebourg/* * Copyright (C) 2011 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.JsonObject; import junit.framework.TestCase; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Map; /** * Tests for Gson serialization of a sub-class object while encountering a base-class type * * @author Inderjeet Singh */ @SuppressWarnings("unused") public class MoreSpecificTypeSerializationTest extends TestCase { private Gson gson; @Override protected void setUp() throws Exception { super.setUp(); gson = new Gson(); } public void testSubclassFields() { ClassWithBaseFields target = new ClassWithBaseFields(new Sub(1, 2)); String json = gson.toJson(target); assertTrue(json.contains("\"b\":1")); assertTrue(json.contains("\"s\":2")); } public void testListOfSubclassFields() { Collection list = new ArrayList(); list.add(new Base(1)); list.add(new Sub(2, 3)); ClassWithContainersOfBaseFields target = new ClassWithContainersOfBaseFields(list, null); String json = gson.toJson(target); assertTrue(json, json.contains("{\"b\":1}")); assertTrue(json, json.contains("{\"s\":3,\"b\":2}")); } public void testMapOfSubclassFields() { Map map = new HashMap(); map.put("base", new Base(1)); map.put("sub", new Sub(2, 3)); ClassWithContainersOfBaseFields target = new ClassWithContainersOfBaseFields(null, map); JsonObject json = gson.toJsonTree(target).getAsJsonObject().get("map").getAsJsonObject(); assertEquals(1, json.get("base").getAsJsonObject().get("b").getAsInt()); JsonObject sub = json.get("sub").getAsJsonObject(); assertEquals(2, sub.get("b").getAsInt()); assertEquals(3, sub.get("s").getAsInt()); } /** * For parameterized type, Gson ignores the more-specific type and sticks to the declared type */ public void testParameterizedSubclassFields() { ClassWithParameterizedBaseFields target = new ClassWithParameterizedBaseFields( new ParameterizedSub("one", "two")); String json = gson.toJson(target); assertTrue(json.contains("\"t\":\"one\"")); assertFalse(json.contains("\"s\"")); } /** * For parameterized type in a List, Gson ignores the more-specific type and sticks to * the declared type */ public void testListOfParameterizedSubclassFields() { Collection> list = new ArrayList>(); list.add(new ParameterizedBase("one")); list.add(new ParameterizedSub("two", "three")); ClassWithContainersOfParameterizedBaseFields target = new ClassWithContainersOfParameterizedBaseFields(list, null); String json = gson.toJson(target); assertTrue(json, json.contains("{\"t\":\"one\"}")); assertFalse(json, json.contains("\"s\":")); } /** * For parameterized type in a map, Gson ignores the more-specific type and sticks to the * declared type */ public void testMapOfParameterizedSubclassFields() { Map> map = new HashMap>(); map.put("base", new ParameterizedBase("one")); map.put("sub", new ParameterizedSub("two", "three")); ClassWithContainersOfParameterizedBaseFields target = new ClassWithContainersOfParameterizedBaseFields(null, map); JsonObject json = gson.toJsonTree(target).getAsJsonObject().get("map").getAsJsonObject(); assertEquals("one", json.get("base").getAsJsonObject().get("t").getAsString()); JsonObject sub = json.get("sub").getAsJsonObject(); assertEquals("two", sub.get("t").getAsString()); assertNull(sub.get("s")); } private static class Base { int b; Base(int b) { this.b = b; } } private static class Sub extends Base { int s; Sub(int b, int s) { super(b); this.s = s; } } private static class ClassWithBaseFields { Base b; ClassWithBaseFields(Base b) { this.b = b; } } private static class ClassWithContainersOfBaseFields { Collection collection; Map map; ClassWithContainersOfBaseFields(Collection collection, Map map) { this.collection = collection; this.map = map; } } private static class ParameterizedBase { T t; ParameterizedBase(T t) { this.t = t; } } private static class ParameterizedSub extends ParameterizedBase { T s; ParameterizedSub(T t, T s) { super(t); this.s = s; } } private static class ClassWithParameterizedBaseFields { ParameterizedBase b; ClassWithParameterizedBaseFields(ParameterizedBase b) { this.b = b; } } private static class ClassWithContainersOfParameterizedBaseFields { Collection> collection; Map> map; ClassWithContainersOfParameterizedBaseFields(Collection> collection, Map> map) { this.collection = collection; this.map = map; } } } google-gson/src/test/java/com/google/gson/functional/InstanceCreatorTest.java0000664000175000017500000001050012132065234027242 0ustar ebourgebourg/* * Copyright (C) 2009 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.common.TestTypes.Base; import com.google.gson.common.TestTypes.ClassWithBaseField; import com.google.gson.common.TestTypes.Sub; import com.google.gson.reflect.TypeToken; import java.util.ArrayList; import java.util.List; import junit.framework.TestCase; import java.lang.reflect.Type; import java.util.SortedSet; import java.util.TreeSet; /** * Functional Test exercising custom serialization only. When test applies to both * serialization and deserialization then add it to CustomTypeAdapterTest. * * @author Inderjeet Singh */ public class InstanceCreatorTest extends TestCase { public void testInstanceCreatorReturnsBaseType() { Gson gson = new GsonBuilder() .registerTypeAdapter(Base.class, new InstanceCreator() { public Base createInstance(Type type) { return new Base(); } }) .create(); String json = "{baseName:'BaseRevised',subName:'Sub'}"; Base base = gson.fromJson(json, Base.class); assertEquals("BaseRevised", base.baseName); } public void testInstanceCreatorReturnsSubTypeForTopLevelObject() { Gson gson = new GsonBuilder() .registerTypeAdapter(Base.class, new InstanceCreator() { public Base createInstance(Type type) { return new Sub(); } }) .create(); String json = "{baseName:'Base',subName:'SubRevised'}"; Base base = gson.fromJson(json, Base.class); assertTrue(base instanceof Sub); Sub sub = (Sub) base; assertFalse("SubRevised".equals(sub.subName)); assertEquals(Sub.SUB_NAME, sub.subName); } public void testInstanceCreatorReturnsSubTypeForField() { Gson gson = new GsonBuilder() .registerTypeAdapter(Base.class, new InstanceCreator() { public Base createInstance(Type type) { return new Sub(); } }) .create(); String json = "{base:{baseName:'Base',subName:'SubRevised'}}"; ClassWithBaseField target = gson.fromJson(json, ClassWithBaseField.class); assertTrue(target.base instanceof Sub); assertEquals(Sub.SUB_NAME, ((Sub)target.base).subName); } // This regressed in Gson 2.0 and 2.1 public void testInstanceCreatorForCollectionType() { @SuppressWarnings("serial") class SubArrayList extends ArrayList {} InstanceCreator> listCreator = new InstanceCreator>() { public List createInstance(Type type) { return new SubArrayList(); } }; Type listOfStringType = new TypeToken>() {}.getType(); Gson gson = new GsonBuilder() .registerTypeAdapter(listOfStringType, listCreator) .create(); List list = gson.fromJson("[\"a\"]", listOfStringType); assertEquals(SubArrayList.class, list.getClass()); } @SuppressWarnings({ "unchecked", "rawtypes" }) public void testInstanceCreatorForParametrizedType() throws Exception { @SuppressWarnings("serial") class SubTreeSet extends TreeSet {} InstanceCreator sortedSetCreator = new InstanceCreator() { public SortedSet createInstance(Type type) { return new SubTreeSet(); } }; Gson gson = new GsonBuilder() .registerTypeAdapter(SortedSet.class, sortedSetCreator) .create(); Type sortedSetType = new TypeToken>() {}.getType(); SortedSet set = gson.fromJson("[\"a\"]", sortedSetType); assertEquals(set.first(), "a"); assertEquals(SubTreeSet.class, set.getClass()); set = gson.fromJson("[\"b\"]", SortedSet.class); assertEquals(set.first(), "b"); assertEquals(SubTreeSet.class, set.getClass()); } } google-gson/src/test/java/com/google/gson/functional/PrintFormattingTest.java0000664000175000017500000000472111650111576027322 0ustar ebourgebourg/* * 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.JsonObject; import com.google.gson.common.TestTypes.BagOfPrimitives; import com.google.gson.common.TestTypes.ClassWithTransientFields; 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.List; /** * Functional tests for print formatting. * * @author Inderjeet Singh * @author Joel Leitch */ public class PrintFormattingTest extends TestCase { private Gson gson; @Override protected void setUp() throws Exception { super.setUp(); gson = new Gson(); } @SuppressWarnings({"unchecked", "rawtypes"}) public void testCompactFormattingLeavesNoWhiteSpace() { List list = new ArrayList(); list.add(new BagOfPrimitives()); list.add(new Nested()); list.add(new PrimitiveArray()); list.add(new ClassWithTransientFields()); String json = gson.toJson(list); assertContainsNoWhiteSpace(json); } public void testJsonObjectWithNullValues() { JsonObject obj = new JsonObject(); obj.addProperty("field1", "value1"); obj.addProperty("field2", (String) null); String json = gson.toJson(obj); assertTrue(json.contains("field1")); assertFalse(json.contains("field2")); } public void testJsonObjectWithNullValuesSerialized() { gson = new GsonBuilder().serializeNulls().create(); JsonObject obj = new JsonObject(); obj.addProperty("field1", "value1"); obj.addProperty("field2", (String) null); String json = gson.toJson(obj); assertTrue(json.contains("field1")); assertTrue(json.contains("field2")); } private static void assertContainsNoWhiteSpace(String str) { for (char c : str.toCharArray()) { assertFalse(Character.isWhitespace(c)); } } } google-gson/src/test/java/com/google/gson/functional/NullObjectAndFieldTest.java0000775000175000017500000002107611675124040027625 0ustar ebourgebourg/* * 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.JsonElement; import com.google.gson.JsonNull; import com.google.gson.JsonObject; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; import com.google.gson.common.TestTypes.BagOfPrimitives; import com.google.gson.common.TestTypes.ClassWithObjects; import junit.framework.TestCase; import java.lang.reflect.Type; import java.util.Collection; /** * Functional tests for the different cases for serializing (or ignoring) null fields and object. * * @author Inderjeet Singh * @author Joel Leitch */ public class NullObjectAndFieldTest extends TestCase { private GsonBuilder gsonBuilder; @Override protected void setUp() throws Exception { super.setUp(); gsonBuilder = new GsonBuilder().serializeNulls(); } public void testTopLevelNullObjectSerialization() { Gson gson = gsonBuilder.create(); String actual = gson.toJson(null); assertEquals("null", actual); actual = gson.toJson(null, String.class); assertEquals("null", actual); } public void testTopLevelNullObjectDeserialization() throws Exception { Gson gson = gsonBuilder.create(); String actual = gson.fromJson("null", String.class); assertNull(actual); } public void testExplicitSerializationOfNulls() { Gson gson = gsonBuilder.create(); ClassWithObjects target = new ClassWithObjects(null); String actual = gson.toJson(target); String expected = "{\"bag\":null}"; assertEquals(expected, actual); } public void testExplicitDeserializationOfNulls() throws Exception { Gson gson = gsonBuilder.create(); ClassWithObjects target = gson.fromJson("{\"bag\":null}", ClassWithObjects.class); assertNull(target.bag); } public void testExplicitSerializationOfNullArrayMembers() { Gson gson = gsonBuilder.create(); ClassWithMembers target = new ClassWithMembers(); String json = gson.toJson(target); assertTrue(json.contains("\"array\":null")); } /** * Added to verify http://code.google.com/p/google-gson/issues/detail?id=68 */ public void testNullWrappedPrimitiveMemberSerialization() { Gson gson = gsonBuilder.serializeNulls().create(); ClassWithNullWrappedPrimitive target = new ClassWithNullWrappedPrimitive(); String json = gson.toJson(target); assertTrue(json.contains("\"value\":null")); } /** * Added to verify http://code.google.com/p/google-gson/issues/detail?id=68 */ public void testNullWrappedPrimitiveMemberDeserialization() { Gson gson = gsonBuilder.create(); String json = "{'value':null}"; ClassWithNullWrappedPrimitive target = gson.fromJson(json, ClassWithNullWrappedPrimitive.class); assertNull(target.value); } public void testExplicitSerializationOfNullCollectionMembers() { Gson gson = gsonBuilder.create(); ClassWithMembers target = new ClassWithMembers(); String json = gson.toJson(target); assertTrue(json.contains("\"col\":null")); } public void testExplicitSerializationOfNullStringMembers() { Gson gson = gsonBuilder.create(); ClassWithMembers target = new ClassWithMembers(); String json = gson.toJson(target); assertTrue(json.contains("\"str\":null")); } public void testCustomSerializationOfNulls() { gsonBuilder.registerTypeAdapter(ClassWithObjects.class, new ClassWithObjectsSerializer()); Gson gson = gsonBuilder.create(); ClassWithObjects target = new ClassWithObjects(new BagOfPrimitives()); String actual = gson.toJson(target); String expected = "{\"bag\":null}"; assertEquals(expected, actual); } public void testPrintPrintingObjectWithNulls() throws Exception { gsonBuilder = new GsonBuilder(); Gson gson = gsonBuilder.create(); String result = gson.toJson(new ClassWithMembers()); assertEquals("{}", result); gson = gsonBuilder.serializeNulls().create(); result = gson.toJson(new ClassWithMembers()); assertTrue(result.contains("\"str\":null")); } public void testPrintPrintingArraysWithNulls() throws Exception { gsonBuilder = new GsonBuilder(); Gson gson = gsonBuilder.create(); String result = gson.toJson(new String[] { "1", null, "3" }); assertEquals("[\"1\",null,\"3\"]", result); gson = gsonBuilder.serializeNulls().create(); result = gson.toJson(new String[] { "1", null, "3" }); assertEquals("[\"1\",null,\"3\"]", result); } // test for issue 389 public void testAbsentJsonElementsAreSetToNull() { Gson gson = new Gson(); ClassWithInitializedMembers target = gson.fromJson("{array:[1,2,3]}", ClassWithInitializedMembers.class); assertTrue(target.array.length == 3 && target.array[1] == 2); assertEquals(ClassWithInitializedMembers.MY_STRING_DEFAULT, target.str1); assertNull(target.str2); assertEquals(ClassWithInitializedMembers.MY_INT_DEFAULT, target.int1); assertEquals(0, target.int2); // test the default value of a primitive int field per JVM spec assertEquals(ClassWithInitializedMembers.MY_BOOLEAN_DEFAULT, target.bool1); assertFalse(target.bool2); // test the default value of a primitive boolean field per JVM spec } public static class ClassWithInitializedMembers { // Using a mix of no-args constructor and field initializers // Also, some fields are intialized and some are not (so initialized per JVM spec) public static final String MY_STRING_DEFAULT = "string"; private static final int MY_INT_DEFAULT = 2; private static final boolean MY_BOOLEAN_DEFAULT = true; int[] array; String str1, str2; int int1 = MY_INT_DEFAULT; int int2; boolean bool1 = MY_BOOLEAN_DEFAULT; boolean bool2; public ClassWithInitializedMembers() { str1 = MY_STRING_DEFAULT; } } private static class ClassWithNullWrappedPrimitive { private Long value; } @SuppressWarnings("unused") private static class ClassWithMembers { String str; int[] array; Collection col; } private static class ClassWithObjectsSerializer implements JsonSerializer { public JsonElement serialize(ClassWithObjects src, Type typeOfSrc, JsonSerializationContext context) { JsonObject obj = new JsonObject(); obj.add("bag", JsonNull.INSTANCE); return obj; } } public void testExplicitNullSetsFieldToNullDuringDeserialization() { Gson gson = new Gson(); String json = "{value:null}"; ObjectWithField obj = gson.fromJson(json, ObjectWithField.class); assertNull(obj.value); } public void testCustomTypeAdapterPassesNullSerialization() { Gson gson = new GsonBuilder() .registerTypeAdapter(ObjectWithField.class, new JsonSerializer() { public JsonElement serialize(ObjectWithField src, Type typeOfSrc, JsonSerializationContext context) { return context.serialize(null); } }).create(); ObjectWithField target = new ObjectWithField(); target.value = "value1"; String json = gson.toJson(target); assertFalse(json.contains("value1")); } public void testCustomTypeAdapterPassesNullDesrialization() { Gson gson = new GsonBuilder() .registerTypeAdapter(ObjectWithField.class, new JsonDeserializer() { public ObjectWithField deserialize(JsonElement json, Type type, JsonDeserializationContext context) { return context.deserialize(null, type); } }).create(); String json = "{value:'value1'}"; ObjectWithField target = gson.fromJson(json, ObjectWithField.class); assertNull(target); } private static class ObjectWithField { String value = ""; } } google-gson/src/test/java/com/google/gson/functional/ReadersWritersTest.java0000664000175000017500000001141311651140076027132 0ustar ebourgebourg/* * 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.JsonStreamParser; import com.google.gson.JsonSyntaxException; import com.google.gson.common.TestTypes.BagOfPrimitives; import com.google.gson.reflect.TypeToken; import java.util.Map; import junit.framework.TestCase; import java.io.CharArrayReader; import java.io.CharArrayWriter; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.io.StringWriter; import java.io.Writer; /** * Functional tests for the support of {@link Reader}s and {@link Writer}s. * * @author Inderjeet Singh * @author Joel Leitch */ public class ReadersWritersTest extends TestCase { private Gson gson; @Override protected void setUp() throws Exception { super.setUp(); gson = new Gson(); } public void testWriterForSerialization() throws Exception { Writer writer = new StringWriter(); BagOfPrimitives src = new BagOfPrimitives(); gson.toJson(src, writer); assertEquals(src.getExpectedJson(), writer.toString()); } public void testReaderForDeserialization() throws Exception { BagOfPrimitives expected = new BagOfPrimitives(); Reader json = new StringReader(expected.getExpectedJson()); BagOfPrimitives actual = gson.fromJson(json, BagOfPrimitives.class); assertEquals(expected, actual); } public void testTopLevelNullObjectSerializationWithWriter() { StringWriter writer = new StringWriter(); gson.toJson(null, writer); assertEquals("null", writer.toString()); } public void testTopLevelNullObjectDeserializationWithReader() { StringReader reader = new StringReader("null"); Integer nullIntObject = gson.fromJson(reader, Integer.class); assertNull(nullIntObject); } public void testTopLevelNullObjectSerializationWithWriterAndSerializeNulls() { Gson gson = new GsonBuilder().serializeNulls().create(); StringWriter writer = new StringWriter(); gson.toJson(null, writer); assertEquals("null", writer.toString()); } public void testTopLevelNullObjectDeserializationWithReaderAndSerializeNulls() { Gson gson = new GsonBuilder().serializeNulls().create(); StringReader reader = new StringReader("null"); Integer nullIntObject = gson.fromJson(reader, Integer.class); assertNull(nullIntObject); } public void testReadWriteTwoStrings() throws IOException { Gson gson= new Gson(); CharArrayWriter writer= new CharArrayWriter(); writer.write(gson.toJson("one").toCharArray()); writer.write(gson.toJson("two").toCharArray()); CharArrayReader reader = new CharArrayReader(writer.toCharArray()); JsonStreamParser parser = new JsonStreamParser(reader); String actualOne = gson.fromJson(parser.next(), String.class); assertEquals("one", actualOne); String actualTwo = gson.fromJson(parser.next(), String.class); assertEquals("two", actualTwo); } public void testReadWriteTwoObjects() throws IOException { Gson gson= new Gson(); CharArrayWriter writer= new CharArrayWriter(); BagOfPrimitives expectedOne = new BagOfPrimitives(1, 1, true, "one"); writer.write(gson.toJson(expectedOne).toCharArray()); BagOfPrimitives expectedTwo = new BagOfPrimitives(2, 2, false, "two"); writer.write(gson.toJson(expectedTwo).toCharArray()); CharArrayReader reader = new CharArrayReader(writer.toCharArray()); JsonStreamParser parser = new JsonStreamParser(reader); BagOfPrimitives actualOne = gson.fromJson(parser.next(), BagOfPrimitives.class); assertEquals("one", actualOne.stringValue); BagOfPrimitives actualTwo = gson.fromJson(parser.next(), BagOfPrimitives.class); assertEquals("two", actualTwo.stringValue); assertFalse(parser.hasNext()); } public void testTypeMismatchThrowsJsonSyntaxExceptionForStrings() { try { gson.fromJson("true", new TypeToken>() {}.getType()); fail(); } catch (JsonSyntaxException expected) { } } public void testTypeMismatchThrowsJsonSyntaxExceptionForReaders() { try { gson.fromJson(new StringReader("true"), new TypeToken>() {}.getType()); fail(); } catch (JsonSyntaxException expected) { } } } google-gson/src/test/java/com/google/gson/functional/ExclusionStrategyFunctionalTest.java0000664000175000017500000001660011700051347031704 0ustar ebourgebourg/* * 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.ExclusionStrategy; import com.google.gson.FieldAttributes; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import junit.framework.TestCase; /** * Performs some functional tests when Gson is instantiated with some common user defined * {@link ExclusionStrategy} objects. * * @author Inderjeet Singh * @author Joel Leitch */ public class ExclusionStrategyFunctionalTest extends TestCase { private static final ExclusionStrategy EXCLUDE_SAMPLE_OBJECT_FOR_TEST = new ExclusionStrategy() { public boolean shouldSkipField(FieldAttributes f) { return false; } public boolean shouldSkipClass(Class clazz) { return clazz == SampleObjectForTest.class; } }; private SampleObjectForTest src; @Override protected void setUp() throws Exception { super.setUp(); src = new SampleObjectForTest(); } public void testExclusionStrategySerialization() throws Exception { Gson gson = createGson(new MyExclusionStrategy(String.class), true); String json = gson.toJson(src); assertFalse(json.contains("\"stringField\"")); assertFalse(json.contains("\"annotatedField\"")); assertTrue(json.contains("\"longField\"")); } public void testExclusionStrategySerializationDoesNotImpactDeserialization() { String json = "{\"annotatedField\":1,\"stringField\":\"x\",\"longField\":2}"; Gson gson = createGson(new MyExclusionStrategy(String.class), true); SampleObjectForTest value = gson.fromJson(json, SampleObjectForTest.class); assertEquals(1, value.annotatedField); assertEquals("x", value.stringField); assertEquals(2, value.longField); } public void testExclusionStrategyDeserialization() throws Exception { Gson gson = createGson(new MyExclusionStrategy(String.class), false); JsonObject json = new JsonObject(); json.add("annotatedField", new JsonPrimitive(src.annotatedField + 5)); json.add("stringField", new JsonPrimitive(src.stringField + "blah,blah")); json.add("longField", new JsonPrimitive(1212311L)); SampleObjectForTest target = gson.fromJson(json, SampleObjectForTest.class); assertEquals(1212311L, target.longField); // assert excluded fields are set to the defaults assertEquals(src.annotatedField, target.annotatedField); assertEquals(src.stringField, target.stringField); } public void testExclusionStrategySerializationDoesNotImpactSerialization() throws Exception { Gson gson = createGson(new MyExclusionStrategy(String.class), false); String json = gson.toJson(src); assertTrue(json.contains("\"stringField\"")); assertTrue(json.contains("\"annotatedField\"")); assertTrue(json.contains("\"longField\"")); } public void testExclusionStrategyWithMode() throws Exception { SampleObjectForTest testObj = new SampleObjectForTest( src.annotatedField + 5, src.stringField + "blah,blah", src.longField + 655L); Gson gson = createGson(new MyExclusionStrategy(String.class), false); JsonObject json = gson.toJsonTree(testObj).getAsJsonObject(); assertEquals(testObj.annotatedField, json.get("annotatedField").getAsInt()); assertEquals(testObj.stringField, json.get("stringField").getAsString()); assertEquals(testObj.longField, json.get("longField").getAsLong()); SampleObjectForTest target = gson.fromJson(json, SampleObjectForTest.class); assertEquals(testObj.longField, target.longField); // assert excluded fields are set to the defaults assertEquals(src.annotatedField, target.annotatedField); assertEquals(src.stringField, target.stringField); } public void testExcludeTopLevelClassSerialization() { Gson gson = new GsonBuilder() .addSerializationExclusionStrategy(EXCLUDE_SAMPLE_OBJECT_FOR_TEST) .create(); assertEquals("null", gson.toJson(new SampleObjectForTest(), SampleObjectForTest.class)); } public void testExcludeTopLevelClassSerializationDoesNotImpactDeserialization() { Gson gson = new GsonBuilder() .addSerializationExclusionStrategy(EXCLUDE_SAMPLE_OBJECT_FOR_TEST) .create(); String json = "{\"annotatedField\":1,\"stringField\":\"x\",\"longField\":2}"; SampleObjectForTest value = gson.fromJson(json, SampleObjectForTest.class); assertEquals(1, value.annotatedField); assertEquals("x", value.stringField); assertEquals(2, value.longField); } public void testExcludeTopLevelClassDeserialization() { Gson gson = new GsonBuilder() .addDeserializationExclusionStrategy(EXCLUDE_SAMPLE_OBJECT_FOR_TEST) .create(); String json = "{\"annotatedField\":1,\"stringField\":\"x\",\"longField\":2}"; SampleObjectForTest value = gson.fromJson(json, SampleObjectForTest.class); assertNull(value); } public void testExcludeTopLevelClassDeserializationDoesNotImpactSerialization() { Gson gson = new GsonBuilder() .addDeserializationExclusionStrategy(EXCLUDE_SAMPLE_OBJECT_FOR_TEST) .create(); String json = gson.toJson(new SampleObjectForTest(), SampleObjectForTest.class); assertTrue(json.contains("\"stringField\"")); assertTrue(json.contains("\"annotatedField\"")); assertTrue(json.contains("\"longField\"")); } private static Gson createGson(ExclusionStrategy exclusionStrategy, boolean serialization) { GsonBuilder gsonBuilder = new GsonBuilder(); if (serialization) { gsonBuilder.addSerializationExclusionStrategy(exclusionStrategy); } else { gsonBuilder.addDeserializationExclusionStrategy(exclusionStrategy); } return gsonBuilder .serializeNulls() .create(); } @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD}) private static @interface Foo { // Field tag only annotation } private static class SampleObjectForTest { @Foo private final int annotatedField; private final String stringField; private final long longField; public SampleObjectForTest() { this(5, "someDefaultValue", 12345L); } public SampleObjectForTest(int annotatedField, String stringField, long longField) { this.annotatedField = annotatedField; this.stringField = stringField; this.longField = longField; } } private static class MyExclusionStrategy implements ExclusionStrategy { private final Class typeToSkip; private MyExclusionStrategy(Class typeToSkip) { this.typeToSkip = typeToSkip; } public boolean shouldSkipClass(Class clazz) { return (clazz == typeToSkip); } public boolean shouldSkipField(FieldAttributes f) { return f.getAnnotation(Foo.class) != null; } } } google-gson/src/test/java/com/google/gson/functional/TypeHierarchyAdapterTest.java0000664000175000017500000001653311663107727030267 0ustar ebourgebourg/* * Copyright (C) 2011 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.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; import com.google.gson.JsonPrimitive; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; import java.lang.reflect.Type; import junit.framework.TestCase; /** * Test that the hierarchy adapter works when subtypes are used. */ public final class TypeHierarchyAdapterTest extends TestCase { public void testTypeHierarchy() { Manager andy = new Manager(); andy.userid = "andy"; andy.startDate = 2005; andy.minions = new Employee[] { new Employee("inder", 2007), new Employee("joel", 2006), new Employee("jesse", 2006), }; CEO eric = new CEO(); eric.userid = "eric"; eric.startDate = 2001; eric.assistant = new Employee("jerome", 2006); eric.minions = new Employee[] { new Employee("larry", 1998), new Employee("sergey", 1998), andy, }; Gson gson = new GsonBuilder() .registerTypeHierarchyAdapter(Employee.class, new EmployeeAdapter()) .setPrettyPrinting() .create(); Company company = new Company(); company.ceo = eric; String json = gson.toJson(company, Company.class); assertEquals("{\n" + " \"ceo\": {\n" + " \"userid\": \"eric\",\n" + " \"startDate\": 2001,\n" + " \"minions\": [\n" + " {\n" + " \"userid\": \"larry\",\n" + " \"startDate\": 1998\n" + " },\n" + " {\n" + " \"userid\": \"sergey\",\n" + " \"startDate\": 1998\n" + " },\n" + " {\n" + " \"userid\": \"andy\",\n" + " \"startDate\": 2005,\n" + " \"minions\": [\n" + " {\n" + " \"userid\": \"inder\",\n" + " \"startDate\": 2007\n" + " },\n" + " {\n" + " \"userid\": \"joel\",\n" + " \"startDate\": 2006\n" + " },\n" + " {\n" + " \"userid\": \"jesse\",\n" + " \"startDate\": 2006\n" + " }\n" + " ]\n" + " }\n" + " ],\n" + " \"assistant\": {\n" + " \"userid\": \"jerome\",\n" + " \"startDate\": 2006\n" + " }\n" + " }\n" + "}", json); Company copied = gson.fromJson(json, Company.class); assertEquals(json, gson.toJson(copied, Company.class)); assertEquals(copied.ceo.userid, company.ceo.userid); assertEquals(copied.ceo.assistant.userid, company.ceo.assistant.userid); assertEquals(copied.ceo.minions[0].userid, company.ceo.minions[0].userid); assertEquals(copied.ceo.minions[1].userid, company.ceo.minions[1].userid); assertEquals(copied.ceo.minions[2].userid, company.ceo.minions[2].userid); assertEquals(((Manager) copied.ceo.minions[2]).minions[0].userid, ((Manager) company.ceo.minions[2]).minions[0].userid); assertEquals(((Manager) copied.ceo.minions[2]).minions[1].userid, ((Manager) company.ceo.minions[2]).minions[1].userid); } public void testRegisterSuperTypeFirst() { Gson gson = new GsonBuilder() .registerTypeHierarchyAdapter(Employee.class, new EmployeeAdapter()) .registerTypeHierarchyAdapter(Manager.class, new ManagerAdapter()) .create(); Manager manager = new Manager(); manager.userid = "inder"; String json = gson.toJson(manager, Manager.class); assertEquals("\"inder\"", json); Manager copied = gson.fromJson(json, Manager.class); assertEquals(manager.userid, copied.userid); } /** This behaviour changed in Gson 2.1; it used to throw. */ public void testRegisterSubTypeFirstAllowed() { new GsonBuilder() .registerTypeHierarchyAdapter(Manager.class, new ManagerAdapter()) .registerTypeHierarchyAdapter(Employee.class, new EmployeeAdapter()) .create(); } static class ManagerAdapter implements JsonSerializer, JsonDeserializer { public Manager deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) { Manager result = new Manager(); result.userid = json.getAsString(); return result; } public JsonElement serialize(Manager src, Type typeOfSrc, JsonSerializationContext context) { return new JsonPrimitive(src.userid); } } static class EmployeeAdapter implements JsonSerializer, JsonDeserializer { public JsonElement serialize(Employee employee, Type typeOfSrc, JsonSerializationContext context) { JsonObject result = new JsonObject(); result.add("userid", context.serialize(employee.userid, String.class)); result.add("startDate", context.serialize(employee.startDate, long.class)); if (employee instanceof Manager) { result.add("minions", context.serialize(((Manager) employee).minions, Employee[].class)); if (employee instanceof CEO) { result.add("assistant", context.serialize(((CEO) employee).assistant, Employee.class)); } } return result; } public Employee deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { JsonObject object = json.getAsJsonObject(); Employee result = null; // if the employee has an assistant, she must be the CEO JsonElement assistant = object.get("assistant"); if (assistant != null) { result = new CEO(); ((CEO) result).assistant = context.deserialize(assistant, Employee.class); } // only managers have minions JsonElement minons = object.get("minions"); if (minons != null) { if (result == null) { result = new Manager(); } ((Manager) result).minions = context.deserialize(minons, Employee[].class); } if (result == null) { result = new Employee(); } result.userid = context.deserialize(object.get("userid"), String.class); result.startDate = context.deserialize(object.get("startDate"), long.class); return result; } } static class Employee { String userid; long startDate; Employee(String userid, long startDate) { this.userid = userid; this.startDate = startDate; } Employee() {} } static class Manager extends Employee { Employee[] minions; } static class CEO extends Manager { Employee assistant; } static class Company { CEO ceo; } } google-gson/src/test/java/com/google/gson/functional/CollectionTest.java0000664000175000017500000003123311650614252026263 0ustar ebourgebourg/* * 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.JsonElement; import com.google.gson.JsonPrimitive; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; import com.google.gson.common.MoreAsserts; import com.google.gson.common.TestTypes.BagOfPrimitives; import com.google.gson.reflect.TypeToken; import junit.framework.TestCase; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Queue; import java.util.Set; /** * Functional tests for Json serialization and deserialization of collections. * * @author Inderjeet Singh * @author Joel Leitch */ public class CollectionTest extends TestCase { private Gson gson; @Override protected void setUp() throws Exception { super.setUp(); gson = new Gson(); } public void testTopLevelCollectionOfIntegersSerialization() { Collection target = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9); Type targetType = new TypeToken>() {}.getType(); String json = gson.toJson(target, targetType); assertEquals("[1,2,3,4,5,6,7,8,9]", json); } public void testTopLevelCollectionOfIntegersDeserialization() { String json = "[0,1,2,3,4,5,6,7,8,9]"; Type collectionType = new TypeToken>() { }.getType(); Collection target = gson.fromJson(json, collectionType); int[] expected = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; MoreAsserts.assertEquals(expected, toIntArray(target)); } public void testTopLevelListOfIntegerCollectionsDeserialization() throws Exception { String json = "[[1,2,3],[4,5,6],[7,8,9]]"; Type collectionType = new TypeToken>>() {}.getType(); List> target = gson.fromJson(json, collectionType); int[][] expected = new int[3][3]; for (int i = 0; i < 3; ++i) { int start = (3 * i) + 1; for (int j = 0; j < 3; ++j) { expected[i][j] = start + j; } } for (int i = 0; i < 3; i++) { MoreAsserts.assertEquals(expected[i], toIntArray(target.get(i))); } } public void testLinkedListSerialization() { List list = new LinkedList(); list.add("a1"); list.add("a2"); Type linkedListType = new TypeToken>() {}.getType(); String json = gson.toJson(list, linkedListType); assertTrue(json.contains("a1")); assertTrue(json.contains("a2")); } public void testLinkedListDeserialization() { String json = "['a1','a2']"; Type linkedListType = new TypeToken>() {}.getType(); List list = gson.fromJson(json, linkedListType); assertEquals("a1", list.get(0)); assertEquals("a2", list.get(1)); } public void testQueueSerialization() { Queue queue = new LinkedList(); queue.add("a1"); queue.add("a2"); Type queueType = new TypeToken>() {}.getType(); String json = gson.toJson(queue, queueType); assertTrue(json.contains("a1")); assertTrue(json.contains("a2")); } public void testQueueDeserialization() { String json = "['a1','a2']"; Type queueType = new TypeToken>() {}.getType(); Queue queue = gson.fromJson(json, queueType); assertEquals("a1", queue.element()); queue.remove(); assertEquals("a2", queue.element()); } public void testNullsInListSerialization() { List list = new ArrayList(); list.add("foo"); list.add(null); list.add("bar"); String expected = "[\"foo\",null,\"bar\"]"; Type typeOfList = new TypeToken>() {}.getType(); String json = gson.toJson(list, typeOfList); assertEquals(expected, json); } public void testNullsInListDeserialization() { List expected = new ArrayList(); expected.add("foo"); expected.add(null); expected.add("bar"); String json = "[\"foo\",null,\"bar\"]"; Type expectedType = new TypeToken>() {}.getType(); List target = gson.fromJson(json, expectedType); for (int i = 0; i < expected.size(); ++i) { assertEquals(expected.get(i), target.get(i)); } } public void testCollectionOfObjectSerialization() { List target = new ArrayList(); target.add("Hello"); target.add("World"); assertEquals("[\"Hello\",\"World\"]", gson.toJson(target)); Type type = new TypeToken>() {}.getType(); assertEquals("[\"Hello\",\"World\"]", gson.toJson(target, type)); } public void testCollectionOfObjectWithNullSerialization() { List target = new ArrayList(); target.add("Hello"); target.add(null); target.add("World"); assertEquals("[\"Hello\",null,\"World\"]", gson.toJson(target)); Type type = new TypeToken>() {}.getType(); assertEquals("[\"Hello\",null,\"World\"]", gson.toJson(target, type)); } public void testCollectionOfStringsSerialization() { List target = new ArrayList(); target.add("Hello"); target.add("World"); assertEquals("[\"Hello\",\"World\"]", gson.toJson(target)); } public void testCollectionOfBagOfPrimitivesSerialization() { List target = new ArrayList(); BagOfPrimitives objA = new BagOfPrimitives(3L, 1, true, "blah"); BagOfPrimitives objB = new BagOfPrimitives(2L, 6, false, "blahB"); target.add(objA); target.add(objB); String result = gson.toJson(target); assertTrue(result.startsWith("[")); assertTrue(result.endsWith("]")); for (BagOfPrimitives obj : target) { assertTrue(result.contains(obj.getExpectedJson())); } } public void testCollectionOfStringsDeserialization() { String json = "[\"Hello\",\"World\"]"; Type collectionType = new TypeToken>() { }.getType(); Collection target = gson.fromJson(json, collectionType); assertTrue(target.contains("Hello")); assertTrue(target.contains("World")); } public void testRawCollectionOfIntegersSerialization() { Collection target = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9); assertEquals("[1,2,3,4,5,6,7,8,9]", gson.toJson(target)); } @SuppressWarnings("rawtypes") public void testRawCollectionSerialization() { BagOfPrimitives bag1 = new BagOfPrimitives(); Collection target = Arrays.asList(bag1, bag1); String json = gson.toJson(target); assertTrue(json.contains(bag1.getExpectedJson())); } @SuppressWarnings("rawtypes") public void testRawCollectionDeserializationNotAlllowed() { String json = "[0,1,2,3,4,5,6,7,8,9]"; Collection integers = gson.fromJson(json, Collection.class); // JsonReader converts numbers to double by default so we need a floating point comparison assertEquals(Arrays.asList(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0), integers); json = "[\"Hello\", \"World\"]"; Collection strings = gson.fromJson(json, Collection.class); assertTrue(strings.contains("Hello")); assertTrue(strings.contains("World")); } @SuppressWarnings({"rawtypes", "unchecked"}) public void testRawCollectionOfBagOfPrimitivesNotAllowed() { BagOfPrimitives bag = new BagOfPrimitives(10, 20, false, "stringValue"); String json = '[' + bag.getExpectedJson() + ',' + bag.getExpectedJson() + ']'; Collection target = gson.fromJson(json, Collection.class); assertEquals(2, target.size()); for (Object bag1 : target) { // Gson 2.0 converts raw objects into maps Map values = (Map) bag1; assertTrue(values.containsValue(10.0)); assertTrue(values.containsValue(20.0)); assertTrue(values.containsValue("stringValue")); } } public void testWildcardPrimitiveCollectionSerilaization() throws Exception { Collection target = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9); Type collectionType = new TypeToken>() { }.getType(); String json = gson.toJson(target, collectionType); assertEquals("[1,2,3,4,5,6,7,8,9]", json); json = gson.toJson(target); assertEquals("[1,2,3,4,5,6,7,8,9]", json); } public void testWildcardPrimitiveCollectionDeserilaization() throws Exception { String json = "[1,2,3,4,5,6,7,8,9]"; Type collectionType = new TypeToken>() { }.getType(); Collection target = gson.fromJson(json, collectionType); assertEquals(9, target.size()); assertTrue(target.contains(1)); assertTrue(target.contains(9)); } public void testWildcardCollectionField() throws Exception { Collection collection = new ArrayList(); BagOfPrimitives objA = new BagOfPrimitives(3L, 1, true, "blah"); BagOfPrimitives objB = new BagOfPrimitives(2L, 6, false, "blahB"); collection.add(objA); collection.add(objB); ObjectWithWildcardCollection target = new ObjectWithWildcardCollection(collection); String json = gson.toJson(target); assertTrue(json.contains(objA.getExpectedJson())); assertTrue(json.contains(objB.getExpectedJson())); target = gson.fromJson(json, ObjectWithWildcardCollection.class); Collection deserializedCollection = target.getCollection(); assertEquals(2, deserializedCollection.size()); assertTrue(deserializedCollection.contains(objA)); assertTrue(deserializedCollection.contains(objB)); } public void testFieldIsArrayList() { HasArrayListField object = new HasArrayListField(); object.longs.add(1L); object.longs.add(3L); String json = gson.toJson(object, HasArrayListField.class); assertEquals("{\"longs\":[1,3]}", json); HasArrayListField copy = gson.fromJson("{\"longs\":[1,3]}", HasArrayListField.class); assertEquals(Arrays.asList(1L, 3L), copy.longs); } public void testUserCollectionTypeAdapter() { Type listOfString = new TypeToken>() {}.getType(); Object stringListSerializer = new JsonSerializer>() { public JsonElement serialize(List src, Type typeOfSrc, JsonSerializationContext context) { return new JsonPrimitive(src.get(0) + ";" + src.get(1)); } }; Gson gson = new GsonBuilder() .registerTypeAdapter(listOfString, stringListSerializer) .create(); assertEquals("\"ab;cd\"", gson.toJson(Arrays.asList("ab", "cd"), listOfString)); } static class HasArrayListField { ArrayList longs = new ArrayList(); } @SuppressWarnings("rawtypes") private static int[] toIntArray(Collection collection) { int[] ints = new int[collection.size()]; int i = 0; for (Iterator iterator = collection.iterator(); iterator.hasNext(); ++i) { Object obj = iterator.next(); if (obj instanceof Integer) { ints[i] = ((Integer)obj).intValue(); } else if (obj instanceof Long) { ints[i] = ((Long)obj).intValue(); } } return ints; } private static class ObjectWithWildcardCollection { private final Collection collection; public ObjectWithWildcardCollection(Collection collection) { this.collection = collection; } public Collection getCollection() { return collection; } } private static class Entry { int value; Entry(int value) { this.value = value; } } public void testSetSerialization() { Set set = new HashSet(); set.add(new Entry(1)); set.add(new Entry(2)); String json = gson.toJson(set); assertTrue(json.contains("1")); assertTrue(json.contains("2")); } public void testSetDeserialization() { String json = "[{value:1},{value:2}]"; Type type = new TypeToken>() {}.getType(); Set set = gson.fromJson(json, type); assertEquals(2, set.size()); for (Entry entry : set) { assertTrue(entry.value == 1 || entry.value == 2); } } } google-gson/src/test/java/com/google/gson/functional/NamingPolicyTest.java0000664000175000017500000001606611642100264026562 0ustar ebourgebourg/* * 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.FieldNamingPolicy; import com.google.gson.FieldNamingStrategy; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.annotations.SerializedName; import com.google.gson.common.TestTypes.ClassWithSerializedNameFields; import com.google.gson.common.TestTypes.StringWrapper; import junit.framework.TestCase; import java.lang.reflect.Field; /** * Functional tests for naming policies. * * @author Inderjeet Singh * @author Joel Leitch */ public class NamingPolicyTest extends TestCase { private GsonBuilder builder; @Override protected void setUp() throws Exception { super.setUp(); builder = new GsonBuilder(); } public void testGsonWithNonDefaultFieldNamingPolicySerialization() { Gson gson = builder.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE).create(); StringWrapper target = new StringWrapper("blah"); assertEquals("{\"SomeConstantStringInstanceField\":\"" + target.someConstantStringInstanceField + "\"}", gson.toJson(target)); } public void testGsonWithNonDefaultFieldNamingPolicyDeserialiation() { Gson gson = builder.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE).create(); String target = "{\"SomeConstantStringInstanceField\":\"someValue\"}"; StringWrapper deserializedObject = gson.fromJson(target, StringWrapper.class); assertEquals("someValue", deserializedObject.someConstantStringInstanceField); } public void testGsonWithLowerCaseDashPolicySerialization() { Gson gson = builder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_DASHES).create(); StringWrapper target = new StringWrapper("blah"); assertEquals("{\"some-constant-string-instance-field\":\"" + target.someConstantStringInstanceField + "\"}", gson.toJson(target)); } public void testGsonWithLowerCaseDashPolicyDeserialiation() { Gson gson = builder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_DASHES).create(); String target = "{\"some-constant-string-instance-field\":\"someValue\"}"; StringWrapper deserializedObject = gson.fromJson(target, StringWrapper.class); assertEquals("someValue", deserializedObject.someConstantStringInstanceField); } public void testGsonWithLowerCaseUnderscorePolicySerialization() { Gson gson = builder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) .create(); StringWrapper target = new StringWrapper("blah"); assertEquals("{\"some_constant_string_instance_field\":\"" + target.someConstantStringInstanceField + "\"}", gson.toJson(target)); } public void testGsonWithLowerCaseUnderscorePolicyDeserialiation() { Gson gson = builder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) .create(); String target = "{\"some_constant_string_instance_field\":\"someValue\"}"; StringWrapper deserializedObject = gson.fromJson(target, StringWrapper.class); assertEquals("someValue", deserializedObject.someConstantStringInstanceField); } public void testGsonWithSerializedNameFieldNamingPolicySerialization() { Gson gson = builder.create(); ClassWithSerializedNameFields expected = new ClassWithSerializedNameFields(5, 6); String actual = gson.toJson(expected); assertEquals(expected.getExpectedJson(), actual); } public void testGsonWithSerializedNameFieldNamingPolicyDeserialization() { Gson gson = builder.create(); ClassWithSerializedNameFields expected = new ClassWithSerializedNameFields(5, 7); ClassWithSerializedNameFields actual = gson.fromJson(expected.getExpectedJson(), ClassWithSerializedNameFields.class); assertEquals(expected.f, actual.f); } public void testGsonDuplicateNameUsingSerializedNameFieldNamingPolicySerialization() { Gson gson = builder.create(); try { ClassWithDuplicateFields target = new ClassWithDuplicateFields(10); gson.toJson(target); fail(); } catch (IllegalArgumentException expected) { } } public void testGsonWithUpperCamelCaseSpacesPolicySerialiation() { Gson gson = builder.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE_WITH_SPACES) .create(); StringWrapper target = new StringWrapper("blah"); assertEquals("{\"Some Constant String Instance Field\":\"" + target.someConstantStringInstanceField + "\"}", gson.toJson(target)); } public void testGsonWithUpperCamelCaseSpacesPolicyDeserialiation() { Gson gson = builder.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE_WITH_SPACES) .create(); String target = "{\"Some Constant String Instance Field\":\"someValue\"}"; StringWrapper deserializedObject = gson.fromJson(target, StringWrapper.class); assertEquals("someValue", deserializedObject.someConstantStringInstanceField); } public void testDeprecatedNamingStrategy() throws Exception { Gson gson = builder.setFieldNamingStrategy(new UpperCaseNamingStrategy()).create(); ClassWithDuplicateFields target = new ClassWithDuplicateFields(10); String actual = gson.toJson(target); assertEquals("{\"A\":10}", actual); } public void testComplexFieldNameStrategy() throws Exception { Gson gson = new Gson(); String json = gson.toJson(new ClassWithComplexFieldName(10)); String escapedFieldName = "@value\\\"_s$\\\\"; assertEquals("{\"" + escapedFieldName + "\":10}", json); ClassWithComplexFieldName obj = gson.fromJson(json, ClassWithComplexFieldName.class); assertEquals(10, obj.value); } /** http://code.google.com/p/google-gson/issues/detail?id=349 */ public void testAtSignInSerializedName() { assertEquals("{\"@foo\":\"bar\"}", new Gson().toJson(new AtName())); } static class AtName { @SerializedName("@foo") String f = "bar"; } private static class UpperCaseNamingStrategy implements FieldNamingStrategy { public String translateName(Field f) { return f.getName().toUpperCase(); } } @SuppressWarnings("unused") private static class ClassWithDuplicateFields { public Integer a; @SerializedName("a") public Double b; public ClassWithDuplicateFields(Integer a) { this(a, null); } public ClassWithDuplicateFields(Double b) { this(null, b); } public ClassWithDuplicateFields(Integer a, Double b) { this.a = a; this.b = b; } } private static class ClassWithComplexFieldName { @SerializedName("@value\"_s$\\") public final long value; ClassWithComplexFieldName(long value) { this.value = value; } } } google-gson/src/test/java/com/google/gson/functional/InterfaceTest.java0000664000175000017500000000366011261553330026070 0ustar ebourgebourg/* * 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 junit.framework.TestCase; /** * Functional tests involving interfaces. * * @author Inderjeet Singh * @author Joel Leitch */ public class InterfaceTest extends TestCase { private static final String OBJ_JSON = "{\"someStringValue\":\"StringValue\"}"; private Gson gson; private TestObject obj; @Override protected void setUp() throws Exception { super.setUp(); gson = new Gson(); obj = new TestObject("StringValue"); } public void testSerializingObjectImplementingInterface() throws Exception { assertEquals(OBJ_JSON, gson.toJson(obj)); } public void testSerializingInterfaceObjectField() throws Exception { TestObjectWrapper objWrapper = new TestObjectWrapper(obj); assertEquals("{\"obj\":" + OBJ_JSON + "}", gson.toJson(objWrapper)); } private static interface TestObjectInterface { // Holder } private static class TestObject implements TestObjectInterface { @SuppressWarnings("unused") private String someStringValue; private TestObject(String value) { this.someStringValue = value; } } private static class TestObjectWrapper { @SuppressWarnings("unused") private TestObjectInterface obj; private TestObjectWrapper(TestObjectInterface obj) { this.obj = obj; } } } google-gson/src/test/java/com/google/gson/reflect/0000775000175000017500000000000012207114634021743 5ustar ebourgebourggoogle-gson/src/test/java/com/google/gson/reflect/TypeTokenTest.java0000664000175000017500000000651411515512024025372 0ustar ebourgebourg/* * Copyright (C) 2010 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.reflect; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.List; import java.util.RandomAccess; import java.util.Set; import junit.framework.TestCase; /** * @author Jesse Wilson */ @SuppressWarnings({"deprecation"}) public final class TypeTokenTest extends TestCase { List listOfInteger = null; List listOfNumber = null; List listOfString = null; List listOfUnknown = null; List> listOfSetOfString = null; List> listOfSetOfUnknown = null; public void testIsAssignableFromRawTypes() { assertTrue(TypeToken.get(Object.class).isAssignableFrom(String.class)); assertFalse(TypeToken.get(String.class).isAssignableFrom(Object.class)); assertTrue(TypeToken.get(RandomAccess.class).isAssignableFrom(ArrayList.class)); assertFalse(TypeToken.get(ArrayList.class).isAssignableFrom(RandomAccess.class)); } public void testIsAssignableFromWithTypeParameters() throws Exception { Type a = getClass().getDeclaredField("listOfInteger").getGenericType(); Type b = getClass().getDeclaredField("listOfNumber").getGenericType(); assertTrue(TypeToken.get(a).isAssignableFrom(a)); assertTrue(TypeToken.get(b).isAssignableFrom(b)); // listOfInteger = listOfNumber; // doesn't compile; must be false assertFalse(TypeToken.get(a).isAssignableFrom(b)); // listOfNumber = listOfInteger; // doesn't compile; must be false assertFalse(TypeToken.get(b).isAssignableFrom(a)); } public void testIsAssignableFromWithBasicWildcards() throws Exception { Type a = getClass().getDeclaredField("listOfString").getGenericType(); Type b = getClass().getDeclaredField("listOfUnknown").getGenericType(); assertTrue(TypeToken.get(a).isAssignableFrom(a)); assertTrue(TypeToken.get(b).isAssignableFrom(b)); // listOfString = listOfUnknown // doesn't compile; must be false assertFalse(TypeToken.get(a).isAssignableFrom(b)); listOfUnknown = listOfString; // compiles; must be true // The following assertion is too difficult to support reliably, so disabling // assertTrue(TypeToken.get(b).isAssignableFrom(a)); } public void testIsAssignableFromWithNestedWildcards() throws Exception { Type a = getClass().getDeclaredField("listOfSetOfString").getGenericType(); Type b = getClass().getDeclaredField("listOfSetOfUnknown").getGenericType(); assertTrue(TypeToken.get(a).isAssignableFrom(a)); assertTrue(TypeToken.get(b).isAssignableFrom(b)); // listOfSetOfString = listOfSetOfUnknown; // doesn't compile; must be false assertFalse(TypeToken.get(a).isAssignableFrom(b)); // listOfSetOfUnknown = listOfSetOfString; // doesn't compile; must be false assertFalse(TypeToken.get(b).isAssignableFrom(a)); } } google-gson/src/test/java/com/google/gson/JsonStreamParserTest.java0000664000175000017500000000412511261460423025265 0ustar ebourgebourg/* * Copyright (C) 2009 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; import junit.framework.TestCase; import java.util.NoSuchElementException; /** * Unit tests for {@link JsonStreamParser} * * @author Inderjeet Singh */ public class JsonStreamParserTest extends TestCase { private JsonStreamParser parser; @Override protected void setUp() throws Exception { super.setUp(); parser = new JsonStreamParser("'one' 'two'"); } public void testParseTwoStrings() { String actualOne = parser.next().getAsString(); assertEquals("one", actualOne); String actualTwo = parser.next().getAsString(); assertEquals("two", actualTwo); } public void testIterator() { assertTrue(parser.hasNext()); assertEquals("one", parser.next().getAsString()); assertTrue(parser.hasNext()); assertEquals("two", parser.next().getAsString()); assertFalse(parser.hasNext()); } public void testNoSideEffectForHasNext() throws Exception { assertTrue(parser.hasNext()); assertTrue(parser.hasNext()); assertTrue(parser.hasNext()); assertEquals("one", parser.next().getAsString()); assertTrue(parser.hasNext()); assertTrue(parser.hasNext()); assertEquals("two", parser.next().getAsString()); assertFalse(parser.hasNext()); assertFalse(parser.hasNext()); } public void testCallingNextBeyondAvailableInput() { parser.next(); parser.next(); try { parser.next(); fail("Parser should not go beyond available input"); } catch (NoSuchElementException expected) { } } } google-gson/src/test/java/com/google/gson/GenericArrayTypeTest.java0000664000175000017500000000361211546731521025246 0ustar ebourgebourg/* * 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; import com.google.gson.internal.$Gson$Types; import com.google.gson.reflect.TypeToken; import junit.framework.TestCase; import java.lang.reflect.GenericArrayType; import java.lang.reflect.Type; import java.util.List; /** * Unit tests for the {@code GenericArrayType}s created by the {@link $Gson$Types} class. * * @author Inderjeet Singh * @author Joel Leitch */ public class GenericArrayTypeTest extends TestCase { private GenericArrayType ourType; @Override protected void setUp() throws Exception { super.setUp(); ourType = $Gson$Types.arrayOf($Gson$Types.newParameterizedTypeWithOwner(null, List.class, String.class)); } public void testOurTypeFunctionality() throws Exception { Type parameterizedType = new TypeToken>() {}.getType(); Type genericArrayType = new TypeToken[]>() {}.getType(); assertEquals(parameterizedType, ourType.getGenericComponentType()); assertEquals(genericArrayType, ourType); assertEquals(genericArrayType.hashCode(), ourType.hashCode()); } public void testNotEquals() throws Exception { Type differentGenericArrayType = new TypeToken[][]>() {}.getType(); assertFalse(differentGenericArrayType.equals(ourType)); assertFalse(ourType.equals(differentGenericArrayType)); } } google-gson/src/test/java/com/google/gson/stream/0000775000175000017500000000000012207114634021612 5ustar ebourgebourggoogle-gson/src/test/java/com/google/gson/stream/JsonReaderTest.java0000664000175000017500000015174012132620557025364 0ustar ebourgebourg/* * Copyright (C) 2010 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.stream; import java.io.EOFException; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.Arrays; import junit.framework.TestCase; import static com.google.gson.stream.JsonToken.BEGIN_ARRAY; import static com.google.gson.stream.JsonToken.BEGIN_OBJECT; import static com.google.gson.stream.JsonToken.BOOLEAN; import static com.google.gson.stream.JsonToken.END_ARRAY; import static com.google.gson.stream.JsonToken.END_OBJECT; import static com.google.gson.stream.JsonToken.NAME; import static com.google.gson.stream.JsonToken.NULL; import static com.google.gson.stream.JsonToken.NUMBER; import static com.google.gson.stream.JsonToken.STRING; @SuppressWarnings("resource") public final class JsonReaderTest extends TestCase { public void testReadArray() throws IOException { JsonReader reader = new JsonReader(reader("[true, true]")); reader.beginArray(); assertEquals(true, reader.nextBoolean()); assertEquals(true, reader.nextBoolean()); reader.endArray(); assertEquals(JsonToken.END_DOCUMENT, reader.peek()); } public void testReadEmptyArray() throws IOException { JsonReader reader = new JsonReader(reader("[]")); reader.beginArray(); assertFalse(reader.hasNext()); reader.endArray(); assertEquals(JsonToken.END_DOCUMENT, reader.peek()); } public void testReadObject() throws IOException { JsonReader reader = new JsonReader(reader( "{\"a\": \"android\", \"b\": \"banana\"}")); reader.beginObject(); assertEquals("a", reader.nextName()); assertEquals("android", reader.nextString()); assertEquals("b", reader.nextName()); assertEquals("banana", reader.nextString()); reader.endObject(); assertEquals(JsonToken.END_DOCUMENT, reader.peek()); } public void testReadEmptyObject() throws IOException { JsonReader reader = new JsonReader(reader("{}")); reader.beginObject(); assertFalse(reader.hasNext()); reader.endObject(); assertEquals(JsonToken.END_DOCUMENT, reader.peek()); } public void testSkipArray() throws IOException { JsonReader reader = new JsonReader(reader( "{\"a\": [\"one\", \"two\", \"three\"], \"b\": 123}")); reader.beginObject(); assertEquals("a", reader.nextName()); reader.skipValue(); assertEquals("b", reader.nextName()); assertEquals(123, reader.nextInt()); reader.endObject(); assertEquals(JsonToken.END_DOCUMENT, reader.peek()); } public void testSkipArrayAfterPeek() throws Exception { JsonReader reader = new JsonReader(reader( "{\"a\": [\"one\", \"two\", \"three\"], \"b\": 123}")); reader.beginObject(); assertEquals("a", reader.nextName()); assertEquals(BEGIN_ARRAY, reader.peek()); reader.skipValue(); assertEquals("b", reader.nextName()); assertEquals(123, reader.nextInt()); reader.endObject(); assertEquals(JsonToken.END_DOCUMENT, reader.peek()); } public void testSkipTopLevelObject() throws Exception { JsonReader reader = new JsonReader(reader( "{\"a\": [\"one\", \"two\", \"three\"], \"b\": 123}")); reader.skipValue(); assertEquals(JsonToken.END_DOCUMENT, reader.peek()); } public void testSkipObject() throws IOException { JsonReader reader = new JsonReader(reader( "{\"a\": { \"c\": [], \"d\": [true, true, {}] }, \"b\": \"banana\"}")); reader.beginObject(); assertEquals("a", reader.nextName()); reader.skipValue(); assertEquals("b", reader.nextName()); reader.skipValue(); reader.endObject(); assertEquals(JsonToken.END_DOCUMENT, reader.peek()); } public void testSkipObjectAfterPeek() throws Exception { String json = "{" + " \"one\": { \"num\": 1 }" + ", \"two\": { \"num\": 2 }" + ", \"three\": { \"num\": 3 }" + "}"; JsonReader reader = new JsonReader(reader(json)); reader.beginObject(); assertEquals("one", reader.nextName()); assertEquals(BEGIN_OBJECT, reader.peek()); reader.skipValue(); assertEquals("two", reader.nextName()); assertEquals(BEGIN_OBJECT, reader.peek()); reader.skipValue(); assertEquals("three", reader.nextName()); reader.skipValue(); reader.endObject(); assertEquals(JsonToken.END_DOCUMENT, reader.peek()); } public void testSkipInteger() throws IOException { JsonReader reader = new JsonReader(reader( "{\"a\":123456789,\"b\":-123456789}")); reader.beginObject(); assertEquals("a", reader.nextName()); reader.skipValue(); assertEquals("b", reader.nextName()); reader.skipValue(); reader.endObject(); assertEquals(JsonToken.END_DOCUMENT, reader.peek()); } public void testSkipDouble() throws IOException { JsonReader reader = new JsonReader(reader( "{\"a\":-123.456e-789,\"b\":123456789.0}")); reader.beginObject(); assertEquals("a", reader.nextName()); reader.skipValue(); assertEquals("b", reader.nextName()); reader.skipValue(); reader.endObject(); assertEquals(JsonToken.END_DOCUMENT, reader.peek()); } public void testHelloWorld() throws IOException { String json = "{\n" + " \"hello\": true,\n" + " \"foo\": [\"world\"]\n" + "}"; JsonReader reader = new JsonReader(reader(json)); reader.beginObject(); assertEquals("hello", reader.nextName()); assertEquals(true, reader.nextBoolean()); assertEquals("foo", reader.nextName()); reader.beginArray(); assertEquals("world", reader.nextString()); reader.endArray(); reader.endObject(); assertEquals(JsonToken.END_DOCUMENT, reader.peek()); } public void testNulls() { try { new JsonReader(null); fail(); } catch (NullPointerException expected) { } } public void testEmptyString() { try { new JsonReader(reader("")).beginArray(); } catch (IOException expected) { } try { new JsonReader(reader("")).beginObject(); } catch (IOException expected) { } } public void testNoTopLevelObject() { try { new JsonReader(reader("true")).nextBoolean(); } catch (IOException expected) { } } public void testCharacterUnescaping() throws IOException { String json = "[\"a\"," + "\"a\\\"\"," + "\"\\\"\"," + "\":\"," + "\",\"," + "\"\\b\"," + "\"\\f\"," + "\"\\n\"," + "\"\\r\"," + "\"\\t\"," + "\" \"," + "\"\\\\\"," + "\"{\"," + "\"}\"," + "\"[\"," + "\"]\"," + "\"\\u0000\"," + "\"\\u0019\"," + "\"\\u20AC\"" + "]"; JsonReader reader = new JsonReader(reader(json)); reader.beginArray(); assertEquals("a", reader.nextString()); assertEquals("a\"", reader.nextString()); assertEquals("\"", reader.nextString()); assertEquals(":", reader.nextString()); assertEquals(",", reader.nextString()); assertEquals("\b", reader.nextString()); assertEquals("\f", reader.nextString()); assertEquals("\n", reader.nextString()); assertEquals("\r", reader.nextString()); assertEquals("\t", reader.nextString()); assertEquals(" ", reader.nextString()); assertEquals("\\", reader.nextString()); assertEquals("{", reader.nextString()); assertEquals("}", reader.nextString()); assertEquals("[", reader.nextString()); assertEquals("]", reader.nextString()); assertEquals("\0", reader.nextString()); assertEquals("\u0019", reader.nextString()); assertEquals("\u20AC", reader.nextString()); reader.endArray(); assertEquals(JsonToken.END_DOCUMENT, reader.peek()); } public void testUnescapingInvalidCharacters() throws IOException { String json = "[\"\\u000g\"]"; JsonReader reader = new JsonReader(reader(json)); reader.beginArray(); try { reader.nextString(); fail(); } catch (NumberFormatException expected) { } } public void testUnescapingTruncatedCharacters() throws IOException { String json = "[\"\\u000"; JsonReader reader = new JsonReader(reader(json)); reader.beginArray(); try { reader.nextString(); fail(); } catch (IOException expected) { } } public void testUnescapingTruncatedSequence() throws IOException { String json = "[\"\\"; JsonReader reader = new JsonReader(reader(json)); reader.beginArray(); try { reader.nextString(); fail(); } catch (IOException expected) { } } public void testIntegersWithFractionalPartSpecified() throws IOException { JsonReader reader = new JsonReader(reader("[1.0,1.0,1.0]")); reader.beginArray(); assertEquals(1.0, reader.nextDouble()); assertEquals(1, reader.nextInt()); assertEquals(1L, reader.nextLong()); } public void testDoubles() throws IOException { String json = "[-0.0," + "1.0," + "1.7976931348623157E308," + "4.9E-324," + "0.0," + "-0.5," + "2.2250738585072014E-308," + "3.141592653589793," + "2.718281828459045]"; JsonReader reader = new JsonReader(reader(json)); reader.beginArray(); assertEquals(-0.0, reader.nextDouble()); assertEquals(1.0, reader.nextDouble()); assertEquals(1.7976931348623157E308, reader.nextDouble()); assertEquals(4.9E-324, reader.nextDouble()); assertEquals(0.0, reader.nextDouble()); assertEquals(-0.5, reader.nextDouble()); assertEquals(2.2250738585072014E-308, reader.nextDouble()); assertEquals(3.141592653589793, reader.nextDouble()); assertEquals(2.718281828459045, reader.nextDouble()); reader.endArray(); assertEquals(JsonToken.END_DOCUMENT, reader.peek()); } public void testStrictNonFiniteDoubles() throws IOException { String json = "[NaN]"; JsonReader reader = new JsonReader(reader(json)); reader.beginArray(); try { reader.nextDouble(); fail(); } catch (MalformedJsonException expected) { } } public void testStrictQuotedNonFiniteDoubles() throws IOException { String json = "[\"NaN\"]"; JsonReader reader = new JsonReader(reader(json)); reader.beginArray(); try { reader.nextDouble(); fail(); } catch (MalformedJsonException expected) { } } public void testLenientNonFiniteDoubles() throws IOException { String json = "[NaN, -Infinity, Infinity]"; JsonReader reader = new JsonReader(reader(json)); reader.setLenient(true); reader.beginArray(); assertTrue(Double.isNaN(reader.nextDouble())); assertEquals(Double.NEGATIVE_INFINITY, reader.nextDouble()); assertEquals(Double.POSITIVE_INFINITY, reader.nextDouble()); reader.endArray(); } public void testLenientQuotedNonFiniteDoubles() throws IOException { String json = "[\"NaN\", \"-Infinity\", \"Infinity\"]"; JsonReader reader = new JsonReader(reader(json)); reader.setLenient(true); reader.beginArray(); assertTrue(Double.isNaN(reader.nextDouble())); assertEquals(Double.NEGATIVE_INFINITY, reader.nextDouble()); assertEquals(Double.POSITIVE_INFINITY, reader.nextDouble()); reader.endArray(); } public void testStrictNonFiniteDoublesWithSkipValue() throws IOException { String json = "[NaN]"; JsonReader reader = new JsonReader(reader(json)); reader.beginArray(); try { reader.skipValue(); fail(); } catch (MalformedJsonException expected) { } } public void testLongs() throws IOException { String json = "[0,0,0," + "1,1,1," + "-1,-1,-1," + "-9223372036854775808," + "9223372036854775807]"; JsonReader reader = new JsonReader(reader(json)); reader.beginArray(); assertEquals(0L, reader.nextLong()); assertEquals(0, reader.nextInt()); assertEquals(0.0, reader.nextDouble()); assertEquals(1L, reader.nextLong()); assertEquals(1, reader.nextInt()); assertEquals(1.0, reader.nextDouble()); assertEquals(-1L, reader.nextLong()); assertEquals(-1, reader.nextInt()); assertEquals(-1.0, reader.nextDouble()); try { reader.nextInt(); fail(); } catch (NumberFormatException expected) { } assertEquals(Long.MIN_VALUE, reader.nextLong()); try { reader.nextInt(); fail(); } catch (NumberFormatException expected) { } assertEquals(Long.MAX_VALUE, reader.nextLong()); reader.endArray(); assertEquals(JsonToken.END_DOCUMENT, reader.peek()); } public void disabled_testNumberWithOctalPrefix() throws IOException { String json = "[01]"; JsonReader reader = new JsonReader(reader(json)); reader.beginArray(); try { reader.peek(); fail(); } catch (MalformedJsonException expected) { } try { reader.nextInt(); fail(); } catch (MalformedJsonException expected) { } try { reader.nextLong(); fail(); } catch (MalformedJsonException expected) { } try { reader.nextDouble(); fail(); } catch (MalformedJsonException expected) { } assertEquals("01", reader.nextString()); reader.endArray(); assertEquals(JsonToken.END_DOCUMENT, reader.peek()); } public void testBooleans() throws IOException { JsonReader reader = new JsonReader(reader("[true,false]")); reader.beginArray(); assertEquals(true, reader.nextBoolean()); assertEquals(false, reader.nextBoolean()); reader.endArray(); assertEquals(JsonToken.END_DOCUMENT, reader.peek()); } public void testPeekingUnquotedStringsPrefixedWithBooleans() throws IOException { JsonReader reader = new JsonReader(reader("[truey]")); reader.setLenient(true); reader.beginArray(); assertEquals(STRING, reader.peek()); try { reader.nextBoolean(); fail(); } catch (IllegalStateException expected) { } assertEquals("truey", reader.nextString()); reader.endArray(); } public void testMalformedNumbers() throws IOException { assertNotANumber("-"); assertNotANumber("."); // exponent lacks digit assertNotANumber("e"); assertNotANumber("0e"); assertNotANumber(".e"); assertNotANumber("0.e"); assertNotANumber("-.0e"); // no integer assertNotANumber("e1"); assertNotANumber(".e1"); assertNotANumber("-e1"); // trailing characters assertNotANumber("1x"); assertNotANumber("1.1x"); assertNotANumber("1e1x"); assertNotANumber("1ex"); assertNotANumber("1.1ex"); assertNotANumber("1.1e1x"); // fraction has no digit assertNotANumber("0."); assertNotANumber("-0."); assertNotANumber("0.e1"); assertNotANumber("-0.e1"); // no leading digit assertNotANumber(".0"); assertNotANumber("-.0"); assertNotANumber(".0e1"); assertNotANumber("-.0e1"); } private void assertNotANumber(String s) throws IOException { JsonReader reader = new JsonReader(reader("[" + s + "]")); reader.setLenient(true); reader.beginArray(); assertEquals(JsonToken.STRING, reader.peek()); assertEquals(s, reader.nextString()); reader.endArray(); } public void testPeekingUnquotedStringsPrefixedWithIntegers() throws IOException { JsonReader reader = new JsonReader(reader("[12.34e5x]")); reader.setLenient(true); reader.beginArray(); assertEquals(STRING, reader.peek()); try { reader.nextInt(); fail(); } catch (IllegalStateException expected) { } assertEquals("12.34e5x", reader.nextString()); } public void testPeekLongMinValue() throws IOException { JsonReader reader = new JsonReader(reader("[-9223372036854775808]")); reader.setLenient(true); reader.beginArray(); assertEquals(NUMBER, reader.peek()); assertEquals(-9223372036854775808L, reader.nextLong()); } public void testPeekLongMaxValue() throws IOException { JsonReader reader = new JsonReader(reader("[9223372036854775807]")); reader.setLenient(true); reader.beginArray(); assertEquals(NUMBER, reader.peek()); assertEquals(9223372036854775807L, reader.nextLong()); } public void testLongLargerThanMaxLongThatWrapsAround() throws IOException { JsonReader reader = new JsonReader(reader("[22233720368547758070]")); reader.setLenient(true); reader.beginArray(); assertEquals(NUMBER, reader.peek()); try { reader.nextLong(); fail(); } catch (NumberFormatException expected) { } } public void testLongLargerThanMinLongThatWrapsAround() throws IOException { JsonReader reader = new JsonReader(reader("[-22233720368547758070]")); reader.setLenient(true); reader.beginArray(); assertEquals(NUMBER, reader.peek()); try { reader.nextLong(); fail(); } catch (NumberFormatException expected) { } } /** * This test fails because there's no double for 9223372036854775808, and our * long parsing uses Double.parseDouble() for fractional values. */ public void disabled_testPeekLargerThanLongMaxValue() throws IOException { JsonReader reader = new JsonReader(reader("[9223372036854775808]")); reader.setLenient(true); reader.beginArray(); assertEquals(NUMBER, reader.peek()); try { reader.nextLong(); fail(); } catch (NumberFormatException e) { } } /** * This test fails because there's no double for -9223372036854775809, and our * long parsing uses Double.parseDouble() for fractional values. */ public void disabled_testPeekLargerThanLongMinValue() throws IOException { JsonReader reader = new JsonReader(reader("[-9223372036854775809]")); reader.setLenient(true); reader.beginArray(); assertEquals(NUMBER, reader.peek()); try { reader.nextLong(); fail(); } catch (NumberFormatException expected) { } assertEquals(-9223372036854775809d, reader.nextDouble()); } /** * This test fails because there's no double for 9223372036854775806, and * our long parsing uses Double.parseDouble() for fractional values. */ public void disabled_testHighPrecisionLong() throws IOException { String json = "[9223372036854775806.000]"; JsonReader reader = new JsonReader(reader(json)); reader.beginArray(); assertEquals(9223372036854775806L, reader.nextLong()); reader.endArray(); } public void testPeekMuchLargerThanLongMinValue() throws IOException { JsonReader reader = new JsonReader(reader("[-92233720368547758080]")); reader.setLenient(true); reader.beginArray(); assertEquals(NUMBER, reader.peek()); try { reader.nextLong(); fail(); } catch (NumberFormatException expected) { } assertEquals(-92233720368547758080d, reader.nextDouble()); } public void testQuotedNumberWithEscape() throws IOException { JsonReader reader = new JsonReader(reader("[\"12\u00334\"]")); reader.setLenient(true); reader.beginArray(); assertEquals(STRING, reader.peek()); assertEquals(1234, reader.nextInt()); } public void testMixedCaseLiterals() throws IOException { JsonReader reader = new JsonReader(reader("[True,TruE,False,FALSE,NULL,nulL]")); reader.beginArray(); assertEquals(true, reader.nextBoolean()); assertEquals(true, reader.nextBoolean()); assertEquals(false, reader.nextBoolean()); assertEquals(false, reader.nextBoolean()); reader.nextNull(); reader.nextNull(); reader.endArray(); assertEquals(JsonToken.END_DOCUMENT, reader.peek()); } public void testMissingValue() throws IOException { JsonReader reader = new JsonReader(reader("{\"a\":}")); reader.beginObject(); assertEquals("a", reader.nextName()); try { reader.nextString(); fail(); } catch (IOException expected) { } } public void testPrematureEndOfInput() throws IOException { JsonReader reader = new JsonReader(reader("{\"a\":true,")); reader.beginObject(); assertEquals("a", reader.nextName()); assertEquals(true, reader.nextBoolean()); try { reader.nextName(); fail(); } catch (IOException expected) { } } public void testPrematurelyClosed() throws IOException { try { JsonReader reader = new JsonReader(reader("{\"a\":[]}")); reader.beginObject(); reader.close(); reader.nextName(); fail(); } catch (IllegalStateException expected) { } try { JsonReader reader = new JsonReader(reader("{\"a\":[]}")); reader.close(); reader.beginObject(); fail(); } catch (IllegalStateException expected) { } try { JsonReader reader = new JsonReader(reader("{\"a\":true}")); reader.beginObject(); reader.nextName(); reader.peek(); reader.close(); reader.nextBoolean(); fail(); } catch (IllegalStateException expected) { } } public void testNextFailuresDoNotAdvance() throws IOException { JsonReader reader = new JsonReader(reader("{\"a\":true}")); reader.beginObject(); try { reader.nextString(); fail(); } catch (IllegalStateException expected) { } assertEquals("a", reader.nextName()); try { reader.nextName(); fail(); } catch (IllegalStateException expected) { } try { reader.beginArray(); fail(); } catch (IllegalStateException expected) { } try { reader.endArray(); fail(); } catch (IllegalStateException expected) { } try { reader.beginObject(); fail(); } catch (IllegalStateException expected) { } try { reader.endObject(); fail(); } catch (IllegalStateException expected) { } assertEquals(true, reader.nextBoolean()); try { reader.nextString(); fail(); } catch (IllegalStateException expected) { } try { reader.nextName(); fail(); } catch (IllegalStateException expected) { } try { reader.beginArray(); fail(); } catch (IllegalStateException expected) { } try { reader.endArray(); fail(); } catch (IllegalStateException expected) { } reader.endObject(); assertEquals(JsonToken.END_DOCUMENT, reader.peek()); reader.close(); } public void testIntegerMismatchFailuresDoNotAdvance() throws IOException { JsonReader reader = new JsonReader(reader("[1.5]")); reader.beginArray(); try { reader.nextInt(); fail(); } catch (NumberFormatException expected) { } assertEquals(1.5d, reader.nextDouble()); reader.endArray(); } public void testStringNullIsNotNull() throws IOException { JsonReader reader = new JsonReader(reader("[\"null\"]")); reader.beginArray(); try { reader.nextNull(); fail(); } catch (IllegalStateException expected) { } } public void testNullLiteralIsNotAString() throws IOException { JsonReader reader = new JsonReader(reader("[null]")); reader.beginArray(); try { reader.nextString(); fail(); } catch (IllegalStateException expected) { } } public void testStrictNameValueSeparator() throws IOException { JsonReader reader = new JsonReader(reader("{\"a\"=true}")); reader.beginObject(); assertEquals("a", reader.nextName()); try { reader.nextBoolean(); fail(); } catch (IOException expected) { } reader = new JsonReader(reader("{\"a\"=>true}")); reader.beginObject(); assertEquals("a", reader.nextName()); try { reader.nextBoolean(); fail(); } catch (IOException expected) { } } public void testLenientNameValueSeparator() throws IOException { JsonReader reader = new JsonReader(reader("{\"a\"=true}")); reader.setLenient(true); reader.beginObject(); assertEquals("a", reader.nextName()); assertEquals(true, reader.nextBoolean()); reader = new JsonReader(reader("{\"a\"=>true}")); reader.setLenient(true); reader.beginObject(); assertEquals("a", reader.nextName()); assertEquals(true, reader.nextBoolean()); } public void testStrictNameValueSeparatorWithSkipValue() throws IOException { JsonReader reader = new JsonReader(reader("{\"a\"=true}")); reader.beginObject(); assertEquals("a", reader.nextName()); try { reader.skipValue(); fail(); } catch (IOException expected) { } reader = new JsonReader(reader("{\"a\"=>true}")); reader.beginObject(); assertEquals("a", reader.nextName()); try { reader.skipValue(); fail(); } catch (IOException expected) { } } public void testCommentsInStringValue() throws Exception { JsonReader reader = new JsonReader(reader("[\"// comment\"]")); reader.beginArray(); assertEquals("// comment", reader.nextString()); reader.endArray(); reader = new JsonReader(reader("{\"a\":\"#someComment\"}")); reader.beginObject(); assertEquals("a", reader.nextName()); assertEquals("#someComment", reader.nextString()); reader.endObject(); reader = new JsonReader(reader("{\"#//a\":\"#some //Comment\"}")); reader.beginObject(); assertEquals("#//a", reader.nextName()); assertEquals("#some //Comment", reader.nextString()); reader.endObject(); } public void testStrictComments() throws IOException { JsonReader reader = new JsonReader(reader("[// comment \n true]")); reader.beginArray(); try { reader.nextBoolean(); fail(); } catch (IOException expected) { } reader = new JsonReader(reader("[# comment \n true]")); reader.beginArray(); try { reader.nextBoolean(); fail(); } catch (IOException expected) { } reader = new JsonReader(reader("[/* comment */ true]")); reader.beginArray(); try { reader.nextBoolean(); fail(); } catch (IOException expected) { } } public void testLenientComments() throws IOException { JsonReader reader = new JsonReader(reader("[// comment \n true]")); reader.setLenient(true); reader.beginArray(); assertEquals(true, reader.nextBoolean()); reader = new JsonReader(reader("[# comment \n true]")); reader.setLenient(true); reader.beginArray(); assertEquals(true, reader.nextBoolean()); reader = new JsonReader(reader("[/* comment */ true]")); reader.setLenient(true); reader.beginArray(); assertEquals(true, reader.nextBoolean()); } public void testStrictCommentsWithSkipValue() throws IOException { JsonReader reader = new JsonReader(reader("[// comment \n true]")); reader.beginArray(); try { reader.skipValue(); fail(); } catch (IOException expected) { } reader = new JsonReader(reader("[# comment \n true]")); reader.beginArray(); try { reader.skipValue(); fail(); } catch (IOException expected) { } reader = new JsonReader(reader("[/* comment */ true]")); reader.beginArray(); try { reader.skipValue(); fail(); } catch (IOException expected) { } } public void testStrictUnquotedNames() throws IOException { JsonReader reader = new JsonReader(reader("{a:true}")); reader.beginObject(); try { reader.nextName(); fail(); } catch (IOException expected) { } } public void testLenientUnquotedNames() throws IOException { JsonReader reader = new JsonReader(reader("{a:true}")); reader.setLenient(true); reader.beginObject(); assertEquals("a", reader.nextName()); } public void testStrictUnquotedNamesWithSkipValue() throws IOException { JsonReader reader = new JsonReader(reader("{a:true}")); reader.beginObject(); try { reader.skipValue(); fail(); } catch (IOException expected) { } } public void testStrictSingleQuotedNames() throws IOException { JsonReader reader = new JsonReader(reader("{'a':true}")); reader.beginObject(); try { reader.nextName(); fail(); } catch (IOException expected) { } } public void testLenientSingleQuotedNames() throws IOException { JsonReader reader = new JsonReader(reader("{'a':true}")); reader.setLenient(true); reader.beginObject(); assertEquals("a", reader.nextName()); } public void testStrictSingleQuotedNamesWithSkipValue() throws IOException { JsonReader reader = new JsonReader(reader("{'a':true}")); reader.beginObject(); try { reader.skipValue(); fail(); } catch (IOException expected) { } } public void testStrictUnquotedStrings() throws IOException { JsonReader reader = new JsonReader(reader("[a]")); reader.beginArray(); try { reader.nextString(); fail(); } catch (MalformedJsonException expected) { } } public void testStrictUnquotedStringsWithSkipValue() throws IOException { JsonReader reader = new JsonReader(reader("[a]")); reader.beginArray(); try { reader.skipValue(); fail(); } catch (MalformedJsonException expected) { } } public void testLenientUnquotedStrings() throws IOException { JsonReader reader = new JsonReader(reader("[a]")); reader.setLenient(true); reader.beginArray(); assertEquals("a", reader.nextString()); } public void testStrictSingleQuotedStrings() throws IOException { JsonReader reader = new JsonReader(reader("['a']")); reader.beginArray(); try { reader.nextString(); fail(); } catch (IOException expected) { } } public void testLenientSingleQuotedStrings() throws IOException { JsonReader reader = new JsonReader(reader("['a']")); reader.setLenient(true); reader.beginArray(); assertEquals("a", reader.nextString()); } public void testStrictSingleQuotedStringsWithSkipValue() throws IOException { JsonReader reader = new JsonReader(reader("['a']")); reader.beginArray(); try { reader.skipValue(); fail(); } catch (IOException expected) { } } public void testStrictSemicolonDelimitedArray() throws IOException { JsonReader reader = new JsonReader(reader("[true;true]")); reader.beginArray(); try { reader.nextBoolean(); reader.nextBoolean(); fail(); } catch (IOException expected) { } } public void testLenientSemicolonDelimitedArray() throws IOException { JsonReader reader = new JsonReader(reader("[true;true]")); reader.setLenient(true); reader.beginArray(); assertEquals(true, reader.nextBoolean()); assertEquals(true, reader.nextBoolean()); } public void testStrictSemicolonDelimitedArrayWithSkipValue() throws IOException { JsonReader reader = new JsonReader(reader("[true;true]")); reader.beginArray(); try { reader.skipValue(); reader.skipValue(); fail(); } catch (IOException expected) { } } public void testStrictSemicolonDelimitedNameValuePair() throws IOException { JsonReader reader = new JsonReader(reader("{\"a\":true;\"b\":true}")); reader.beginObject(); assertEquals("a", reader.nextName()); try { reader.nextBoolean(); reader.nextName(); fail(); } catch (IOException expected) { } } public void testLenientSemicolonDelimitedNameValuePair() throws IOException { JsonReader reader = new JsonReader(reader("{\"a\":true;\"b\":true}")); reader.setLenient(true); reader.beginObject(); assertEquals("a", reader.nextName()); assertEquals(true, reader.nextBoolean()); assertEquals("b", reader.nextName()); } public void testStrictSemicolonDelimitedNameValuePairWithSkipValue() throws IOException { JsonReader reader = new JsonReader(reader("{\"a\":true;\"b\":true}")); reader.beginObject(); assertEquals("a", reader.nextName()); try { reader.skipValue(); reader.skipValue(); fail(); } catch (IOException expected) { } } public void testStrictUnnecessaryArraySeparators() throws IOException { JsonReader reader = new JsonReader(reader("[true,,true]")); reader.beginArray(); assertEquals(true, reader.nextBoolean()); try { reader.nextNull(); fail(); } catch (IOException expected) { } reader = new JsonReader(reader("[,true]")); reader.beginArray(); try { reader.nextNull(); fail(); } catch (IOException expected) { } reader = new JsonReader(reader("[true,]")); reader.beginArray(); assertEquals(true, reader.nextBoolean()); try { reader.nextNull(); fail(); } catch (IOException expected) { } reader = new JsonReader(reader("[,]")); reader.beginArray(); try { reader.nextNull(); fail(); } catch (IOException expected) { } } public void testLenientUnnecessaryArraySeparators() throws IOException { JsonReader reader = new JsonReader(reader("[true,,true]")); reader.setLenient(true); reader.beginArray(); assertEquals(true, reader.nextBoolean()); reader.nextNull(); assertEquals(true, reader.nextBoolean()); reader.endArray(); reader = new JsonReader(reader("[,true]")); reader.setLenient(true); reader.beginArray(); reader.nextNull(); assertEquals(true, reader.nextBoolean()); reader.endArray(); reader = new JsonReader(reader("[true,]")); reader.setLenient(true); reader.beginArray(); assertEquals(true, reader.nextBoolean()); reader.nextNull(); reader.endArray(); reader = new JsonReader(reader("[,]")); reader.setLenient(true); reader.beginArray(); reader.nextNull(); reader.nextNull(); reader.endArray(); } public void testStrictUnnecessaryArraySeparatorsWithSkipValue() throws IOException { JsonReader reader = new JsonReader(reader("[true,,true]")); reader.beginArray(); assertEquals(true, reader.nextBoolean()); try { reader.skipValue(); fail(); } catch (IOException expected) { } reader = new JsonReader(reader("[,true]")); reader.beginArray(); try { reader.skipValue(); fail(); } catch (IOException expected) { } reader = new JsonReader(reader("[true,]")); reader.beginArray(); assertEquals(true, reader.nextBoolean()); try { reader.skipValue(); fail(); } catch (IOException expected) { } reader = new JsonReader(reader("[,]")); reader.beginArray(); try { reader.skipValue(); fail(); } catch (IOException expected) { } } public void testStrictMultipleTopLevelValues() throws IOException { JsonReader reader = new JsonReader(reader("[] []")); reader.beginArray(); reader.endArray(); try { reader.peek(); fail(); } catch (IOException expected) { } } public void testLenientMultipleTopLevelValues() throws IOException { JsonReader reader = new JsonReader(reader("[] true {}")); reader.setLenient(true); reader.beginArray(); reader.endArray(); assertEquals(true, reader.nextBoolean()); reader.beginObject(); reader.endObject(); assertEquals(JsonToken.END_DOCUMENT, reader.peek()); } public void testStrictMultipleTopLevelValuesWithSkipValue() throws IOException { JsonReader reader = new JsonReader(reader("[] []")); reader.beginArray(); reader.endArray(); try { reader.skipValue(); fail(); } catch (IOException expected) { } } public void testStrictTopLevelString() { JsonReader reader = new JsonReader(reader("\"a\"")); try { reader.nextString(); fail(); } catch (IOException expected) { } } public void testLenientTopLevelString() throws IOException { JsonReader reader = new JsonReader(reader("\"a\"")); reader.setLenient(true); assertEquals("a", reader.nextString()); assertEquals(JsonToken.END_DOCUMENT, reader.peek()); } public void testStrictTopLevelValueType() { JsonReader reader = new JsonReader(reader("true")); try { reader.nextBoolean(); fail(); } catch (IOException expected) { } } public void testLenientTopLevelValueType() throws IOException { JsonReader reader = new JsonReader(reader("true")); reader.setLenient(true); assertEquals(true, reader.nextBoolean()); } public void testStrictTopLevelValueTypeWithSkipValue() { JsonReader reader = new JsonReader(reader("true")); try { reader.skipValue(); fail(); } catch (IOException expected) { } } public void testStrictNonExecutePrefix() { JsonReader reader = new JsonReader(reader(")]}'\n []")); try { reader.beginArray(); fail(); } catch (IOException expected) { } } public void testStrictNonExecutePrefixWithSkipValue() { JsonReader reader = new JsonReader(reader(")]}'\n []")); try { reader.skipValue(); fail(); } catch (IOException expected) { } } public void testLenientNonExecutePrefix() throws IOException { JsonReader reader = new JsonReader(reader(")]}'\n []")); reader.setLenient(true); reader.beginArray(); reader.endArray(); assertEquals(JsonToken.END_DOCUMENT, reader.peek()); } public void testLenientNonExecutePrefixWithLeadingWhitespace() throws IOException { JsonReader reader = new JsonReader(reader("\r\n \t)]}'\n []")); reader.setLenient(true); reader.beginArray(); reader.endArray(); assertEquals(JsonToken.END_DOCUMENT, reader.peek()); } public void testLenientPartialNonExecutePrefix() { JsonReader reader = new JsonReader(reader(")]}' []")); reader.setLenient(true); try { assertEquals(")", reader.nextString()); reader.nextString(); fail(); } catch (IOException expected) { } } public void testBomIgnoredAsFirstCharacterOfDocument() throws IOException { JsonReader reader = new JsonReader(reader("\ufeff[]")); reader.beginArray(); reader.endArray(); } public void testBomForbiddenAsOtherCharacterInDocument() throws IOException { JsonReader reader = new JsonReader(reader("[\ufeff]")); reader.beginArray(); try { reader.endArray(); fail(); } catch (IOException expected) { } } public void testFailWithPosition() throws IOException { testFailWithPosition("Expected value at line 6 column 5", "[\n\n\n\n\n\"a\",}]"); } public void testFailWithPositionGreaterThanBufferSize() throws IOException { String spaces = repeat(' ', 8192); testFailWithPosition("Expected value at line 6 column 5", "[\n\n" + spaces + "\n\n\n\"a\",}]"); } public void testFailWithPositionOverSlashSlashEndOfLineComment() throws IOException { testFailWithPosition("Expected value at line 5 column 6", "\n// foo\n\n//bar\r\n[\"a\",}"); } public void testFailWithPositionOverHashEndOfLineComment() throws IOException { testFailWithPosition("Expected value at line 5 column 6", "\n# foo\n\n#bar\r\n[\"a\",}"); } public void testFailWithPositionOverCStyleComment() throws IOException { testFailWithPosition("Expected value at line 6 column 12", "\n\n/* foo\n*\n*\r\nbar */[\"a\",}"); } public void testFailWithPositionOverQuotedString() throws IOException { testFailWithPosition("Expected value at line 5 column 3", "[\"foo\nbar\r\nbaz\n\",\n }"); } public void testFailWithPositionOverUnquotedString() throws IOException { testFailWithPosition("Expected value at line 5 column 2", "[\n\nabcd\n\n,}"); } public void testFailWithEscapedNewlineCharacter() throws IOException { testFailWithPosition("Expected value at line 5 column 3", "[\n\n\"\\\n\n\",}"); } public void testFailWithPositionIsOffsetByBom() throws IOException { testFailWithPosition("Expected value at line 1 column 6", "\ufeff[\"a\",}]"); } private void testFailWithPosition(String message, String json) throws IOException { // Validate that it works reading the string normally. JsonReader reader1 = new JsonReader(reader(json)); reader1.setLenient(true); reader1.beginArray(); reader1.nextString(); try { reader1.peek(); fail(); } catch (IOException expected) { assertEquals(message, expected.getMessage()); } // Also validate that it works when skipping. JsonReader reader2 = new JsonReader(reader(json)); reader2.setLenient(true); reader2.beginArray(); reader2.skipValue(); try { reader2.peek(); fail(); } catch (IOException expected) { assertEquals(message, expected.getMessage()); } } public void testStrictVeryLongNumber() throws IOException { JsonReader reader = new JsonReader(reader("[0." + repeat('9', 8192) + "]")); reader.beginArray(); try { assertEquals(1d, reader.nextDouble()); fail(); } catch (MalformedJsonException expected) { } } public void testLenientVeryLongNumber() throws IOException { JsonReader reader = new JsonReader(reader("[0." + repeat('9', 8192) + "]")); reader.setLenient(true); reader.beginArray(); assertEquals(JsonToken.STRING, reader.peek()); assertEquals(1d, reader.nextDouble()); reader.endArray(); assertEquals(JsonToken.END_DOCUMENT, reader.peek()); } public void testVeryLongUnquotedLiteral() throws IOException { String literal = "a" + repeat('b', 8192) + "c"; JsonReader reader = new JsonReader(reader("[" + literal + "]")); reader.setLenient(true); reader.beginArray(); assertEquals(literal, reader.nextString()); reader.endArray(); } public void testDeeplyNestedArrays() throws IOException { // this is nested 40 levels deep; Gson is tuned for nesting is 30 levels deep or fewer JsonReader reader = new JsonReader(reader( "[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]")); for (int i = 0; i < 40; i++) { reader.beginArray(); } for (int i = 0; i < 40; i++) { reader.endArray(); } assertEquals(JsonToken.END_DOCUMENT, reader.peek()); } public void testDeeplyNestedObjects() throws IOException { // Build a JSON document structured like {"a":{"a":{"a":{"a":true}}}}, but 40 levels deep String array = "{\"a\":%s}"; String json = "true"; for (int i = 0; i < 40; i++) { json = String.format(array, json); } JsonReader reader = new JsonReader(reader(json)); for (int i = 0; i < 40; i++) { reader.beginObject(); assertEquals("a", reader.nextName()); } assertEquals(true, reader.nextBoolean()); for (int i = 0; i < 40; i++) { reader.endObject(); } assertEquals(JsonToken.END_DOCUMENT, reader.peek()); } // http://code.google.com/p/google-gson/issues/detail?id=409 public void testStringEndingInSlash() throws IOException { JsonReader reader = new JsonReader(reader("/")); reader.setLenient(true); try { reader.peek(); fail(); } catch (MalformedJsonException expected) { } } public void testDocumentWithCommentEndingInSlash() throws IOException { JsonReader reader = new JsonReader(reader("/* foo *//")); reader.setLenient(true); try { reader.peek(); fail(); } catch (MalformedJsonException expected) { } } public void testStringWithLeadingSlash() throws IOException { JsonReader reader = new JsonReader(reader("/x")); reader.setLenient(true); try { reader.peek(); fail(); } catch (MalformedJsonException expected) { } } public void testUnterminatedObject() throws IOException { JsonReader reader = new JsonReader(reader("{\"a\":\"android\"x")); reader.setLenient(true); reader.beginObject(); assertEquals("a", reader.nextName()); assertEquals("android", reader.nextString()); try { reader.peek(); fail(); } catch (MalformedJsonException expected) { } } public void testVeryLongQuotedString() throws IOException { char[] stringChars = new char[1024 * 16]; Arrays.fill(stringChars, 'x'); String string = new String(stringChars); String json = "[\"" + string + "\"]"; JsonReader reader = new JsonReader(reader(json)); reader.beginArray(); assertEquals(string, reader.nextString()); reader.endArray(); } public void testVeryLongUnquotedString() throws IOException { char[] stringChars = new char[1024 * 16]; Arrays.fill(stringChars, 'x'); String string = new String(stringChars); String json = "[" + string + "]"; JsonReader reader = new JsonReader(reader(json)); reader.setLenient(true); reader.beginArray(); assertEquals(string, reader.nextString()); reader.endArray(); } public void testVeryLongUnterminatedString() throws IOException { char[] stringChars = new char[1024 * 16]; Arrays.fill(stringChars, 'x'); String string = new String(stringChars); String json = "[" + string; JsonReader reader = new JsonReader(reader(json)); reader.setLenient(true); reader.beginArray(); assertEquals(string, reader.nextString()); try { reader.peek(); fail(); } catch (EOFException expected) { } } public void testSkipVeryLongUnquotedString() throws IOException { JsonReader reader = new JsonReader(reader("[" + repeat('x', 8192) + "]")); reader.setLenient(true); reader.beginArray(); reader.skipValue(); reader.endArray(); } public void testSkipTopLevelUnquotedString() throws IOException { JsonReader reader = new JsonReader(reader(repeat('x', 8192))); reader.setLenient(true); reader.skipValue(); assertEquals(JsonToken.END_DOCUMENT, reader.peek()); } public void testSkipVeryLongQuotedString() throws IOException { JsonReader reader = new JsonReader(reader("[\"" + repeat('x', 8192) + "\"]")); reader.beginArray(); reader.skipValue(); reader.endArray(); } public void testSkipTopLevelQuotedString() throws IOException { JsonReader reader = new JsonReader(reader("\"" + repeat('x', 8192) + "\"")); reader.setLenient(true); reader.skipValue(); assertEquals(JsonToken.END_DOCUMENT, reader.peek()); } public void testStringAsNumberWithTruncatedExponent() throws IOException { JsonReader reader = new JsonReader(reader("[123e]")); reader.setLenient(true); reader.beginArray(); assertEquals(STRING, reader.peek()); } public void testStringAsNumberWithDigitAndNonDigitExponent() throws IOException { JsonReader reader = new JsonReader(reader("[123e4b]")); reader.setLenient(true); reader.beginArray(); assertEquals(STRING, reader.peek()); } public void testStringAsNumberWithNonDigitExponent() throws IOException { JsonReader reader = new JsonReader(reader("[123eb]")); reader.setLenient(true); reader.beginArray(); assertEquals(STRING, reader.peek()); } public void testEmptyStringName() throws IOException { JsonReader reader = new JsonReader(reader("{\"\":true}")); reader.setLenient(true); assertEquals(BEGIN_OBJECT, reader.peek()); reader.beginObject(); assertEquals(NAME, reader.peek()); assertEquals("", reader.nextName()); assertEquals(JsonToken.BOOLEAN, reader.peek()); assertEquals(true, reader.nextBoolean()); assertEquals(JsonToken.END_OBJECT, reader.peek()); reader.endObject(); assertEquals(JsonToken.END_DOCUMENT, reader.peek()); } public void testStrictExtraCommasInMaps() throws IOException { JsonReader reader = new JsonReader(reader("{\"a\":\"b\",}")); reader.beginObject(); assertEquals("a", reader.nextName()); assertEquals("b", reader.nextString()); try { reader.peek(); fail(); } catch (IOException expected) { } } public void testLenientExtraCommasInMaps() throws IOException { JsonReader reader = new JsonReader(reader("{\"a\":\"b\",}")); reader.setLenient(true); reader.beginObject(); assertEquals("a", reader.nextName()); assertEquals("b", reader.nextString()); try { reader.peek(); fail(); } catch (IOException expected) { } } private String repeat(char c, int count) { char[] array = new char[count]; Arrays.fill(array, c); return new String(array); } public void testMalformedDocuments() throws IOException { assertDocument("{]", BEGIN_OBJECT, IOException.class); assertDocument("{,", BEGIN_OBJECT, IOException.class); assertDocument("{{", BEGIN_OBJECT, IOException.class); assertDocument("{[", BEGIN_OBJECT, IOException.class); assertDocument("{:", BEGIN_OBJECT, IOException.class); assertDocument("{\"name\",", BEGIN_OBJECT, NAME, IOException.class); assertDocument("{\"name\",", BEGIN_OBJECT, NAME, IOException.class); assertDocument("{\"name\":}", BEGIN_OBJECT, NAME, IOException.class); assertDocument("{\"name\"::", BEGIN_OBJECT, NAME, IOException.class); assertDocument("{\"name\":,", BEGIN_OBJECT, NAME, IOException.class); assertDocument("{\"name\"=}", BEGIN_OBJECT, NAME, IOException.class); assertDocument("{\"name\"=>}", BEGIN_OBJECT, NAME, IOException.class); assertDocument("{\"name\"=>\"string\":", BEGIN_OBJECT, NAME, STRING, IOException.class); assertDocument("{\"name\"=>\"string\"=", BEGIN_OBJECT, NAME, STRING, IOException.class); assertDocument("{\"name\"=>\"string\"=>", BEGIN_OBJECT, NAME, STRING, IOException.class); assertDocument("{\"name\"=>\"string\",", BEGIN_OBJECT, NAME, STRING, IOException.class); assertDocument("{\"name\"=>\"string\",\"name\"", BEGIN_OBJECT, NAME, STRING, NAME); assertDocument("[}", BEGIN_ARRAY, IOException.class); assertDocument("[,]", BEGIN_ARRAY, NULL, NULL, END_ARRAY); assertDocument("{", BEGIN_OBJECT, IOException.class); assertDocument("{\"name\"", BEGIN_OBJECT, NAME, IOException.class); assertDocument("{\"name\",", BEGIN_OBJECT, NAME, IOException.class); assertDocument("{'name'", BEGIN_OBJECT, NAME, IOException.class); assertDocument("{'name',", BEGIN_OBJECT, NAME, IOException.class); assertDocument("{name", BEGIN_OBJECT, NAME, IOException.class); assertDocument("[", BEGIN_ARRAY, IOException.class); assertDocument("[string", BEGIN_ARRAY, STRING, IOException.class); assertDocument("[\"string\"", BEGIN_ARRAY, STRING, IOException.class); assertDocument("['string'", BEGIN_ARRAY, STRING, IOException.class); assertDocument("[123", BEGIN_ARRAY, NUMBER, IOException.class); assertDocument("[123,", BEGIN_ARRAY, NUMBER, IOException.class); assertDocument("{\"name\":123", BEGIN_OBJECT, NAME, NUMBER, IOException.class); assertDocument("{\"name\":123,", BEGIN_OBJECT, NAME, NUMBER, IOException.class); assertDocument("{\"name\":\"string\"", BEGIN_OBJECT, NAME, STRING, IOException.class); assertDocument("{\"name\":\"string\",", BEGIN_OBJECT, NAME, STRING, IOException.class); assertDocument("{\"name\":'string'", BEGIN_OBJECT, NAME, STRING, IOException.class); assertDocument("{\"name\":'string',", BEGIN_OBJECT, NAME, STRING, IOException.class); assertDocument("{\"name\":false", BEGIN_OBJECT, NAME, BOOLEAN, IOException.class); assertDocument("{\"name\":false,,", BEGIN_OBJECT, NAME, BOOLEAN, IOException.class); } /** * This test behave slightly differently in Gson 2.2 and earlier. It fails * during peek rather than during nextString(). */ public void testUnterminatedStringFailure() throws IOException { JsonReader reader = new JsonReader(reader("[\"string")); reader.setLenient(true); reader.beginArray(); assertEquals(JsonToken.STRING, reader.peek()); try { reader.nextString(); fail(); } catch (MalformedJsonException expected) { } } private void assertDocument(String document, Object... expectations) throws IOException { JsonReader reader = new JsonReader(reader(document)); reader.setLenient(true); for (Object expectation : expectations) { if (expectation == BEGIN_OBJECT) { reader.beginObject(); } else if (expectation == BEGIN_ARRAY) { reader.beginArray(); } else if (expectation == END_OBJECT) { reader.endObject(); } else if (expectation == END_ARRAY) { reader.endArray(); } else if (expectation == NAME) { assertEquals("name", reader.nextName()); } else if (expectation == BOOLEAN) { assertEquals(false, reader.nextBoolean()); } else if (expectation == STRING) { assertEquals("string", reader.nextString()); } else if (expectation == NUMBER) { assertEquals(123, reader.nextInt()); } else if (expectation == NULL) { reader.nextNull(); } else if (expectation == IOException.class) { try { reader.peek(); fail(); } catch (IOException expected) { } } else { throw new AssertionError(); } } } /** * Returns a reader that returns one character at a time. */ private Reader reader(final String s) { if (true) return new StringReader(s); return new Reader() { int position = 0; @Override public int read(char[] buffer, int offset, int count) throws IOException { if (position == s.length()) { return -1; } else if (count > 0) { buffer[offset] = s.charAt(position++); return 1; } else { throw new IllegalArgumentException(); } } @Override public void close() throws IOException { } }; } } google-gson/src/test/java/com/google/gson/stream/JsonWriterTest.java0000664000175000017500000004127612132065234025433 0ustar ebourgebourg/* * Copyright (C) 2010 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.stream; import java.io.IOException; import java.io.StringWriter; import java.math.BigDecimal; import java.math.BigInteger; import junit.framework.TestCase; @SuppressWarnings("resource") public final class JsonWriterTest extends TestCase { public void testWrongTopLevelType() throws IOException { StringWriter stringWriter = new StringWriter(); JsonWriter jsonWriter = new JsonWriter(stringWriter); try { jsonWriter.value("a"); fail(); } catch (IllegalStateException expected) { } } public void testTwoNames() throws IOException { StringWriter stringWriter = new StringWriter(); JsonWriter jsonWriter = new JsonWriter(stringWriter); jsonWriter.beginObject(); jsonWriter.name("a"); try { jsonWriter.name("a"); fail(); } catch (IllegalStateException expected) { } } public void testNameWithoutValue() throws IOException { StringWriter stringWriter = new StringWriter(); JsonWriter jsonWriter = new JsonWriter(stringWriter); jsonWriter.beginObject(); jsonWriter.name("a"); try { jsonWriter.endObject(); fail(); } catch (IllegalStateException expected) { } } public void testValueWithoutName() throws IOException { StringWriter stringWriter = new StringWriter(); JsonWriter jsonWriter = new JsonWriter(stringWriter); jsonWriter.beginObject(); try { jsonWriter.value(true); fail(); } catch (IllegalStateException expected) { } } public void testMultipleTopLevelValues() throws IOException { StringWriter stringWriter = new StringWriter(); JsonWriter jsonWriter = new JsonWriter(stringWriter); jsonWriter.beginArray().endArray(); try { jsonWriter.beginArray(); fail(); } catch (IllegalStateException expected) { } } public void testBadNestingObject() throws IOException { StringWriter stringWriter = new StringWriter(); JsonWriter jsonWriter = new JsonWriter(stringWriter); jsonWriter.beginArray(); jsonWriter.beginObject(); try { jsonWriter.endArray(); fail(); } catch (IllegalStateException expected) { } } public void testBadNestingArray() throws IOException { StringWriter stringWriter = new StringWriter(); JsonWriter jsonWriter = new JsonWriter(stringWriter); jsonWriter.beginArray(); jsonWriter.beginArray(); try { jsonWriter.endObject(); fail(); } catch (IllegalStateException expected) { } } public void testNullName() throws IOException { StringWriter stringWriter = new StringWriter(); JsonWriter jsonWriter = new JsonWriter(stringWriter); jsonWriter.beginObject(); try { jsonWriter.name(null); fail(); } catch (NullPointerException expected) { } } public void testNullStringValue() throws IOException { StringWriter stringWriter = new StringWriter(); JsonWriter jsonWriter = new JsonWriter(stringWriter); jsonWriter.beginObject(); jsonWriter.name("a"); jsonWriter.value((String) null); jsonWriter.endObject(); assertEquals("{\"a\":null}", stringWriter.toString()); } public void testNonFiniteDoubles() throws IOException { StringWriter stringWriter = new StringWriter(); JsonWriter jsonWriter = new JsonWriter(stringWriter); jsonWriter.beginArray(); try { jsonWriter.value(Double.NaN); fail(); } catch (IllegalArgumentException expected) { } try { jsonWriter.value(Double.NEGATIVE_INFINITY); fail(); } catch (IllegalArgumentException expected) { } try { jsonWriter.value(Double.POSITIVE_INFINITY); fail(); } catch (IllegalArgumentException expected) { } } public void testNonFiniteBoxedDoubles() throws IOException { StringWriter stringWriter = new StringWriter(); JsonWriter jsonWriter = new JsonWriter(stringWriter); jsonWriter.beginArray(); try { jsonWriter.value(new Double(Double.NaN)); fail(); } catch (IllegalArgumentException expected) { } try { jsonWriter.value(new Double(Double.NEGATIVE_INFINITY)); fail(); } catch (IllegalArgumentException expected) { } try { jsonWriter.value(new Double(Double.POSITIVE_INFINITY)); fail(); } catch (IllegalArgumentException expected) { } } public void testDoubles() throws IOException { StringWriter stringWriter = new StringWriter(); JsonWriter jsonWriter = new JsonWriter(stringWriter); jsonWriter.beginArray(); jsonWriter.value(-0.0); jsonWriter.value(1.0); jsonWriter.value(Double.MAX_VALUE); jsonWriter.value(Double.MIN_VALUE); jsonWriter.value(0.0); jsonWriter.value(-0.5); jsonWriter.value(2.2250738585072014E-308); jsonWriter.value(Math.PI); jsonWriter.value(Math.E); jsonWriter.endArray(); jsonWriter.close(); assertEquals("[-0.0," + "1.0," + "1.7976931348623157E308," + "4.9E-324," + "0.0," + "-0.5," + "2.2250738585072014E-308," + "3.141592653589793," + "2.718281828459045]", stringWriter.toString()); } public void testLongs() throws IOException { StringWriter stringWriter = new StringWriter(); JsonWriter jsonWriter = new JsonWriter(stringWriter); jsonWriter.beginArray(); jsonWriter.value(0); jsonWriter.value(1); jsonWriter.value(-1); jsonWriter.value(Long.MIN_VALUE); jsonWriter.value(Long.MAX_VALUE); jsonWriter.endArray(); jsonWriter.close(); assertEquals("[0," + "1," + "-1," + "-9223372036854775808," + "9223372036854775807]", stringWriter.toString()); } public void testNumbers() throws IOException { StringWriter stringWriter = new StringWriter(); JsonWriter jsonWriter = new JsonWriter(stringWriter); jsonWriter.beginArray(); jsonWriter.value(new BigInteger("0")); jsonWriter.value(new BigInteger("9223372036854775808")); jsonWriter.value(new BigInteger("-9223372036854775809")); jsonWriter.value(new BigDecimal("3.141592653589793238462643383")); jsonWriter.endArray(); jsonWriter.close(); assertEquals("[0," + "9223372036854775808," + "-9223372036854775809," + "3.141592653589793238462643383]", stringWriter.toString()); } public void testBooleans() throws IOException { StringWriter stringWriter = new StringWriter(); JsonWriter jsonWriter = new JsonWriter(stringWriter); jsonWriter.beginArray(); jsonWriter.value(true); jsonWriter.value(false); jsonWriter.endArray(); assertEquals("[true,false]", stringWriter.toString()); } public void testNulls() throws IOException { StringWriter stringWriter = new StringWriter(); JsonWriter jsonWriter = new JsonWriter(stringWriter); jsonWriter.beginArray(); jsonWriter.nullValue(); jsonWriter.endArray(); assertEquals("[null]", stringWriter.toString()); } public void testStrings() throws IOException { StringWriter stringWriter = new StringWriter(); JsonWriter jsonWriter = new JsonWriter(stringWriter); jsonWriter.beginArray(); jsonWriter.value("a"); jsonWriter.value("a\""); jsonWriter.value("\""); jsonWriter.value(":"); jsonWriter.value(","); jsonWriter.value("\b"); jsonWriter.value("\f"); jsonWriter.value("\n"); jsonWriter.value("\r"); jsonWriter.value("\t"); jsonWriter.value(" "); jsonWriter.value("\\"); jsonWriter.value("{"); jsonWriter.value("}"); jsonWriter.value("["); jsonWriter.value("]"); jsonWriter.value("\0"); jsonWriter.value("\u0019"); jsonWriter.endArray(); assertEquals("[\"a\"," + "\"a\\\"\"," + "\"\\\"\"," + "\":\"," + "\",\"," + "\"\\b\"," + "\"\\f\"," + "\"\\n\"," + "\"\\r\"," + "\"\\t\"," + "\" \"," + "\"\\\\\"," + "\"{\"," + "\"}\"," + "\"[\"," + "\"]\"," + "\"\\u0000\"," + "\"\\u0019\"]", stringWriter.toString()); } public void testUnicodeLineBreaksEscaped() throws IOException { StringWriter stringWriter = new StringWriter(); JsonWriter jsonWriter = new JsonWriter(stringWriter); jsonWriter.beginArray(); jsonWriter.value("\u2028 \u2029"); jsonWriter.endArray(); assertEquals("[\"\\u2028 \\u2029\"]", stringWriter.toString()); } public void testEmptyArray() throws IOException { StringWriter stringWriter = new StringWriter(); JsonWriter jsonWriter = new JsonWriter(stringWriter); jsonWriter.beginArray(); jsonWriter.endArray(); assertEquals("[]", stringWriter.toString()); } public void testEmptyObject() throws IOException { StringWriter stringWriter = new StringWriter(); JsonWriter jsonWriter = new JsonWriter(stringWriter); jsonWriter.beginObject(); jsonWriter.endObject(); assertEquals("{}", stringWriter.toString()); } public void testObjectsInArrays() throws IOException { StringWriter stringWriter = new StringWriter(); JsonWriter jsonWriter = new JsonWriter(stringWriter); jsonWriter.beginArray(); jsonWriter.beginObject(); jsonWriter.name("a").value(5); jsonWriter.name("b").value(false); jsonWriter.endObject(); jsonWriter.beginObject(); jsonWriter.name("c").value(6); jsonWriter.name("d").value(true); jsonWriter.endObject(); jsonWriter.endArray(); assertEquals("[{\"a\":5,\"b\":false}," + "{\"c\":6,\"d\":true}]", stringWriter.toString()); } public void testArraysInObjects() throws IOException { StringWriter stringWriter = new StringWriter(); JsonWriter jsonWriter = new JsonWriter(stringWriter); jsonWriter.beginObject(); jsonWriter.name("a"); jsonWriter.beginArray(); jsonWriter.value(5); jsonWriter.value(false); jsonWriter.endArray(); jsonWriter.name("b"); jsonWriter.beginArray(); jsonWriter.value(6); jsonWriter.value(true); jsonWriter.endArray(); jsonWriter.endObject(); assertEquals("{\"a\":[5,false]," + "\"b\":[6,true]}", stringWriter.toString()); } public void testDeepNestingArrays() throws IOException { StringWriter stringWriter = new StringWriter(); JsonWriter jsonWriter = new JsonWriter(stringWriter); for (int i = 0; i < 20; i++) { jsonWriter.beginArray(); } for (int i = 0; i < 20; i++) { jsonWriter.endArray(); } assertEquals("[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]", stringWriter.toString()); } public void testDeepNestingObjects() throws IOException { StringWriter stringWriter = new StringWriter(); JsonWriter jsonWriter = new JsonWriter(stringWriter); jsonWriter.beginObject(); for (int i = 0; i < 20; i++) { jsonWriter.name("a"); jsonWriter.beginObject(); } for (int i = 0; i < 20; i++) { jsonWriter.endObject(); } jsonWriter.endObject(); assertEquals("{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":" + "{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{" + "}}}}}}}}}}}}}}}}}}}}}", stringWriter.toString()); } public void testRepeatedName() throws IOException { StringWriter stringWriter = new StringWriter(); JsonWriter jsonWriter = new JsonWriter(stringWriter); jsonWriter.beginObject(); jsonWriter.name("a").value(true); jsonWriter.name("a").value(false); jsonWriter.endObject(); // JsonWriter doesn't attempt to detect duplicate names assertEquals("{\"a\":true,\"a\":false}", stringWriter.toString()); } public void testPrettyPrintObject() throws IOException { StringWriter stringWriter = new StringWriter(); JsonWriter jsonWriter = new JsonWriter(stringWriter); jsonWriter.setIndent(" "); jsonWriter.beginObject(); jsonWriter.name("a").value(true); jsonWriter.name("b").value(false); jsonWriter.name("c").value(5.0); jsonWriter.name("e").nullValue(); jsonWriter.name("f").beginArray(); jsonWriter.value(6.0); jsonWriter.value(7.0); jsonWriter.endArray(); jsonWriter.name("g").beginObject(); jsonWriter.name("h").value(8.0); jsonWriter.name("i").value(9.0); jsonWriter.endObject(); jsonWriter.endObject(); String expected = "{\n" + " \"a\": true,\n" + " \"b\": false,\n" + " \"c\": 5.0,\n" + " \"e\": null,\n" + " \"f\": [\n" + " 6.0,\n" + " 7.0\n" + " ],\n" + " \"g\": {\n" + " \"h\": 8.0,\n" + " \"i\": 9.0\n" + " }\n" + "}"; assertEquals(expected, stringWriter.toString()); } public void testPrettyPrintArray() throws IOException { StringWriter stringWriter = new StringWriter(); JsonWriter jsonWriter = new JsonWriter(stringWriter); jsonWriter.setIndent(" "); jsonWriter.beginArray(); jsonWriter.value(true); jsonWriter.value(false); jsonWriter.value(5.0); jsonWriter.nullValue(); jsonWriter.beginObject(); jsonWriter.name("a").value(6.0); jsonWriter.name("b").value(7.0); jsonWriter.endObject(); jsonWriter.beginArray(); jsonWriter.value(8.0); jsonWriter.value(9.0); jsonWriter.endArray(); jsonWriter.endArray(); String expected = "[\n" + " true,\n" + " false,\n" + " 5.0,\n" + " null,\n" + " {\n" + " \"a\": 6.0,\n" + " \"b\": 7.0\n" + " },\n" + " [\n" + " 8.0,\n" + " 9.0\n" + " ]\n" + "]"; assertEquals(expected, stringWriter.toString()); } public void testLenientWriterPermitsMultipleTopLevelValues() throws IOException { StringWriter stringWriter = new StringWriter(); JsonWriter writer = new JsonWriter(stringWriter); writer.setLenient(true); writer.beginArray(); writer.endArray(); writer.beginArray(); writer.endArray(); writer.close(); assertEquals("[][]", stringWriter.toString()); } public void testStrictWriterDoesNotPermitMultipleTopLevelValues() throws IOException { StringWriter stringWriter = new StringWriter(); JsonWriter writer = new JsonWriter(stringWriter); writer.beginArray(); writer.endArray(); try { writer.beginArray(); fail(); } catch (IllegalStateException expected) { } } public void testClosedWriterThrowsOnStructure() throws IOException { StringWriter stringWriter = new StringWriter(); JsonWriter writer = new JsonWriter(stringWriter); writer.beginArray(); writer.endArray(); writer.close(); try { writer.beginArray(); fail(); } catch (IllegalStateException expected) { } try { writer.endArray(); fail(); } catch (IllegalStateException expected) { } try { writer.beginObject(); fail(); } catch (IllegalStateException expected) { } try { writer.endObject(); fail(); } catch (IllegalStateException expected) { } } public void testClosedWriterThrowsOnName() throws IOException { StringWriter stringWriter = new StringWriter(); JsonWriter writer = new JsonWriter(stringWriter); writer.beginArray(); writer.endArray(); writer.close(); try { writer.name("a"); fail(); } catch (IllegalStateException expected) { } } public void testClosedWriterThrowsOnValue() throws IOException { StringWriter stringWriter = new StringWriter(); JsonWriter writer = new JsonWriter(stringWriter); writer.beginArray(); writer.endArray(); writer.close(); try { writer.value("a"); fail(); } catch (IllegalStateException expected) { } } public void testClosedWriterThrowsOnFlush() throws IOException { StringWriter stringWriter = new StringWriter(); JsonWriter writer = new JsonWriter(stringWriter); writer.beginArray(); writer.endArray(); writer.close(); try { writer.flush(); fail(); } catch (IllegalStateException expected) { } } public void testWriterCloseIsIdempotent() throws IOException { StringWriter stringWriter = new StringWriter(); JsonWriter writer = new JsonWriter(stringWriter); writer.beginArray(); writer.endArray(); writer.close(); writer.close(); } } google-gson/src/test/java/com/google/gson/OverrideCoreTypeAdaptersTest.java0000664000175000017500000000552211774402546026756 0ustar ebourgebourg/* * Copyright (C) 2012 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; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; import java.io.IOException; import java.util.Locale; import junit.framework.TestCase; /** * @author Jesse Wilson */ public class OverrideCoreTypeAdaptersTest extends TestCase { private static final TypeAdapter booleanAsIntAdapter = new TypeAdapter() { @Override public void write(JsonWriter out, Boolean value) throws IOException { out.value(value ? 1 : 0); } @Override public Boolean read(JsonReader in) throws IOException { int value = in.nextInt(); return value != 0; } }; private static final TypeAdapter swapCaseStringAdapter = new TypeAdapter() { @Override public void write(JsonWriter out, String value) throws IOException { out.value(value.toUpperCase(Locale.US)); } @Override public String read(JsonReader in) throws IOException { return in.nextString().toLowerCase(Locale.US); } }; public void testOverrideWrapperBooleanAdapter() { Gson gson = new GsonBuilder() .registerTypeAdapter(Boolean.class, booleanAsIntAdapter) .create(); assertEquals("true", gson.toJson(true, boolean.class)); assertEquals("1", gson.toJson(true, Boolean.class)); assertEquals(Boolean.TRUE, gson.fromJson("true", boolean.class)); assertEquals(Boolean.TRUE, gson.fromJson("1", Boolean.class)); assertEquals(Boolean.FALSE, gson.fromJson("0", Boolean.class)); } public void testOverridePrimitiveBooleanAdapter() { Gson gson = new GsonBuilder() .registerTypeAdapter(boolean.class, booleanAsIntAdapter) .create(); assertEquals("1", gson.toJson(true, boolean.class)); assertEquals("true", gson.toJson(true, Boolean.class)); assertEquals(Boolean.TRUE, gson.fromJson("1", boolean.class)); assertEquals(Boolean.TRUE, gson.fromJson("true", Boolean.class)); assertEquals("0", gson.toJson(false, boolean.class)); } public void testOverrideStringAdapter() { Gson gson = new GsonBuilder() .registerTypeAdapter(String.class, swapCaseStringAdapter) .create(); assertEquals("\"HELLO\"", gson.toJson("Hello", String.class)); assertEquals("hello", gson.fromJson("\"Hello\"", String.class)); } } google-gson/src/test/java/com/google/gson/internal/0000775000175000017500000000000012207114634022133 5ustar ebourgebourggoogle-gson/src/test/java/com/google/gson/internal/LinkedHashTreeMapTest.java0000664000175000017500000002321012144252255027126 0ustar ebourgebourg/* * Copyright (C) 2012 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.internal; import com.google.gson.common.MoreAsserts; import com.google.gson.internal.LinkedHashTreeMap.AvlBuilder; import com.google.gson.internal.LinkedHashTreeMap.AvlIterator; import com.google.gson.internal.LinkedHashTreeMap.Node; import junit.framework.TestCase; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.Map; import java.util.Random; public final class LinkedHashTreeMapTest extends TestCase { public void testIterationOrder() { LinkedHashTreeMap map = new LinkedHashTreeMap(); map.put("a", "android"); map.put("c", "cola"); map.put("b", "bbq"); assertIterationOrder(map.keySet(), "a", "c", "b"); assertIterationOrder(map.values(), "android", "cola", "bbq"); } public void testRemoveRootDoesNotDoubleUnlink() { LinkedHashTreeMap map = new LinkedHashTreeMap(); map.put("a", "android"); map.put("c", "cola"); map.put("b", "bbq"); Iterator> it = map.entrySet().iterator(); it.next(); it.next(); it.next(); it.remove(); assertIterationOrder(map.keySet(), "a", "c"); } public void testPutNullKeyFails() { LinkedHashTreeMap map = new LinkedHashTreeMap(); try { map.put(null, "android"); fail(); } catch (NullPointerException expected) { } } public void testPutNonComparableKeyFails() { LinkedHashTreeMap map = new LinkedHashTreeMap(); try { map.put(new Object(), "android"); fail(); } catch (ClassCastException expected) {} } @SuppressWarnings("SuspiciousMethodCalls") public void testContainsNonComparableKeyReturnsFalse() { LinkedHashTreeMap map = new LinkedHashTreeMap(); map.put("a", "android"); assertFalse(map.containsKey(new Object())); } public void testContainsNullKeyIsAlwaysFalse() { LinkedHashTreeMap map = new LinkedHashTreeMap(); map.put("a", "android"); assertFalse(map.containsKey(null)); } public void testPutOverrides() throws Exception { LinkedHashTreeMap map = new LinkedHashTreeMap(); assertNull(map.put("d", "donut")); assertNull(map.put("e", "eclair")); assertNull(map.put("f", "froyo")); assertEquals(3, map.size()); assertEquals("donut", map.get("d")); assertEquals("donut", map.put("d", "done")); assertEquals(3, map.size()); } public void testEmptyStringValues() { LinkedHashTreeMap map = new LinkedHashTreeMap(); map.put("a", ""); assertTrue(map.containsKey("a")); assertEquals("", map.get("a")); } // NOTE that this does not happen every time, but given the below predictable random, // this test will consistently fail (assuming the initial size is 16 and rehashing // size remains at 3/4) public void disabled_testForceDoublingAndRehash() throws Exception { Random random = new Random(1367593214724L); LinkedHashTreeMap map = new LinkedHashTreeMap(); String[] keys = new String[1000]; for (int i = 0; i < keys.length; i++) { keys[i] = Integer.toString(Math.abs(random.nextInt()), 36) + "-" + i; map.put(keys[i], "" + i); } for (int i = 0; i < keys.length; i++) { String key = keys[i]; assertTrue(map.containsKey(key)); assertEquals("" + i, map.get(key)); } } public void testClear() { LinkedHashTreeMap map = new LinkedHashTreeMap(); map.put("a", "android"); map.put("c", "cola"); map.put("b", "bbq"); map.clear(); assertIterationOrder(map.keySet()); assertEquals(0, map.size()); } public void testEqualsAndHashCode() throws Exception { LinkedHashTreeMap map1 = new LinkedHashTreeMap(); map1.put("A", 1); map1.put("B", 2); map1.put("C", 3); map1.put("D", 4); LinkedHashTreeMap map2 = new LinkedHashTreeMap(); map2.put("C", 3); map2.put("B", 2); map2.put("D", 4); map2.put("A", 1); MoreAsserts.assertEqualsAndHashCode(map1, map2); } public void testAvlWalker() { assertAvlWalker(node(node("a"), "b", node("c")), "a", "b", "c"); assertAvlWalker(node(node(node("a"), "b", node("c")), "d", node(node("e"), "f", node("g"))), "a", "b", "c", "d", "e", "f", "g"); assertAvlWalker(node(node(null, "a", node("b")), "c", node(node("d"), "e", null)), "a", "b", "c", "d", "e"); assertAvlWalker(node(null, "a", node(null, "b", node(null, "c", node("d")))), "a", "b", "c", "d"); assertAvlWalker(node(node(node(node("a"), "b", null), "c", null), "d", null), "a", "b", "c", "d"); } private void assertAvlWalker(Node root, String... values) { AvlIterator iterator = new AvlIterator(); iterator.reset(root); for (String value : values) { assertEquals(value, iterator.next().getKey()); } assertNull(iterator.next()); } public void testAvlBuilder() { assertAvlBuilder(1, "a"); assertAvlBuilder(2, "(. a b)"); assertAvlBuilder(3, "(a b c)"); assertAvlBuilder(4, "(a b (. c d))"); assertAvlBuilder(5, "(a b (c d e))"); assertAvlBuilder(6, "((. a b) c (d e f))"); assertAvlBuilder(7, "((a b c) d (e f g))"); assertAvlBuilder(8, "((a b c) d (e f (. g h)))"); assertAvlBuilder(9, "((a b c) d (e f (g h i)))"); assertAvlBuilder(10, "((a b c) d ((. e f) g (h i j)))"); assertAvlBuilder(11, "((a b c) d ((e f g) h (i j k)))"); assertAvlBuilder(12, "((a b (. c d)) e ((f g h) i (j k l)))"); assertAvlBuilder(13, "((a b (c d e)) f ((g h i) j (k l m)))"); assertAvlBuilder(14, "(((. a b) c (d e f)) g ((h i j) k (l m n)))"); assertAvlBuilder(15, "(((a b c) d (e f g)) h ((i j k) l (m n o)))"); assertAvlBuilder(16, "(((a b c) d (e f g)) h ((i j k) l (m n (. o p))))"); assertAvlBuilder(30, "((((. a b) c (d e f)) g ((h i j) k (l m n))) o " + "(((p q r) s (t u v)) w ((x y z) A (B C D))))"); assertAvlBuilder(31, "((((a b c) d (e f g)) h ((i j k) l (m n o))) p " + "(((q r s) t (u v w)) x ((y z A) B (C D E))))"); } private void assertAvlBuilder(int size, String expected) { char[] values = "abcdefghijklmnopqrstuvwxyzABCDE".toCharArray(); AvlBuilder avlBuilder = new AvlBuilder(); avlBuilder.reset(size); for (int i = 0; i < size; i++) { avlBuilder.add(node(Character.toString(values[i]))); } assertTree(expected, avlBuilder.root()); } public void testDoubleCapacity() { @SuppressWarnings("unchecked") // Arrays and generics don't get along. Node[] oldTable = new Node[1]; oldTable[0] = node(node(node("a"), "b", node("c")), "d", node(node("e"), "f", node("g"))); Node[] newTable = LinkedHashTreeMap.doubleCapacity(oldTable); assertTree("(b d f)", newTable[0]); // Even hash codes! assertTree("(a c (. e g))", newTable[1]); // Odd hash codes! for (Node node : newTable) { if (node != null) { assertConsistent(node); } } } private static final Node head = new Node(); private Node node(String value) { return new Node(null, value, value.hashCode(), head, head); } private Node node(Node left, String value, Node right) { Node result = node(value); if (left != null) { result.left = left; left.parent = result; } if (right != null) { result.right = right; right.parent = result; } return result; } private void assertTree(String expected, Node root) { assertEquals(expected, toString(root)); assertConsistent(root); } private void assertConsistent(Node node) { int leftHeight = 0; if (node.left != null) { assertConsistent(node.left); assertSame(node, node.left.parent); leftHeight = node.left.height; } int rightHeight = 0; if (node.right != null) { assertConsistent(node.right); assertSame(node, node.right.parent); rightHeight = node.right.height; } if (node.parent != null) { assertTrue(node.parent.left == node || node.parent.right == node); } if (Math.max(leftHeight, rightHeight) + 1 != node.height) { fail(); } } private String toString(Node root) { if (root == null) { return "."; } else if (root.left == null && root.right == null) { return String.valueOf(root.key); } else { return String.format("(%s %s %s)", toString(root.left), root.key, toString(root.right)); } } private void assertIterationOrder(Iterable actual, T... expected) { ArrayList actualList = new ArrayList(); for (T t : actual) { actualList.add(t); } assertEquals(Arrays.asList(expected), actualList); } } google-gson/src/test/java/com/google/gson/internal/LinkedTreeMapTest.java0000664000175000017500000001113212140760644026324 0ustar ebourgebourg/* * Copyright (C) 2012 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.internal; import com.google.gson.common.MoreAsserts; import junit.framework.TestCase; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.Map; import java.util.Random; public final class LinkedTreeMapTest extends TestCase { public void testIterationOrder() { LinkedTreeMap map = new LinkedTreeMap(); map.put("a", "android"); map.put("c", "cola"); map.put("b", "bbq"); assertIterationOrder(map.keySet(), "a", "c", "b"); assertIterationOrder(map.values(), "android", "cola", "bbq"); } public void testRemoveRootDoesNotDoubleUnlink() { LinkedTreeMap map = new LinkedTreeMap(); map.put("a", "android"); map.put("c", "cola"); map.put("b", "bbq"); Iterator> it = map.entrySet().iterator(); it.next(); it.next(); it.next(); it.remove(); assertIterationOrder(map.keySet(), "a", "c"); } public void testPutNullKeyFails() { LinkedTreeMap map = new LinkedTreeMap(); try { map.put(null, "android"); fail(); } catch (NullPointerException expected) { } } public void testPutNonComparableKeyFails() { LinkedTreeMap map = new LinkedTreeMap(); try { map.put(new Object(), "android"); fail(); } catch (ClassCastException expected) {} } @SuppressWarnings("SuspiciousMethodCalls") public void testContainsNonComparableKeyReturnsFalse() { LinkedTreeMap map = new LinkedTreeMap(); map.put("a", "android"); assertFalse(map.containsKey(new Object())); } public void testContainsNullKeyIsAlwaysFalse() { LinkedTreeMap map = new LinkedTreeMap(); map.put("a", "android"); assertFalse(map.containsKey(null)); } public void testPutOverrides() throws Exception { LinkedTreeMap map = new LinkedTreeMap(); assertNull(map.put("d", "donut")); assertNull(map.put("e", "eclair")); assertNull(map.put("f", "froyo")); assertEquals(3, map.size()); assertEquals("donut", map.get("d")); assertEquals("donut", map.put("d", "done")); assertEquals(3, map.size()); } public void testEmptyStringValues() { LinkedTreeMap map = new LinkedTreeMap(); map.put("a", ""); assertTrue(map.containsKey("a")); assertEquals("", map.get("a")); } public void testLargeSetOfRandomKeys() throws Exception { Random random = new Random(1367593214724L); LinkedTreeMap map = new LinkedTreeMap(); String[] keys = new String[1000]; for (int i = 0; i < keys.length; i++) { keys[i] = Integer.toString(Math.abs(random.nextInt()), 36) + "-" + i; map.put(keys[i], "" + i); } for (int i = 0; i < keys.length; i++) { String key = keys[i]; assertTrue(map.containsKey(key)); assertEquals("" + i, map.get(key)); } } public void testClear() { LinkedTreeMap map = new LinkedTreeMap(); map.put("a", "android"); map.put("c", "cola"); map.put("b", "bbq"); map.clear(); assertIterationOrder(map.keySet()); assertEquals(0, map.size()); } public void testEqualsAndHashCode() throws Exception { LinkedTreeMap map1 = new LinkedTreeMap(); map1.put("A", 1); map1.put("B", 2); map1.put("C", 3); map1.put("D", 4); LinkedTreeMap map2 = new LinkedTreeMap(); map2.put("C", 3); map2.put("B", 2); map2.put("D", 4); map2.put("A", 1); MoreAsserts.assertEqualsAndHashCode(map1, map2); } private void assertIterationOrder(Iterable actual, T... expected) { ArrayList actualList = new ArrayList(); for (T t : actual) { actualList.add(t); } assertEquals(Arrays.asList(expected), actualList); } } google-gson/src/test/java/com/google/gson/internal/LinkedHashTreeMap.java0000664000175000017500000006337612144252255026307 0ustar ebourgebourg/* * Copyright (C) 2010 The Android Open Source Project * Copyright (C) 2012 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.internal; import java.io.ObjectStreamException; import java.io.Serializable; import java.util.AbstractMap; import java.util.AbstractSet; import java.util.Arrays; import java.util.Comparator; import java.util.ConcurrentModificationException; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.NoSuchElementException; import java.util.Set; /** * A map of comparable keys to values. Unlike {@code TreeMap}, this class uses * insertion order for iteration order. Comparison order is only used as an * optimization for efficient insertion and removal. * *

This implementation was derived from Android 4.1's TreeMap and * LinkedHashMap classes. */ public final class LinkedHashTreeMap extends AbstractMap implements Serializable { private static final int MAX_CAPACITY = 8192; @SuppressWarnings({ "unchecked", "rawtypes" }) // to avoid Comparable>> private static final Comparator NATURAL_ORDER = new Comparator() { public int compare(Comparable a, Comparable b) { return a.compareTo(b); } }; Comparator comparator; Node[] table; final Node header; int size = 0; int modCount = 0; int threshold; /** * Create a natural order, empty tree map whose keys must be mutually * comparable and non-null. */ @SuppressWarnings("unchecked") // unsafe! this assumes K is comparable public LinkedHashTreeMap() { this((Comparator) NATURAL_ORDER); } /** * Create a tree map ordered by {@code comparator}. This map's keys may only * be null if {@code comparator} permits. * * @param comparator the comparator to order elements with, or {@code null} to * use the natural ordering. */ @SuppressWarnings({ "unchecked", "rawtypes" }) // unsafe! if comparator is null, this assumes K is comparable public LinkedHashTreeMap(Comparator comparator) { this.comparator = comparator != null ? comparator : (Comparator) NATURAL_ORDER; this.header = new Node(); this.table = new Node[16]; // TODO: sizing/resizing policies this.threshold = (table.length / 2) + (table.length / 4); // 3/4 capacity } @Override public int size() { return size; } @Override public V get(Object key) { Node node = findByObject(key); return node != null ? node.value : null; } @Override public boolean containsKey(Object key) { return findByObject(key) != null; } @Override public V put(K key, V value) { if (key == null) { throw new NullPointerException("key == null"); } Node created = find(key, true); V result = created.value; created.value = value; return result; } @Override public void clear() { Arrays.fill(table, null); size = 0; modCount++; // Clear all links to help GC Node header = this.header; for (Node e = header.next; e != header; ) { Node next = e.next; e.next = e.prev = null; e = next; } header.next = header.prev = header; } @Override public V remove(Object key) { Node node = removeInternalByKey(key); return node != null ? node.value : null; } /** * Returns the node at or adjacent to the given key, creating it if requested. * * @throws ClassCastException if {@code key} and the tree's keys aren't * mutually comparable. */ Node find(K key, boolean create) { Comparator comparator = this.comparator; Node[] table = this.table; int hash = secondaryHash(key.hashCode()); int index = hash & (table.length - 1); Node nearest = table[index]; int comparison = 0; if (nearest != null) { // Micro-optimization: avoid polymorphic calls to Comparator.compare(). @SuppressWarnings("unchecked") // Throws a ClassCastException below if there's trouble. Comparable comparableKey = (comparator == NATURAL_ORDER) ? (Comparable) key : null; while (true) { comparison = (comparableKey != null) ? comparableKey.compareTo(nearest.key) : comparator.compare(key, nearest.key); // We found the requested key. if (comparison == 0) { return nearest; } // If it exists, the key is in a subtree. Go deeper. Node child = (comparison < 0) ? nearest.left : nearest.right; if (child == null) { break; } nearest = child; } } // The key doesn't exist in this tree. if (!create) { return null; } // Create the node and add it to the tree or the table. Node header = this.header; Node created; if (nearest == null) { // Check that the value is comparable if we didn't do any comparisons. if (comparator == NATURAL_ORDER && !(key instanceof Comparable)) { throw new ClassCastException(key.getClass().getName() + " is not Comparable"); } created = new Node(nearest, key, hash, header, header.prev); table[index] = created; } else { created = new Node(nearest, key, hash, header, header.prev); if (comparison < 0) { // nearest.key is higher nearest.left = created; } else { // comparison > 0, nearest.key is lower nearest.right = created; } rebalance(nearest, true); } if (size++ > threshold) { doubleCapacity(); } modCount++; return created; } @SuppressWarnings("unchecked") Node findByObject(Object key) { try { return key != null ? find((K) key, false) : null; } catch (ClassCastException e) { return null; } } /** * Returns this map's entry that has the same key and value as {@code * entry}, or null if this map has no such entry. * *

This method uses the comparator for key equality rather than {@code * equals}. If this map's comparator isn't consistent with equals (such as * {@code String.CASE_INSENSITIVE_ORDER}), then {@code remove()} and {@code * contains()} will violate the collections API. */ Node findByEntry(Entry entry) { Node mine = findByObject(entry.getKey()); boolean valuesEqual = mine != null && equal(mine.value, entry.getValue()); return valuesEqual ? mine : null; } private boolean equal(Object a, Object b) { return a == b || (a != null && a.equals(b)); } /** * Applies a supplemental hash function to a given hashCode, which defends * against poor quality hash functions. This is critical because HashMap * uses power-of-two length hash tables, that otherwise encounter collisions * for hashCodes that do not differ in lower or upper bits. */ private static int secondaryHash(int h) { // Doug Lea's supplemental hash function h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4); } /** * Removes {@code node} from this tree, rearranging the tree's structure as * necessary. * * @param unlink true to also unlink this node from the iteration linked list. */ void removeInternal(Node node, boolean unlink) { if (unlink) { node.prev.next = node.next; node.next.prev = node.prev; node.next = node.prev = null; // Help the GC (for performance) } Node left = node.left; Node right = node.right; Node originalParent = node.parent; if (left != null && right != null) { /* * To remove a node with both left and right subtrees, move an * adjacent node from one of those subtrees into this node's place. * * Removing the adjacent node may change this node's subtrees. This * node may no longer have two subtrees once the adjacent node is * gone! */ Node adjacent = (left.height > right.height) ? left.last() : right.first(); removeInternal(adjacent, false); // takes care of rebalance and size-- int leftHeight = 0; left = node.left; if (left != null) { leftHeight = left.height; adjacent.left = left; left.parent = adjacent; node.left = null; } int rightHeight = 0; right = node.right; if (right != null) { rightHeight = right.height; adjacent.right = right; right.parent = adjacent; node.right = null; } adjacent.height = Math.max(leftHeight, rightHeight) + 1; replaceInParent(node, adjacent); return; } else if (left != null) { replaceInParent(node, left); node.left = null; } else if (right != null) { replaceInParent(node, right); node.right = null; } else { replaceInParent(node, null); } rebalance(originalParent, false); size--; modCount++; } Node removeInternalByKey(Object key) { Node node = findByObject(key); if (node != null) { removeInternal(node, true); } return node; } private void replaceInParent(Node node, Node replacement) { Node parent = node.parent; node.parent = null; if (replacement != null) { replacement.parent = parent; } if (parent != null) { if (parent.left == node) { parent.left = replacement; } else { assert (parent.right == node); parent.right = replacement; } } else { int index = node.hash & (table.length - 1); table[index] = replacement; } } /** * Rebalances the tree by making any AVL rotations necessary between the * newly-unbalanced node and the tree's root. * * @param insert true if the node was unbalanced by an insert; false if it * was by a removal. */ private void rebalance(Node unbalanced, boolean insert) { for (Node node = unbalanced; node != null; node = node.parent) { Node left = node.left; Node right = node.right; int leftHeight = left != null ? left.height : 0; int rightHeight = right != null ? right.height : 0; int delta = leftHeight - rightHeight; if (delta == -2) { Node rightLeft = right.left; Node rightRight = right.right; int rightRightHeight = rightRight != null ? rightRight.height : 0; int rightLeftHeight = rightLeft != null ? rightLeft.height : 0; int rightDelta = rightLeftHeight - rightRightHeight; if (rightDelta == -1 || (rightDelta == 0 && !insert)) { rotateLeft(node); // AVL right right } else { assert (rightDelta == 1); rotateRight(right); // AVL right left rotateLeft(node); } if (insert) { break; // no further rotations will be necessary } } else if (delta == 2) { Node leftLeft = left.left; Node leftRight = left.right; int leftRightHeight = leftRight != null ? leftRight.height : 0; int leftLeftHeight = leftLeft != null ? leftLeft.height : 0; int leftDelta = leftLeftHeight - leftRightHeight; if (leftDelta == 1 || (leftDelta == 0 && !insert)) { rotateRight(node); // AVL left left } else { assert (leftDelta == -1); rotateLeft(left); // AVL left right rotateRight(node); } if (insert) { break; // no further rotations will be necessary } } else if (delta == 0) { node.height = leftHeight + 1; // leftHeight == rightHeight if (insert) { break; // the insert caused balance, so rebalancing is done! } } else { assert (delta == -1 || delta == 1); node.height = Math.max(leftHeight, rightHeight) + 1; if (!insert) { break; // the height hasn't changed, so rebalancing is done! } } } } /** * Rotates the subtree so that its root's right child is the new root. */ private void rotateLeft(Node root) { Node left = root.left; Node pivot = root.right; Node pivotLeft = pivot.left; Node pivotRight = pivot.right; // move the pivot's left child to the root's right root.right = pivotLeft; if (pivotLeft != null) { pivotLeft.parent = root; } replaceInParent(root, pivot); // move the root to the pivot's left pivot.left = root; root.parent = pivot; // fix heights root.height = Math.max(left != null ? left.height : 0, pivotLeft != null ? pivotLeft.height : 0) + 1; pivot.height = Math.max(root.height, pivotRight != null ? pivotRight.height : 0) + 1; } /** * Rotates the subtree so that its root's left child is the new root. */ private void rotateRight(Node root) { Node pivot = root.left; Node right = root.right; Node pivotLeft = pivot.left; Node pivotRight = pivot.right; // move the pivot's right child to the root's left root.left = pivotRight; if (pivotRight != null) { pivotRight.parent = root; } replaceInParent(root, pivot); // move the root to the pivot's right pivot.right = root; root.parent = pivot; // fixup heights root.height = Math.max(right != null ? right.height : 0, pivotRight != null ? pivotRight.height : 0) + 1; pivot.height = Math.max(root.height, pivotLeft != null ? pivotLeft.height : 0) + 1; } private EntrySet entrySet; private KeySet keySet; @Override public Set> entrySet() { EntrySet result = entrySet; return result != null ? result : (entrySet = new EntrySet()); } @Override public Set keySet() { KeySet result = keySet; return result != null ? result : (keySet = new KeySet()); } static final class Node implements Entry { Node parent; Node left; Node right; Node next; Node prev; final K key; final int hash; V value; int height; /** Create the header entry */ Node() { key = null; hash = -1; next = prev = this; } /** Create a regular entry */ Node(Node parent, K key, int hash, Node next, Node prev) { this.parent = parent; this.key = key; this.hash = hash; this.height = 1; this.next = next; this.prev = prev; prev.next = this; next.prev = this; } public K getKey() { return key; } public V getValue() { return value; } public V setValue(V value) { V oldValue = this.value; this.value = value; return oldValue; } @SuppressWarnings("rawtypes") @Override public boolean equals(Object o) { if (o instanceof Entry) { Entry other = (Entry) o; return (key == null ? other.getKey() == null : key.equals(other.getKey())) && (value == null ? other.getValue() == null : value.equals(other.getValue())); } return false; } @Override public int hashCode() { return (key == null ? 0 : key.hashCode()) ^ (value == null ? 0 : value.hashCode()); } @Override public String toString() { return key + "=" + value; } /** * Returns the first node in this subtree. */ public Node first() { Node node = this; Node child = node.left; while (child != null) { node = child; child = node.left; } return node; } /** * Returns the last node in this subtree. */ public Node last() { Node node = this; Node child = node.right; while (child != null) { node = child; child = node.right; } return node; } } private void doubleCapacity() { table = doubleCapacity(table); threshold = (table.length / 2) + (table.length / 4); // 3/4 capacity } /** * Returns a new array containing the same nodes as {@code oldTable}, but with * twice as many trees, each of (approximately) half the previous size. */ static Node[] doubleCapacity(Node[] oldTable) { int oldCapacity = oldTable.length; if (oldCapacity >= MAX_CAPACITY) { return oldTable; } int newCapacity = oldCapacity * 2; @SuppressWarnings("unchecked") // Arrays and generics don't get along. Node[] newTable = new Node[newCapacity]; AvlIterator iterator = new AvlIterator(); AvlBuilder leftBuilder = new AvlBuilder(); AvlBuilder rightBuilder = new AvlBuilder(); // Split each tree into two trees. for (int i = 0; i < oldCapacity; i++) { Node root = oldTable[i]; if (root == null) { continue; } // Compute the sizes of the left and right trees. iterator.reset(root); int leftSize = 0; int rightSize = 0; for (Node node; (node = iterator.next()) != null; ) { if ((node.hash & (newCapacity - 1)) == i) { leftSize++; } else { rightSize++; } } // Split the tree into two. Node leftRoot = null; Node rightRoot = null; if (leftSize > 0 && rightSize > 0) { leftBuilder.reset(leftSize); rightBuilder.reset(rightSize); iterator.reset(root); for (Node node; (node = iterator.next()) != null; ) { if ((node.hash & (newCapacity - 1)) == i) { leftBuilder.add(node); } else { rightBuilder.add(node); } } leftRoot = leftBuilder.root(); rightRoot = rightBuilder.root(); } else if (leftSize > 0) { leftRoot = root; } else { rightRoot = root; } // Populate the enlarged array with these new roots. newTable[i] = leftRoot; newTable[i + oldCapacity] = rightRoot; } return newTable; } /** * Walks an AVL tree in iteration order. Once a node has been returned, its * left, right and parent links are no longer used. For this * reason it is safe to transform these links as you walk a tree. * *

Warning: this iterator is destructive. It clears the * parent node of all nodes in the tree. It is an error to make a partial * iteration of a tree. */ static class AvlIterator { /** This stack is a singly linked list, linked by the 'parent' field. */ private Node stackTop; void reset(Node root) { Node stackTop = null; for (Node n = root; n != null; n = n.left) { n.parent = stackTop; stackTop = n; // Stack push. } this.stackTop = stackTop; } public Node next() { Node stackTop = this.stackTop; if (stackTop == null) { return null; } Node result = stackTop; stackTop = result.parent; result.parent = null; for (Node n = result.right; n != null; n = n.left) { n.parent = stackTop; stackTop = n; // Stack push. } this.stackTop = stackTop; return result; } } /** * Builds AVL trees of a predetermined size by accepting nodes of increasing * value. To use: *

    *
  1. Call {@link #reset} to initialize the target size size. *
  2. Call {@link #add} size times with increasing values. *
  3. Call {@link #root} to get the root of the balanced tree. *
* *

The returned tree will satisfy the AVL constraint: for every node * N, the height of N.left and N.right is different by at * most 1. It accomplishes this by omitting deepest-level leaf nodes when * building trees whose size isn't a power of 2 minus 1. * *

Unlike rebuilding a tree from scratch, this approach requires no value * comparisons. Using this class to create a tree of size S is * {@code O(S)}. */ final static class AvlBuilder { /** This stack is a singly linked list, linked by the 'parent' field. */ private Node stack; private int leavesToSkip; private int leavesSkipped; private int size; void reset(int targetSize) { // compute the target tree size. This is a power of 2 minus one, like 15 or 31. int treeCapacity = Integer.highestOneBit(targetSize) * 2 - 1; leavesToSkip = treeCapacity - targetSize; size = 0; leavesSkipped = 0; stack = null; } void add(Node node) { node.left = node.parent = node.right = null; node.height = 1; // Skip a leaf if necessary. if (leavesToSkip > 0 && (size & 1) == 0) { size++; leavesToSkip--; leavesSkipped++; } node.parent = stack; stack = node; // Stack push. size++; // Skip a leaf if necessary. if (leavesToSkip > 0 && (size & 1) == 0) { size++; leavesToSkip--; leavesSkipped++; } /* * Combine 3 nodes into subtrees whenever the size is one less than a * multiple of 4. For example we combine the nodes A, B, C into a * 3-element tree with B as the root. * * Combine two subtrees and a spare single value whenever the size is one * less than a multiple of 8. For example at 8 we may combine subtrees * (A B C) and (E F G) with D as the root to form ((A B C) D (E F G)). * * Just as we combine single nodes when size nears a multiple of 4, and * 3-element trees when size nears a multiple of 8, we combine subtrees of * size (N-1) whenever the total size is 2N-1 whenever N is a power of 2. */ for (int scale = 4; (size & scale - 1) == scale - 1; scale *= 2) { if (leavesSkipped == 0) { // Pop right, center and left, then make center the top of the stack. Node right = stack; Node center = right.parent; Node left = center.parent; center.parent = left.parent; stack = center; // Construct a tree. center.left = left; center.right = right; center.height = right.height + 1; left.parent = center; right.parent = center; } else if (leavesSkipped == 1) { // Pop right and center, then make center the top of the stack. Node right = stack; Node center = right.parent; stack = center; // Construct a tree with no left child. center.right = right; center.height = right.height + 1; right.parent = center; leavesSkipped = 0; } else if (leavesSkipped == 2) { leavesSkipped = 0; } } } Node root() { Node stackTop = this.stack; if (stackTop.parent != null) { throw new IllegalStateException(); } return stackTop; } } private abstract class LinkedTreeMapIterator implements Iterator { Node next = header.next; Node lastReturned = null; int expectedModCount = modCount; public final boolean hasNext() { return next != header; } final Node nextNode() { Node e = next; if (e == header) { throw new NoSuchElementException(); } if (modCount != expectedModCount) { throw new ConcurrentModificationException(); } next = e.next; return lastReturned = e; } public final void remove() { if (lastReturned == null) { throw new IllegalStateException(); } removeInternal(lastReturned, true); lastReturned = null; expectedModCount = modCount; } } class EntrySet extends AbstractSet> { @Override public int size() { return size; } @Override public Iterator> iterator() { return new LinkedTreeMapIterator>() { public Entry next() { return nextNode(); } }; } @Override public boolean contains(Object o) { return o instanceof Entry && findByEntry((Entry) o) != null; } @Override public boolean remove(Object o) { if (!(o instanceof Entry)) { return false; } Node node = findByEntry((Entry) o); if (node == null) { return false; } removeInternal(node, true); return true; } @Override public void clear() { LinkedHashTreeMap.this.clear(); } } class KeySet extends AbstractSet { @Override public int size() { return size; } @Override public Iterator iterator() { return new LinkedTreeMapIterator() { public K next() { return nextNode().key; } }; } @Override public boolean contains(Object o) { return containsKey(o); } @Override public boolean remove(Object key) { return removeInternalByKey(key) != null; } @Override public void clear() { LinkedHashTreeMap.this.clear(); } } /** * If somebody is unlucky enough to have to serialize one of these, serialize * it as a LinkedHashMap so that they won't need Gson on the other side to * deserialize it. Using serialization defeats our DoS defence, so most apps * shouldn't use it. */ private Object writeReplace() throws ObjectStreamException { return new LinkedHashMap(this); } } google-gson/src/test/java/com/google/gson/internal/bind/0000775000175000017500000000000012207114634023047 5ustar ebourgebourggoogle-gson/src/test/java/com/google/gson/internal/bind/JsonTreeWriterTest.java0000664000175000017500000001162312132065234027501 0ustar ebourgebourg/* * Copyright (C) 2011 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.internal.bind; import com.google.gson.JsonNull; import java.io.IOException; import junit.framework.TestCase; @SuppressWarnings("resource") public final class JsonTreeWriterTest extends TestCase { public void testArray() throws IOException { JsonTreeWriter writer = new JsonTreeWriter(); writer.beginArray(); writer.value(1); writer.value(2); writer.value(3); writer.endArray(); assertEquals("[1,2,3]", writer.get().toString()); } public void testNestedArray() throws IOException { JsonTreeWriter writer = new JsonTreeWriter(); writer.beginArray(); writer.beginArray(); writer.endArray(); writer.beginArray(); writer.beginArray(); writer.endArray(); writer.endArray(); writer.endArray(); assertEquals("[[],[[]]]", writer.get().toString()); } public void testObject() throws IOException { JsonTreeWriter writer = new JsonTreeWriter(); writer.beginObject(); writer.name("A").value(1); writer.name("B").value(2); writer.endObject(); assertEquals("{\"A\":1,\"B\":2}", writer.get().toString()); } public void testNestedObject() throws IOException { JsonTreeWriter writer = new JsonTreeWriter(); writer.beginObject(); writer.name("A"); writer.beginObject(); writer.name("B"); writer.beginObject(); writer.endObject(); writer.endObject(); writer.name("C"); writer.beginObject(); writer.endObject(); writer.endObject(); assertEquals("{\"A\":{\"B\":{}},\"C\":{}}", writer.get().toString()); } public void testWriteAfterClose() throws Exception { JsonTreeWriter writer = new JsonTreeWriter(); writer.setLenient(true); writer.beginArray(); writer.value("A"); writer.endArray(); writer.close(); try { writer.beginArray(); fail(); } catch (IllegalStateException expected) { } } public void testPrematureClose() throws Exception { JsonTreeWriter writer = new JsonTreeWriter(); writer.setLenient(true); writer.beginArray(); try { writer.close(); fail(); } catch (IOException expected) { } } public void testSerializeNullsFalse() throws IOException { JsonTreeWriter writer = new JsonTreeWriter(); writer.setSerializeNulls(false); writer.beginObject(); writer.name("A"); writer.nullValue(); writer.endObject(); assertEquals("{}", writer.get().toString()); } public void testSerializeNullsTrue() throws IOException { JsonTreeWriter writer = new JsonTreeWriter(); writer.setSerializeNulls(true); writer.beginObject(); writer.name("A"); writer.nullValue(); writer.endObject(); assertEquals("{\"A\":null}", writer.get().toString()); } public void testEmptyWriter() { JsonTreeWriter writer = new JsonTreeWriter(); assertEquals(JsonNull.INSTANCE, writer.get()); } public void testLenientNansAndInfinities() throws IOException { JsonTreeWriter writer = new JsonTreeWriter(); writer.setLenient(true); writer.beginArray(); writer.value(Double.NaN); writer.value(Double.NEGATIVE_INFINITY); writer.value(Double.POSITIVE_INFINITY); writer.endArray(); assertEquals("[NaN,-Infinity,Infinity]", writer.get().toString()); } public void testStrictNansAndInfinities() throws IOException { JsonTreeWriter writer = new JsonTreeWriter(); writer.setLenient(false); writer.beginArray(); try { writer.value(Double.NaN); fail(); } catch (IllegalArgumentException expected) { } try { writer.value(Double.NEGATIVE_INFINITY); fail(); } catch (IllegalArgumentException expected) { } try { writer.value(Double.POSITIVE_INFINITY); fail(); } catch (IllegalArgumentException expected) { } } public void testStrictBoxedNansAndInfinities() throws IOException { JsonTreeWriter writer = new JsonTreeWriter(); writer.setLenient(false); writer.beginArray(); try { writer.value(new Double(Double.NaN)); fail(); } catch (IllegalArgumentException expected) { } try { writer.value(new Double(Double.NEGATIVE_INFINITY)); fail(); } catch (IllegalArgumentException expected) { } try { writer.value(new Double(Double.POSITIVE_INFINITY)); fail(); } catch (IllegalArgumentException expected) { } } } google-gson/src/test/java/com/google/gson/internal/bind/JsonElementReaderTest.java0000664000175000017500000002241712132065234030124 0ustar ebourgebourg/* * Copyright (C) 2011 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.internal.bind; import com.google.gson.JsonElement; import com.google.gson.JsonParser; import com.google.gson.stream.JsonToken; import java.io.IOException; import junit.framework.TestCase; @SuppressWarnings("resource") public final class JsonElementReaderTest extends TestCase { public void testNumbers() throws IOException { JsonElement element = new JsonParser().parse("[1, 2, 3]"); JsonTreeReader reader = new JsonTreeReader(element); reader.beginArray(); assertEquals(1, reader.nextInt()); assertEquals(2L, reader.nextLong()); assertEquals(3.0, reader.nextDouble()); reader.endArray(); } public void testLenientNansAndInfinities() throws IOException { JsonElement element = new JsonParser().parse("[NaN, -Infinity, Infinity]"); JsonTreeReader reader = new JsonTreeReader(element); reader.setLenient(true); reader.beginArray(); assertTrue(Double.isNaN(reader.nextDouble())); assertEquals(Double.NEGATIVE_INFINITY, reader.nextDouble()); assertEquals(Double.POSITIVE_INFINITY, reader.nextDouble()); reader.endArray(); } public void testStrictNansAndInfinities() throws IOException { JsonElement element = new JsonParser().parse("[NaN, -Infinity, Infinity]"); JsonTreeReader reader = new JsonTreeReader(element); reader.setLenient(false); reader.beginArray(); try { reader.nextDouble(); fail(); } catch (NumberFormatException e) { } assertEquals("NaN", reader.nextString()); try { reader.nextDouble(); fail(); } catch (NumberFormatException e) { } assertEquals("-Infinity", reader.nextString()); try { reader.nextDouble(); fail(); } catch (NumberFormatException e) { } assertEquals("Infinity", reader.nextString()); reader.endArray(); } public void testNumbersFromStrings() throws IOException { JsonElement element = new JsonParser().parse("[\"1\", \"2\", \"3\"]"); JsonTreeReader reader = new JsonTreeReader(element); reader.beginArray(); assertEquals(1, reader.nextInt()); assertEquals(2L, reader.nextLong()); assertEquals(3.0, reader.nextDouble()); reader.endArray(); } public void testStringsFromNumbers() throws IOException { JsonElement element = new JsonParser().parse("[1]"); JsonTreeReader reader = new JsonTreeReader(element); reader.beginArray(); assertEquals("1", reader.nextString()); reader.endArray(); } public void testBooleans() throws IOException { JsonElement element = new JsonParser().parse("[true, false]"); JsonTreeReader reader = new JsonTreeReader(element); reader.beginArray(); assertEquals(true, reader.nextBoolean()); assertEquals(false, reader.nextBoolean()); reader.endArray(); } public void testNulls() throws IOException { JsonElement element = new JsonParser().parse("[null,null]"); JsonTreeReader reader = new JsonTreeReader(element); reader.beginArray(); reader.nextNull(); reader.nextNull(); reader.endArray(); } public void testStrings() throws IOException { JsonElement element = new JsonParser().parse("[\"A\",\"B\"]"); JsonTreeReader reader = new JsonTreeReader(element); reader.beginArray(); assertEquals("A", reader.nextString()); assertEquals("B", reader.nextString()); reader.endArray(); } public void testArray() throws IOException { JsonElement element = new JsonParser().parse("[1, 2, 3]"); JsonTreeReader reader = new JsonTreeReader(element); assertEquals(JsonToken.BEGIN_ARRAY, reader.peek()); reader.beginArray(); assertEquals(JsonToken.NUMBER, reader.peek()); assertEquals(1, reader.nextInt()); assertEquals(JsonToken.NUMBER, reader.peek()); assertEquals(2, reader.nextInt()); assertEquals(JsonToken.NUMBER, reader.peek()); assertEquals(3, reader.nextInt()); assertEquals(JsonToken.END_ARRAY, reader.peek()); reader.endArray(); assertEquals(JsonToken.END_DOCUMENT, reader.peek()); } public void testObject() throws IOException { JsonElement element = new JsonParser().parse("{\"A\": 1, \"B\": 2}"); JsonTreeReader reader = new JsonTreeReader(element); assertEquals(JsonToken.BEGIN_OBJECT, reader.peek()); reader.beginObject(); assertEquals(JsonToken.NAME, reader.peek()); assertEquals("A", reader.nextName()); assertEquals(JsonToken.NUMBER, reader.peek()); assertEquals(1, reader.nextInt()); assertEquals(JsonToken.NAME, reader.peek()); assertEquals("B", reader.nextName()); assertEquals(JsonToken.NUMBER, reader.peek()); assertEquals(2, reader.nextInt()); assertEquals(JsonToken.END_OBJECT, reader.peek()); reader.endObject(); assertEquals(JsonToken.END_DOCUMENT, reader.peek()); } public void testEmptyArray() throws IOException { JsonElement element = new JsonParser().parse("[]"); JsonTreeReader reader = new JsonTreeReader(element); reader.beginArray(); reader.endArray(); } public void testNestedArrays() throws IOException { JsonElement element = new JsonParser().parse("[[],[[]]]"); JsonTreeReader reader = new JsonTreeReader(element); reader.beginArray(); reader.beginArray(); reader.endArray(); reader.beginArray(); reader.beginArray(); reader.endArray(); reader.endArray(); reader.endArray(); } public void testNestedObjects() throws IOException { JsonElement element = new JsonParser().parse("{\"A\":{},\"B\":{\"C\":{}}}"); JsonTreeReader reader = new JsonTreeReader(element); reader.beginObject(); assertEquals("A", reader.nextName()); reader.beginObject(); reader.endObject(); assertEquals("B", reader.nextName()); reader.beginObject(); assertEquals("C", reader.nextName()); reader.beginObject(); reader.endObject(); reader.endObject(); reader.endObject(); } public void testEmptyObject() throws IOException { JsonElement element = new JsonParser().parse("{}"); JsonTreeReader reader = new JsonTreeReader(element); reader.beginObject(); reader.endObject(); } public void testSkipValue() throws IOException { JsonElement element = new JsonParser().parse("[\"A\",{\"B\":[[]]},\"C\",[[]],\"D\",null]"); JsonTreeReader reader = new JsonTreeReader(element); reader.beginArray(); assertEquals("A", reader.nextString()); reader.skipValue(); assertEquals("C", reader.nextString()); reader.skipValue(); assertEquals("D", reader.nextString()); reader.skipValue(); reader.endArray(); } public void testWrongType() throws IOException { JsonElement element = new JsonParser().parse("[[],\"A\"]"); JsonTreeReader reader = new JsonTreeReader(element); reader.beginArray(); try { reader.nextBoolean(); fail(); } catch (IllegalStateException expected) { } try { reader.nextNull(); fail(); } catch (IllegalStateException expected) { } try { reader.nextString(); fail(); } catch (IllegalStateException expected) { } try { reader.nextInt(); fail(); } catch (IllegalStateException expected) { } try { reader.nextLong(); fail(); } catch (IllegalStateException expected) { } try { reader.nextDouble(); fail(); } catch (IllegalStateException expected) { } try { reader.nextName(); fail(); } catch (IllegalStateException expected) { } try { reader.beginObject(); fail(); } catch (IllegalStateException expected) { } try { reader.endArray(); fail(); } catch (IllegalStateException expected) { } try { reader.endObject(); fail(); } catch (IllegalStateException expected) { } reader.beginArray(); reader.endArray(); try { reader.nextBoolean(); fail(); } catch (IllegalStateException expected) { } try { reader.nextNull(); fail(); } catch (IllegalStateException expected) { } try { reader.nextInt(); fail(); } catch (NumberFormatException expected) { } try { reader.nextLong(); fail(); } catch (NumberFormatException expected) { } try { reader.nextDouble(); fail(); } catch (NumberFormatException expected) { } try { reader.nextName(); fail(); } catch (IllegalStateException expected) { } assertEquals("A", reader.nextString()); reader.endArray(); } public void testEarlyClose() throws IOException { JsonElement element = new JsonParser().parse("[1, 2, 3]"); JsonTreeReader reader = new JsonTreeReader(element); reader.beginArray(); reader.close(); try { reader.peek(); fail(); } catch (IllegalStateException expected) { } } } google-gson/src/test/java/com/google/gson/VersionExclusionStrategyTest.java0000664000175000017500000000363311662650451027077 0ustar ebourgebourg/* * 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; import com.google.gson.annotations.Since; import com.google.gson.internal.Excluder; import junit.framework.TestCase; /** * Unit tests for the {@link Excluder} class. * * @author Joel Leitch */ public class VersionExclusionStrategyTest extends TestCase { private static final double VERSION = 5.0D; public void testClassAndFieldAreAtSameVersion() throws Exception { Excluder excluder = Excluder.DEFAULT.withVersion(VERSION); assertFalse(excluder.excludeClass(MockObject.class, true)); assertFalse(excluder.excludeField(MockObject.class.getField("someField"), true)); } public void testClassAndFieldAreBehindInVersion() throws Exception { Excluder excluder = Excluder.DEFAULT.withVersion(VERSION + 1); assertFalse(excluder.excludeClass(MockObject.class, true)); assertFalse(excluder.excludeField(MockObject.class.getField("someField"), true)); } public void testClassAndFieldAreAheadInVersion() throws Exception { Excluder excluder = Excluder.DEFAULT.withVersion(VERSION - 1); assertTrue(excluder.excludeClass(MockObject.class, true)); assertTrue(excluder.excludeField(MockObject.class.getField("someField"), true)); } @Since(VERSION) private static class MockObject { @SuppressWarnings("unused") @Since(VERSION) public final int someField = 0; } } google-gson/src/test/java/com/google/gson/FieldAttributesTest.java0000664000175000017500000000476211662362306025132 0ustar ebourgebourg/* * Copyright (C) 2009 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; import com.google.gson.reflect.TypeToken; import junit.framework.TestCase; import java.lang.reflect.Modifier; import java.lang.reflect.Type; import java.util.List; /** * Unit tests for the {@link FieldAttributes} class. * * @author Inderjeet Singh * @author Joel Leitch */ public class FieldAttributesTest extends TestCase { private FieldAttributes fieldAttributes; @Override protected void setUp() throws Exception { super.setUp(); fieldAttributes = new FieldAttributes(Foo.class.getField("bar")); } public void testNullField() throws Exception { try { new FieldAttributes(null); fail("Field parameter can not be null"); } catch (NullPointerException expected) { } } public void testDeclaringClass() throws Exception { assertEquals(Foo.class, fieldAttributes.getDeclaringClass()); } public void testModifiers() throws Exception { assertFalse(fieldAttributes.hasModifier(Modifier.STATIC)); assertFalse(fieldAttributes.hasModifier(Modifier.FINAL)); assertFalse(fieldAttributes.hasModifier(Modifier.ABSTRACT)); assertFalse(fieldAttributes.hasModifier(Modifier.VOLATILE)); assertFalse(fieldAttributes.hasModifier(Modifier.PROTECTED)); assertTrue(fieldAttributes.hasModifier(Modifier.PUBLIC)); assertTrue(fieldAttributes.hasModifier(Modifier.TRANSIENT)); } public void testIsSynthetic() throws Exception { assertFalse(fieldAttributes.isSynthetic()); } public void testName() throws Exception { assertEquals("bar", fieldAttributes.getName()); } public void testDeclaredTypeAndClass() throws Exception { Type expectedType = new TypeToken>() {}.getType(); assertEquals(expectedType, fieldAttributes.getDeclaredType()); assertEquals(List.class, fieldAttributes.getDeclaredClass()); } private static class Foo { @SuppressWarnings("unused") public transient List bar; } } google-gson/src/test/java/com/google/gson/JsonArrayTest.java0000664000175000017500000000345112014561057023736 0ustar ebourgebourg/* * Copyright (C) 2011 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; import com.google.gson.common.MoreAsserts; import junit.framework.TestCase; /** * @author Jesse Wilson */ public final class JsonArrayTest extends TestCase { public void testEqualsOnEmptyArray() { MoreAsserts.assertEqualsAndHashCode(new JsonArray(), new JsonArray()); } public void testEqualsNonEmptyArray() { JsonArray a = new JsonArray(); JsonArray b = new JsonArray(); assertEquals(a, a); a.add(new JsonObject()); assertFalse(a.equals(b)); assertFalse(b.equals(a)); b.add(new JsonObject()); MoreAsserts.assertEqualsAndHashCode(a, b); a.add(new JsonObject()); assertFalse(a.equals(b)); assertFalse(b.equals(a)); b.add(JsonNull.INSTANCE); assertFalse(a.equals(b)); assertFalse(b.equals(a)); } public void testDeepCopy() { JsonArray original = new JsonArray(); JsonArray firstEntry = new JsonArray(); original.add(firstEntry); JsonArray copy = original.deepCopy(); original.add(new JsonPrimitive("y")); assertEquals(1, copy.size()); firstEntry.add(new JsonPrimitive("z")); assertEquals(1, original.get(0).getAsJsonArray().size()); assertEquals(0, copy.get(0).getAsJsonArray().size()); } } google-gson/src/test/java/com/google/gson/GsonBuilderTest.java0000775000175000017500000000464511773463175024271 0ustar ebourgebourg/* * 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; import java.lang.reflect.Modifier; import java.lang.reflect.Type; import junit.framework.TestCase; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; /** * Unit tests for {@link GsonBuilder}. * * @author Inderjeet Singh */ public class GsonBuilderTest extends TestCase { private static final TypeAdapter NULL_TYPE_ADAPTER = new TypeAdapter() { @Override public void write(JsonWriter out, Object value) { throw new AssertionError(); } @Override public Object read(JsonReader in) { throw new AssertionError(); } }; public void testCreatingMoreThanOnce() { GsonBuilder builder = new GsonBuilder(); builder.create(); builder.create(); } public void testExcludeFieldsWithModifiers() { Gson gson = new GsonBuilder() .excludeFieldsWithModifiers(Modifier.VOLATILE, Modifier.PRIVATE) .create(); assertEquals("{\"d\":\"d\"}", gson.toJson(new HasModifiers())); } public void testRegisterTypeAdapterForCoreType() { Type[] types = { byte.class, int.class, double.class, Short.class, Long.class, String.class, }; for (Type type : types) { new GsonBuilder().registerTypeAdapter(type, NULL_TYPE_ADAPTER); } } @SuppressWarnings("unused") static class HasModifiers { private String a = "a"; volatile String b = "b"; private volatile String c = "c"; String d = "d"; } public void testTransientFieldExclusion() { Gson gson = new GsonBuilder() .excludeFieldsWithModifiers() .create(); assertEquals("{\"a\":\"a\"}", gson.toJson(new HasTransients())); } static class HasTransients { transient String a = "a"; } } google-gson/src/main/0000775000175000017500000000000012207114635014344 5ustar ebourgebourggoogle-gson/src/main/java/0000775000175000017500000000000012207114635015265 5ustar ebourgebourggoogle-gson/src/main/java/com/0000775000175000017500000000000012207114635016043 5ustar ebourgebourggoogle-gson/src/main/java/com/google/0000775000175000017500000000000012207114635017317 5ustar ebourgebourggoogle-gson/src/main/java/com/google/gson/0000775000175000017500000000000012207114636020266 5ustar ebourgebourggoogle-gson/src/main/java/com/google/gson/LongSerializationPolicy.java0000664000175000017500000000336011662260056025752 0ustar ebourgebourg/* * Copyright (C) 2009 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; /** * Defines the expected format for a {@code long} or {@code Long} type when its serialized. * * @since 1.3 * * @author Inderjeet Singh * @author Joel Leitch */ public enum LongSerializationPolicy { /** * This is the "default" serialization policy that will output a {@code long} object as a JSON * number. For example, assume an object has a long field named "f" then the serialized output * would be: * {@code {"f":123}}. */ DEFAULT() { public JsonElement serialize(Long value) { return new JsonPrimitive(value); } }, /** * Serializes a long value as a quoted string. For example, assume an object has a long field * named "f" then the serialized output would be: * {@code {"f":"123"}}. */ STRING() { public JsonElement serialize(Long value) { return new JsonPrimitive(String.valueOf(value)); } }; /** * Serialize this {@code value} using this serialization policy. * * @param value the long value to be serialized into a {@link JsonElement} * @return the serialized version of {@code value} */ public abstract JsonElement serialize(Long value); } google-gson/src/main/java/com/google/gson/package-info.java0000664000175000017500000000067711031562765023473 0ustar ebourgebourg/** * This package provides the {@link com.google.gson.Gson} class to convert Json to Java and * vice-versa. * *

The primary class to use is {@link com.google.gson.Gson} which can be constructed with * {@code new Gson()} (using default settings) or by using {@link com.google.gson.GsonBuilder} * (to configure various options such as using versioning and so on).

* * @author Inderjeet Singh, Joel Leitch */ package com.google.gson;google-gson/src/main/java/com/google/gson/Gson.java0000664000175000017500000011412312103756054022042 0ustar ebourgebourg/* * 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; import com.google.gson.internal.ConstructorConstructor; import com.google.gson.internal.Excluder; import com.google.gson.internal.Primitives; import com.google.gson.internal.Streams; import com.google.gson.internal.bind.ArrayTypeAdapter; import com.google.gson.internal.bind.CollectionTypeAdapterFactory; import com.google.gson.internal.bind.DateTypeAdapter; import com.google.gson.internal.bind.JsonTreeReader; import com.google.gson.internal.bind.JsonTreeWriter; import com.google.gson.internal.bind.MapTypeAdapterFactory; import com.google.gson.internal.bind.ObjectTypeAdapter; import com.google.gson.internal.bind.ReflectiveTypeAdapterFactory; import com.google.gson.internal.bind.SqlDateTypeAdapter; import com.google.gson.internal.bind.TimeTypeAdapter; import com.google.gson.internal.bind.TypeAdapters; import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonWriter; import com.google.gson.stream.MalformedJsonException; import java.io.EOFException; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.io.StringWriter; import java.io.Writer; import java.lang.reflect.Type; import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; /** * This is the main class for using Gson. Gson is typically used by first constructing a * Gson instance and then invoking {@link #toJson(Object)} or {@link #fromJson(String, Class)} * methods on it. * *

You can create a Gson instance by invoking {@code new Gson()} if the default configuration * is all you need. You can also use {@link GsonBuilder} to build a Gson instance with various * configuration options such as versioning support, pretty printing, custom * {@link JsonSerializer}s, {@link JsonDeserializer}s, and {@link InstanceCreator}s.

* *

Here is an example of how Gson is used for a simple Class: * *

 * Gson gson = new Gson(); // Or use new GsonBuilder().create();
 * MyType target = new MyType();
 * String json = gson.toJson(target); // serializes target to Json
 * MyType target2 = gson.fromJson(json, MyType.class); // deserializes json into target2
 * 

* *

If the object that your are serializing/deserializing is a {@code ParameterizedType} * (i.e. contains at least one type parameter and may be an array) then you must use the * {@link #toJson(Object, Type)} or {@link #fromJson(String, Type)} method. Here is an * example for serializing and deserialing a {@code ParameterizedType}: * *

 * Type listType = new TypeToken<List<String>>() {}.getType();
 * List<String> target = new LinkedList<String>();
 * target.add("blah");
 *
 * Gson gson = new Gson();
 * String json = gson.toJson(target, listType);
 * List<String> target2 = gson.fromJson(json, listType);
 * 

* *

See the Gson User Guide * for a more complete set of examples.

* * @see com.google.gson.reflect.TypeToken * * @author Inderjeet Singh * @author Joel Leitch * @author Jesse Wilson */ public final class Gson { static final boolean DEFAULT_JSON_NON_EXECUTABLE = false; private static final String JSON_NON_EXECUTABLE_PREFIX = ")]}'\n"; /** * This thread local guards against reentrant calls to getAdapter(). In * certain object graphs, creating an adapter for a type may recursively * require an adapter for the same type! Without intervention, the recursive * lookup would stack overflow. We cheat by returning a proxy type adapter. * The proxy is wired up once the initial adapter has been created. */ private final ThreadLocal, FutureTypeAdapter>> calls = new ThreadLocal, FutureTypeAdapter>>(); private final Map, TypeAdapter> typeTokenCache = Collections.synchronizedMap(new HashMap, TypeAdapter>()); private final List factories; private final ConstructorConstructor constructorConstructor; private final boolean serializeNulls; private final boolean htmlSafe; private final boolean generateNonExecutableJson; private final boolean prettyPrinting; final JsonDeserializationContext deserializationContext = new JsonDeserializationContext() { @SuppressWarnings("unchecked") public T deserialize(JsonElement json, Type typeOfT) throws JsonParseException { return (T) fromJson(json, typeOfT); } }; final JsonSerializationContext serializationContext = new JsonSerializationContext() { public JsonElement serialize(Object src) { return toJsonTree(src); } public JsonElement serialize(Object src, Type typeOfSrc) { return toJsonTree(src, typeOfSrc); } }; /** * Constructs a Gson object with default configuration. The default configuration has the * following settings: *
    *
  • The JSON generated by toJson methods is in compact representation. This * means that all the unneeded white-space is removed. You can change this behavior with * {@link GsonBuilder#setPrettyPrinting()}.
  • *
  • The generated JSON omits all the fields that are null. Note that nulls in arrays are * kept as is since an array is an ordered list. Moreover, if a field is not null, but its * generated JSON is empty, the field is kept. You can configure Gson to serialize null values * by setting {@link GsonBuilder#serializeNulls()}.
  • *
  • Gson provides default serialization and deserialization for Enums, {@link Map}, * {@link java.net.URL}, {@link java.net.URI}, {@link java.util.Locale}, {@link java.util.Date}, * {@link java.math.BigDecimal}, and {@link java.math.BigInteger} classes. If you would prefer * to change the default representation, you can do so by registering a type adapter through * {@link GsonBuilder#registerTypeAdapter(Type, Object)}.
  • *
  • The default Date format is same as {@link java.text.DateFormat#DEFAULT}. This format * ignores the millisecond portion of the date during serialization. You can change * this by invoking {@link GsonBuilder#setDateFormat(int)} or * {@link GsonBuilder#setDateFormat(String)}.
  • *
  • By default, Gson ignores the {@link com.google.gson.annotations.Expose} annotation. * You can enable Gson to serialize/deserialize only those fields marked with this annotation * through {@link GsonBuilder#excludeFieldsWithoutExposeAnnotation()}.
  • *
  • By default, Gson ignores the {@link com.google.gson.annotations.Since} annotation. You * can enable Gson to use this annotation through {@link GsonBuilder#setVersion(double)}.
  • *
  • The default field naming policy for the output Json is same as in Java. So, a Java class * field versionNumber will be output as "versionNumber@quot; in * Json. The same rules are applied for mapping incoming Json to the Java classes. You can * change this policy through {@link GsonBuilder#setFieldNamingPolicy(FieldNamingPolicy)}.
  • *
  • By default, Gson excludes transient or static fields from * consideration for serialization and deserialization. You can change this behavior through * {@link GsonBuilder#excludeFieldsWithModifiers(int...)}.
  • *
*/ public Gson() { this(Excluder.DEFAULT, FieldNamingPolicy.IDENTITY, Collections.>emptyMap(), false, false, DEFAULT_JSON_NON_EXECUTABLE, true, false, false, LongSerializationPolicy.DEFAULT, Collections.emptyList()); } Gson(final Excluder excluder, final FieldNamingStrategy fieldNamingPolicy, final Map> instanceCreators, boolean serializeNulls, boolean complexMapKeySerialization, boolean generateNonExecutableGson, boolean htmlSafe, boolean prettyPrinting, boolean serializeSpecialFloatingPointValues, LongSerializationPolicy longSerializationPolicy, List typeAdapterFactories) { this.constructorConstructor = new ConstructorConstructor(instanceCreators); this.serializeNulls = serializeNulls; this.generateNonExecutableJson = generateNonExecutableGson; this.htmlSafe = htmlSafe; this.prettyPrinting = prettyPrinting; List factories = new ArrayList(); // built-in type adapters that cannot be overridden factories.add(TypeAdapters.JSON_ELEMENT_FACTORY); factories.add(ObjectTypeAdapter.FACTORY); // the excluder must precede all adapters that handle user-defined types factories.add(excluder); // user's type adapters factories.addAll(typeAdapterFactories); // type adapters for basic platform types factories.add(TypeAdapters.STRING_FACTORY); factories.add(TypeAdapters.INTEGER_FACTORY); factories.add(TypeAdapters.BOOLEAN_FACTORY); factories.add(TypeAdapters.BYTE_FACTORY); factories.add(TypeAdapters.SHORT_FACTORY); factories.add(TypeAdapters.newFactory(long.class, Long.class, longAdapter(longSerializationPolicy))); factories.add(TypeAdapters.newFactory(double.class, Double.class, doubleAdapter(serializeSpecialFloatingPointValues))); factories.add(TypeAdapters.newFactory(float.class, Float.class, floatAdapter(serializeSpecialFloatingPointValues))); factories.add(TypeAdapters.NUMBER_FACTORY); factories.add(TypeAdapters.CHARACTER_FACTORY); factories.add(TypeAdapters.STRING_BUILDER_FACTORY); factories.add(TypeAdapters.STRING_BUFFER_FACTORY); factories.add(TypeAdapters.newFactory(BigDecimal.class, TypeAdapters.BIG_DECIMAL)); factories.add(TypeAdapters.newFactory(BigInteger.class, TypeAdapters.BIG_INTEGER)); factories.add(TypeAdapters.URL_FACTORY); factories.add(TypeAdapters.URI_FACTORY); factories.add(TypeAdapters.UUID_FACTORY); factories.add(TypeAdapters.LOCALE_FACTORY); factories.add(TypeAdapters.INET_ADDRESS_FACTORY); factories.add(TypeAdapters.BIT_SET_FACTORY); factories.add(DateTypeAdapter.FACTORY); factories.add(TypeAdapters.CALENDAR_FACTORY); factories.add(TimeTypeAdapter.FACTORY); factories.add(SqlDateTypeAdapter.FACTORY); factories.add(TypeAdapters.TIMESTAMP_FACTORY); factories.add(ArrayTypeAdapter.FACTORY); factories.add(TypeAdapters.ENUM_FACTORY); factories.add(TypeAdapters.CLASS_FACTORY); // type adapters for composite and user-defined types factories.add(new CollectionTypeAdapterFactory(constructorConstructor)); factories.add(new MapTypeAdapterFactory(constructorConstructor, complexMapKeySerialization)); factories.add(new ReflectiveTypeAdapterFactory( constructorConstructor, fieldNamingPolicy, excluder)); this.factories = Collections.unmodifiableList(factories); } private TypeAdapter doubleAdapter(boolean serializeSpecialFloatingPointValues) { if (serializeSpecialFloatingPointValues) { return TypeAdapters.DOUBLE; } return new TypeAdapter() { @Override public Double read(JsonReader in) throws IOException { if (in.peek() == JsonToken.NULL) { in.nextNull(); return null; } return in.nextDouble(); } @Override public void write(JsonWriter out, Number value) throws IOException { if (value == null) { out.nullValue(); return; } double doubleValue = value.doubleValue(); checkValidFloatingPoint(doubleValue); out.value(value); } }; } private TypeAdapter floatAdapter(boolean serializeSpecialFloatingPointValues) { if (serializeSpecialFloatingPointValues) { return TypeAdapters.FLOAT; } return new TypeAdapter() { @Override public Float read(JsonReader in) throws IOException { if (in.peek() == JsonToken.NULL) { in.nextNull(); return null; } return (float) in.nextDouble(); } @Override public void write(JsonWriter out, Number value) throws IOException { if (value == null) { out.nullValue(); return; } float floatValue = value.floatValue(); checkValidFloatingPoint(floatValue); out.value(value); } }; } private void checkValidFloatingPoint(double value) { if (Double.isNaN(value) || Double.isInfinite(value)) { throw new IllegalArgumentException(value + " is not a valid double value as per JSON specification. To override this" + " behavior, use GsonBuilder.serializeSpecialFloatingPointValues() method."); } } private TypeAdapter longAdapter(LongSerializationPolicy longSerializationPolicy) { if (longSerializationPolicy == LongSerializationPolicy.DEFAULT) { return TypeAdapters.LONG; } return new TypeAdapter() { @Override public Number read(JsonReader in) throws IOException { if (in.peek() == JsonToken.NULL) { in.nextNull(); return null; } return in.nextLong(); } @Override public void write(JsonWriter out, Number value) throws IOException { if (value == null) { out.nullValue(); return; } out.value(value.toString()); } }; } /** * Returns the type adapter for {@code} type. * * @throws IllegalArgumentException if this GSON cannot serialize and * deserialize {@code type}. */ @SuppressWarnings("unchecked") public TypeAdapter getAdapter(TypeToken type) { TypeAdapter cached = typeTokenCache.get(type); if (cached != null) { return (TypeAdapter) cached; } Map, FutureTypeAdapter> threadCalls = calls.get(); boolean requiresThreadLocalCleanup = false; if (threadCalls == null) { threadCalls = new HashMap, FutureTypeAdapter>(); calls.set(threadCalls); requiresThreadLocalCleanup = true; } // the key and value type parameters always agree FutureTypeAdapter ongoingCall = (FutureTypeAdapter) threadCalls.get(type); if (ongoingCall != null) { return ongoingCall; } try { FutureTypeAdapter call = new FutureTypeAdapter(); threadCalls.put(type, call); for (TypeAdapterFactory factory : factories) { TypeAdapter candidate = factory.create(this, type); if (candidate != null) { call.setDelegate(candidate); typeTokenCache.put(type, candidate); return candidate; } } throw new IllegalArgumentException("GSON cannot handle " + type); } finally { threadCalls.remove(type); if (requiresThreadLocalCleanup) { calls.remove(); } } } /** * This method is used to get an alternate type adapter for the specified type. This is used * to access a type adapter that is overridden by a {@link TypeAdapterFactory} that you * may have registered. This features is typically used when you want to register a type * adapter that does a little bit of work but then delegates further processing to the Gson * default type adapter. Here is an example: *

Let's say we want to write a type adapter that counts the number of objects being read * from or written to JSON. We can achieve this by writing a type adapter factory that uses * the getDelegateAdapter method: *

 {@code
   *  class StatsTypeAdapterFactory implements TypeAdapterFactory {
   *    public int numReads = 0;
   *    public int numWrites = 0;
   *    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
   *      final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
   *      return new TypeAdapter<T>() {
   *        public void write(JsonWriter out, T value) throws IOException {
   *          ++numWrites;
   *          delegate.write(out, value);
   *        }
   *        public T read(JsonReader in) throws IOException {
   *          ++numReads;
   *          return delegate.read(in);
   *        }
   *      };
   *    }
   *  }
   *  } 
* This factory can now be used like this: *
 {@code
   *  StatsTypeAdapterFactory stats = new StatsTypeAdapterFactory();
   *  Gson gson = new GsonBuilder().registerTypeAdapterFactory(stats).create();
   *  // Call gson.toJson() and fromJson methods on objects
   *  System.out.println("Num JSON reads" + stats.numReads);
   *  System.out.println("Num JSON writes" + stats.numWrites);
   *  }
* Note that since you can not override type adapter factories for String and Java primitive * types, our stats factory will not count the number of String or primitives that will be * read or written. * @param skipPast The type adapter factory that needs to be skipped while searching for * a matching type adapter. In most cases, you should just pass this (the type adapter * factory from where {@link #getDelegateAdapter} method is being invoked). * @param type Type for which the delegate adapter is being searched for. * * @since 2.2 */ public TypeAdapter getDelegateAdapter(TypeAdapterFactory skipPast, TypeToken type) { boolean skipPastFound = false; for (TypeAdapterFactory factory : factories) { if (!skipPastFound) { if (factory == skipPast) { skipPastFound = true; } continue; } TypeAdapter candidate = factory.create(this, type); if (candidate != null) { return candidate; } } throw new IllegalArgumentException("GSON cannot serialize " + type); } /** * Returns the type adapter for {@code} type. * * @throws IllegalArgumentException if this GSON cannot serialize and * deserialize {@code type}. */ public TypeAdapter getAdapter(Class type) { return getAdapter(TypeToken.get(type)); } /** * This method serializes the specified object into its equivalent representation as a tree of * {@link JsonElement}s. This method should be used when the specified object is not a generic * type. This method uses {@link Class#getClass()} to get the type for the specified object, but * the {@code getClass()} loses the generic type information because of the Type Erasure feature * of Java. Note that this method works fine if the any of the object fields are of generic type, * just the object itself should not be of a generic type. If the object is of generic type, use * {@link #toJsonTree(Object, Type)} instead. * * @param src the object for which Json representation is to be created setting for Gson * @return Json representation of {@code src}. * @since 1.4 */ public JsonElement toJsonTree(Object src) { if (src == null) { return JsonNull.INSTANCE; } return toJsonTree(src, src.getClass()); } /** * This method serializes the specified object, including those of generic types, into its * equivalent representation as a tree of {@link JsonElement}s. This method must be used if the * specified object is a generic type. For non-generic objects, use {@link #toJsonTree(Object)} * instead. * * @param src the object for which JSON representation is to be created * @param typeOfSrc The specific genericized type of src. You can obtain * this type by using the {@link com.google.gson.reflect.TypeToken} class. For example, * to get the type for {@code Collection}, you should use: *
   * Type typeOfSrc = new TypeToken<Collection<Foo>>(){}.getType();
   * 
* @return Json representation of {@code src} * @since 1.4 */ public JsonElement toJsonTree(Object src, Type typeOfSrc) { JsonTreeWriter writer = new JsonTreeWriter(); toJson(src, typeOfSrc, writer); return writer.get(); } /** * This method serializes the specified object into its equivalent Json representation. * This method should be used when the specified object is not a generic type. This method uses * {@link Class#getClass()} to get the type for the specified object, but the * {@code getClass()} loses the generic type information because of the Type Erasure feature * of Java. Note that this method works fine if the any of the object fields are of generic type, * just the object itself should not be of a generic type. If the object is of generic type, use * {@link #toJson(Object, Type)} instead. If you want to write out the object to a * {@link Writer}, use {@link #toJson(Object, Appendable)} instead. * * @param src the object for which Json representation is to be created setting for Gson * @return Json representation of {@code src}. */ public String toJson(Object src) { if (src == null) { return toJson(JsonNull.INSTANCE); } return toJson(src, src.getClass()); } /** * This method serializes the specified object, including those of generic types, into its * equivalent Json representation. This method must be used if the specified object is a generic * type. For non-generic objects, use {@link #toJson(Object)} instead. If you want to write out * the object to a {@link Appendable}, use {@link #toJson(Object, Type, Appendable)} instead. * * @param src the object for which JSON representation is to be created * @param typeOfSrc The specific genericized type of src. You can obtain * this type by using the {@link com.google.gson.reflect.TypeToken} class. For example, * to get the type for {@code Collection}, you should use: *
   * Type typeOfSrc = new TypeToken<Collection<Foo>>(){}.getType();
   * 
* @return Json representation of {@code src} */ public String toJson(Object src, Type typeOfSrc) { StringWriter writer = new StringWriter(); toJson(src, typeOfSrc, writer); return writer.toString(); } /** * This method serializes the specified object into its equivalent Json representation. * This method should be used when the specified object is not a generic type. This method uses * {@link Class#getClass()} to get the type for the specified object, but the * {@code getClass()} loses the generic type information because of the Type Erasure feature * of Java. Note that this method works fine if the any of the object fields are of generic type, * just the object itself should not be of a generic type. If the object is of generic type, use * {@link #toJson(Object, Type, Appendable)} instead. * * @param src the object for which Json representation is to be created setting for Gson * @param writer Writer to which the Json representation needs to be written * @throws JsonIOException if there was a problem writing to the writer * @since 1.2 */ public void toJson(Object src, Appendable writer) throws JsonIOException { if (src != null) { toJson(src, src.getClass(), writer); } else { toJson(JsonNull.INSTANCE, writer); } } /** * This method serializes the specified object, including those of generic types, into its * equivalent Json representation. This method must be used if the specified object is a generic * type. For non-generic objects, use {@link #toJson(Object, Appendable)} instead. * * @param src the object for which JSON representation is to be created * @param typeOfSrc The specific genericized type of src. You can obtain * this type by using the {@link com.google.gson.reflect.TypeToken} class. For example, * to get the type for {@code Collection}, you should use: *
   * Type typeOfSrc = new TypeToken<Collection<Foo>>(){}.getType();
   * 
* @param writer Writer to which the Json representation of src needs to be written. * @throws JsonIOException if there was a problem writing to the writer * @since 1.2 */ public void toJson(Object src, Type typeOfSrc, Appendable writer) throws JsonIOException { try { JsonWriter jsonWriter = newJsonWriter(Streams.writerForAppendable(writer)); toJson(src, typeOfSrc, jsonWriter); } catch (IOException e) { throw new JsonIOException(e); } } /** * Writes the JSON representation of {@code src} of type {@code typeOfSrc} to * {@code writer}. * @throws JsonIOException if there was a problem writing to the writer */ @SuppressWarnings("unchecked") public void toJson(Object src, Type typeOfSrc, JsonWriter writer) throws JsonIOException { TypeAdapter adapter = getAdapter(TypeToken.get(typeOfSrc)); boolean oldLenient = writer.isLenient(); writer.setLenient(true); boolean oldHtmlSafe = writer.isHtmlSafe(); writer.setHtmlSafe(htmlSafe); boolean oldSerializeNulls = writer.getSerializeNulls(); writer.setSerializeNulls(serializeNulls); try { ((TypeAdapter) adapter).write(writer, src); } catch (IOException e) { throw new JsonIOException(e); } finally { writer.setLenient(oldLenient); writer.setHtmlSafe(oldHtmlSafe); writer.setSerializeNulls(oldSerializeNulls); } } /** * Converts a tree of {@link JsonElement}s into its equivalent JSON representation. * * @param jsonElement root of a tree of {@link JsonElement}s * @return JSON String representation of the tree * @since 1.4 */ public String toJson(JsonElement jsonElement) { StringWriter writer = new StringWriter(); toJson(jsonElement, writer); return writer.toString(); } /** * Writes out the equivalent JSON for a tree of {@link JsonElement}s. * * @param jsonElement root of a tree of {@link JsonElement}s * @param writer Writer to which the Json representation needs to be written * @throws JsonIOException if there was a problem writing to the writer * @since 1.4 */ public void toJson(JsonElement jsonElement, Appendable writer) throws JsonIOException { try { JsonWriter jsonWriter = newJsonWriter(Streams.writerForAppendable(writer)); toJson(jsonElement, jsonWriter); } catch (IOException e) { throw new RuntimeException(e); } } /** * Returns a new JSON writer configured for this GSON and with the non-execute * prefix if that is configured. */ private JsonWriter newJsonWriter(Writer writer) throws IOException { if (generateNonExecutableJson) { writer.write(JSON_NON_EXECUTABLE_PREFIX); } JsonWriter jsonWriter = new JsonWriter(writer); if (prettyPrinting) { jsonWriter.setIndent(" "); } jsonWriter.setSerializeNulls(serializeNulls); return jsonWriter; } /** * Writes the JSON for {@code jsonElement} to {@code writer}. * @throws JsonIOException if there was a problem writing to the writer */ public void toJson(JsonElement jsonElement, JsonWriter writer) throws JsonIOException { boolean oldLenient = writer.isLenient(); writer.setLenient(true); boolean oldHtmlSafe = writer.isHtmlSafe(); writer.setHtmlSafe(htmlSafe); boolean oldSerializeNulls = writer.getSerializeNulls(); writer.setSerializeNulls(serializeNulls); try { Streams.write(jsonElement, writer); } catch (IOException e) { throw new JsonIOException(e); } finally { writer.setLenient(oldLenient); writer.setHtmlSafe(oldHtmlSafe); writer.setSerializeNulls(oldSerializeNulls); } } /** * This method deserializes the specified Json into an object of the specified class. It is not * suitable to use if the specified class is a generic type since it will not have the generic * type information because of the Type Erasure feature of Java. Therefore, this method should not * be used if the desired type is a generic type. Note that this method works fine if the any of * the fields of the specified object are generics, just the object itself should not be a * generic type. For the cases when the object is of generic type, invoke * {@link #fromJson(String, Type)}. If you have the Json in a {@link Reader} instead of * a String, use {@link #fromJson(Reader, Class)} instead. * * @param the type of the desired object * @param json the string from which the object is to be deserialized * @param classOfT the class of T * @return an object of type T from the string * @throws JsonSyntaxException if json is not a valid representation for an object of type * classOfT */ public T fromJson(String json, Class classOfT) throws JsonSyntaxException { Object object = fromJson(json, (Type) classOfT); return Primitives.wrap(classOfT).cast(object); } /** * This method deserializes the specified Json into an object of the specified type. This method * is useful if the specified object is a generic type. For non-generic objects, use * {@link #fromJson(String, Class)} instead. If you have the Json in a {@link Reader} instead of * a String, use {@link #fromJson(Reader, Type)} instead. * * @param the type of the desired object * @param json the string from which the object is to be deserialized * @param typeOfT The specific genericized type of src. You can obtain this type by using the * {@link com.google.gson.reflect.TypeToken} class. For example, to get the type for * {@code Collection}, you should use: *
   * Type typeOfT = new TypeToken<Collection<Foo>>(){}.getType();
   * 
* @return an object of type T from the string * @throws JsonParseException if json is not a valid representation for an object of type typeOfT * @throws JsonSyntaxException if json is not a valid representation for an object of type */ @SuppressWarnings("unchecked") public T fromJson(String json, Type typeOfT) throws JsonSyntaxException { if (json == null) { return null; } StringReader reader = new StringReader(json); T target = (T) fromJson(reader, typeOfT); return target; } /** * This method deserializes the Json read from the specified reader into an object of the * specified class. It is not suitable to use if the specified class is a generic type since it * will not have the generic type information because of the Type Erasure feature of Java. * Therefore, this method should not be used if the desired type is a generic type. Note that * this method works fine if the any of the fields of the specified object are generics, just the * object itself should not be a generic type. For the cases when the object is of generic type, * invoke {@link #fromJson(Reader, Type)}. If you have the Json in a String form instead of a * {@link Reader}, use {@link #fromJson(String, Class)} instead. * * @param the type of the desired object * @param json the reader producing the Json from which the object is to be deserialized. * @param classOfT the class of T * @return an object of type T from the string * @throws JsonIOException if there was a problem reading from the Reader * @throws JsonSyntaxException if json is not a valid representation for an object of type * @since 1.2 */ public T fromJson(Reader json, Class classOfT) throws JsonSyntaxException, JsonIOException { JsonReader jsonReader = new JsonReader(json); Object object = fromJson(jsonReader, classOfT); assertFullConsumption(object, jsonReader); return Primitives.wrap(classOfT).cast(object); } /** * This method deserializes the Json read from the specified reader into an object of the * specified type. This method is useful if the specified object is a generic type. For * non-generic objects, use {@link #fromJson(Reader, Class)} instead. If you have the Json in a * String form instead of a {@link Reader}, use {@link #fromJson(String, Type)} instead. * * @param the type of the desired object * @param json the reader producing Json from which the object is to be deserialized * @param typeOfT The specific genericized type of src. You can obtain this type by using the * {@link com.google.gson.reflect.TypeToken} class. For example, to get the type for * {@code Collection}, you should use: *
   * Type typeOfT = new TypeToken<Collection<Foo>>(){}.getType();
   * 
* @return an object of type T from the json * @throws JsonIOException if there was a problem reading from the Reader * @throws JsonSyntaxException if json is not a valid representation for an object of type * @since 1.2 */ @SuppressWarnings("unchecked") public T fromJson(Reader json, Type typeOfT) throws JsonIOException, JsonSyntaxException { JsonReader jsonReader = new JsonReader(json); T object = (T) fromJson(jsonReader, typeOfT); assertFullConsumption(object, jsonReader); return object; } private static void assertFullConsumption(Object obj, JsonReader reader) { try { if (obj != null && reader.peek() != JsonToken.END_DOCUMENT) { throw new JsonIOException("JSON document was not fully consumed."); } } catch (MalformedJsonException e) { throw new JsonSyntaxException(e); } catch (IOException e) { throw new JsonIOException(e); } } /** * Reads the next JSON value from {@code reader} and convert it to an object * of type {@code typeOfT}. * Since Type is not parameterized by T, this method is type unsafe and should be used carefully * * @throws JsonIOException if there was a problem writing to the Reader * @throws JsonSyntaxException if json is not a valid representation for an object of type */ @SuppressWarnings("unchecked") public T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException { boolean isEmpty = true; boolean oldLenient = reader.isLenient(); reader.setLenient(true); try { reader.peek(); isEmpty = false; TypeToken typeToken = (TypeToken) TypeToken.get(typeOfT); TypeAdapter typeAdapter = getAdapter(typeToken); T object = typeAdapter.read(reader); return object; } catch (EOFException e) { /* * For compatibility with JSON 1.5 and earlier, we return null for empty * documents instead of throwing. */ if (isEmpty) { return null; } throw new JsonSyntaxException(e); } catch (IllegalStateException e) { throw new JsonSyntaxException(e); } catch (IOException e) { // TODO(inder): Figure out whether it is indeed right to rethrow this as JsonSyntaxException throw new JsonSyntaxException(e); } finally { reader.setLenient(oldLenient); } } /** * This method deserializes the Json read from the specified parse tree into an object of the * specified type. It is not suitable to use if the specified class is a generic type since it * will not have the generic type information because of the Type Erasure feature of Java. * Therefore, this method should not be used if the desired type is a generic type. Note that * this method works fine if the any of the fields of the specified object are generics, just the * object itself should not be a generic type. For the cases when the object is of generic type, * invoke {@link #fromJson(JsonElement, Type)}. * @param the type of the desired object * @param json the root of the parse tree of {@link JsonElement}s from which the object is to * be deserialized * @param classOfT The class of T * @return an object of type T from the json * @throws JsonSyntaxException if json is not a valid representation for an object of type typeOfT * @since 1.3 */ public T fromJson(JsonElement json, Class classOfT) throws JsonSyntaxException { Object object = fromJson(json, (Type) classOfT); return Primitives.wrap(classOfT).cast(object); } /** * This method deserializes the Json read from the specified parse tree into an object of the * specified type. This method is useful if the specified object is a generic type. For * non-generic objects, use {@link #fromJson(JsonElement, Class)} instead. * * @param the type of the desired object * @param json the root of the parse tree of {@link JsonElement}s from which the object is to * be deserialized * @param typeOfT The specific genericized type of src. You can obtain this type by using the * {@link com.google.gson.reflect.TypeToken} class. For example, to get the type for * {@code Collection}, you should use: *
   * Type typeOfT = new TypeToken<Collection<Foo>>(){}.getType();
   * 
* @return an object of type T from the json * @throws JsonSyntaxException if json is not a valid representation for an object of type typeOfT * @since 1.3 */ @SuppressWarnings("unchecked") public T fromJson(JsonElement json, Type typeOfT) throws JsonSyntaxException { if (json == null) { return null; } return (T) fromJson(new JsonTreeReader(json), typeOfT); } static class FutureTypeAdapter extends TypeAdapter { private TypeAdapter delegate; public void setDelegate(TypeAdapter typeAdapter) { if (delegate != null) { throw new AssertionError(); } delegate = typeAdapter; } @Override public T read(JsonReader in) throws IOException { if (delegate == null) { throw new IllegalStateException(); } return delegate.read(in); } @Override public void write(JsonWriter out, T value) throws IOException { if (delegate == null) { throw new IllegalStateException(); } delegate.write(out, value); } } @Override public String toString() { return new StringBuilder("{serializeNulls:") .append(serializeNulls) .append("factories:").append(factories) .append(",instanceCreators:").append(constructorConstructor) .append("}") .toString(); } } google-gson/src/main/java/com/google/gson/intercept/0000775000175000017500000000000012207114635022262 5ustar ebourgebourggoogle-gson/src/main/java/com/google/gson/FieldNamingStrategy.java0000664000175000017500000000241311547373517025044 0ustar ebourgebourg/* * 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; import java.lang.reflect.Field; /** * A mechanism for providing custom field naming in Gson. This allows the client code to translate * field names into a particular convention that is not supported as a normal Java field * declaration rules. For example, Java does not support "-" characters in a field name. * * @author Inderjeet Singh * @author Joel Leitch * @since 1.3 */ public interface FieldNamingStrategy { /** * Translates the field name into its JSON field name representation. * * @param f the field object that we are translating * @return the translated field name. * @since 1.3 */ public String translateName(Field f); } google-gson/src/main/java/com/google/gson/TypeAdapter.java0000664000175000017500000002506511700051532023353 0ustar ebourgebourg/* * Copyright (C) 2011 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; import com.google.gson.internal.bind.JsonTreeWriter; import com.google.gson.internal.bind.JsonTreeReader; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonWriter; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.io.StringWriter; import java.io.Writer; /** * Converts Java objects to and from JSON. * *

Defining a type's JSON form

* By default Gson converts application classes to JSON using its built-in type * adapters. If Gson's default JSON conversion isn't appropriate for a type, * extend this class to customize the conversion. Here's an example of a type * adapter for an (X,Y) coordinate point:
   {@code
 *
 *   public class PointAdapter extends TypeAdapter {
 *     public Point read(JsonReader reader) throws IOException {
 *       if (reader.peek() == JsonToken.NULL) {
 *         reader.nextNull();
 *         return null;
 *       }
 *       String xy = reader.nextString();
 *       String[] parts = xy.split(",");
 *       int x = Integer.parseInt(parts[0]);
 *       int y = Integer.parseInt(parts[1]);
 *       return new Point(x, y);
 *     }
 *     public void write(JsonWriter writer, Point value) throws IOException {
 *       if (value == null) {
 *         writer.nullValue();
 *         return;
 *       }
 *       String xy = value.getX() + "," + value.getY();
 *       writer.value(xy);
 *     }
 *   }}
* With this type adapter installed, Gson will convert {@code Points} to JSON as * strings like {@code "5,8"} rather than objects like {@code {"x":5,"y":8}}. In * this case the type adapter binds a rich Java class to a compact JSON value. * *

The {@link #read(JsonReader) read()} method must read exactly one value * and {@link #write(JsonWriter,Object) write()} must write exactly one value. * For primitive types this is means readers should make exactly one call to * {@code nextBoolean()}, {@code nextDouble()}, {@code nextInt()}, {@code * nextLong()}, {@code nextString()} or {@code nextNull()}. Writers should make * exactly one call to one of value() or nullValue(). * For arrays, type adapters should start with a call to {@code beginArray()}, * convert all elements, and finish with a call to {@code endArray()}. For * objects, they should start with {@code beginObject()}, convert the object, * and finish with {@code endObject()}. Failing to convert a value or converting * too many values may cause the application to crash. * *

Type adapters should be prepared to read null from the stream and write it * to the stream. Alternatively, they should use {@link #nullSafe()} method while * registering the type adapter with Gson. If your {@code Gson} instance * has been configured to {@link GsonBuilder#serializeNulls()}, these nulls will be * written to the final document. Otherwise the value (and the corresponding name * when writing to a JSON object) will be omitted automatically. In either case * your type adapter must handle null. * *

To use a custom type adapter with Gson, you must register it with a * {@link GsonBuilder}:

   {@code
 *
 *   GsonBuilder builder = new GsonBuilder();
 *   builder.registerTypeAdapter(Point.class, new PointAdapter());
 *   // if PointAdapter didn't check for nulls in its read/write methods, you should instead use
 *   // builder.registerTypeAdapter(Point.class, new PointAdapter().nullSafe());
 *   ...
 *   Gson gson = builder.create();
 * }
* * @since 2.1 */ // non-Javadoc: // //

JSON Conversion

//

A type adapter registered with Gson is automatically invoked while serializing // or deserializing JSON. However, you can also use type adapters directly to serialize // and deserialize JSON. Here is an example for deserialization:

   {@code
//
//   String json = "{'origin':'0,0','points':['1,2','3,4']}";
//   TypeAdapter graphAdapter = gson.getAdapter(Graph.class);
//   Graph graph = graphAdapter.fromJson(json);
// }
// And an example for serialization:
   {@code
//
//   Graph graph = new Graph(...);
//   TypeAdapter graphAdapter = gson.getAdapter(Graph.class);
//   String json = graphAdapter.toJson(graph);
// }
// //

Type adapters are type-specific. For example, a {@code // TypeAdapter} can convert {@code Date} instances to JSON and JSON to // instances of {@code Date}, but cannot convert any other types. // public abstract class TypeAdapter { /** * Writes one JSON value (an array, object, string, number, boolean or null) * for {@code value}. * * @param value the Java object to write. May be null. */ public abstract void write(JsonWriter out, T value) throws IOException; /** * Converts {@code value} to a JSON document and writes it to {@code out}. * Unlike Gson's similar {@link Gson#toJson(JsonElement, Appendable) toJson} * method, this write is strict. Create a {@link * JsonWriter#setLenient(boolean) lenient} {@code JsonWriter} and call * {@link #write(com.google.gson.stream.JsonWriter, Object)} for lenient * writing. * * @param value the Java object to convert. May be null. * @since 2.2 */ public final void toJson(Writer out, T value) throws IOException { JsonWriter writer = new JsonWriter(out); write(writer, value); } /** * This wrapper method is used to make a type adapter null tolerant. In general, a * type adapter is required to handle nulls in write and read methods. Here is how this * is typically done:
*

   {@code
   *
   * Gson gson = new GsonBuilder().registerTypeAdapter(Foo.class,
   *   new TypeAdapter() {
   *     public Foo read(JsonReader in) throws IOException {
   *       if (in.peek() == JsonToken.NULL) {
   *         in.nextNull();
   *         return null;
   *       }
   *       // read a Foo from in and return it
   *     }
   *     public void write(JsonWriter out, Foo src) throws IOException {
   *       if (src == null) {
   *         out.nullValue();
   *         return;
   *       }
   *       // write src as JSON to out
   *     }
   *   }).create();
   * }
* You can avoid this boilerplate handling of nulls by wrapping your type adapter with * this method. Here is how we will rewrite the above example: *
   {@code
   *
   * Gson gson = new GsonBuilder().registerTypeAdapter(Foo.class,
   *   new TypeAdapter() {
   *     public Foo read(JsonReader in) throws IOException {
   *       // read a Foo from in and return it
   *     }
   *     public void write(JsonWriter out, Foo src) throws IOException {
   *       // write src as JSON to out
   *     }
   *   }.nullSafe()).create();
   * }
* Note that we didn't need to check for nulls in our type adapter after we used nullSafe. */ public final TypeAdapter nullSafe() { return new TypeAdapter() { @Override public void write(JsonWriter out, T value) throws IOException { if (value == null) { out.nullValue(); } else { TypeAdapter.this.write(out, value); } } @Override public T read(JsonReader reader) throws IOException { if (reader.peek() == JsonToken.NULL) { reader.nextNull(); return null; } return TypeAdapter.this.read(reader); } }; } /** * Converts {@code value} to a JSON document. Unlike Gson's similar {@link * Gson#toJson(Object) toJson} method, this write is strict. Create a {@link * JsonWriter#setLenient(boolean) lenient} {@code JsonWriter} and call * {@link #write(com.google.gson.stream.JsonWriter, Object)} for lenient * writing. * * @param value the Java object to convert. May be null. * @since 2.2 */ public final String toJson(T value) throws IOException { StringWriter stringWriter = new StringWriter(); toJson(stringWriter, value); return stringWriter.toString(); } /** * Converts {@code value} to a JSON tree. * * @param value the Java object to convert. May be null. * @return the converted JSON tree. May be {@link JsonNull}. * @since 2.2 */ public final JsonElement toJsonTree(T value) { try { JsonTreeWriter jsonWriter = new JsonTreeWriter(); write(jsonWriter, value); return jsonWriter.get(); } catch (IOException e) { throw new JsonIOException(e); } } /** * Reads one JSON value (an array, object, string, number, boolean or null) * and converts it to a Java object. Returns the converted object. * * @return the converted Java object. May be null. */ public abstract T read(JsonReader in) throws IOException; /** * Converts the JSON document in {@code in} to a Java object. Unlike Gson's * similar {@link Gson#fromJson(java.io.Reader, Class) fromJson} method, this * read is strict. Create a {@link JsonReader#setLenient(boolean) lenient} * {@code JsonReader} and call {@link #read(JsonReader)} for lenient reading. * * @return the converted Java object. May be null. * @since 2.2 */ public final T fromJson(Reader in) throws IOException { JsonReader reader = new JsonReader(in); return read(reader); } /** * Converts the JSON document in {@code json} to a Java object. Unlike Gson's * similar {@link Gson#fromJson(String, Class) fromJson} method, this read is * strict. Create a {@link JsonReader#setLenient(boolean) lenient} {@code * JsonReader} and call {@link #read(JsonReader)} for lenient reading. * * @return the converted Java object. May be null. * @since 2.2 */ public final T fromJson(String json) throws IOException { return fromJson(new StringReader(json)); } /** * Converts {@code jsonTree} to a Java object. * * @param jsonTree the Java object to convert. May be {@link JsonNull}. * @since 2.2 */ public final T fromJsonTree(JsonElement jsonTree) { try { JsonReader jsonReader = new JsonTreeReader(jsonTree); return read(jsonReader); } catch (IOException e) { throw new JsonIOException(e); } } } google-gson/src/main/java/com/google/gson/FieldAttributes.java0000664000175000017500000001051011663173625024230 0ustar ebourgebourg/* * Copyright (C) 2009 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; import com.google.gson.internal.$Gson$Preconditions; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.lang.reflect.Type; import java.util.Arrays; import java.util.Collection; /** * A data object that stores attributes of a field. * *

This class is immutable; therefore, it can be safely shared across threads. * * @author Inderjeet Singh * @author Joel Leitch * * @since 1.4 */ public final class FieldAttributes { private final Field field; /** * Constructs a Field Attributes object from the {@code f}. * * @param f the field to pull attributes from */ public FieldAttributes(Field f) { $Gson$Preconditions.checkNotNull(f); this.field = f; } /** * @return the declaring class that contains this field */ public Class getDeclaringClass() { return field.getDeclaringClass(); } /** * @return the name of the field */ public String getName() { return field.getName(); } /** *

For example, assume the following class definition: *

   * public class Foo {
   *   private String bar;
   *   private List<String> red;
   * }
   *
   * Type listParmeterizedType = new TypeToken<List<String>>() {}.getType();
   * 
* *

This method would return {@code String.class} for the {@code bar} field and * {@code listParameterizedType} for the {@code red} field. * * @return the specific type declared for this field */ public Type getDeclaredType() { return field.getGenericType(); } /** * Returns the {@code Class} object that was declared for this field. * *

For example, assume the following class definition: *

   * public class Foo {
   *   private String bar;
   *   private List<String> red;
   * }
   * 
* *

This method would return {@code String.class} for the {@code bar} field and * {@code List.class} for the {@code red} field. * * @return the specific class object that was declared for the field */ public Class getDeclaredClass() { return field.getType(); } /** * Return the {@code T} annotation object from this field if it exist; otherwise returns * {@code null}. * * @param annotation the class of the annotation that will be retrieved * @return the annotation instance if it is bound to the field; otherwise {@code null} */ public T getAnnotation(Class annotation) { return field.getAnnotation(annotation); } /** * Return the annotations that are present on this field. * * @return an array of all the annotations set on the field * @since 1.4 */ public Collection getAnnotations() { return Arrays.asList(field.getAnnotations()); } /** * Returns {@code true} if the field is defined with the {@code modifier}. * *

This method is meant to be called as: *

   * boolean hasPublicModifier = fieldAttribute.hasModifier(java.lang.reflect.Modifier.PUBLIC);
   * 
* * @see java.lang.reflect.Modifier */ public boolean hasModifier(int modifier) { return (field.getModifiers() & modifier) != 0; } /** * This is exposed internally only for the removing synthetic fields from the JSON output. * * @return true if the field is synthetic; otherwise false * @throws IllegalAccessException * @throws IllegalArgumentException */ Object get(Object instance) throws IllegalAccessException { return field.get(instance); } /** * This is exposed internally only for the removing synthetic fields from the JSON output. * * @return true if the field is synthetic; otherwise false */ boolean isSynthetic() { return field.isSynthetic(); } } google-gson/src/main/java/com/google/gson/JsonDeserializer.java0000664000175000017500000000713511666476221024424 0ustar ebourgebourg/* * 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; import java.lang.reflect.Type; /** *

Interface representing a custom deserializer for Json. You should write a custom * deserializer, if you are not happy with the default deserialization done by Gson. You will * also need to register this deserializer through * {@link GsonBuilder#registerTypeAdapter(Type, Object)}.

* *

Let us look at example where defining a deserializer will be useful. The {@code Id} class * defined below has two fields: {@code clazz} and {@code value}.

* *
 * public class Id<T> {
 *   private final Class<T> clazz;
 *   private final long value;
 *   public Id(Class<T> clazz, long value) {
 *     this.clazz = clazz;
 *     this.value = value;
 *   }
 *   public long getValue() {
 *     return value;
 *   }
 * }
 * 
* *

The default deserialization of {@code Id(com.foo.MyObject.class, 20L)} will require the * Json string to be {"clazz":com.foo.MyObject,"value":20}. Suppose, you already know * the type of the field that the {@code Id} will be deserialized into, and hence just want to * deserialize it from a Json string {@code 20}. You can achieve that by writing a custom * deserializer:

* *
 * class IdDeserializer implements JsonDeserializer<Id>() {
 *   public Id deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
 *       throws JsonParseException {
 *     return new Id((Class)typeOfT, id.getValue());
 *   }
 * 
* *

You will also need to register {@code IdDeserializer} with Gson as follows:

* *
 * Gson gson = new GsonBuilder().registerTypeAdapter(Id.class, new IdDeserializer()).create();
 * 
* *

New applications should prefer {@link TypeAdapter}, whose streaming API * is more efficient than this interface's tree API. * * @author Inderjeet Singh * @author Joel Leitch * * @param type for which the deserializer is being registered. It is possible that a * deserializer may be asked to deserialize a specific generic type of the T. */ public interface JsonDeserializer { /** * Gson invokes this call-back method during deserialization when it encounters a field of the * specified type. *

In the implementation of this call-back method, you should consider invoking * {@link JsonDeserializationContext#deserialize(JsonElement, Type)} method to create objects * for any non-trivial field of the returned object. However, you should never invoke it on the * the same type passing {@code json} since that will cause an infinite loop (Gson will call your * call-back method again). * * @param json The Json data being deserialized * @param typeOfT The type of the Object to deserialize to * @return a deserialized object of the specified type typeOfT which is a subclass of {@code T} * @throws JsonParseException if json is not in the expected format of {@code typeofT} */ public T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException; } google-gson/src/main/java/com/google/gson/JsonSerializer.java0000664000175000017500000000653111666476221024112 0ustar ebourgebourg/* * 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; import java.lang.reflect.Type; /** * Interface representing a custom serializer for Json. You should write a custom serializer, if * you are not happy with the default serialization done by Gson. You will also need to register * this serializer through {@link com.google.gson.GsonBuilder#registerTypeAdapter(Type, Object)}. * *

Let us look at example where defining a serializer will be useful. The {@code Id} class * defined below has two fields: {@code clazz} and {@code value}.

* *

 * public class Id<T> {
 *   private final Class<T> clazz;
 *   private final long value;
 *
 *   public Id(Class<T> clazz, long value) {
 *     this.clazz = clazz;
 *     this.value = value;
 *   }
 *
 *   public long getValue() {
 *     return value;
 *   }
 * }
 * 

* *

The default serialization of {@code Id(com.foo.MyObject.class, 20L)} will be * {"clazz":com.foo.MyObject,"value":20}. Suppose, you just want the output to be * the value instead, which is {@code 20} in this case. You can achieve that by writing a custom * serializer:

* *

 * class IdSerializer implements JsonSerializer<Id>() {
 *   public JsonElement serialize(Id id, Type typeOfId, JsonSerializationContext context) {
 *     return new JsonPrimitive(id.getValue());
 *   }
 * }
 * 

* *

You will also need to register {@code IdSerializer} with Gson as follows:

*
 * Gson gson = new GsonBuilder().registerTypeAdapter(Id.class, new IdSerializer()).create();
 * 
* *

New applications should prefer {@link TypeAdapter}, whose streaming API * is more efficient than this interface's tree API. * * @author Inderjeet Singh * @author Joel Leitch * * @param type for which the serializer is being registered. It is possible that a serializer * may be asked to serialize a specific generic type of the T. */ public interface JsonSerializer { /** * Gson invokes this call-back method during serialization when it encounters a field of the * specified type. * *

In the implementation of this call-back method, you should consider invoking * {@link JsonSerializationContext#serialize(Object, Type)} method to create JsonElements for any * non-trivial field of the {@code src} object. However, you should never invoke it on the * {@code src} object itself since that will cause an infinite loop (Gson will call your * call-back method again).

* * @param src the object that needs to be converted to Json. * @param typeOfSrc the actual type (fully genericized version) of the source object. * @return a JsonElement corresponding to the specified object. */ public JsonElement serialize(T src, Type typeOfSrc, JsonSerializationContext context); } google-gson/src/main/java/com/google/gson/TypeAdapterFactory.java0000664000175000017500000001470011675144001024702 0ustar ebourgebourg/* * Copyright (C) 2011 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; import com.google.gson.reflect.TypeToken; /** * Creates type adapters for set of related types. Type adapter factories are * most useful when several types share similar structure in their JSON form. * *

Example: Converting enums to lowercase

* In this example, we implement a factory that creates type adapters for all * enums. The type adapters will write enums in lowercase, despite the fact * that they're defined in {@code CONSTANT_CASE} in the corresponding Java * model:
   {@code
 *
 *   public class LowercaseEnumTypeAdapterFactory implements TypeAdapter.Factory {
 *     public  TypeAdapter create(Gson gson, TypeToken type) {
 *       Class rawType = (Class) type.getRawType();
 *       if (!rawType.isEnum()) {
 *         return null;
 *       }
 *
 *       final Map lowercaseToConstant = new HashMap();
 *       for (T constant : rawType.getEnumConstants()) {
 *         lowercaseToConstant.put(toLowercase(constant), constant);
 *       }
 *
 *       return new TypeAdapter() {
 *         public void write(JsonWriter out, T value) throws IOException {
 *           if (value == null) {
 *             out.nullValue();
 *           } else {
 *             out.value(toLowercase(value));
 *           }
 *         }
 *
 *         public T read(JsonReader reader) throws IOException {
 *           if (reader.peek() == JsonToken.NULL) {
 *             reader.nextNull();
 *             return null;
 *           } else {
 *             return lowercaseToConstant.get(reader.nextString());
 *           }
 *         }
 *       };
 *     }
 *
 *     private String toLowercase(Object o) {
 *       return o.toString().toLowerCase(Locale.US);
 *     }
 *   }
 * }
* *

Type adapter factories select which types they provide type adapters * for. If a factory cannot support a given type, it must return null when * that type is passed to {@link #create}. Factories should expect {@code * create()} to be called on them for many types and should return null for * most of those types. In the above example the factory returns null for * calls to {@code create()} where {@code type} is not an enum. * *

A factory is typically called once per type, but the returned type * adapter may be used many times. It is most efficient to do expensive work * like reflection in {@code create()} so that the type adapter's {@code * read()} and {@code write()} methods can be very fast. In this example the * mapping from lowercase name to enum value is computed eagerly. * *

As with type adapters, factories must be registered with a {@link * com.google.gson.GsonBuilder} for them to take effect:

   {@code
 *
 *  GsonBuilder builder = new GsonBuilder();
 *  builder.registerTypeAdapterFactory(new LowercaseEnumTypeAdapterFactory());
 *  ...
 *  Gson gson = builder.create();
 * }
* If multiple factories support the same type, the factory registered earlier * takes precedence. * *

Example: composing other type adapters

* In this example we implement a factory for Guava's {@code Multiset} * collection type. The factory can be used to create type adapters for * multisets of any element type: the type adapter for {@code * Multiset} is different from the type adapter for {@code * Multiset}. * *

The type adapter delegates to another type adapter for the * multiset elements. It figures out the element type by reflecting on the * multiset's type token. A {@code Gson} is passed in to {@code create} for * just this purpose:

   {@code
 *
 *   public class MultisetTypeAdapterFactory implements TypeAdapter.Factory {
 *     public  TypeAdapter create(Gson gson, TypeToken typeToken) {
 *       Type type = typeToken.getType();
 *       if (typeToken.getRawType() != Multiset.class
 *           || !(type instanceof ParameterizedType)) {
 *         return null;
 *       }
 *
 *       Type elementType = ((ParameterizedType) type).getActualTypeArguments()[0];
 *       TypeAdapter elementAdapter = gson.getAdapter(TypeToken.get(elementType));
 *       return (TypeAdapter) newMultisetAdapter(elementAdapter);
 *     }
 *
 *     private  TypeAdapter> newMultisetAdapter(
 *         final TypeAdapter elementAdapter) {
 *       return new TypeAdapter>() {
 *         public void write(JsonWriter out, Multiset value) throws IOException {
 *           if (value == null) {
 *             out.nullValue();
 *             return;
 *           }
 *
 *           out.beginArray();
 *           for (Multiset.Entry entry : value.entrySet()) {
 *             out.value(entry.getCount());
 *             elementAdapter.write(out, entry.getElement());
 *           }
 *           out.endArray();
 *         }
 *
 *         public Multiset read(JsonReader in) throws IOException {
 *           if (in.peek() == JsonToken.NULL) {
 *             in.nextNull();
 *             return null;
 *           }
 *
 *           Multiset result = LinkedHashMultiset.create();
 *           in.beginArray();
 *           while (in.hasNext()) {
 *             int count = in.nextInt();
 *             E element = elementAdapter.read(in);
 *             result.add(element, count);
 *           }
 *           in.endArray();
 *           return result;
 *         }
 *       };
 *     }
 *   }
 * }
* Delegating from one type adapter to another is extremely powerful; it's * the foundation of how Gson converts Java objects and collections. Whenever * possible your factory should retrieve its delegate type adapter in the * {@code create()} method; this ensures potentially-expensive type adapter * creation happens only once. * * @since 2.1 */ public interface TypeAdapterFactory { /** * Returns a type adapter for {@code type}, or null if this factory doesn't * support {@code type}. */ TypeAdapter create(Gson gson, TypeToken type); } google-gson/src/main/java/com/google/gson/JsonNull.java0000775000175000017500000000304212021236623022672 0ustar ebourgebourg/* * 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; /** * A class representing a Json {@code null} value. * * @author Inderjeet Singh * @author Joel Leitch * @since 1.2 */ public final class JsonNull extends JsonElement { /** * singleton for JsonNull * * @since 1.8 */ public static final JsonNull INSTANCE = new JsonNull(); /** * Creates a new JsonNull object. * Deprecated since Gson version 1.8. Use {@link #INSTANCE} instead */ @Deprecated public JsonNull() { // Do nothing } @Override JsonNull deepCopy() { return INSTANCE; } /** * All instances of JsonNull have the same hash code since they are indistinguishable */ @Override public int hashCode() { return JsonNull.class.hashCode(); } /** * All instances of JsonNull are the same */ @Override public boolean equals(Object other) { return this == other || other instanceof JsonNull; } } google-gson/src/main/java/com/google/gson/JsonArray.java0000664000175000017500000002167112021236623023043 0ustar ebourgebourg/* * 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; import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * A class representing an array type in Json. An array is a list of {@link JsonElement}s each of * which can be of a different type. This is an ordered list, meaning that the order in which * elements are added is preserved. * * @author Inderjeet Singh * @author Joel Leitch */ public final class JsonArray extends JsonElement implements Iterable { private final List elements; /** * Creates an empty JsonArray. */ public JsonArray() { elements = new ArrayList(); } @Override JsonArray deepCopy() { JsonArray result = new JsonArray(); for (JsonElement element : elements) { result.add(element.deepCopy()); } return result; } /** * Adds the specified element to self. * * @param element the element that needs to be added to the array. */ public void add(JsonElement element) { if (element == null) { element = JsonNull.INSTANCE; } elements.add(element); } /** * Adds all the elements of the specified array to self. * * @param array the array whose elements need to be added to the array. */ public void addAll(JsonArray array) { elements.addAll(array.elements); } /** * Returns the number of elements in the array. * * @return the number of elements in the array. */ public int size() { return elements.size(); } /** * Returns an iterator to navigate the elemetns of the array. Since the array is an ordered list, * the iterator navigates the elements in the order they were inserted. * * @return an iterator to navigate the elements of the array. */ public Iterator iterator() { return elements.iterator(); } /** * Returns the ith element of the array. * * @param i the index of the element that is being sought. * @return the element present at the ith index. * @throws IndexOutOfBoundsException if i is negative or greater than or equal to the * {@link #size()} of the array. */ public JsonElement get(int i) { return elements.get(i); } /** * convenience method to get this array as a {@link Number} if it contains a single element. * * @return get this element as a number if it is single element array. * @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and * is not a valid Number. * @throws IllegalStateException if the array has more than one element. */ @Override public Number getAsNumber() { if (elements.size() == 1) { return elements.get(0).getAsNumber(); } throw new IllegalStateException(); } /** * convenience method to get this array as a {@link String} if it contains a single element. * * @return get this element as a String if it is single element array. * @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and * is not a valid String. * @throws IllegalStateException if the array has more than one element. */ @Override public String getAsString() { if (elements.size() == 1) { return elements.get(0).getAsString(); } throw new IllegalStateException(); } /** * convenience method to get this array as a double if it contains a single element. * * @return get this element as a double if it is single element array. * @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and * is not a valid double. * @throws IllegalStateException if the array has more than one element. */ @Override public double getAsDouble() { if (elements.size() == 1) { return elements.get(0).getAsDouble(); } throw new IllegalStateException(); } /** * convenience method to get this array as a {@link BigDecimal} if it contains a single element. * * @return get this element as a {@link BigDecimal} if it is single element array. * @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive}. * @throws NumberFormatException if the element at index 0 is not a valid {@link BigDecimal}. * @throws IllegalStateException if the array has more than one element. * @since 1.2 */ @Override public BigDecimal getAsBigDecimal() { if (elements.size() == 1) { return elements.get(0).getAsBigDecimal(); } throw new IllegalStateException(); } /** * convenience method to get this array as a {@link BigInteger} if it contains a single element. * * @return get this element as a {@link BigInteger} if it is single element array. * @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive}. * @throws NumberFormatException if the element at index 0 is not a valid {@link BigInteger}. * @throws IllegalStateException if the array has more than one element. * @since 1.2 */ @Override public BigInteger getAsBigInteger() { if (elements.size() == 1) { return elements.get(0).getAsBigInteger(); } throw new IllegalStateException(); } /** * convenience method to get this array as a float if it contains a single element. * * @return get this element as a float if it is single element array. * @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and * is not a valid float. * @throws IllegalStateException if the array has more than one element. */ @Override public float getAsFloat() { if (elements.size() == 1) { return elements.get(0).getAsFloat(); } throw new IllegalStateException(); } /** * convenience method to get this array as a long if it contains a single element. * * @return get this element as a long if it is single element array. * @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and * is not a valid long. * @throws IllegalStateException if the array has more than one element. */ @Override public long getAsLong() { if (elements.size() == 1) { return elements.get(0).getAsLong(); } throw new IllegalStateException(); } /** * convenience method to get this array as an integer if it contains a single element. * * @return get this element as an integer if it is single element array. * @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and * is not a valid integer. * @throws IllegalStateException if the array has more than one element. */ @Override public int getAsInt() { if (elements.size() == 1) { return elements.get(0).getAsInt(); } throw new IllegalStateException(); } @Override public byte getAsByte() { if (elements.size() == 1) { return elements.get(0).getAsByte(); } throw new IllegalStateException(); } @Override public char getAsCharacter() { if (elements.size() == 1) { return elements.get(0).getAsCharacter(); } throw new IllegalStateException(); } /** * convenience method to get this array as a primitive short if it contains a single element. * * @return get this element as a primitive short if it is single element array. * @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and * is not a valid short. * @throws IllegalStateException if the array has more than one element. */ @Override public short getAsShort() { if (elements.size() == 1) { return elements.get(0).getAsShort(); } throw new IllegalStateException(); } /** * convenience method to get this array as a boolean if it contains a single element. * * @return get this element as a boolean if it is single element array. * @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and * is not a valid boolean. * @throws IllegalStateException if the array has more than one element. */ @Override public boolean getAsBoolean() { if (elements.size() == 1) { return elements.get(0).getAsBoolean(); } throw new IllegalStateException(); } @Override public boolean equals(Object o) { return (o == this) || (o instanceof JsonArray && ((JsonArray) o).elements.equals(elements)); } @Override public int hashCode() { return elements.hashCode(); } } google-gson/src/main/java/com/google/gson/InstanceCreator.java0000664000175000017500000000715711164717143024232 0ustar ebourgebourg/* * 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; import java.lang.reflect.Type; /** * This interface is implemented to create instances of a class that does not define a no-args * constructor. If you can modify the class, you should instead add a private, or public * no-args constructor. However, that is not possible for library classes, such as JDK classes, or * a third-party library that you do not have source-code of. In such cases, you should define an * instance creator for the class. Implementations of this interface should be registered with * {@link GsonBuilder#registerTypeAdapter(Type, Object)} method before Gson will be able to use * them. *

Let us look at an example where defining an InstanceCreator might be useful. The * {@code Id} class defined below does not have a default no-args constructor.

* *
 * public class Id<T> {
 *   private final Class<T> clazz;
 *   private final long value;
 *   public Id(Class<T> clazz, long value) {
 *     this.clazz = clazz;
 *     this.value = value;
 *   }
 * }
 * 
* *

If Gson encounters an object of type {@code Id} during deserialization, it will throw an * exception. The easiest way to solve this problem will be to add a (public or private) no-args * constructor as follows:

* *
 * private Id() {
 *   this(Object.class, 0L);
 * }
 * 
* *

However, let us assume that the developer does not have access to the source-code of the * {@code Id} class, or does not want to define a no-args constructor for it. The developer * can solve this problem by defining an {@code InstanceCreator} for {@code Id}:

* *
 * class IdInstanceCreator implements InstanceCreator<Id> {
 *   public Id createInstance(Type type) {
 *     return new Id(Object.class, 0L);
 *   }
 * }
 * 
* *

Note that it does not matter what the fields of the created instance contain since Gson will * overwrite them with the deserialized values specified in Json. You should also ensure that a * new object is returned, not a common object since its fields will be overwritten. * The developer will need to register {@code IdInstanceCreator} with Gson as follows:

* *
 * Gson gson = new GsonBuilder().registerTypeAdapter(Id.class, new IdInstanceCreator()).create();
 * 
* * @param the type of object that will be created by this implementation. * * @author Inderjeet Singh * @author Joel Leitch */ public interface InstanceCreator { /** * Gson invokes this call-back method during deserialization to create an instance of the * specified type. The fields of the returned instance are overwritten with the data present * in the Json. Since the prior contents of the object are destroyed and overwritten, do not * return an instance that is useful elsewhere. In particular, do not return a common instance, * always use {@code new} to create a new instance. * * @param type the parameterized T represented as a {@link Type}. * @return a default object instance of type T. */ public T createInstance(Type type); } google-gson/src/main/java/com/google/gson/JsonIOException.java0000664000175000017500000000250711662265342024162 0ustar ebourgebourg/* * 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; /** * This exception is raised when Gson was unable to read an input stream * or write to one. * * @author Inderjeet Singh * @author Joel Leitch */ public final class JsonIOException extends JsonParseException { private static final long serialVersionUID = 1L; public JsonIOException(String msg) { super(msg); } public JsonIOException(String msg, Throwable cause) { super(msg, cause); } /** * Creates exception with the specified cause. Consider using * {@link #JsonIOException(String, Throwable)} instead if you can describe what happened. * * @param cause root exception that caused this exception to be thrown. */ public JsonIOException(Throwable cause) { super(cause); } } google-gson/src/main/java/com/google/gson/JsonDeserializationContext.java0000664000175000017500000000320211641462661026460 0ustar ebourgebourg/* * 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; import java.lang.reflect.Type; /** * Context for deserialization that is passed to a custom deserializer during invocation of its * {@link JsonDeserializer#deserialize(JsonElement, Type, JsonDeserializationContext)} * method. * * @author Inderjeet Singh * @author Joel Leitch */ public interface JsonDeserializationContext { /** * Invokes default deserialization on the specified object. It should never be invoked on * the element received as a parameter of the * {@link JsonDeserializer#deserialize(JsonElement, Type, JsonDeserializationContext)} method. Doing * so will result in an infinite loop since Gson will in-turn call the custom deserializer again. * * @param json the parse tree. * @param typeOfT type of the expected return value. * @param The type of the deserialized object. * @return An object of type typeOfT. * @throws JsonParseException if the parse tree does not contain expected data. */ public T deserialize(JsonElement json, Type typeOfT) throws JsonParseException; }google-gson/src/main/java/com/google/gson/JsonStreamParser.java0000664000175000017500000000733411662265342024407 0ustar ebourgebourg/* * Copyright (C) 2009 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; import java.io.EOFException; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.Iterator; import java.util.NoSuchElementException; import com.google.gson.internal.Streams; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonToken; import com.google.gson.stream.MalformedJsonException; /** * A streaming parser that allows reading of multiple {@link JsonElement}s from the specified reader * asynchronously. * *

This class is conditionally thread-safe (see Item 70, Effective Java second edition). To * properly use this class across multiple threads, you will need to add some external * synchronization. For example: * *

 * JsonStreamParser parser = new JsonStreamParser("['first'] {'second':10} 'third'");
 * JsonElement element;
 * synchronized (parser) {  // synchronize on an object shared by threads
 *   if (parser.hasNext()) {
 *     element = parser.next();
 *   }
 * }
 * 
* * @author Inderjeet Singh * @author Joel Leitch * @since 1.4 */ public final class JsonStreamParser implements Iterator { private final JsonReader parser; private final Object lock; /** * @param json The string containing JSON elements concatenated to each other. * @since 1.4 */ public JsonStreamParser(String json) { this(new StringReader(json)); } /** * @param reader The data stream containing JSON elements concatenated to each other. * @since 1.4 */ public JsonStreamParser(Reader reader) { parser = new JsonReader(reader); parser.setLenient(true); lock = new Object(); } /** * Returns the next available {@link JsonElement} on the reader. Null if none available. * * @return the next available {@link JsonElement} on the reader. Null if none available. * @throws JsonParseException if the incoming stream is malformed JSON. * @since 1.4 */ public JsonElement next() throws JsonParseException { if (!hasNext()) { throw new NoSuchElementException(); } try { return Streams.parse(parser); } catch (StackOverflowError e) { throw new JsonParseException("Failed parsing JSON source to Json", e); } catch (OutOfMemoryError e) { throw new JsonParseException("Failed parsing JSON source to Json", e); } catch (JsonParseException e) { throw e.getCause() instanceof EOFException ? new NoSuchElementException() : e; } } /** * Returns true if a {@link JsonElement} is available on the input for consumption * @return true if a {@link JsonElement} is available on the input, false otherwise * @since 1.4 */ public boolean hasNext() { synchronized (lock) { try { return parser.peek() != JsonToken.END_DOCUMENT; } catch (MalformedJsonException e) { throw new JsonSyntaxException(e); } catch (IOException e) { throw new JsonIOException(e); } } } /** * This optional {@link Iterator} method is not relevant for stream parsing and hence is not * implemented. * @since 1.4 */ public void remove() { throw new UnsupportedOperationException(); } } google-gson/src/main/java/com/google/gson/annotations/0000775000175000017500000000000012207114635022622 5ustar ebourgebourggoogle-gson/src/main/java/com/google/gson/annotations/package-info.java0000664000175000017500000000026111012435371026004 0ustar ebourgebourg/** * This package provides annotations that can be used with {@link com.google.gson.Gson}. * * @author Inderjeet Singh, Joel Leitch */ package com.google.gson.annotations;google-gson/src/main/java/com/google/gson/annotations/Since.java0000664000175000017500000000430411164717143024533 0ustar ebourgebourg/* * 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.annotations; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * An annotation that indicates the version number since a member or a type has been present. * This annotation is useful to manage versioning of your Json classes for a web-service. * *

* This annotation has no effect unless you build {@link com.google.gson.Gson} with a * {@link com.google.gson.GsonBuilder} and invoke * {@link com.google.gson.GsonBuilder#setVersion(double)} method. * *

Here is an example of how this annotation is meant to be used:

*
 * public class User {
 *   private String firstName;
 *   private String lastName;
 *   @Since(1.0) private String emailAddress;
 *   @Since(1.0) private String password;
 *   @Since(1.1) private Address address;
 * }
 * 
* *

If you created Gson with {@code new Gson()}, the {@code toJson()} and {@code fromJson()} * methods will use all the fields for serialization and deserialization. However, if you created * Gson with {@code Gson gson = new GsonBuilder().setVersion(1.0).create()} then the * {@code toJson()} and {@code fromJson()} methods of Gson will exclude the {@code address} field * since it's version number is set to {@code 1.1}.

* * @author Inderjeet Singh * @author Joel Leitch */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD, ElementType.TYPE}) public @interface Since { /** * the value indicating a version number since this member * or type has been present. */ double value(); } google-gson/src/main/java/com/google/gson/annotations/Until.java0000664000175000017500000000477511164717143024601 0ustar ebourgebourg/* * 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.annotations; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * An annotation that indicates the version number until a member or a type should be present. * Basically, if Gson is created with a version number that exceeds the value stored in the * {@code Until} annotation then the field will be ignored from the JSON output. This annotation * is useful to manage versioning of your JSON classes for a web-service. * *

* This annotation has no effect unless you build {@link com.google.gson.Gson} with a * {@link com.google.gson.GsonBuilder} and invoke * {@link com.google.gson.GsonBuilder#setVersion(double)} method. * *

Here is an example of how this annotation is meant to be used:

*
 * public class User {
 *   private String firstName;
 *   private String lastName;
 *   @Until(1.1) private String emailAddress;
 *   @Until(1.1) private String password;
 * }
 * 
* *

If you created Gson with {@code new Gson()}, the {@code toJson()} and {@code fromJson()} * methods will use all the fields for serialization and deserialization. However, if you created * Gson with {@code Gson gson = new GsonBuilder().setVersion(1.2).create()} then the * {@code toJson()} and {@code fromJson()} methods of Gson will exclude the {@code emailAddress} * and {@code password} fields from the example above, because the version number passed to the * GsonBuilder, {@code 1.2}, exceeds the version number set on the {@code Until} annotation, * {@code 1.1}, for those fields. * * @author Inderjeet Singh * @author Joel Leitch * @since 1.3 */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD, ElementType.TYPE}) public @interface Until { /** * the value indicating a version number until this member * or type should be ignored. */ double value(); } google-gson/src/main/java/com/google/gson/annotations/Expose.java0000664000175000017500000000661011262434120024725 0ustar ebourgebourg/* * 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.annotations; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * An annotation that indicates this member should be exposed for JSON * serialization or deserialization. * *

This annotation has no effect unless you build {@link com.google.gson.Gson} * with a {@link com.google.gson.GsonBuilder} and invoke * {@link com.google.gson.GsonBuilder#excludeFieldsWithoutExposeAnnotation()} * method.

* *

Here is an example of how this annotation is meant to be used: *

 * public class User {
 *   @Expose private String firstName;
 *   @Expose(serialize = false) private String lastName;
 *   @Expose (serialize = false, deserialize = false) private String emailAddress;
 *   private String password;
 * }
 * 

* If you created Gson with {@code new Gson()}, the {@code toJson()} and {@code fromJson()} * methods will use the {@code password} field along-with {@code firstName}, {@code lastName}, * and {@code emailAddress} for serialization and deserialization. However, if you created Gson * with {@code Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create()} * then the {@code toJson()} and {@code fromJson()} methods of Gson will exclude the * {@code password} field. This is because the {@code password} field is not marked with the * {@code @Expose} annotation. Gson will also exclude {@code lastName} and {@code emailAddress} * from serialization since {@code serialize} is set to {@code false}. Similarly, Gson will * exclude {@code emailAddress} from deserialization since {@code deserialize} is set to false. * *

Note that another way to achieve the same effect would have been to just mark the * {@code password} field as {@code transient}, and Gson would have excluded it even with default * settings. The {@code @Expose} annotation is useful in a style of programming where you want to * explicitly specify all fields that should get considered for serialization or deserialization. * * @author Inderjeet Singh * @author Joel Leitch */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Expose { /** * If {@code true}, the field marked with this annotation is written out in the JSON while * serializing. If {@code false}, the field marked with this annotation is skipped from the * serialized output. Defaults to {@code true}. * @since 1.4 */ public boolean serialize() default true; /** * If {@code true}, the field marked with this annotation is deserialized from the JSON. * If {@code false}, the field marked with this annotation is skipped during deserialization. * Defaults to {@code true}. * @since 1.4 */ public boolean deserialize() default true; } google-gson/src/main/java/com/google/gson/annotations/SerializedName.java0000664000175000017500000000470511164717143026373 0ustar ebourgebourg/* * 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.annotations; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * An annotation that indicates this member should be serialized to JSON with * the provided name value as its field name. * *

This annotation will override any {@link com.google.gson.FieldNamingPolicy}, including * the default field naming policy, that may have been set on the {@link com.google.gson.Gson} * instance. A different naming policy can set using the {@code GsonBuilder} class. See * {@link com.google.gson.GsonBuilder#setFieldNamingPolicy(com.google.gson.FieldNamingPolicy)} * for more information.

* *

Here is an example of how this annotation is meant to be used:

*
 * public class SomeClassWithFields {
 *   @SerializedName("name") private final String someField;
 *   private final String someOtherField;
 *
 *   public SomeClassWithFields(String a, String b) {
 *     this.someField = a;
 *     this.someOtherField = b;
 *   }
 * }
 * 
* *

The following shows the output that is generated when serializing an instance of the * above example class:

*
 * SomeClassWithFields objectToSerialize = new SomeClassWithFields("a", "b");
 * Gson gson = new Gson();
 * String jsonRepresentation = gson.toJson(objectToSerialize);
 * System.out.println(jsonRepresentation);
 *
 * ===== OUTPUT =====
 * {"name":"a","someOtherField":"b"}
 * 
* *

NOTE: The value you specify in this annotation must be a valid JSON field name.

* * @see com.google.gson.FieldNamingPolicy * * @author Inderjeet Singh * @author Joel Leitch */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface SerializedName { /** * @return the desired name of the field when it is serialized */ String value(); } google-gson/src/main/java/com/google/gson/JsonParser.java0000775000175000017500000000613311773644753023244 0ustar ebourgebourg/* * Copyright (C) 2009 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; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import com.google.gson.internal.Streams; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonToken; import com.google.gson.stream.MalformedJsonException; /** * A parser to parse Json into a parse tree of {@link JsonElement}s * * @author Inderjeet Singh * @author Joel Leitch * @since 1.3 */ public final class JsonParser { /** * Parses the specified JSON string into a parse tree * * @param json JSON text * @return a parse tree of {@link JsonElement}s corresponding to the specified JSON * @throws JsonParseException if the specified text is not valid JSON * @since 1.3 */ public JsonElement parse(String json) throws JsonSyntaxException { return parse(new StringReader(json)); } /** * Parses the specified JSON string into a parse tree * * @param json JSON text * @return a parse tree of {@link JsonElement}s corresponding to the specified JSON * @throws JsonParseException if the specified text is not valid JSON * @since 1.3 */ public JsonElement parse(Reader json) throws JsonIOException, JsonSyntaxException { try { JsonReader jsonReader = new JsonReader(json); JsonElement element = parse(jsonReader); if (!element.isJsonNull() && jsonReader.peek() != JsonToken.END_DOCUMENT) { throw new JsonSyntaxException("Did not consume the entire document."); } return element; } catch (MalformedJsonException e) { throw new JsonSyntaxException(e); } catch (IOException e) { throw new JsonIOException(e); } catch (NumberFormatException e) { throw new JsonSyntaxException(e); } } /** * Returns the next value from the JSON stream as a parse tree. * * @throws JsonParseException if there is an IOException or if the specified * text is not valid JSON * @since 1.6 */ public JsonElement parse(JsonReader json) throws JsonIOException, JsonSyntaxException { boolean lenient = json.isLenient(); json.setLenient(true); try { return Streams.parse(json); } catch (StackOverflowError e) { throw new JsonParseException("Failed parsing JSON source: " + json + " to Json", e); } catch (OutOfMemoryError e) { throw new JsonParseException("Failed parsing JSON source: " + json + " to Json", e); } finally { json.setLenient(lenient); } } } google-gson/src/main/java/com/google/gson/GsonBuilder.java0000664000175000017500000005650211773463175023372 0ustar ebourgebourg/* * 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; import java.lang.reflect.Type; import java.sql.Timestamp; import java.text.DateFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import com.google.gson.internal.$Gson$Preconditions; import com.google.gson.internal.Excluder; import com.google.gson.internal.bind.TypeAdapters; import com.google.gson.reflect.TypeToken; /** *

Use this builder to construct a {@link Gson} instance when you need to set configuration * options other than the default. For {@link Gson} with default configuration, it is simpler to * use {@code new Gson()}. {@code GsonBuilder} is best used by creating it, and then invoking its * various configuration methods, and finally calling create.

* *

The following is an example shows how to use the {@code GsonBuilder} to construct a Gson * instance: * *

 * Gson gson = new GsonBuilder()
 *     .registerTypeAdapter(Id.class, new IdTypeAdapter())
 *     .enableComplexMapKeySerialization()
 *     .serializeNulls()
 *     .setDateFormat(DateFormat.LONG)
 *     .setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)
 *     .setPrettyPrinting()
 *     .setVersion(1.0)
 *     .create();
 * 

* *

NOTES: *

    *
  • the order of invocation of configuration methods does not matter.
  • *
  • The default serialization of {@link Date} and its subclasses in Gson does * not contain time-zone information. So, if you are using date/time instances, * use {@code GsonBuilder} and its {@code setDateFormat} methods.
  • *
*

* * @author Inderjeet Singh * @author Joel Leitch * @author Jesse Wilson */ public final class GsonBuilder { private Excluder excluder = Excluder.DEFAULT; private LongSerializationPolicy longSerializationPolicy = LongSerializationPolicy.DEFAULT; private FieldNamingStrategy fieldNamingPolicy = FieldNamingPolicy.IDENTITY; private final Map> instanceCreators = new HashMap>(); private final List factories = new ArrayList(); /** tree-style hierarchy factories. These come after factories for backwards compatibility. */ private final List hierarchyFactories = new ArrayList(); private boolean serializeNulls; private String datePattern; private int dateStyle = DateFormat.DEFAULT; private int timeStyle = DateFormat.DEFAULT; private boolean complexMapKeySerialization; private boolean serializeSpecialFloatingPointValues; private boolean escapeHtmlChars = true; private boolean prettyPrinting; private boolean generateNonExecutableJson; /** * Creates a GsonBuilder instance that can be used to build Gson with various configuration * settings. GsonBuilder follows the builder pattern, and it is typically used by first * invoking various configuration methods to set desired options, and finally calling * {@link #create()}. */ public GsonBuilder() { } /** * Configures Gson to enable versioning support. * * @param ignoreVersionsAfter any field or type marked with a version higher than this value * are ignored during serialization or deserialization. * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern */ public GsonBuilder setVersion(double ignoreVersionsAfter) { excluder = excluder.withVersion(ignoreVersionsAfter); return this; } /** * Configures Gson to excludes all class fields that have the specified modifiers. By default, * Gson will exclude all fields marked transient or static. This method will override that * behavior. * * @param modifiers the field modifiers. You must use the modifiers specified in the * {@link java.lang.reflect.Modifier} class. For example, * {@link java.lang.reflect.Modifier#TRANSIENT}, * {@link java.lang.reflect.Modifier#STATIC}. * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern */ public GsonBuilder excludeFieldsWithModifiers(int... modifiers) { excluder = excluder.withModifiers(modifiers); return this; } /** * Makes the output JSON non-executable in Javascript by prefixing the generated JSON with some * special text. This prevents attacks from third-party sites through script sourcing. See * Gson Issue 42 * for details. * * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern * @since 1.3 */ public GsonBuilder generateNonExecutableJson() { this.generateNonExecutableJson = true; return this; } /** * Configures Gson to exclude all fields from consideration for serialization or deserialization * that do not have the {@link com.google.gson.annotations.Expose} annotation. * * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern */ public GsonBuilder excludeFieldsWithoutExposeAnnotation() { excluder = excluder.excludeFieldsWithoutExposeAnnotation(); return this; } /** * Configure Gson to serialize null fields. By default, Gson omits all fields that are null * during serialization. * * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern * @since 1.2 */ public GsonBuilder serializeNulls() { this.serializeNulls = true; return this; } /** * Enabling this feature will only change the serialized form if the map key is * a complex type (i.e. non-primitive) in its serialized JSON * form. The default implementation of map serialization uses {@code toString()} * on the key; however, when this is called then one of the following cases * apply: * *

Maps as JSON objects

* For this case, assume that a type adapter is registered to serialize and * deserialize some {@code Point} class, which contains an x and y coordinate, * to/from the JSON Primitive string value {@code "(x,y)"}. The Java map would * then be serialized as a {@link JsonObject}. * *

Below is an example: *

  {@code
   *   Gson gson = new GsonBuilder()
   *       .register(Point.class, new MyPointTypeAdapter())
   *       .enableComplexMapKeySerialization()
   *       .create();
   *
   *   Map original = new LinkedHashMap();
   *   original.put(new Point(5, 6), "a");
   *   original.put(new Point(8, 8), "b");
   *   System.out.println(gson.toJson(original, type));
   * }
* The above code prints this JSON object:
  {@code
   *   {
   *     "(5,6)": "a",
   *     "(8,8)": "b"
   *   }
   * }
* *

Maps as JSON arrays

* For this case, assume that a type adapter was NOT registered for some * {@code Point} class, but rather the default Gson serialization is applied. * In this case, some {@code new Point(2,3)} would serialize as {@code * {"x":2,"y":5}}. * *

Given the assumption above, a {@code Map} will be * serialize as an array of arrays (can be viewed as an entry set of pairs). * *

Below is an example of serializing complex types as JSON arrays: *

 {@code
   *   Gson gson = new GsonBuilder()
   *       .enableComplexMapKeySerialization()
   *       .create();
   *
   *   Map original = new LinkedHashMap();
   *   original.put(new Point(5, 6), "a");
   *   original.put(new Point(8, 8), "b");
   *   System.out.println(gson.toJson(original, type));
   * }
   *
   * The JSON output would look as follows:
   * 
   {@code
   *   [
   *     [
   *       {
   *         "x": 5,
   *         "y": 6
   *       },
   *       "a"
   *     ],
   *     [
   *       {
   *         "x": 8,
   *         "y": 8
   *       },
   *       "b"
   *     ]
   *   ]
   * }
* * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern * @since 1.7 */ public GsonBuilder enableComplexMapKeySerialization() { complexMapKeySerialization = true; return this; } /** * Configures Gson to exclude inner classes during serialization. * * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern * @since 1.3 */ public GsonBuilder disableInnerClassSerialization() { excluder = excluder.disableInnerClassSerialization(); return this; } /** * Configures Gson to apply a specific serialization policy for {@code Long} and {@code long} * objects. * * @param serializationPolicy the particular policy to use for serializing longs. * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern * @since 1.3 */ public GsonBuilder setLongSerializationPolicy(LongSerializationPolicy serializationPolicy) { this.longSerializationPolicy = serializationPolicy; return this; } /** * Configures Gson to apply a specific naming policy to an object's field during serialization * and deserialization. * * @param namingConvention the JSON field naming convention to use for serialization and * deserialization. * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern */ public GsonBuilder setFieldNamingPolicy(FieldNamingPolicy namingConvention) { this.fieldNamingPolicy = namingConvention; return this; } /** * Configures Gson to apply a specific naming policy strategy to an object's field during * serialization and deserialization. * * @param fieldNamingStrategy the actual naming strategy to apply to the fields * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern * @since 1.3 */ public GsonBuilder setFieldNamingStrategy(FieldNamingStrategy fieldNamingStrategy) { this.fieldNamingPolicy = fieldNamingStrategy; return this; } /** * Configures Gson to apply a set of exclusion strategies during both serialization and * deserialization. Each of the {@code strategies} will be applied as a disjunction rule. * This means that if one of the {@code strategies} suggests that a field (or class) should be * skipped then that field (or object) is skipped during serializaiton/deserialization. * * @param strategies the set of strategy object to apply during object (de)serialization. * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern * @since 1.4 */ public GsonBuilder setExclusionStrategies(ExclusionStrategy... strategies) { for (ExclusionStrategy strategy : strategies) { excluder = excluder.withExclusionStrategy(strategy, true, true); } return this; } /** * Configures Gson to apply the passed in exclusion strategy during serialization. * If this method is invoked numerous times with different exclusion strategy objects * then the exclusion strategies that were added will be applied as a disjunction rule. * This means that if one of the added exclusion strategies suggests that a field (or * class) should be skipped then that field (or object) is skipped during its * serialization. * * @param strategy an exclusion strategy to apply during serialization. * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern * @since 1.7 */ public GsonBuilder addSerializationExclusionStrategy(ExclusionStrategy strategy) { excluder = excluder.withExclusionStrategy(strategy, true, false); return this; } /** * Configures Gson to apply the passed in exclusion strategy during deserialization. * If this method is invoked numerous times with different exclusion strategy objects * then the exclusion strategies that were added will be applied as a disjunction rule. * This means that if one of the added exclusion strategies suggests that a field (or * class) should be skipped then that field (or object) is skipped during its * deserialization. * * @param strategy an exclusion strategy to apply during deserialization. * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern * @since 1.7 */ public GsonBuilder addDeserializationExclusionStrategy(ExclusionStrategy strategy) { excluder = excluder.withExclusionStrategy(strategy, false, true); return this; } /** * Configures Gson to output Json that fits in a page for pretty printing. This option only * affects Json serialization. * * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern */ public GsonBuilder setPrettyPrinting() { prettyPrinting = true; return this; } /** * By default, Gson escapes HTML characters such as < > etc. Use this option to configure * Gson to pass-through HTML characters as is. * * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern * @since 1.3 */ public GsonBuilder disableHtmlEscaping() { this.escapeHtmlChars = false; return this; } /** * Configures Gson to serialize {@code Date} objects according to the pattern provided. You can * call this method or {@link #setDateFormat(int)} multiple times, but only the last invocation * will be used to decide the serialization format. * *

The date format will be used to serialize and deserialize {@link java.util.Date}, {@link * java.sql.Timestamp} and {@link java.sql.Date}. * *

Note that this pattern must abide by the convention provided by {@code SimpleDateFormat} * class. See the documentation in {@link java.text.SimpleDateFormat} for more information on * valid date and time patterns.

* * @param pattern the pattern that dates will be serialized/deserialized to/from * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern * @since 1.2 */ public GsonBuilder setDateFormat(String pattern) { // TODO(Joel): Make this fail fast if it is an invalid date format this.datePattern = pattern; return this; } /** * Configures Gson to to serialize {@code Date} objects according to the style value provided. * You can call this method or {@link #setDateFormat(String)} multiple times, but only the last * invocation will be used to decide the serialization format. * *

Note that this style value should be one of the predefined constants in the * {@code DateFormat} class. See the documentation in {@link java.text.DateFormat} for more * information on the valid style constants.

* * @param style the predefined date style that date objects will be serialized/deserialized * to/from * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern * @since 1.2 */ public GsonBuilder setDateFormat(int style) { this.dateStyle = style; this.datePattern = null; return this; } /** * Configures Gson to to serialize {@code Date} objects according to the style value provided. * You can call this method or {@link #setDateFormat(String)} multiple times, but only the last * invocation will be used to decide the serialization format. * *

Note that this style value should be one of the predefined constants in the * {@code DateFormat} class. See the documentation in {@link java.text.DateFormat} for more * information on the valid style constants.

* * @param dateStyle the predefined date style that date objects will be serialized/deserialized * to/from * @param timeStyle the predefined style for the time portion of the date objects * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern * @since 1.2 */ public GsonBuilder setDateFormat(int dateStyle, int timeStyle) { this.dateStyle = dateStyle; this.timeStyle = timeStyle; this.datePattern = null; return this; } /** * Configures Gson for custom serialization or deserialization. This method combines the * registration of an {@link TypeAdapter}, {@link InstanceCreator}, {@link JsonSerializer}, and a * {@link JsonDeserializer}. It is best used when a single object {@code typeAdapter} implements * all the required interfaces for custom serialization with Gson. If a type adapter was * previously registered for the specified {@code type}, it is overwritten. * *

This registers the type specified and no other types: you must manually register related * types! For example, applications registering {@code boolean.class} should also register {@code * Boolean.class}. * * @param type the type definition for the type adapter being registered * @param typeAdapter This object must implement at least one of the {@link TypeAdapter}, * {@link InstanceCreator}, {@link JsonSerializer}, and a {@link JsonDeserializer} interfaces. * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern */ @SuppressWarnings({"unchecked", "rawtypes"}) public GsonBuilder registerTypeAdapter(Type type, Object typeAdapter) { $Gson$Preconditions.checkArgument(typeAdapter instanceof JsonSerializer || typeAdapter instanceof JsonDeserializer || typeAdapter instanceof InstanceCreator || typeAdapter instanceof TypeAdapter); if (typeAdapter instanceof InstanceCreator) { instanceCreators.put(type, (InstanceCreator) typeAdapter); } if (typeAdapter instanceof JsonSerializer || typeAdapter instanceof JsonDeserializer) { TypeToken typeToken = TypeToken.get(type); factories.add(TreeTypeAdapter.newFactoryWithMatchRawType(typeToken, typeAdapter)); } if (typeAdapter instanceof TypeAdapter) { factories.add(TypeAdapters.newFactory(TypeToken.get(type), (TypeAdapter)typeAdapter)); } return this; } /** * Register a factory for type adapters. Registering a factory is useful when the type * adapter needs to be configured based on the type of the field being processed. Gson * is designed to handle a large number of factories, so you should consider registering * them to be at par with registering an individual type adapter. * * @since 2.1 */ public GsonBuilder registerTypeAdapterFactory(TypeAdapterFactory factory) { factories.add(factory); return this; } /** * Configures Gson for custom serialization or deserialization for an inheritance type hierarchy. * This method combines the registration of a {@link TypeAdapter}, {@link JsonSerializer} and * a {@link JsonDeserializer}. If a type adapter was previously registered for the specified * type hierarchy, it is overridden. If a type adapter is registered for a specific type in * the type hierarchy, it will be invoked instead of the one registered for the type hierarchy. * * @param baseType the class definition for the type adapter being registered for the base class * or interface * @param typeAdapter This object must implement at least one of {@link TypeAdapter}, * {@link JsonSerializer} or {@link JsonDeserializer} interfaces. * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern * @since 1.7 */ @SuppressWarnings({"unchecked", "rawtypes"}) public GsonBuilder registerTypeHierarchyAdapter(Class baseType, Object typeAdapter) { $Gson$Preconditions.checkArgument(typeAdapter instanceof JsonSerializer || typeAdapter instanceof JsonDeserializer || typeAdapter instanceof TypeAdapter); if (typeAdapter instanceof JsonDeserializer || typeAdapter instanceof JsonSerializer) { hierarchyFactories.add(0, TreeTypeAdapter.newTypeHierarchyFactory(baseType, typeAdapter)); } if (typeAdapter instanceof TypeAdapter) { factories.add(TypeAdapters.newTypeHierarchyFactory(baseType, (TypeAdapter)typeAdapter)); } return this; } /** * Section 2.4 of JSON specification disallows * special double values (NaN, Infinity, -Infinity). However, * Javascript * specification (see section 4.3.20, 4.3.22, 4.3.23) allows these values as valid Javascript * values. Moreover, most JavaScript engines will accept these special values in JSON without * problem. So, at a practical level, it makes sense to accept these values as valid JSON even * though JSON specification disallows them. * *

Gson always accepts these special values during deserialization. However, it outputs * strictly compliant JSON. Hence, if it encounters a float value {@link Float#NaN}, * {@link Float#POSITIVE_INFINITY}, {@link Float#NEGATIVE_INFINITY}, or a double value * {@link Double#NaN}, {@link Double#POSITIVE_INFINITY}, {@link Double#NEGATIVE_INFINITY}, it * will throw an {@link IllegalArgumentException}. This method provides a way to override the * default behavior when you know that the JSON receiver will be able to handle these special * values. * * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern * @since 1.3 */ public GsonBuilder serializeSpecialFloatingPointValues() { this.serializeSpecialFloatingPointValues = true; return this; } /** * Creates a {@link Gson} instance based on the current configuration. This method is free of * side-effects to this {@code GsonBuilder} instance and hence can be called multiple times. * * @return an instance of Gson configured with the options currently set in this builder */ public Gson create() { List factories = new ArrayList(); factories.addAll(this.factories); Collections.reverse(factories); factories.addAll(this.hierarchyFactories); addTypeAdaptersForDate(datePattern, dateStyle, timeStyle, factories); return new Gson(excluder, fieldNamingPolicy, instanceCreators, serializeNulls, complexMapKeySerialization, generateNonExecutableJson, escapeHtmlChars, prettyPrinting, serializeSpecialFloatingPointValues, longSerializationPolicy, factories); } private void addTypeAdaptersForDate(String datePattern, int dateStyle, int timeStyle, List factories) { DefaultDateTypeAdapter dateTypeAdapter; if (datePattern != null && !"".equals(datePattern.trim())) { dateTypeAdapter = new DefaultDateTypeAdapter(datePattern); } else if (dateStyle != DateFormat.DEFAULT && timeStyle != DateFormat.DEFAULT) { dateTypeAdapter = new DefaultDateTypeAdapter(dateStyle, timeStyle); } else { return; } factories.add(TreeTypeAdapter.newFactory(TypeToken.get(Date.class), dateTypeAdapter)); factories.add(TreeTypeAdapter.newFactory(TypeToken.get(Timestamp.class), dateTypeAdapter)); factories.add(TreeTypeAdapter.newFactory(TypeToken.get(java.sql.Date.class), dateTypeAdapter)); } } google-gson/src/main/java/com/google/gson/FieldNamingPolicy.java0000664000175000017500000001313511662356307024500 0ustar ebourgebourg/* * 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; import java.lang.reflect.Field; /** * An enumeration that defines a few standard naming conventions for JSON field names. * This enumeration should be used in conjunction with {@link com.google.gson.GsonBuilder} * to configure a {@link com.google.gson.Gson} instance to properly translate Java field * names into the desired JSON field names. * * @author Inderjeet Singh * @author Joel Leitch */ public enum FieldNamingPolicy implements FieldNamingStrategy { /** * Using this naming policy with Gson will ensure that the field name is * unchanged. */ IDENTITY() { public String translateName(Field f) { return f.getName(); } }, /** * Using this naming policy with Gson will ensure that the first "letter" of the Java * field name is capitalized when serialized to its JSON form. * *

Here's a few examples of the form "Java Field Name" ---> "JSON Field Name":

*
    *
  • someFieldName ---> SomeFieldName
  • *
  • _someFieldName ---> _SomeFieldName
  • *
*/ UPPER_CAMEL_CASE() { public String translateName(Field f) { return upperCaseFirstLetter(f.getName()); } }, /** * Using this naming policy with Gson will ensure that the first "letter" of the Java * field name is capitalized when serialized to its JSON form and the words will be * separated by a space. * *

Here's a few examples of the form "Java Field Name" ---> "JSON Field Name":

*
    *
  • someFieldName ---> Some Field Name
  • *
  • _someFieldName ---> _Some Field Name
  • *
* * @since 1.4 */ UPPER_CAMEL_CASE_WITH_SPACES() { public String translateName(Field f) { return upperCaseFirstLetter(separateCamelCase(f.getName(), " ")); } }, /** * Using this naming policy with Gson will modify the Java Field name from its camel cased * form to a lower case field name where each word is separated by an underscore (_). * *

Here's a few examples of the form "Java Field Name" ---> "JSON Field Name":

*
    *
  • someFieldName ---> some_field_name
  • *
  • _someFieldName ---> _some_field_name
  • *
  • aStringField ---> a_string_field
  • *
  • aURL ---> a_u_r_l
  • *
*/ LOWER_CASE_WITH_UNDERSCORES() { public String translateName(Field f) { return separateCamelCase(f.getName(), "_").toLowerCase(); } }, /** * Using this naming policy with Gson will modify the Java Field name from its camel cased * form to a lower case field name where each word is separated by a dash (-). * *

Here's a few examples of the form "Java Field Name" ---> "JSON Field Name":

*
    *
  • someFieldName ---> some-field-name
  • *
  • _someFieldName ---> _some-field-name
  • *
  • aStringField ---> a-string-field
  • *
  • aURL ---> a-u-r-l
  • *
* Using dashes in JavaScript is not recommended since dash is also used for a minus sign in * expressions. This requires that a field named with dashes is always accessed as a quoted * property like {@code myobject['my-field']}. Accessing it as an object field * {@code myobject.my-field} will result in an unintended javascript expression. * @since 1.4 */ LOWER_CASE_WITH_DASHES() { public String translateName(Field f) { return separateCamelCase(f.getName(), "-").toLowerCase(); } }; /** * Converts the field name that uses camel-case define word separation into * separate words that are separated by the provided {@code separatorString}. */ private static String separateCamelCase(String name, String separator) { StringBuilder translation = new StringBuilder(); for (int i = 0; i < name.length(); i++) { char character = name.charAt(i); if (Character.isUpperCase(character) && translation.length() != 0) { translation.append(separator); } translation.append(character); } return translation.toString(); } /** * Ensures the JSON field names begins with an upper case letter. */ private static String upperCaseFirstLetter(String name) { StringBuilder fieldNameBuilder = new StringBuilder(); int index = 0; char firstCharacter = name.charAt(index); while (index < name.length() - 1) { if (Character.isLetter(firstCharacter)) { break; } fieldNameBuilder.append(firstCharacter); firstCharacter = name.charAt(++index); } if (index == name.length()) { return fieldNameBuilder.toString(); } if (!Character.isUpperCase(firstCharacter)) { String modifiedTarget = modifyString(Character.toUpperCase(firstCharacter), name, ++index); return fieldNameBuilder.append(modifiedTarget).toString(); } else { return name; } } private static String modifyString(char firstCharacter, String srcString, int indexOfSubstring) { return (indexOfSubstring < srcString.length()) ? firstCharacter + srcString.substring(indexOfSubstring) : String.valueOf(firstCharacter); } }google-gson/src/main/java/com/google/gson/TreeTypeAdapter.java0000664000175000017500000001201111741621667024177 0ustar ebourgebourg/* * Copyright (C) 2011 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; import com.google.gson.internal.$Gson$Preconditions; import com.google.gson.internal.Streams; import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; import java.io.IOException; /** * Adapts a Gson 1.x tree-style adapter as a streaming TypeAdapter. Since the * tree adapter may be serialization-only or deserialization-only, this class * has a facility to lookup a delegate type adapter on demand. */ final class TreeTypeAdapter extends TypeAdapter { private final JsonSerializer serializer; private final JsonDeserializer deserializer; private final Gson gson; private final TypeToken typeToken; private final TypeAdapterFactory skipPast; /** The delegate is lazily created because it may not be needed, and creating it may fail. */ private TypeAdapter delegate; private TreeTypeAdapter(JsonSerializer serializer, JsonDeserializer deserializer, Gson gson, TypeToken typeToken, TypeAdapterFactory skipPast) { this.serializer = serializer; this.deserializer = deserializer; this.gson = gson; this.typeToken = typeToken; this.skipPast = skipPast; } @Override public T read(JsonReader in) throws IOException { if (deserializer == null) { return delegate().read(in); } JsonElement value = Streams.parse(in); if (value.isJsonNull()) { return null; } return deserializer.deserialize(value, typeToken.getType(), gson.deserializationContext); } @Override public void write(JsonWriter out, T value) throws IOException { if (serializer == null) { delegate().write(out, value); return; } if (value == null) { out.nullValue(); return; } JsonElement tree = serializer.serialize(value, typeToken.getType(), gson.serializationContext); Streams.write(tree, out); } private TypeAdapter delegate() { TypeAdapter d = delegate; return d != null ? d : (delegate = gson.getDelegateAdapter(skipPast, typeToken)); } /** * Returns a new factory that will match each type against {@code exactType}. */ public static TypeAdapterFactory newFactory(TypeToken exactType, Object typeAdapter) { return new SingleTypeFactory(typeAdapter, exactType, false, null); } /** * Returns a new factory that will match each type and its raw type against * {@code exactType}. */ public static TypeAdapterFactory newFactoryWithMatchRawType( TypeToken exactType, Object typeAdapter) { // only bother matching raw types if exact type is a raw type boolean matchRawType = exactType.getType() == exactType.getRawType(); return new SingleTypeFactory(typeAdapter, exactType, matchRawType, null); } /** * Returns a new factory that will match each type's raw type for assignability * to {@code hierarchyType}. */ public static TypeAdapterFactory newTypeHierarchyFactory( Class hierarchyType, Object typeAdapter) { return new SingleTypeFactory(typeAdapter, null, false, hierarchyType); } private static class SingleTypeFactory implements TypeAdapterFactory { private final TypeToken exactType; private final boolean matchRawType; private final Class hierarchyType; private final JsonSerializer serializer; private final JsonDeserializer deserializer; private SingleTypeFactory(Object typeAdapter, TypeToken exactType, boolean matchRawType, Class hierarchyType) { serializer = typeAdapter instanceof JsonSerializer ? (JsonSerializer) typeAdapter : null; deserializer = typeAdapter instanceof JsonDeserializer ? (JsonDeserializer) typeAdapter : null; $Gson$Preconditions.checkArgument(serializer != null || deserializer != null); this.exactType = exactType; this.matchRawType = matchRawType; this.hierarchyType = hierarchyType; } @SuppressWarnings("unchecked") // guarded by typeToken.equals() call public TypeAdapter create(Gson gson, TypeToken type) { boolean matches = exactType != null ? exactType.equals(type) || matchRawType && exactType.getType() == type.getRawType() : hierarchyType.isAssignableFrom(type.getRawType()); return matches ? new TreeTypeAdapter((JsonSerializer) serializer, (JsonDeserializer) deserializer, gson, type, this) : null; } } } google-gson/src/main/java/com/google/gson/reflect/0000775000175000017500000000000012207114636021712 5ustar ebourgebourggoogle-gson/src/main/java/com/google/gson/reflect/package-info.java0000664000175000017500000000025611012435371025077 0ustar ebourgebourg/** * This package provides utility classes for finding type information for generic types. * * @author Inderjeet Singh, Joel Leitch */ package com.google.gson.reflect;google-gson/src/main/java/com/google/gson/reflect/TypeToken.java0000664000175000017500000002255011662265342024510 0ustar ebourgebourg/* * 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.reflect; import com.google.gson.internal.$Gson$Types; import com.google.gson.internal.$Gson$Preconditions; import java.lang.reflect.GenericArrayType; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import java.util.HashMap; import java.util.Map; /** * Represents a generic type {@code T}. Java doesn't yet provide a way to * represent generic types, so this class does. Forces clients to create a * subclass of this class which enables retrieval the type information even at * runtime. * *

For example, to create a type literal for {@code List}, you can * create an empty anonymous inner class: * *

* {@code TypeToken> list = new TypeToken>() {};} * *

This syntax cannot be used to create type literals that have wildcard * parameters, such as {@code Class} or {@code List}. * * @author Bob Lee * @author Sven Mawson * @author Jesse Wilson */ public class TypeToken { final Class rawType; final Type type; final int hashCode; /** * Constructs a new type literal. Derives represented class from type * parameter. * *

Clients create an empty anonymous subclass. Doing so embeds the type * parameter in the anonymous class's type hierarchy so we can reconstitute it * at runtime despite erasure. */ @SuppressWarnings("unchecked") protected TypeToken() { this.type = getSuperclassTypeParameter(getClass()); this.rawType = (Class) $Gson$Types.getRawType(type); this.hashCode = type.hashCode(); } /** * Unsafe. Constructs a type literal manually. */ @SuppressWarnings("unchecked") TypeToken(Type type) { this.type = $Gson$Types.canonicalize($Gson$Preconditions.checkNotNull(type)); this.rawType = (Class) $Gson$Types.getRawType(this.type); this.hashCode = this.type.hashCode(); } /** * Returns the type from super class's type parameter in {@link $Gson$Types#canonicalize * canonical form}. */ static Type getSuperclassTypeParameter(Class subclass) { Type superclass = subclass.getGenericSuperclass(); if (superclass instanceof Class) { throw new RuntimeException("Missing type parameter."); } ParameterizedType parameterized = (ParameterizedType) superclass; return $Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]); } /** * Returns the raw (non-generic) type for this type. */ public final Class getRawType() { return rawType; } /** * Gets underlying {@code Type} instance. */ public final Type getType() { return type; } /** * Check if this type is assignable from the given class object. * * @deprecated this implementation may be inconsistent with javac for types * with wildcards. */ @Deprecated public boolean isAssignableFrom(Class cls) { return isAssignableFrom((Type) cls); } /** * Check if this type is assignable from the given Type. * * @deprecated this implementation may be inconsistent with javac for types * with wildcards. */ @Deprecated public boolean isAssignableFrom(Type from) { if (from == null) { return false; } if (type.equals(from)) { return true; } if (type instanceof Class) { return rawType.isAssignableFrom($Gson$Types.getRawType(from)); } else if (type instanceof ParameterizedType) { return isAssignableFrom(from, (ParameterizedType) type, new HashMap()); } else if (type instanceof GenericArrayType) { return rawType.isAssignableFrom($Gson$Types.getRawType(from)) && isAssignableFrom(from, (GenericArrayType) type); } else { throw buildUnexpectedTypeError( type, Class.class, ParameterizedType.class, GenericArrayType.class); } } /** * Check if this type is assignable from the given type token. * * @deprecated this implementation may be inconsistent with javac for types * with wildcards. */ @Deprecated public boolean isAssignableFrom(TypeToken token) { return isAssignableFrom(token.getType()); } /** * Private helper function that performs some assignability checks for * the provided GenericArrayType. */ private static boolean isAssignableFrom(Type from, GenericArrayType to) { Type toGenericComponentType = to.getGenericComponentType(); if (toGenericComponentType instanceof ParameterizedType) { Type t = from; if (from instanceof GenericArrayType) { t = ((GenericArrayType) from).getGenericComponentType(); } else if (from instanceof Class) { Class classType = (Class) from; while (classType.isArray()) { classType = classType.getComponentType(); } t = classType; } return isAssignableFrom(t, (ParameterizedType) toGenericComponentType, new HashMap()); } // No generic defined on "to"; therefore, return true and let other // checks determine assignability return true; } /** * Private recursive helper function to actually do the type-safe checking * of assignability. */ private static boolean isAssignableFrom(Type from, ParameterizedType to, Map typeVarMap) { if (from == null) { return false; } if (to.equals(from)) { return true; } // First figure out the class and any type information. Class clazz = $Gson$Types.getRawType(from); ParameterizedType ptype = null; if (from instanceof ParameterizedType) { ptype = (ParameterizedType) from; } // Load up parameterized variable info if it was parameterized. if (ptype != null) { Type[] tArgs = ptype.getActualTypeArguments(); TypeVariable[] tParams = clazz.getTypeParameters(); for (int i = 0; i < tArgs.length; i++) { Type arg = tArgs[i]; TypeVariable var = tParams[i]; while (arg instanceof TypeVariable) { TypeVariable v = (TypeVariable) arg; arg = typeVarMap.get(v.getName()); } typeVarMap.put(var.getName(), arg); } // check if they are equivalent under our current mapping. if (typeEquals(ptype, to, typeVarMap)) { return true; } } for (Type itype : clazz.getGenericInterfaces()) { if (isAssignableFrom(itype, to, new HashMap(typeVarMap))) { return true; } } // Interfaces didn't work, try the superclass. Type sType = clazz.getGenericSuperclass(); return isAssignableFrom(sType, to, new HashMap(typeVarMap)); } /** * Checks if two parameterized types are exactly equal, under the variable * replacement described in the typeVarMap. */ private static boolean typeEquals(ParameterizedType from, ParameterizedType to, Map typeVarMap) { if (from.getRawType().equals(to.getRawType())) { Type[] fromArgs = from.getActualTypeArguments(); Type[] toArgs = to.getActualTypeArguments(); for (int i = 0; i < fromArgs.length; i++) { if (!matches(fromArgs[i], toArgs[i], typeVarMap)) { return false; } } return true; } return false; } private static AssertionError buildUnexpectedTypeError( Type token, Class... expected) { // Build exception message StringBuilder exceptionMessage = new StringBuilder("Unexpected type. Expected one of: "); for (Class clazz : expected) { exceptionMessage.append(clazz.getName()).append(", "); } exceptionMessage.append("but got: ").append(token.getClass().getName()) .append(", for type token: ").append(token.toString()).append('.'); return new AssertionError(exceptionMessage.toString()); } /** * Checks if two types are the same or are equivalent under a variable mapping * given in the type map that was provided. */ private static boolean matches(Type from, Type to, Map typeMap) { return to.equals(from) || (from instanceof TypeVariable && to.equals(typeMap.get(((TypeVariable) from).getName()))); } @Override public final int hashCode() { return this.hashCode; } @Override public final boolean equals(Object o) { return o instanceof TypeToken && $Gson$Types.equals(type, ((TypeToken) o).type); } @Override public final String toString() { return $Gson$Types.typeToString(type); } /** * Gets type literal for the given {@code Type} instance. */ public static TypeToken get(Type type) { return new TypeToken(type); } /** * Gets type literal for the given {@code Class} instance. */ public static TypeToken get(Class type) { return new TypeToken(type); } } google-gson/src/main/java/com/google/gson/JsonPrimitive.java0000664000175000017500000002314412021236623023732 0ustar ebourgebourg/* * 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; import java.math.BigDecimal; import java.math.BigInteger; import com.google.gson.internal.$Gson$Preconditions; import com.google.gson.internal.LazilyParsedNumber; /** * A class representing a Json primitive value. A primitive value * is either a String, a Java primitive, or a Java primitive * wrapper type. * * @author Inderjeet Singh * @author Joel Leitch */ public final class JsonPrimitive extends JsonElement { private static final Class[] PRIMITIVE_TYPES = { int.class, long.class, short.class, float.class, double.class, byte.class, boolean.class, char.class, Integer.class, Long.class, Short.class, Float.class, Double.class, Byte.class, Boolean.class, Character.class }; private Object value; /** * Create a primitive containing a boolean value. * * @param bool the value to create the primitive with. */ public JsonPrimitive(Boolean bool) { setValue(bool); } /** * Create a primitive containing a {@link Number}. * * @param number the value to create the primitive with. */ public JsonPrimitive(Number number) { setValue(number); } /** * Create a primitive containing a String value. * * @param string the value to create the primitive with. */ public JsonPrimitive(String string) { setValue(string); } /** * Create a primitive containing a character. The character is turned into a one character String * since Json only supports String. * * @param c the value to create the primitive with. */ public JsonPrimitive(Character c) { setValue(c); } /** * Create a primitive using the specified Object. It must be an instance of {@link Number}, a * Java primitive type, or a String. * * @param primitive the value to create the primitive with. */ JsonPrimitive(Object primitive) { setValue(primitive); } @Override JsonPrimitive deepCopy() { return this; } void setValue(Object primitive) { if (primitive instanceof Character) { // convert characters to strings since in JSON, characters are represented as a single // character string char c = ((Character) primitive).charValue(); this.value = String.valueOf(c); } else { $Gson$Preconditions.checkArgument(primitive instanceof Number || isPrimitiveOrString(primitive)); this.value = primitive; } } /** * Check whether this primitive contains a boolean value. * * @return true if this primitive contains a boolean value, false otherwise. */ public boolean isBoolean() { return value instanceof Boolean; } /** * convenience method to get this element as a {@link Boolean}. * * @return get this element as a {@link Boolean}. */ @Override Boolean getAsBooleanWrapper() { return (Boolean) value; } /** * convenience method to get this element as a boolean value. * * @return get this element as a primitive boolean value. */ @Override public boolean getAsBoolean() { if (isBoolean()) { return getAsBooleanWrapper().booleanValue(); } else { // Check to see if the value as a String is "true" in any case. return Boolean.parseBoolean(getAsString()); } } /** * Check whether this primitive contains a Number. * * @return true if this primitive contains a Number, false otherwise. */ public boolean isNumber() { return value instanceof Number; } /** * convenience method to get this element as a Number. * * @return get this element as a Number. * @throws NumberFormatException if the value contained is not a valid Number. */ @Override public Number getAsNumber() { return value instanceof String ? new LazilyParsedNumber((String) value) : (Number) value; } /** * Check whether this primitive contains a String value. * * @return true if this primitive contains a String value, false otherwise. */ public boolean isString() { return value instanceof String; } /** * convenience method to get this element as a String. * * @return get this element as a String. */ @Override public String getAsString() { if (isNumber()) { return getAsNumber().toString(); } else if (isBoolean()) { return getAsBooleanWrapper().toString(); } else { return (String) value; } } /** * convenience method to get this element as a primitive double. * * @return get this element as a primitive double. * @throws NumberFormatException if the value contained is not a valid double. */ @Override public double getAsDouble() { return isNumber() ? getAsNumber().doubleValue() : Double.parseDouble(getAsString()); } /** * convenience method to get this element as a {@link BigDecimal}. * * @return get this element as a {@link BigDecimal}. * @throws NumberFormatException if the value contained is not a valid {@link BigDecimal}. */ @Override public BigDecimal getAsBigDecimal() { return value instanceof BigDecimal ? (BigDecimal) value : new BigDecimal(value.toString()); } /** * convenience method to get this element as a {@link BigInteger}. * * @return get this element as a {@link BigInteger}. * @throws NumberFormatException if the value contained is not a valid {@link BigInteger}. */ @Override public BigInteger getAsBigInteger() { return value instanceof BigInteger ? (BigInteger) value : new BigInteger(value.toString()); } /** * convenience method to get this element as a float. * * @return get this element as a float. * @throws NumberFormatException if the value contained is not a valid float. */ @Override public float getAsFloat() { return isNumber() ? getAsNumber().floatValue() : Float.parseFloat(getAsString()); } /** * convenience method to get this element as a primitive long. * * @return get this element as a primitive long. * @throws NumberFormatException if the value contained is not a valid long. */ @Override public long getAsLong() { return isNumber() ? getAsNumber().longValue() : Long.parseLong(getAsString()); } /** * convenience method to get this element as a primitive short. * * @return get this element as a primitive short. * @throws NumberFormatException if the value contained is not a valid short value. */ @Override public short getAsShort() { return isNumber() ? getAsNumber().shortValue() : Short.parseShort(getAsString()); } /** * convenience method to get this element as a primitive integer. * * @return get this element as a primitive integer. * @throws NumberFormatException if the value contained is not a valid integer. */ @Override public int getAsInt() { return isNumber() ? getAsNumber().intValue() : Integer.parseInt(getAsString()); } @Override public byte getAsByte() { return isNumber() ? getAsNumber().byteValue() : Byte.parseByte(getAsString()); } @Override public char getAsCharacter() { return getAsString().charAt(0); } private static boolean isPrimitiveOrString(Object target) { if (target instanceof String) { return true; } Class classOfPrimitive = target.getClass(); for (Class standardPrimitive : PRIMITIVE_TYPES) { if (standardPrimitive.isAssignableFrom(classOfPrimitive)) { return true; } } return false; } @Override public int hashCode() { if (value == null) { return 31; } // Using recommended hashing algorithm from Effective Java for longs and doubles if (isIntegral(this)) { long value = getAsNumber().longValue(); return (int) (value ^ (value >>> 32)); } if (value instanceof Number) { long value = Double.doubleToLongBits(getAsNumber().doubleValue()); return (int) (value ^ (value >>> 32)); } return value.hashCode(); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null || getClass() != obj.getClass()) { return false; } JsonPrimitive other = (JsonPrimitive)obj; if (value == null) { return other.value == null; } if (isIntegral(this) && isIntegral(other)) { return getAsNumber().longValue() == other.getAsNumber().longValue(); } if (value instanceof Number && other.value instanceof Number) { double a = getAsNumber().doubleValue(); // Java standard types other than double return true for two NaN. So, need // special handling for double. double b = other.getAsNumber().doubleValue(); return a == b || (Double.isNaN(a) && Double.isNaN(b)); } return value.equals(other.value); } /** * Returns true if the specified number is an integral type * (Long, Integer, Short, Byte, BigInteger) */ private static boolean isIntegral(JsonPrimitive primitive) { if (primitive.value instanceof Number) { Number number = (Number) primitive.value; return number instanceof BigInteger || number instanceof Long || number instanceof Integer || number instanceof Short || number instanceof Byte; } return false; } } google-gson/src/main/java/com/google/gson/JsonObject.java0000664000175000017500000001413012140760644023172 0ustar ebourgebourg/* * 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; import com.google.gson.internal.LinkedTreeMap; import java.util.Map; import java.util.Set; /** * A class representing an object type in Json. An object consists of name-value pairs where names * are strings, and values are any other type of {@link JsonElement}. This allows for a creating a * tree of JsonElements. The member elements of this object are maintained in order they were added. * * @author Inderjeet Singh * @author Joel Leitch */ public final class JsonObject extends JsonElement { private final LinkedTreeMap members = new LinkedTreeMap(); @Override JsonObject deepCopy() { JsonObject result = new JsonObject(); for (Map.Entry entry : members.entrySet()) { result.add(entry.getKey(), entry.getValue().deepCopy()); } return result; } /** * Adds a member, which is a name-value pair, to self. The name must be a String, but the value * can be an arbitrary JsonElement, thereby allowing you to build a full tree of JsonElements * rooted at this node. * * @param property name of the member. * @param value the member object. */ public void add(String property, JsonElement value) { if (value == null) { value = JsonNull.INSTANCE; } members.put(property, value); } /** * Removes the {@code property} from this {@link JsonObject}. * * @param property name of the member that should be removed. * @return the {@link JsonElement} object that is being removed. * @since 1.3 */ public JsonElement remove(String property) { return members.remove(property); } /** * Convenience method to add a primitive member. The specified value is converted to a * JsonPrimitive of String. * * @param property name of the member. * @param value the string value associated with the member. */ public void addProperty(String property, String value) { add(property, createJsonElement(value)); } /** * Convenience method to add a primitive member. The specified value is converted to a * JsonPrimitive of Number. * * @param property name of the member. * @param value the number value associated with the member. */ public void addProperty(String property, Number value) { add(property, createJsonElement(value)); } /** * Convenience method to add a boolean member. The specified value is converted to a * JsonPrimitive of Boolean. * * @param property name of the member. * @param value the number value associated with the member. */ public void addProperty(String property, Boolean value) { add(property, createJsonElement(value)); } /** * Convenience method to add a char member. The specified value is converted to a * JsonPrimitive of Character. * * @param property name of the member. * @param value the number value associated with the member. */ public void addProperty(String property, Character value) { add(property, createJsonElement(value)); } /** * Creates the proper {@link JsonElement} object from the given {@code value} object. * * @param value the object to generate the {@link JsonElement} for * @return a {@link JsonPrimitive} if the {@code value} is not null, otherwise a {@link JsonNull} */ private JsonElement createJsonElement(Object value) { return value == null ? JsonNull.INSTANCE : new JsonPrimitive(value); } /** * Returns a set of members of this object. The set is ordered, and the order is in which the * elements were added. * * @return a set of members of this object. */ public Set> entrySet() { return members.entrySet(); } /** * Convenience method to check if a member with the specified name is present in this object. * * @param memberName name of the member that is being checked for presence. * @return true if there is a member with the specified name, false otherwise. */ public boolean has(String memberName) { return members.containsKey(memberName); } /** * Returns the member with the specified name. * * @param memberName name of the member that is being requested. * @return the member matching the name. Null if no such member exists. */ public JsonElement get(String memberName) { return members.get(memberName); } /** * Convenience method to get the specified member as a JsonPrimitive element. * * @param memberName name of the member being requested. * @return the JsonPrimitive corresponding to the specified member. */ public JsonPrimitive getAsJsonPrimitive(String memberName) { return (JsonPrimitive) members.get(memberName); } /** * Convenience method to get the specified member as a JsonArray. * * @param memberName name of the member being requested. * @return the JsonArray corresponding to the specified member. */ public JsonArray getAsJsonArray(String memberName) { return (JsonArray) members.get(memberName); } /** * Convenience method to get the specified member as a JsonObject. * * @param memberName name of the member being requested. * @return the JsonObject corresponding to the specified member. */ public JsonObject getAsJsonObject(String memberName) { return (JsonObject) members.get(memberName); } @Override public boolean equals(Object o) { return (o == this) || (o instanceof JsonObject && ((JsonObject) o).members.equals(members)); } @Override public int hashCode() { return members.hashCode(); } } google-gson/src/main/java/com/google/gson/stream/0000775000175000017500000000000012207114635021560 5ustar ebourgebourggoogle-gson/src/main/java/com/google/gson/stream/JsonToken.java0000664000175000017500000000403012020747672024340 0ustar ebourgebourg/* * Copyright (C) 2010 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.stream; /** * A structure, name or value type in a JSON-encoded string. * * @author Jesse Wilson * @since 1.6 */ public enum JsonToken { /** * The opening of a JSON array. Written using {@link JsonWriter#beginArray} * and read using {@link JsonReader#beginArray}. */ BEGIN_ARRAY, /** * The closing of a JSON array. Written using {@link JsonWriter#endArray} * and read using {@link JsonReader#endArray}. */ END_ARRAY, /** * The opening of a JSON object. Written using {@link JsonWriter#beginObject} * and read using {@link JsonReader#beginObject}. */ BEGIN_OBJECT, /** * The closing of a JSON object. Written using {@link JsonWriter#endObject} * and read using {@link JsonReader#endObject}. */ END_OBJECT, /** * A JSON property name. Within objects, tokens alternate between names and * their values. Written using {@link JsonWriter#name} and read using {@link * JsonReader#nextName} */ NAME, /** * A JSON string. */ STRING, /** * A JSON number represented in this API by a Java {@code double}, {@code * long}, or {@code int}. */ NUMBER, /** * A JSON {@code true} or {@code false}. */ BOOLEAN, /** * A JSON {@code null}. */ NULL, /** * The end of the JSON stream. This sentinel value is returned by {@link * JsonReader#peek()} to signal that the JSON-encoded value has no more * tokens. */ END_DOCUMENT } google-gson/src/main/java/com/google/gson/stream/MalformedJsonException.java0000664000175000017500000000276411465650315027060 0ustar ebourgebourg/* * Copyright (C) 2010 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.stream; import java.io.IOException; /** * Thrown when a reader encounters malformed JSON. Some syntax errors can be * ignored by calling {@link JsonReader#setLenient(boolean)}. */ public final class MalformedJsonException extends IOException { private static final long serialVersionUID = 1L; public MalformedJsonException(String msg) { super(msg); } public MalformedJsonException(String msg, Throwable throwable) { super(msg); // Using initCause() instead of calling super() because Java 1.5 didn't retrofit IOException // with a constructor with Throwable. This was done in Java 1.6 initCause(throwable); } public MalformedJsonException(Throwable throwable) { // Using initCause() instead of calling super() because Java 1.5 didn't retrofit IOException // with a constructor with Throwable. This was done in Java 1.6 initCause(throwable); } } google-gson/src/main/java/com/google/gson/stream/JsonWriter.java0000664000175000017500000004413712012541742024537 0ustar ebourgebourg/* * Copyright (C) 2010 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.stream; import java.io.Closeable; import java.io.Flushable; import java.io.IOException; import java.io.Writer; import static com.google.gson.stream.JsonScope.DANGLING_NAME; import static com.google.gson.stream.JsonScope.EMPTY_ARRAY; import static com.google.gson.stream.JsonScope.EMPTY_DOCUMENT; import static com.google.gson.stream.JsonScope.EMPTY_OBJECT; import static com.google.gson.stream.JsonScope.NONEMPTY_ARRAY; import static com.google.gson.stream.JsonScope.NONEMPTY_DOCUMENT; import static com.google.gson.stream.JsonScope.NONEMPTY_OBJECT; /** * Writes a JSON (RFC 4627) * encoded value to a stream, one token at a time. The stream includes both * literal values (strings, numbers, booleans and nulls) as well as the begin * and end delimiters of objects and arrays. * *

Encoding JSON

* To encode your data as JSON, create a new {@code JsonWriter}. Each JSON * document must contain one top-level array or object. Call methods on the * writer as you walk the structure's contents, nesting arrays and objects as * necessary: *
    *
  • To write arrays, first call {@link #beginArray()}. * Write each of the array's elements with the appropriate {@link #value} * methods or by nesting other arrays and objects. Finally close the array * using {@link #endArray()}. *
  • To write objects, first call {@link #beginObject()}. * Write each of the object's properties by alternating calls to * {@link #name} with the property's value. Write property values with the * appropriate {@link #value} method or by nesting other objects or arrays. * Finally close the object using {@link #endObject()}. *
* *

Example

* Suppose we'd like to encode a stream of messages such as the following:
 {@code
 * [
 *   {
 *     "id": 912345678901,
 *     "text": "How do I stream JSON in Java?",
 *     "geo": null,
 *     "user": {
 *       "name": "json_newb",
 *       "followers_count": 41
 *      }
 *   },
 *   {
 *     "id": 912345678902,
 *     "text": "@json_newb just use JsonWriter!",
 *     "geo": [50.454722, -104.606667],
 *     "user": {
 *       "name": "jesse",
 *       "followers_count": 2
 *     }
 *   }
 * ]}
* This code encodes the above structure:
   {@code
 *   public void writeJsonStream(OutputStream out, List messages) throws IOException {
 *     JsonWriter writer = new JsonWriter(new OutputStreamWriter(out, "UTF-8"));
 *     writer.setIndentSpaces(4);
 *     writeMessagesArray(writer, messages);
 *     writer.close();
 *   }
 *
 *   public void writeMessagesArray(JsonWriter writer, List messages) throws IOException {
 *     writer.beginArray();
 *     for (Message message : messages) {
 *       writeMessage(writer, message);
 *     }
 *     writer.endArray();
 *   }
 *
 *   public void writeMessage(JsonWriter writer, Message message) throws IOException {
 *     writer.beginObject();
 *     writer.name("id").value(message.getId());
 *     writer.name("text").value(message.getText());
 *     if (message.getGeo() != null) {
 *       writer.name("geo");
 *       writeDoublesArray(writer, message.getGeo());
 *     } else {
 *       writer.name("geo").nullValue();
 *     }
 *     writer.name("user");
 *     writeUser(writer, message.getUser());
 *     writer.endObject();
 *   }
 *
 *   public void writeUser(JsonWriter writer, User user) throws IOException {
 *     writer.beginObject();
 *     writer.name("name").value(user.getName());
 *     writer.name("followers_count").value(user.getFollowersCount());
 *     writer.endObject();
 *   }
 *
 *   public void writeDoublesArray(JsonWriter writer, List doubles) throws IOException {
 *     writer.beginArray();
 *     for (Double value : doubles) {
 *       writer.value(value);
 *     }
 *     writer.endArray();
 *   }}
* *

Each {@code JsonWriter} may be used to write a single JSON stream. * Instances of this class are not thread safe. Calls that would result in a * malformed JSON string will fail with an {@link IllegalStateException}. * * @author Jesse Wilson * @since 1.6 */ public class JsonWriter implements Closeable, Flushable { /* * From RFC 4627, "All Unicode characters may be placed within the * quotation marks except for the characters that must be escaped: * quotation mark, reverse solidus, and the control characters * (U+0000 through U+001F)." * * We also escape '\u2028' and '\u2029', which JavaScript interprets as * newline characters. This prevents eval() from failing with a syntax * error. http://code.google.com/p/google-gson/issues/detail?id=341 */ private static final String[] REPLACEMENT_CHARS; private static final String[] HTML_SAFE_REPLACEMENT_CHARS; static { REPLACEMENT_CHARS = new String[128]; for (int i = 0; i <= 0x1f; i++) { REPLACEMENT_CHARS[i] = String.format("\\u%04x", (int) i); } REPLACEMENT_CHARS['"'] = "\\\""; REPLACEMENT_CHARS['\\'] = "\\\\"; REPLACEMENT_CHARS['\t'] = "\\t"; REPLACEMENT_CHARS['\b'] = "\\b"; REPLACEMENT_CHARS['\n'] = "\\n"; REPLACEMENT_CHARS['\r'] = "\\r"; REPLACEMENT_CHARS['\f'] = "\\f"; HTML_SAFE_REPLACEMENT_CHARS = REPLACEMENT_CHARS.clone(); HTML_SAFE_REPLACEMENT_CHARS['<'] = "\\u003c"; HTML_SAFE_REPLACEMENT_CHARS['>'] = "\\u003e"; HTML_SAFE_REPLACEMENT_CHARS['&'] = "\\u0026"; HTML_SAFE_REPLACEMENT_CHARS['='] = "\\u003d"; HTML_SAFE_REPLACEMENT_CHARS['\''] = "\\u0027"; } /** The output data, containing at most one top-level array or object. */ private final Writer out; private int[] stack = new int[32]; private int stackSize = 0; { push(EMPTY_DOCUMENT); } /** * A string containing a full set of spaces for a single level of * indentation, or null for no pretty printing. */ private String indent; /** * The name/value separator; either ":" or ": ". */ private String separator = ":"; private boolean lenient; private boolean htmlSafe; private String deferredName; private boolean serializeNulls = true; /** * Creates a new instance that writes a JSON-encoded stream to {@code out}. * For best performance, ensure {@link Writer} is buffered; wrapping in * {@link java.io.BufferedWriter BufferedWriter} if necessary. */ public JsonWriter(Writer out) { if (out == null) { throw new NullPointerException("out == null"); } this.out = out; } /** * Sets the indentation string to be repeated for each level of indentation * in the encoded document. If {@code indent.isEmpty()} the encoded document * will be compact. Otherwise the encoded document will be more * human-readable. * * @param indent a string containing only whitespace. */ public final void setIndent(String indent) { if (indent.length() == 0) { this.indent = null; this.separator = ":"; } else { this.indent = indent; this.separator = ": "; } } /** * Configure this writer to relax its syntax rules. By default, this writer * only emits well-formed JSON as specified by RFC 4627. Setting the writer * to lenient permits the following: *

    *
  • Top-level values of any type. With strict writing, the top-level * value must be an object or an array. *
  • Numbers may be {@link Double#isNaN() NaNs} or {@link * Double#isInfinite() infinities}. *
*/ public final void setLenient(boolean lenient) { this.lenient = lenient; } /** * Returns true if this writer has relaxed syntax rules. */ public boolean isLenient() { return lenient; } /** * Configure this writer to emit JSON that's safe for direct inclusion in HTML * and XML documents. This escapes the HTML characters {@code <}, {@code >}, * {@code &} and {@code =} before writing them to the stream. Without this * setting, your XML/HTML encoder should replace these characters with the * corresponding escape sequences. */ public final void setHtmlSafe(boolean htmlSafe) { this.htmlSafe = htmlSafe; } /** * Returns true if this writer writes JSON that's safe for inclusion in HTML * and XML documents. */ public final boolean isHtmlSafe() { return htmlSafe; } /** * Sets whether object members are serialized when their value is null. * This has no impact on array elements. The default is true. */ public final void setSerializeNulls(boolean serializeNulls) { this.serializeNulls = serializeNulls; } /** * Returns true if object members are serialized when their value is null. * This has no impact on array elements. The default is true. */ public final boolean getSerializeNulls() { return serializeNulls; } /** * Begins encoding a new array. Each call to this method must be paired with * a call to {@link #endArray}. * * @return this writer. */ public JsonWriter beginArray() throws IOException { writeDeferredName(); return open(EMPTY_ARRAY, "["); } /** * Ends encoding the current array. * * @return this writer. */ public JsonWriter endArray() throws IOException { return close(EMPTY_ARRAY, NONEMPTY_ARRAY, "]"); } /** * Begins encoding a new object. Each call to this method must be paired * with a call to {@link #endObject}. * * @return this writer. */ public JsonWriter beginObject() throws IOException { writeDeferredName(); return open(EMPTY_OBJECT, "{"); } /** * Ends encoding the current object. * * @return this writer. */ public JsonWriter endObject() throws IOException { return close(EMPTY_OBJECT, NONEMPTY_OBJECT, "}"); } /** * Enters a new scope by appending any necessary whitespace and the given * bracket. */ private JsonWriter open(int empty, String openBracket) throws IOException { beforeValue(true); push(empty); out.write(openBracket); return this; } /** * Closes the current scope by appending any necessary whitespace and the * given bracket. */ private JsonWriter close(int empty, int nonempty, String closeBracket) throws IOException { int context = peek(); if (context != nonempty && context != empty) { throw new IllegalStateException("Nesting problem."); } if (deferredName != null) { throw new IllegalStateException("Dangling name: " + deferredName); } stackSize--; if (context == nonempty) { newline(); } out.write(closeBracket); return this; } private void push(int newTop) { if (stackSize == stack.length) { int[] newStack = new int[stackSize * 2]; System.arraycopy(stack, 0, newStack, 0, stackSize); stack = newStack; } stack[stackSize++] = newTop; } /** * Returns the value on the top of the stack. */ private int peek() { if (stackSize == 0) { throw new IllegalStateException("JsonWriter is closed."); } return stack[stackSize - 1]; } /** * Replace the value on the top of the stack with the given value. */ private void replaceTop(int topOfStack) { stack[stackSize - 1] = topOfStack; } /** * Encodes the property name. * * @param name the name of the forthcoming value. May not be null. * @return this writer. */ public JsonWriter name(String name) throws IOException { if (name == null) { throw new NullPointerException("name == null"); } if (deferredName != null) { throw new IllegalStateException(); } if (stackSize == 0) { throw new IllegalStateException("JsonWriter is closed."); } deferredName = name; return this; } private void writeDeferredName() throws IOException { if (deferredName != null) { beforeName(); string(deferredName); deferredName = null; } } /** * Encodes {@code value}. * * @param value the literal string value, or null to encode a null literal. * @return this writer. */ public JsonWriter value(String value) throws IOException { if (value == null) { return nullValue(); } writeDeferredName(); beforeValue(false); string(value); return this; } /** * Encodes {@code null}. * * @return this writer. */ public JsonWriter nullValue() throws IOException { if (deferredName != null) { if (serializeNulls) { writeDeferredName(); } else { deferredName = null; return this; // skip the name and the value } } beforeValue(false); out.write("null"); return this; } /** * Encodes {@code value}. * * @return this writer. */ public JsonWriter value(boolean value) throws IOException { writeDeferredName(); beforeValue(false); out.write(value ? "true" : "false"); return this; } /** * Encodes {@code value}. * * @param value a finite value. May not be {@link Double#isNaN() NaNs} or * {@link Double#isInfinite() infinities}. * @return this writer. */ public JsonWriter value(double value) throws IOException { if (Double.isNaN(value) || Double.isInfinite(value)) { throw new IllegalArgumentException("Numeric values must be finite, but was " + value); } writeDeferredName(); beforeValue(false); out.append(Double.toString(value)); return this; } /** * Encodes {@code value}. * * @return this writer. */ public JsonWriter value(long value) throws IOException { writeDeferredName(); beforeValue(false); out.write(Long.toString(value)); return this; } /** * Encodes {@code value}. * * @param value a finite value. May not be {@link Double#isNaN() NaNs} or * {@link Double#isInfinite() infinities}. * @return this writer. */ public JsonWriter value(Number value) throws IOException { if (value == null) { return nullValue(); } writeDeferredName(); String string = value.toString(); if (!lenient && (string.equals("-Infinity") || string.equals("Infinity") || string.equals("NaN"))) { throw new IllegalArgumentException("Numeric values must be finite, but was " + value); } beforeValue(false); out.append(string); return this; } /** * Ensures all buffered data is written to the underlying {@link Writer} * and flushes that writer. */ public void flush() throws IOException { if (stackSize == 0) { throw new IllegalStateException("JsonWriter is closed."); } out.flush(); } /** * Flushes and closes this writer and the underlying {@link Writer}. * * @throws IOException if the JSON document is incomplete. */ public void close() throws IOException { out.close(); int size = stackSize; if (size > 1 || size == 1 && stack[size - 1] != NONEMPTY_DOCUMENT) { throw new IOException("Incomplete document"); } stackSize = 0; } private void string(String value) throws IOException { String[] replacements = htmlSafe ? HTML_SAFE_REPLACEMENT_CHARS : REPLACEMENT_CHARS; out.write("\""); int last = 0; int length = value.length(); for (int i = 0; i < length; i++) { char c = value.charAt(i); String replacement; if (c < 128) { replacement = replacements[c]; if (replacement == null) { continue; } } else if (c == '\u2028') { replacement = "\\u2028"; } else if (c == '\u2029') { replacement = "\\u2029"; } else { continue; } if (last < i) { out.write(value, last, i - last); } out.write(replacement); last = i + 1; } if (last < length) { out.write(value, last, length - last); } out.write("\""); } private void newline() throws IOException { if (indent == null) { return; } out.write("\n"); for (int i = 1, size = stackSize; i < size; i++) { out.write(indent); } } /** * Inserts any necessary separators and whitespace before a name. Also * adjusts the stack to expect the name's value. */ private void beforeName() throws IOException { int context = peek(); if (context == NONEMPTY_OBJECT) { // first in object out.write(','); } else if (context != EMPTY_OBJECT) { // not in an object! throw new IllegalStateException("Nesting problem."); } newline(); replaceTop(DANGLING_NAME); } /** * Inserts any necessary separators and whitespace before a literal value, * inline array, or inline object. Also adjusts the stack to expect either a * closing bracket or another element. * * @param root true if the value is a new array or object, the two values * permitted as top-level elements. */ @SuppressWarnings("fallthrough") private void beforeValue(boolean root) throws IOException { switch (peek()) { case NONEMPTY_DOCUMENT: if (!lenient) { throw new IllegalStateException( "JSON must have only one top-level value."); } // fall-through case EMPTY_DOCUMENT: // first in document if (!lenient && !root) { throw new IllegalStateException( "JSON must start with an array or an object."); } replaceTop(NONEMPTY_DOCUMENT); break; case EMPTY_ARRAY: // first in array replaceTop(NONEMPTY_ARRAY); newline(); break; case NONEMPTY_ARRAY: // another in array out.append(','); newline(); break; case DANGLING_NAME: // value for name out.append(separator); replaceTop(NONEMPTY_OBJECT); break; default: throw new IllegalStateException("Nesting problem."); } } } google-gson/src/main/java/com/google/gson/stream/JsonReader.java0000664000175000017500000013612112130607047024462 0ustar ebourgebourg/* * Copyright (C) 2010 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.stream; import com.google.gson.internal.JsonReaderInternalAccess; import com.google.gson.internal.bind.JsonTreeReader; import java.io.Closeable; import java.io.EOFException; import java.io.IOException; import java.io.Reader; /** * Reads a JSON (RFC 4627) * encoded value as a stream of tokens. This stream includes both literal * values (strings, numbers, booleans, and nulls) as well as the begin and * end delimiters of objects and arrays. The tokens are traversed in * depth-first order, the same order that they appear in the JSON document. * Within JSON objects, name/value pairs are represented by a single token. * *

Parsing JSON

* To create a recursive descent parser for your own JSON streams, first create * an entry point method that creates a {@code JsonReader}. * *

Next, create handler methods for each structure in your JSON text. You'll * need a method for each object type and for each array type. *

    *
  • Within array handling methods, first call {@link * #beginArray} to consume the array's opening bracket. Then create a * while loop that accumulates values, terminating when {@link #hasNext} * is false. Finally, read the array's closing bracket by calling {@link * #endArray}. *
  • Within object handling methods, first call {@link * #beginObject} to consume the object's opening brace. Then create a * while loop that assigns values to local variables based on their name. * This loop should terminate when {@link #hasNext} is false. Finally, * read the object's closing brace by calling {@link #endObject}. *
*

When a nested object or array is encountered, delegate to the * corresponding handler method. * *

When an unknown name is encountered, strict parsers should fail with an * exception. Lenient parsers should call {@link #skipValue()} to recursively * skip the value's nested tokens, which may otherwise conflict. * *

If a value may be null, you should first check using {@link #peek()}. * Null literals can be consumed using either {@link #nextNull()} or {@link * #skipValue()}. * *

Example

* Suppose we'd like to parse a stream of messages such as the following:
 {@code
 * [
 *   {
 *     "id": 912345678901,
 *     "text": "How do I read a JSON stream in Java?",
 *     "geo": null,
 *     "user": {
 *       "name": "json_newb",
 *       "followers_count": 41
 *      }
 *   },
 *   {
 *     "id": 912345678902,
 *     "text": "@json_newb just use JsonReader!",
 *     "geo": [50.454722, -104.606667],
 *     "user": {
 *       "name": "jesse",
 *       "followers_count": 2
 *     }
 *   }
 * ]}
* This code implements the parser for the above structure:
   {@code
 *
 *   public List readJsonStream(InputStream in) throws IOException {
 *     JsonReader reader = new JsonReader(new InputStreamReader(in, "UTF-8"));
 *     try {
 *       return readMessagesArray(reader);
 *     } finally {
 *       reader.close();
 *     }
 *   }
 *
 *   public List readMessagesArray(JsonReader reader) throws IOException {
 *     List messages = new ArrayList();
 *
 *     reader.beginArray();
 *     while (reader.hasNext()) {
 *       messages.add(readMessage(reader));
 *     }
 *     reader.endArray();
 *     return messages;
 *   }
 *
 *   public Message readMessage(JsonReader reader) throws IOException {
 *     long id = -1;
 *     String text = null;
 *     User user = null;
 *     List geo = null;
 *
 *     reader.beginObject();
 *     while (reader.hasNext()) {
 *       String name = reader.nextName();
 *       if (name.equals("id")) {
 *         id = reader.nextLong();
 *       } else if (name.equals("text")) {
 *         text = reader.nextString();
 *       } else if (name.equals("geo") && reader.peek() != JsonToken.NULL) {
 *         geo = readDoublesArray(reader);
 *       } else if (name.equals("user")) {
 *         user = readUser(reader);
 *       } else {
 *         reader.skipValue();
 *       }
 *     }
 *     reader.endObject();
 *     return new Message(id, text, user, geo);
 *   }
 *
 *   public List readDoublesArray(JsonReader reader) throws IOException {
 *     List doubles = new ArrayList();
 *
 *     reader.beginArray();
 *     while (reader.hasNext()) {
 *       doubles.add(reader.nextDouble());
 *     }
 *     reader.endArray();
 *     return doubles;
 *   }
 *
 *   public User readUser(JsonReader reader) throws IOException {
 *     String username = null;
 *     int followersCount = -1;
 *
 *     reader.beginObject();
 *     while (reader.hasNext()) {
 *       String name = reader.nextName();
 *       if (name.equals("name")) {
 *         username = reader.nextString();
 *       } else if (name.equals("followers_count")) {
 *         followersCount = reader.nextInt();
 *       } else {
 *         reader.skipValue();
 *       }
 *     }
 *     reader.endObject();
 *     return new User(username, followersCount);
 *   }}
* *

Number Handling

* This reader permits numeric values to be read as strings and string values to * be read as numbers. For example, both elements of the JSON array {@code * [1, "1"]} may be read using either {@link #nextInt} or {@link #nextString}. * This behavior is intended to prevent lossy numeric conversions: double is * JavaScript's only numeric type and very large values like {@code * 9007199254740993} cannot be represented exactly on that platform. To minimize * precision loss, extremely large values should be written and read as strings * in JSON. * *

Non-Execute Prefix

* Web servers that serve private data using JSON may be vulnerable to
Cross-site * request forgery attacks. In such an attack, a malicious site gains access * to a private JSON file by executing it with an HTML {@code