• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.gson.metrics;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertTrue;
21 
22 import com.google.gson.Gson;
23 import com.google.gson.JsonParseException;
24 import com.google.gson.annotations.Expose;
25 import com.google.gson.reflect.TypeToken;
26 import java.io.StringWriter;
27 import java.lang.reflect.Type;
28 import java.util.ArrayList;
29 import java.util.HashMap;
30 import java.util.List;
31 import java.util.Map;
32 import org.junit.Before;
33 import org.junit.Ignore;
34 import org.junit.Test;
35 
36 /**
37  * Tests to measure performance for Gson. All tests in this file will be disabled in code. To run
38  * them remove disabled_ prefix from the tests and run them.
39  *
40  * @author Inderjeet Singh
41  * @author Joel Leitch
42  */
43 public class PerformanceTest {
44   private static final int COLLECTION_SIZE = 5000;
45 
46   private static final int NUM_ITERATIONS = 100;
47 
48   private Gson gson;
49 
50   @Before
setUp()51   public void setUp() throws Exception {
52     gson = new Gson();
53   }
54 
55   @Test
testDummy()56   public void testDummy() {
57     // This is here to prevent Junit for complaining when we disable all tests.
58   }
59 
60   @Test
61   @Ignore
disabled_testStringDeserialization()62   public void disabled_testStringDeserialization() {
63     StringBuilder sb = new StringBuilder(8096);
64     sb.append("Error Yippie");
65 
66     while (true) {
67       try {
68         String stackTrace = sb.toString();
69         sb.append(stackTrace);
70         String json = "{\"message\":\"Error message.\"," + "\"stackTrace\":\"" + stackTrace + "\"}";
71         parseLongJson(json);
72         System.out.println("Gson could handle a string of size: " + stackTrace.length());
73       } catch (JsonParseException expected) {
74         break;
75       }
76     }
77   }
78 
parseLongJson(String json)79   private void parseLongJson(String json) throws JsonParseException {
80     ExceptionHolder target = gson.fromJson(json, ExceptionHolder.class);
81     assertTrue(target.message.contains("Error"));
82     assertTrue(target.stackTrace.contains("Yippie"));
83   }
84 
85   private static class ExceptionHolder {
86     public final String message;
87     public final String stackTrace;
88 
89     // For use by Gson
90     @SuppressWarnings("unused")
ExceptionHolder()91     private ExceptionHolder() {
92       this("", "");
93     }
ExceptionHolder(String message, String stackTrace)94     public ExceptionHolder(String message, String stackTrace) {
95       this.message = message;
96       this.stackTrace = stackTrace;
97     }
98   }
99 
100   @SuppressWarnings("unused")
101   private static class CollectionEntry {
102     final String name;
103     final String value;
104 
105     // For use by Gson
CollectionEntry()106     private CollectionEntry() {
107       this(null, null);
108     }
109 
CollectionEntry(String name, String value)110     CollectionEntry(String name, String value) {
111       this.name = name;
112       this.value = value;
113     }
114   }
115 
116   /**
117    * Created in response to http://code.google.com/p/google-gson/issues/detail?id=96
118    */
119   @Test
120   @Ignore
disabled_testLargeCollectionSerialization()121   public void disabled_testLargeCollectionSerialization() {
122     int count = 1400000;
123     List<CollectionEntry> list = new ArrayList<>(count);
124     for (int i = 0; i < count; ++i) {
125       list.add(new CollectionEntry("name"+i,"value"+i));
126     }
127     gson.toJson(list);
128   }
129 
130   /**
131    * Created in response to http://code.google.com/p/google-gson/issues/detail?id=96
132    */
133   @Test
134   @Ignore
disabled_testLargeCollectionDeserialization()135   public void disabled_testLargeCollectionDeserialization() {
136     StringBuilder sb = new StringBuilder();
137     int count = 87000;
138     boolean first = true;
139     sb.append('[');
140     for (int i = 0; i < count; ++i) {
141       if (first) {
142         first = false;
143       } else {
144         sb.append(',');
145       }
146       sb.append("{name:'name").append(i).append("',value:'value").append(i).append("'}");
147     }
148     sb.append(']');
149     String json = sb.toString();
150     Type collectionType = new TypeToken<ArrayList<CollectionEntry>>(){}.getType();
151     List<CollectionEntry> list = gson.fromJson(json, collectionType);
152     assertEquals(count, list.size());
153   }
154 
155   /**
156    * Created in response to http://code.google.com/p/google-gson/issues/detail?id=96
157    */
158   // Last I tested, Gson was able to serialize upto 14MB byte array
159   @Test
160   @Ignore
disabled_testByteArraySerialization()161   public void disabled_testByteArraySerialization() {
162     for (int size = 4145152; true; size += 1036288) {
163       byte[] ba = new byte[size];
164       for (int i = 0; i < size; ++i) {
165         ba[i] = 0x05;
166       }
167       gson.toJson(ba);
168       System.out.printf("Gson could serialize a byte array of size: %d\n", size);
169     }
170   }
171 
172   /**
173    * Created in response to http://code.google.com/p/google-gson/issues/detail?id=96
174    */
175   // Last I tested, Gson was able to deserialize a byte array of 11MB
176   @Test
177   @Ignore
disabled_testByteArrayDeserialization()178   public void disabled_testByteArrayDeserialization() {
179     for (int numElements = 10639296; true; numElements += 16384) {
180       StringBuilder sb = new StringBuilder(numElements*2);
181       sb.append("[");
182       boolean first = true;
183       for (int i = 0; i < numElements; ++i) {
184         if (first) {
185           first = false;
186         } else {
187           sb.append(",");
188         }
189         sb.append("5");
190       }
191       sb.append("]");
192       String json = sb.toString();
193       byte[] ba = gson.fromJson(json, byte[].class);
194       System.out.printf("Gson could deserialize a byte array of size: %d\n", ba.length);
195     }
196   }
197 
198 // The tests to measure serialization and deserialization performance of Gson
199 // Based on the discussion at
200 // http://groups.google.com/group/google-gson/browse_thread/thread/7a50b17a390dfaeb
201 // Test results: 10/19/2009
202 // Serialize classes avg time: 60 ms
203 // Deserialized classes avg time: 70 ms
204 // Serialize exposed classes avg time: 159 ms
205 // Deserialized exposed classes avg time: 173 ms
206 
207   @Test
208   @Ignore
disabled_testSerializeClasses()209   public void disabled_testSerializeClasses() {
210     ClassWithList c = new ClassWithList("str");
211     for (int i = 0; i < COLLECTION_SIZE; ++i) {
212       c.list.add(new ClassWithField("element-" + i));
213     }
214     StringWriter w = new StringWriter();
215     long t1 = System.currentTimeMillis();
216     for (int i = 0; i < NUM_ITERATIONS; ++i) {
217       gson.toJson(c, w);
218     }
219     long t2 = System.currentTimeMillis();
220     long avg = (t2 - t1) / NUM_ITERATIONS;
221     System.out.printf("Serialize classes avg time: %d ms\n", avg);
222   }
223 
224   @Test
225   @Ignore
disabled_testDeserializeClasses()226   public void disabled_testDeserializeClasses() {
227     String json = buildJsonForClassWithList();
228     ClassWithList[] target = new ClassWithList[NUM_ITERATIONS];
229     long t1 = System.currentTimeMillis();
230     for (int i = 0; i < NUM_ITERATIONS; ++i) {
231       target[i] = gson.fromJson(json, ClassWithList.class);
232     }
233     long t2 = System.currentTimeMillis();
234     long avg = (t2 - t1) / NUM_ITERATIONS;
235     System.out.printf("Deserialize classes avg time: %d ms\n", avg);
236   }
237 
238   @Test
239   @Ignore
disabled_testLargeObjectSerializationAndDeserialization()240   public void disabled_testLargeObjectSerializationAndDeserialization() {
241     Map<String, Long> largeObject = new HashMap<>();
242     for (long l = 0; l < 100000; l++) {
243       largeObject.put("field" + l, l);
244     }
245 
246     long t1 = System.currentTimeMillis();
247     String json = gson.toJson(largeObject);
248     long t2 = System.currentTimeMillis();
249     System.out.printf("Large object serialized in: %d ms\n", (t2 - t1));
250 
251     t1 = System.currentTimeMillis();
252     gson.fromJson(json, new TypeToken<Map<String, Long>>() {}.getType());
253     t2 = System.currentTimeMillis();
254     System.out.printf("Large object deserialized in: %d ms\n", (t2 - t1));
255 
256   }
257 
258   @Test
259   @Ignore
disabled_testSerializeExposedClasses()260   public void disabled_testSerializeExposedClasses() {
261     ClassWithListOfObjects c1 = new ClassWithListOfObjects("str");
262     for (int i1 = 0; i1 < COLLECTION_SIZE; ++i1) {
263       c1.list.add(new ClassWithExposedField("element-" + i1));
264     }
265     ClassWithListOfObjects c = c1;
266     StringWriter w = new StringWriter();
267     long t1 = System.currentTimeMillis();
268     for (int i = 0; i < NUM_ITERATIONS; ++i) {
269       gson.toJson(c, w);
270     }
271     long t2 = System.currentTimeMillis();
272     long avg = (t2 - t1) / NUM_ITERATIONS;
273     System.out.printf("Serialize exposed classes avg time: %d ms\n", avg);
274   }
275 
276   @Test
277   @Ignore
disabled_testDeserializeExposedClasses()278   public void disabled_testDeserializeExposedClasses() {
279     String json = buildJsonForClassWithList();
280     ClassWithListOfObjects[] target = new ClassWithListOfObjects[NUM_ITERATIONS];
281     long t1 = System.currentTimeMillis();
282     for (int i = 0; i < NUM_ITERATIONS; ++i) {
283       target[i] = gson.fromJson(json, ClassWithListOfObjects.class);
284     }
285     long t2 = System.currentTimeMillis();
286     long avg = (t2 - t1) / NUM_ITERATIONS;
287     System.out.printf("Deserialize exposed classes avg time: %d ms\n", avg);
288   }
289 
290   @Test
291   @Ignore
disabled_testLargeGsonMapRoundTrip()292   public void disabled_testLargeGsonMapRoundTrip() throws Exception {
293     Map<Long, Long> original = new HashMap<>();
294     for (long i = 0; i < 1000000; i++) {
295       original.put(i, i + 1);
296     }
297 
298     Gson gson = new Gson();
299     String json = gson.toJson(original);
300     Type longToLong = new TypeToken<Map<Long, Long>>(){}.getType();
301     gson.fromJson(json, longToLong);
302   }
303 
buildJsonForClassWithList()304   private String buildJsonForClassWithList() {
305     StringBuilder sb = new StringBuilder("{");
306     sb.append("field:").append("'str',");
307     sb.append("list:[");
308     boolean first = true;
309     for (int i = 0; i < COLLECTION_SIZE; ++i) {
310       if (first) {
311         first = false;
312       } else {
313         sb.append(",");
314       }
315       sb.append("{field:'element-" + i + "'}");
316     }
317     sb.append("]");
318     sb.append("}");
319     String json = sb.toString();
320     return json;
321   }
322 
323   @SuppressWarnings("unused")
324   private static final class ClassWithList {
325     final String field;
326     final List<ClassWithField> list = new ArrayList<>(COLLECTION_SIZE);
ClassWithList()327     ClassWithList() {
328       this(null);
329     }
ClassWithList(String field)330     ClassWithList(String field) {
331       this.field = field;
332     }
333   }
334 
335   @SuppressWarnings("unused")
336   private static final class ClassWithField {
337     final String field;
ClassWithField()338     ClassWithField() {
339       this("");
340     }
ClassWithField(String field)341     public ClassWithField(String field) {
342       this.field = field;
343     }
344   }
345 
346   @SuppressWarnings("unused")
347   private static final class ClassWithListOfObjects {
348     @Expose
349     final String field;
350     @Expose
351     final List<ClassWithExposedField> list = new ArrayList<>(COLLECTION_SIZE);
ClassWithListOfObjects()352     ClassWithListOfObjects() {
353       this(null);
354     }
ClassWithListOfObjects(String field)355     ClassWithListOfObjects(String field) {
356       this.field = field;
357     }
358   }
359 
360   @SuppressWarnings("unused")
361   private static final class ClassWithExposedField {
362     @Expose
363     final String field;
ClassWithExposedField()364     ClassWithExposedField() {
365       this("");
366     }
ClassWithExposedField(String field)367     ClassWithExposedField(String field) {
368       this.field = field;
369     }
370   }
371 }
372