]>
Commit | Line | Data |
---|---|---|
cfd903b6 MG |
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; | |
18 | ||
19 | import com.google.gson.internal.ConstructorConstructor; | |
20 | import com.google.gson.internal.Excluder; | |
21 | import com.google.gson.internal.Primitives; | |
22 | import com.google.gson.internal.Streams; | |
23 | import com.google.gson.internal.bind.ArrayTypeAdapter; | |
24 | import com.google.gson.internal.bind.CollectionTypeAdapterFactory; | |
25 | import com.google.gson.internal.bind.DateTypeAdapter; | |
26 | import com.google.gson.internal.bind.JsonTreeReader; | |
27 | import com.google.gson.internal.bind.JsonTreeWriter; | |
28 | import com.google.gson.internal.bind.MapTypeAdapterFactory; | |
29 | import com.google.gson.internal.bind.ObjectTypeAdapter; | |
30 | import com.google.gson.internal.bind.ReflectiveTypeAdapterFactory; | |
31 | import com.google.gson.internal.bind.SqlDateTypeAdapter; | |
32 | import com.google.gson.internal.bind.TimeTypeAdapter; | |
33 | import com.google.gson.internal.bind.TypeAdapters; | |
34 | import com.google.gson.reflect.TypeToken; | |
35 | import com.google.gson.stream.JsonReader; | |
36 | import com.google.gson.stream.JsonToken; | |
37 | import com.google.gson.stream.JsonWriter; | |
38 | import com.google.gson.stream.MalformedJsonException; | |
39 | import java.io.EOFException; | |
40 | import java.io.IOException; | |
41 | import java.io.Reader; | |
42 | import java.io.StringReader; | |
43 | import java.io.StringWriter; | |
44 | import java.io.Writer; | |
45 | import java.lang.reflect.Type; | |
46 | import java.math.BigDecimal; | |
47 | import java.math.BigInteger; | |
48 | import java.util.ArrayList; | |
49 | import java.util.Collections; | |
50 | import java.util.HashMap; | |
51 | import java.util.List; | |
52 | import java.util.Map; | |
53 | ||
54 | /** | |
55 | * This is the main class for using Gson. Gson is typically used by first constructing a | |
56 | * Gson instance and then invoking {@link #toJson(Object)} or {@link #fromJson(String, Class)} | |
57 | * methods on it. | |
58 | * | |
59 | * <p>You can create a Gson instance by invoking {@code new Gson()} if the default configuration | |
60 | * is all you need. You can also use {@link GsonBuilder} to build a Gson instance with various | |
61 | * configuration options such as versioning support, pretty printing, custom | |
62 | * {@link JsonSerializer}s, {@link JsonDeserializer}s, and {@link InstanceCreator}s.</p> | |
63 | * | |
64 | * <p>Here is an example of how Gson is used for a simple Class: | |
65 | * | |
66 | * <pre> | |
67 | * Gson gson = new Gson(); // Or use new GsonBuilder().create(); | |
68 | * MyType target = new MyType(); | |
69 | * String json = gson.toJson(target); // serializes target to Json | |
70 | * MyType target2 = gson.fromJson(json, MyType.class); // deserializes json into target2 | |
71 | * </pre></p> | |
72 | * | |
73 | * <p>If the object that your are serializing/deserializing is a {@code ParameterizedType} | |
74 | * (i.e. contains at least one type parameter and may be an array) then you must use the | |
75 | * {@link #toJson(Object, Type)} or {@link #fromJson(String, Type)} method. Here is an | |
76 | * example for serializing and deserialing a {@code ParameterizedType}: | |
77 | * | |
78 | * <pre> | |
79 | * Type listType = new TypeToken<List<String>>() {}.getType(); | |
80 | * List<String> target = new LinkedList<String>(); | |
81 | * target.add("blah"); | |
82 | * | |
83 | * Gson gson = new Gson(); | |
84 | * String json = gson.toJson(target, listType); | |
85 | * List<String> target2 = gson.fromJson(json, listType); | |
86 | * </pre></p> | |
87 | * | |
88 | * <p>See the <a href="https://sites.google.com/site/gson/gson-user-guide">Gson User Guide</a> | |
89 | * for a more complete set of examples.</p> | |
90 | * | |
91 | * @see com.google.gson.reflect.TypeToken | |
92 | * | |
93 | * @author Inderjeet Singh | |
94 | * @author Joel Leitch | |
95 | * @author Jesse Wilson | |
96 | */ | |
97 | public final class Gson { | |
98 | static final boolean DEFAULT_JSON_NON_EXECUTABLE = false; | |
99 | ||
100 | private static final String JSON_NON_EXECUTABLE_PREFIX = ")]}'\n"; | |
101 | ||
102 | /** | |
103 | * This thread local guards against reentrant calls to getAdapter(). In | |
104 | * certain object graphs, creating an adapter for a type may recursively | |
105 | * require an adapter for the same type! Without intervention, the recursive | |
106 | * lookup would stack overflow. We cheat by returning a proxy type adapter. | |
107 | * The proxy is wired up once the initial adapter has been created. | |
108 | */ | |
109 | private final ThreadLocal<Map<TypeToken<?>, FutureTypeAdapter<?>>> calls | |
110 | = new ThreadLocal<Map<TypeToken<?>, FutureTypeAdapter<?>>>(); | |
111 | ||
112 | private final Map<TypeToken<?>, TypeAdapter<?>> typeTokenCache | |
113 | = Collections.synchronizedMap(new HashMap<TypeToken<?>, TypeAdapter<?>>()); | |
114 | ||
115 | private final List<TypeAdapterFactory> factories; | |
116 | private final ConstructorConstructor constructorConstructor; | |
117 | ||
118 | private final boolean serializeNulls; | |
119 | private final boolean htmlSafe; | |
120 | private final boolean generateNonExecutableJson; | |
121 | private final boolean prettyPrinting; | |
122 | ||
123 | final JsonDeserializationContext deserializationContext = new JsonDeserializationContext() { | |
124 | @SuppressWarnings("unchecked") | |
125 | public <T> T deserialize(JsonElement json, Type typeOfT) throws JsonParseException { | |
126 | return (T) fromJson(json, typeOfT); | |
127 | } | |
128 | }; | |
129 | ||
130 | final JsonSerializationContext serializationContext = new JsonSerializationContext() { | |
131 | public JsonElement serialize(Object src) { | |
132 | return toJsonTree(src); | |
133 | } | |
134 | public JsonElement serialize(Object src, Type typeOfSrc) { | |
135 | return toJsonTree(src, typeOfSrc); | |
136 | } | |
137 | }; | |
138 | ||
139 | /** | |
140 | * Constructs a Gson object with default configuration. The default configuration has the | |
141 | * following settings: | |
142 | * <ul> | |
143 | * <li>The JSON generated by <code>toJson</code> methods is in compact representation. This | |
144 | * means that all the unneeded white-space is removed. You can change this behavior with | |
145 | * {@link GsonBuilder#setPrettyPrinting()}. </li> | |
146 | * <li>The generated JSON omits all the fields that are null. Note that nulls in arrays are | |
147 | * kept as is since an array is an ordered list. Moreover, if a field is not null, but its | |
148 | * generated JSON is empty, the field is kept. You can configure Gson to serialize null values | |
149 | * by setting {@link GsonBuilder#serializeNulls()}.</li> | |
150 | * <li>Gson provides default serialization and deserialization for Enums, {@link Map}, | |
151 | * {@link java.net.URL}, {@link java.net.URI}, {@link java.util.Locale}, {@link java.util.Date}, | |
152 | * {@link java.math.BigDecimal}, and {@link java.math.BigInteger} classes. If you would prefer | |
153 | * to change the default representation, you can do so by registering a type adapter through | |
154 | * {@link GsonBuilder#registerTypeAdapter(Type, Object)}. </li> | |
155 | * <li>The default Date format is same as {@link java.text.DateFormat#DEFAULT}. This format | |
156 | * ignores the millisecond portion of the date during serialization. You can change | |
157 | * this by invoking {@link GsonBuilder#setDateFormat(int)} or | |
158 | * {@link GsonBuilder#setDateFormat(String)}. </li> | |
159 | * <li>By default, Gson ignores the {@link com.google.gson.annotations.Expose} annotation. | |
160 | * You can enable Gson to serialize/deserialize only those fields marked with this annotation | |
161 | * through {@link GsonBuilder#excludeFieldsWithoutExposeAnnotation()}. </li> | |
162 | * <li>By default, Gson ignores the {@link com.google.gson.annotations.Since} annotation. You | |
163 | * can enable Gson to use this annotation through {@link GsonBuilder#setVersion(double)}.</li> | |
164 | * <li>The default field naming policy for the output Json is same as in Java. So, a Java class | |
165 | * field <code>versionNumber</code> will be output as <code>"versionNumber@quot;</code> in | |
166 | * Json. The same rules are applied for mapping incoming Json to the Java classes. You can | |
167 | * change this policy through {@link GsonBuilder#setFieldNamingPolicy(FieldNamingPolicy)}.</li> | |
168 | * <li>By default, Gson excludes <code>transient</code> or <code>static</code> fields from | |
169 | * consideration for serialization and deserialization. You can change this behavior through | |
170 | * {@link GsonBuilder#excludeFieldsWithModifiers(int...)}.</li> | |
171 | * </ul> | |
172 | */ | |
173 | public Gson() { | |
174 | this(Excluder.DEFAULT, FieldNamingPolicy.IDENTITY, | |
175 | Collections.<Type, InstanceCreator<?>>emptyMap(), false, false, DEFAULT_JSON_NON_EXECUTABLE, | |
176 | true, false, false, LongSerializationPolicy.DEFAULT, | |
177 | Collections.<TypeAdapterFactory>emptyList()); | |
178 | } | |
179 | ||
180 | Gson(final Excluder excluder, final FieldNamingStrategy fieldNamingPolicy, | |
181 | final Map<Type, InstanceCreator<?>> instanceCreators, boolean serializeNulls, | |
182 | boolean complexMapKeySerialization, boolean generateNonExecutableGson, boolean htmlSafe, | |
183 | boolean prettyPrinting, boolean serializeSpecialFloatingPointValues, | |
184 | LongSerializationPolicy longSerializationPolicy, | |
185 | List<TypeAdapterFactory> typeAdapterFactories) { | |
186 | this.constructorConstructor = new ConstructorConstructor(instanceCreators); | |
187 | this.serializeNulls = serializeNulls; | |
188 | this.generateNonExecutableJson = generateNonExecutableGson; | |
189 | this.htmlSafe = htmlSafe; | |
190 | this.prettyPrinting = prettyPrinting; | |
191 | ||
192 | List<TypeAdapterFactory> factories = new ArrayList<TypeAdapterFactory>(); | |
193 | ||
194 | // built-in type adapters that cannot be overridden | |
195 | factories.add(TypeAdapters.JSON_ELEMENT_FACTORY); | |
196 | factories.add(ObjectTypeAdapter.FACTORY); | |
197 | ||
198 | // the excluder must precede all adapters that handle user-defined types | |
199 | factories.add(excluder); | |
200 | ||
201 | // user's type adapters | |
202 | factories.addAll(typeAdapterFactories); | |
203 | ||
204 | // type adapters for basic platform types | |
205 | factories.add(TypeAdapters.STRING_FACTORY); | |
206 | factories.add(TypeAdapters.INTEGER_FACTORY); | |
207 | factories.add(TypeAdapters.BOOLEAN_FACTORY); | |
208 | factories.add(TypeAdapters.BYTE_FACTORY); | |
209 | factories.add(TypeAdapters.SHORT_FACTORY); | |
210 | factories.add(TypeAdapters.newFactory(long.class, Long.class, | |
211 | longAdapter(longSerializationPolicy))); | |
212 | factories.add(TypeAdapters.newFactory(double.class, Double.class, | |
213 | doubleAdapter(serializeSpecialFloatingPointValues))); | |
214 | factories.add(TypeAdapters.newFactory(float.class, Float.class, | |
215 | floatAdapter(serializeSpecialFloatingPointValues))); | |
216 | factories.add(TypeAdapters.NUMBER_FACTORY); | |
217 | factories.add(TypeAdapters.CHARACTER_FACTORY); | |
218 | factories.add(TypeAdapters.STRING_BUILDER_FACTORY); | |
219 | factories.add(TypeAdapters.STRING_BUFFER_FACTORY); | |
220 | factories.add(TypeAdapters.newFactory(BigDecimal.class, TypeAdapters.BIG_DECIMAL)); | |
221 | factories.add(TypeAdapters.newFactory(BigInteger.class, TypeAdapters.BIG_INTEGER)); | |
222 | factories.add(TypeAdapters.URL_FACTORY); | |
223 | factories.add(TypeAdapters.URI_FACTORY); | |
224 | factories.add(TypeAdapters.UUID_FACTORY); | |
225 | factories.add(TypeAdapters.LOCALE_FACTORY); | |
226 | factories.add(TypeAdapters.INET_ADDRESS_FACTORY); | |
227 | factories.add(TypeAdapters.BIT_SET_FACTORY); | |
228 | factories.add(DateTypeAdapter.FACTORY); | |
229 | factories.add(TypeAdapters.CALENDAR_FACTORY); | |
230 | factories.add(TimeTypeAdapter.FACTORY); | |
231 | factories.add(SqlDateTypeAdapter.FACTORY); | |
232 | factories.add(TypeAdapters.TIMESTAMP_FACTORY); | |
233 | factories.add(ArrayTypeAdapter.FACTORY); | |
234 | factories.add(TypeAdapters.ENUM_FACTORY); | |
235 | factories.add(TypeAdapters.CLASS_FACTORY); | |
236 | ||
237 | // type adapters for composite and user-defined types | |
238 | factories.add(new CollectionTypeAdapterFactory(constructorConstructor)); | |
239 | factories.add(new MapTypeAdapterFactory(constructorConstructor, complexMapKeySerialization)); | |
240 | factories.add(new ReflectiveTypeAdapterFactory( | |
241 | constructorConstructor, fieldNamingPolicy, excluder)); | |
242 | ||
243 | this.factories = Collections.unmodifiableList(factories); | |
244 | } | |
245 | ||
246 | private TypeAdapter<Number> doubleAdapter(boolean serializeSpecialFloatingPointValues) { | |
247 | if (serializeSpecialFloatingPointValues) { | |
248 | return TypeAdapters.DOUBLE; | |
249 | } | |
250 | return new TypeAdapter<Number>() { | |
251 | @Override public Double read(JsonReader in) throws IOException { | |
252 | if (in.peek() == JsonToken.NULL) { | |
253 | in.nextNull(); | |
254 | return null; | |
255 | } | |
256 | return in.nextDouble(); | |
257 | } | |
258 | @Override public void write(JsonWriter out, Number value) throws IOException { | |
259 | if (value == null) { | |
260 | out.nullValue(); | |
261 | return; | |
262 | } | |
263 | double doubleValue = value.doubleValue(); | |
264 | checkValidFloatingPoint(doubleValue); | |
265 | out.value(value); | |
266 | } | |
267 | }; | |
268 | } | |
269 | ||
270 | private TypeAdapter<Number> floatAdapter(boolean serializeSpecialFloatingPointValues) { | |
271 | if (serializeSpecialFloatingPointValues) { | |
272 | return TypeAdapters.FLOAT; | |
273 | } | |
274 | return new TypeAdapter<Number>() { | |
275 | @Override public Float read(JsonReader in) throws IOException { | |
276 | if (in.peek() == JsonToken.NULL) { | |
277 | in.nextNull(); | |
278 | return null; | |
279 | } | |
280 | return (float) in.nextDouble(); | |
281 | } | |
282 | @Override public void write(JsonWriter out, Number value) throws IOException { | |
283 | if (value == null) { | |
284 | out.nullValue(); | |
285 | return; | |
286 | } | |
287 | float floatValue = value.floatValue(); | |
288 | checkValidFloatingPoint(floatValue); | |
289 | out.value(value); | |
290 | } | |
291 | }; | |
292 | } | |
293 | ||
294 | private void checkValidFloatingPoint(double value) { | |
295 | if (Double.isNaN(value) || Double.isInfinite(value)) { | |
296 | throw new IllegalArgumentException(value | |
297 | + " is not a valid double value as per JSON specification. To override this" | |
298 | + " behavior, use GsonBuilder.serializeSpecialFloatingPointValues() method."); | |
299 | } | |
300 | } | |
301 | ||
302 | private TypeAdapter<Number> longAdapter(LongSerializationPolicy longSerializationPolicy) { | |
303 | if (longSerializationPolicy == LongSerializationPolicy.DEFAULT) { | |
304 | return TypeAdapters.LONG; | |
305 | } | |
306 | return new TypeAdapter<Number>() { | |
307 | @Override public Number read(JsonReader in) throws IOException { | |
308 | if (in.peek() == JsonToken.NULL) { | |
309 | in.nextNull(); | |
310 | return null; | |
311 | } | |
312 | return in.nextLong(); | |
313 | } | |
314 | @Override public void write(JsonWriter out, Number value) throws IOException { | |
315 | if (value == null) { | |
316 | out.nullValue(); | |
317 | return; | |
318 | } | |
319 | out.value(value.toString()); | |
320 | } | |
321 | }; | |
322 | } | |
323 | ||
324 | /** | |
325 | * Returns the type adapter for {@code} type. | |
326 | * | |
327 | * @throws IllegalArgumentException if this GSON cannot serialize and | |
328 | * deserialize {@code type}. | |
329 | */ | |
330 | @SuppressWarnings("unchecked") | |
331 | public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) { | |
332 | TypeAdapter<?> cached = typeTokenCache.get(type); | |
333 | if (cached != null) { | |
334 | return (TypeAdapter<T>) cached; | |
335 | } | |
336 | ||
337 | Map<TypeToken<?>, FutureTypeAdapter<?>> threadCalls = calls.get(); | |
338 | boolean requiresThreadLocalCleanup = false; | |
339 | if (threadCalls == null) { | |
340 | threadCalls = new HashMap<TypeToken<?>, FutureTypeAdapter<?>>(); | |
341 | calls.set(threadCalls); | |
342 | requiresThreadLocalCleanup = true; | |
343 | } | |
344 | ||
345 | // the key and value type parameters always agree | |
346 | FutureTypeAdapter<T> ongoingCall = (FutureTypeAdapter<T>) threadCalls.get(type); | |
347 | if (ongoingCall != null) { | |
348 | return ongoingCall; | |
349 | } | |
350 | ||
351 | try { | |
352 | FutureTypeAdapter<T> call = new FutureTypeAdapter<T>(); | |
353 | threadCalls.put(type, call); | |
354 | ||
355 | for (TypeAdapterFactory factory : factories) { | |
356 | TypeAdapter<T> candidate = factory.create(this, type); | |
357 | if (candidate != null) { | |
358 | call.setDelegate(candidate); | |
359 | typeTokenCache.put(type, candidate); | |
360 | return candidate; | |
361 | } | |
362 | } | |
363 | throw new IllegalArgumentException("GSON cannot handle " + type); | |
364 | } finally { | |
365 | threadCalls.remove(type); | |
366 | ||
367 | if (requiresThreadLocalCleanup) { | |
368 | calls.remove(); | |
369 | } | |
370 | } | |
371 | } | |
372 | ||
373 | /** | |
374 | * This method is used to get an alternate type adapter for the specified type. This is used | |
375 | * to access a type adapter that is overridden by a {@link TypeAdapterFactory} that you | |
376 | * may have registered. This features is typically used when you want to register a type | |
377 | * adapter that does a little bit of work but then delegates further processing to the Gson | |
378 | * default type adapter. Here is an example: | |
379 | * <p>Let's say we want to write a type adapter that counts the number of objects being read | |
380 | * from or written to JSON. We can achieve this by writing a type adapter factory that uses | |
381 | * the <code>getDelegateAdapter</code> method: | |
382 | * <pre> {@code | |
383 | * class StatsTypeAdapterFactory implements TypeAdapterFactory { | |
384 | * public int numReads = 0; | |
385 | * public int numWrites = 0; | |
386 | * public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) { | |
387 | * final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type); | |
388 | * return new TypeAdapter<T>() { | |
389 | * public void write(JsonWriter out, T value) throws IOException { | |
390 | * ++numWrites; | |
391 | * delegate.write(out, value); | |
392 | * } | |
393 | * public T read(JsonReader in) throws IOException { | |
394 | * ++numReads; | |
395 | * return delegate.read(in); | |
396 | * } | |
397 | * }; | |
398 | * } | |
399 | * } | |
400 | * } </pre> | |
401 | * This factory can now be used like this: | |
402 | * <pre> {@code | |
403 | * StatsTypeAdapterFactory stats = new StatsTypeAdapterFactory(); | |
404 | * Gson gson = new GsonBuilder().registerTypeAdapterFactory(stats).create(); | |
405 | * // Call gson.toJson() and fromJson methods on objects | |
406 | * System.out.println("Num JSON reads" + stats.numReads); | |
407 | * System.out.println("Num JSON writes" + stats.numWrites); | |
408 | * }</pre> | |
409 | * Note that since you can not override type adapter factories for String and Java primitive | |
410 | * types, our stats factory will not count the number of String or primitives that will be | |
411 | * read or written. | |
412 | * @param skipPast The type adapter factory that needs to be skipped while searching for | |
413 | * a matching type adapter. In most cases, you should just pass <i>this</i> (the type adapter | |
414 | * factory from where {@link #getDelegateAdapter} method is being invoked). | |
415 | * @param type Type for which the delegate adapter is being searched for. | |
416 | * | |
417 | * @since 2.2 | |
418 | */ | |
419 | public <T> TypeAdapter<T> getDelegateAdapter(TypeAdapterFactory skipPast, TypeToken<T> type) { | |
420 | boolean skipPastFound = false; | |
421 | ||
422 | for (TypeAdapterFactory factory : factories) { | |
423 | if (!skipPastFound) { | |
424 | if (factory == skipPast) { | |
425 | skipPastFound = true; | |
426 | } | |
427 | continue; | |
428 | } | |
429 | ||
430 | TypeAdapter<T> candidate = factory.create(this, type); | |
431 | if (candidate != null) { | |
432 | return candidate; | |
433 | } | |
434 | } | |
435 | throw new IllegalArgumentException("GSON cannot serialize " + type); | |
436 | } | |
437 | ||
438 | /** | |
439 | * Returns the type adapter for {@code} type. | |
440 | * | |
441 | * @throws IllegalArgumentException if this GSON cannot serialize and | |
442 | * deserialize {@code type}. | |
443 | */ | |
444 | public <T> TypeAdapter<T> getAdapter(Class<T> type) { | |
445 | return getAdapter(TypeToken.get(type)); | |
446 | } | |
447 | ||
448 | /** | |
449 | * This method serializes the specified object into its equivalent representation as a tree of | |
450 | * {@link JsonElement}s. This method should be used when the specified object is not a generic | |
451 | * type. This method uses {@link Class#getClass()} to get the type for the specified object, but | |
452 | * the {@code getClass()} loses the generic type information because of the Type Erasure feature | |
453 | * of Java. Note that this method works fine if the any of the object fields are of generic type, | |
454 | * just the object itself should not be of a generic type. If the object is of generic type, use | |
455 | * {@link #toJsonTree(Object, Type)} instead. | |
456 | * | |
457 | * @param src the object for which Json representation is to be created setting for Gson | |
458 | * @return Json representation of {@code src}. | |
459 | * @since 1.4 | |
460 | */ | |
461 | public JsonElement toJsonTree(Object src) { | |
462 | if (src == null) { | |
463 | return JsonNull.INSTANCE; | |
464 | } | |
465 | return toJsonTree(src, src.getClass()); | |
466 | } | |
467 | ||
468 | /** | |
469 | * This method serializes the specified object, including those of generic types, into its | |
470 | * equivalent representation as a tree of {@link JsonElement}s. This method must be used if the | |
471 | * specified object is a generic type. For non-generic objects, use {@link #toJsonTree(Object)} | |
472 | * instead. | |
473 | * | |
474 | * @param src the object for which JSON representation is to be created | |
475 | * @param typeOfSrc The specific genericized type of src. You can obtain | |
476 | * this type by using the {@link com.google.gson.reflect.TypeToken} class. For example, | |
477 | * to get the type for {@code Collection<Foo>}, you should use: | |
478 | * <pre> | |
479 | * Type typeOfSrc = new TypeToken<Collection<Foo>>(){}.getType(); | |
480 | * </pre> | |
481 | * @return Json representation of {@code src} | |
482 | * @since 1.4 | |
483 | */ | |
484 | public JsonElement toJsonTree(Object src, Type typeOfSrc) { | |
485 | JsonTreeWriter writer = new JsonTreeWriter(); | |
486 | toJson(src, typeOfSrc, writer); | |
487 | return writer.get(); | |
488 | } | |
489 | ||
490 | /** | |
491 | * This method serializes the specified object into its equivalent Json representation. | |
492 | * This method should be used when the specified object is not a generic type. This method uses | |
493 | * {@link Class#getClass()} to get the type for the specified object, but the | |
494 | * {@code getClass()} loses the generic type information because of the Type Erasure feature | |
495 | * of Java. Note that this method works fine if the any of the object fields are of generic type, | |
496 | * just the object itself should not be of a generic type. If the object is of generic type, use | |
497 | * {@link #toJson(Object, Type)} instead. If you want to write out the object to a | |
498 | * {@link Writer}, use {@link #toJson(Object, Appendable)} instead. | |
499 | * | |
500 | * @param src the object for which Json representation is to be created setting for Gson | |
501 | * @return Json representation of {@code src}. | |
502 | */ | |
503 | public String toJson(Object src) { | |
504 | if (src == null) { | |
505 | return toJson(JsonNull.INSTANCE); | |
506 | } | |
507 | return toJson(src, src.getClass()); | |
508 | } | |
509 | ||
510 | /** | |
511 | * This method serializes the specified object, including those of generic types, into its | |
512 | * equivalent Json representation. This method must be used if the specified object is a generic | |
513 | * type. For non-generic objects, use {@link #toJson(Object)} instead. If you want to write out | |
514 | * the object to a {@link Appendable}, use {@link #toJson(Object, Type, Appendable)} instead. | |
515 | * | |
516 | * @param src the object for which JSON representation is to be created | |
517 | * @param typeOfSrc The specific genericized type of src. You can obtain | |
518 | * this type by using the {@link com.google.gson.reflect.TypeToken} class. For example, | |
519 | * to get the type for {@code Collection<Foo>}, you should use: | |
520 | * <pre> | |
521 | * Type typeOfSrc = new TypeToken<Collection<Foo>>(){}.getType(); | |
522 | * </pre> | |
523 | * @return Json representation of {@code src} | |
524 | */ | |
525 | public String toJson(Object src, Type typeOfSrc) { | |
526 | StringWriter writer = new StringWriter(); | |
527 | toJson(src, typeOfSrc, writer); | |
528 | return writer.toString(); | |
529 | } | |
530 | ||
531 | /** | |
532 | * This method serializes the specified object into its equivalent Json representation. | |
533 | * This method should be used when the specified object is not a generic type. This method uses | |
534 | * {@link Class#getClass()} to get the type for the specified object, but the | |
535 | * {@code getClass()} loses the generic type information because of the Type Erasure feature | |
536 | * of Java. Note that this method works fine if the any of the object fields are of generic type, | |
537 | * just the object itself should not be of a generic type. If the object is of generic type, use | |
538 | * {@link #toJson(Object, Type, Appendable)} instead. | |
539 | * | |
540 | * @param src the object for which Json representation is to be created setting for Gson | |
541 | * @param writer Writer to which the Json representation needs to be written | |
542 | * @throws JsonIOException if there was a problem writing to the writer | |
543 | * @since 1.2 | |
544 | */ | |
545 | public void toJson(Object src, Appendable writer) throws JsonIOException { | |
546 | if (src != null) { | |
547 | toJson(src, src.getClass(), writer); | |
548 | } else { | |
549 | toJson(JsonNull.INSTANCE, writer); | |
550 | } | |
551 | } | |
552 | ||
553 | /** | |
554 | * This method serializes the specified object, including those of generic types, into its | |
555 | * equivalent Json representation. This method must be used if the specified object is a generic | |
556 | * type. For non-generic objects, use {@link #toJson(Object, Appendable)} instead. | |
557 | * | |
558 | * @param src the object for which JSON representation is to be created | |
559 | * @param typeOfSrc The specific genericized type of src. You can obtain | |
560 | * this type by using the {@link com.google.gson.reflect.TypeToken} class. For example, | |
561 | * to get the type for {@code Collection<Foo>}, you should use: | |
562 | * <pre> | |
563 | * Type typeOfSrc = new TypeToken<Collection<Foo>>(){}.getType(); | |
564 | * </pre> | |
565 | * @param writer Writer to which the Json representation of src needs to be written. | |
566 | * @throws JsonIOException if there was a problem writing to the writer | |
567 | * @since 1.2 | |
568 | */ | |
569 | public void toJson(Object src, Type typeOfSrc, Appendable writer) throws JsonIOException { | |
570 | try { | |
571 | JsonWriter jsonWriter = newJsonWriter(Streams.writerForAppendable(writer)); | |
572 | toJson(src, typeOfSrc, jsonWriter); | |
573 | } catch (IOException e) { | |
574 | throw new JsonIOException(e); | |
575 | } | |
576 | } | |
577 | ||
578 | /** | |
579 | * Writes the JSON representation of {@code src} of type {@code typeOfSrc} to | |
580 | * {@code writer}. | |
581 | * @throws JsonIOException if there was a problem writing to the writer | |
582 | */ | |
583 | @SuppressWarnings("unchecked") | |
584 | public void toJson(Object src, Type typeOfSrc, JsonWriter writer) throws JsonIOException { | |
585 | TypeAdapter<?> adapter = getAdapter(TypeToken.get(typeOfSrc)); | |
586 | boolean oldLenient = writer.isLenient(); | |
587 | writer.setLenient(true); | |
588 | boolean oldHtmlSafe = writer.isHtmlSafe(); | |
589 | writer.setHtmlSafe(htmlSafe); | |
590 | boolean oldSerializeNulls = writer.getSerializeNulls(); | |
591 | writer.setSerializeNulls(serializeNulls); | |
592 | try { | |
593 | ((TypeAdapter<Object>) adapter).write(writer, src); | |
594 | } catch (IOException e) { | |
595 | throw new JsonIOException(e); | |
596 | } finally { | |
597 | writer.setLenient(oldLenient); | |
598 | writer.setHtmlSafe(oldHtmlSafe); | |
599 | writer.setSerializeNulls(oldSerializeNulls); | |
600 | } | |
601 | } | |
602 | ||
603 | /** | |
604 | * Converts a tree of {@link JsonElement}s into its equivalent JSON representation. | |
605 | * | |
606 | * @param jsonElement root of a tree of {@link JsonElement}s | |
607 | * @return JSON String representation of the tree | |
608 | * @since 1.4 | |
609 | */ | |
610 | public String toJson(JsonElement jsonElement) { | |
611 | StringWriter writer = new StringWriter(); | |
612 | toJson(jsonElement, writer); | |
613 | return writer.toString(); | |
614 | } | |
615 | ||
616 | /** | |
617 | * Writes out the equivalent JSON for a tree of {@link JsonElement}s. | |
618 | * | |
619 | * @param jsonElement root of a tree of {@link JsonElement}s | |
620 | * @param writer Writer to which the Json representation needs to be written | |
621 | * @throws JsonIOException if there was a problem writing to the writer | |
622 | * @since 1.4 | |
623 | */ | |
624 | public void toJson(JsonElement jsonElement, Appendable writer) throws JsonIOException { | |
625 | try { | |
626 | JsonWriter jsonWriter = newJsonWriter(Streams.writerForAppendable(writer)); | |
627 | toJson(jsonElement, jsonWriter); | |
628 | } catch (IOException e) { | |
629 | throw new RuntimeException(e); | |
630 | } | |
631 | } | |
632 | ||
633 | /** | |
634 | * Returns a new JSON writer configured for this GSON and with the non-execute | |
635 | * prefix if that is configured. | |
636 | */ | |
637 | private JsonWriter newJsonWriter(Writer writer) throws IOException { | |
638 | if (generateNonExecutableJson) { | |
639 | writer.write(JSON_NON_EXECUTABLE_PREFIX); | |
640 | } | |
641 | JsonWriter jsonWriter = new JsonWriter(writer); | |
642 | if (prettyPrinting) { | |
643 | jsonWriter.setIndent(" "); | |
644 | } | |
645 | jsonWriter.setSerializeNulls(serializeNulls); | |
646 | return jsonWriter; | |
647 | } | |
648 | ||
649 | /** | |
650 | * Writes the JSON for {@code jsonElement} to {@code writer}. | |
651 | * @throws JsonIOException if there was a problem writing to the writer | |
652 | */ | |
653 | public void toJson(JsonElement jsonElement, JsonWriter writer) throws JsonIOException { | |
654 | boolean oldLenient = writer.isLenient(); | |
655 | writer.setLenient(true); | |
656 | boolean oldHtmlSafe = writer.isHtmlSafe(); | |
657 | writer.setHtmlSafe(htmlSafe); | |
658 | boolean oldSerializeNulls = writer.getSerializeNulls(); | |
659 | writer.setSerializeNulls(serializeNulls); | |
660 | try { | |
661 | Streams.write(jsonElement, writer); | |
662 | } catch (IOException e) { | |
663 | throw new JsonIOException(e); | |
664 | } finally { | |
665 | writer.setLenient(oldLenient); | |
666 | writer.setHtmlSafe(oldHtmlSafe); | |
667 | writer.setSerializeNulls(oldSerializeNulls); | |
668 | } | |
669 | } | |
670 | ||
671 | /** | |
672 | * This method deserializes the specified Json into an object of the specified class. It is not | |
673 | * suitable to use if the specified class is a generic type since it will not have the generic | |
674 | * type information because of the Type Erasure feature of Java. Therefore, this method should not | |
675 | * be used if the desired type is a generic type. Note that this method works fine if the any of | |
676 | * the fields of the specified object are generics, just the object itself should not be a | |
677 | * generic type. For the cases when the object is of generic type, invoke | |
678 | * {@link #fromJson(String, Type)}. If you have the Json in a {@link Reader} instead of | |
679 | * a String, use {@link #fromJson(Reader, Class)} instead. | |
680 | * | |
681 | * @param <T> the type of the desired object | |
682 | * @param json the string from which the object is to be deserialized | |
683 | * @param classOfT the class of T | |
684 | * @return an object of type T from the string | |
685 | * @throws JsonSyntaxException if json is not a valid representation for an object of type | |
686 | * classOfT | |
687 | */ | |
688 | public <T> T fromJson(String json, Class<T> classOfT) throws JsonSyntaxException { | |
689 | Object object = fromJson(json, (Type) classOfT); | |
690 | return Primitives.wrap(classOfT).cast(object); | |
691 | } | |
692 | ||
693 | /** | |
694 | * This method deserializes the specified Json into an object of the specified type. This method | |
695 | * is useful if the specified object is a generic type. For non-generic objects, use | |
696 | * {@link #fromJson(String, Class)} instead. If you have the Json in a {@link Reader} instead of | |
697 | * a String, use {@link #fromJson(Reader, Type)} instead. | |
698 | * | |
699 | * @param <T> the type of the desired object | |
700 | * @param json the string from which the object is to be deserialized | |
701 | * @param typeOfT The specific genericized type of src. You can obtain this type by using the | |
702 | * {@link com.google.gson.reflect.TypeToken} class. For example, to get the type for | |
703 | * {@code Collection<Foo>}, you should use: | |
704 | * <pre> | |
705 | * Type typeOfT = new TypeToken<Collection<Foo>>(){}.getType(); | |
706 | * </pre> | |
707 | * @return an object of type T from the string | |
708 | * @throws JsonParseException if json is not a valid representation for an object of type typeOfT | |
709 | * @throws JsonSyntaxException if json is not a valid representation for an object of type | |
710 | */ | |
711 | @SuppressWarnings("unchecked") | |
712 | public <T> T fromJson(String json, Type typeOfT) throws JsonSyntaxException { | |
713 | if (json == null) { | |
714 | return null; | |
715 | } | |
716 | StringReader reader = new StringReader(json); | |
717 | T target = (T) fromJson(reader, typeOfT); | |
718 | return target; | |
719 | } | |
720 | ||
721 | /** | |
722 | * This method deserializes the Json read from the specified reader into an object of the | |
723 | * specified class. It is not suitable to use if the specified class is a generic type since it | |
724 | * will not have the generic type information because of the Type Erasure feature of Java. | |
725 | * Therefore, this method should not be used if the desired type is a generic type. Note that | |
726 | * this method works fine if the any of the fields of the specified object are generics, just the | |
727 | * object itself should not be a generic type. For the cases when the object is of generic type, | |
728 | * invoke {@link #fromJson(Reader, Type)}. If you have the Json in a String form instead of a | |
729 | * {@link Reader}, use {@link #fromJson(String, Class)} instead. | |
730 | * | |
731 | * @param <T> the type of the desired object | |
732 | * @param json the reader producing the Json from which the object is to be deserialized. | |
733 | * @param classOfT the class of T | |
734 | * @return an object of type T from the string | |
735 | * @throws JsonIOException if there was a problem reading from the Reader | |
736 | * @throws JsonSyntaxException if json is not a valid representation for an object of type | |
737 | * @since 1.2 | |
738 | */ | |
739 | public <T> T fromJson(Reader json, Class<T> classOfT) throws JsonSyntaxException, JsonIOException { | |
740 | JsonReader jsonReader = new JsonReader(json); | |
741 | Object object = fromJson(jsonReader, classOfT); | |
742 | assertFullConsumption(object, jsonReader); | |
743 | return Primitives.wrap(classOfT).cast(object); | |
744 | } | |
745 | ||
746 | /** | |
747 | * This method deserializes the Json read from the specified reader into an object of the | |
748 | * specified type. This method is useful if the specified object is a generic type. For | |
749 | * non-generic objects, use {@link #fromJson(Reader, Class)} instead. If you have the Json in a | |
750 | * String form instead of a {@link Reader}, use {@link #fromJson(String, Type)} instead. | |
751 | * | |
752 | * @param <T> the type of the desired object | |
753 | * @param json the reader producing Json from which the object is to be deserialized | |
754 | * @param typeOfT The specific genericized type of src. You can obtain this type by using the | |
755 | * {@link com.google.gson.reflect.TypeToken} class. For example, to get the type for | |
756 | * {@code Collection<Foo>}, you should use: | |
757 | * <pre> | |
758 | * Type typeOfT = new TypeToken<Collection<Foo>>(){}.getType(); | |
759 | * </pre> | |
760 | * @return an object of type T from the json | |
761 | * @throws JsonIOException if there was a problem reading from the Reader | |
762 | * @throws JsonSyntaxException if json is not a valid representation for an object of type | |
763 | * @since 1.2 | |
764 | */ | |
765 | @SuppressWarnings("unchecked") | |
766 | public <T> T fromJson(Reader json, Type typeOfT) throws JsonIOException, JsonSyntaxException { | |
767 | JsonReader jsonReader = new JsonReader(json); | |
768 | T object = (T) fromJson(jsonReader, typeOfT); | |
769 | assertFullConsumption(object, jsonReader); | |
770 | return object; | |
771 | } | |
772 | ||
773 | private static void assertFullConsumption(Object obj, JsonReader reader) { | |
774 | try { | |
775 | if (obj != null && reader.peek() != JsonToken.END_DOCUMENT) { | |
776 | throw new JsonIOException("JSON document was not fully consumed."); | |
777 | } | |
778 | } catch (MalformedJsonException e) { | |
779 | throw new JsonSyntaxException(e); | |
780 | } catch (IOException e) { | |
781 | throw new JsonIOException(e); | |
782 | } | |
783 | } | |
784 | ||
785 | /** | |
786 | * Reads the next JSON value from {@code reader} and convert it to an object | |
787 | * of type {@code typeOfT}. | |
788 | * Since Type is not parameterized by T, this method is type unsafe and should be used carefully | |
789 | * | |
790 | * @throws JsonIOException if there was a problem writing to the Reader | |
791 | * @throws JsonSyntaxException if json is not a valid representation for an object of type | |
792 | */ | |
793 | @SuppressWarnings("unchecked") | |
794 | public <T> T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException { | |
795 | boolean isEmpty = true; | |
796 | boolean oldLenient = reader.isLenient(); | |
797 | reader.setLenient(true); | |
798 | try { | |
799 | reader.peek(); | |
800 | isEmpty = false; | |
801 | TypeToken<T> typeToken = (TypeToken<T>) TypeToken.get(typeOfT); | |
802 | TypeAdapter<T> typeAdapter = getAdapter(typeToken); | |
803 | T object = typeAdapter.read(reader); | |
804 | return object; | |
805 | } catch (EOFException e) { | |
806 | /* | |
807 | * For compatibility with JSON 1.5 and earlier, we return null for empty | |
808 | * documents instead of throwing. | |
809 | */ | |
810 | if (isEmpty) { | |
811 | return null; | |
812 | } | |
813 | throw new JsonSyntaxException(e); | |
814 | } catch (IllegalStateException e) { | |
815 | throw new JsonSyntaxException(e); | |
816 | } catch (IOException e) { | |
817 | // TODO(inder): Figure out whether it is indeed right to rethrow this as JsonSyntaxException | |
818 | throw new JsonSyntaxException(e); | |
819 | } finally { | |
820 | reader.setLenient(oldLenient); | |
821 | } | |
822 | } | |
823 | ||
824 | /** | |
825 | * This method deserializes the Json read from the specified parse tree into an object of the | |
826 | * specified type. It is not suitable to use if the specified class is a generic type since it | |
827 | * will not have the generic type information because of the Type Erasure feature of Java. | |
828 | * Therefore, this method should not be used if the desired type is a generic type. Note that | |
829 | * this method works fine if the any of the fields of the specified object are generics, just the | |
830 | * object itself should not be a generic type. For the cases when the object is of generic type, | |
831 | * invoke {@link #fromJson(JsonElement, Type)}. | |
832 | * @param <T> the type of the desired object | |
833 | * @param json the root of the parse tree of {@link JsonElement}s from which the object is to | |
834 | * be deserialized | |
835 | * @param classOfT The class of T | |
836 | * @return an object of type T from the json | |
837 | * @throws JsonSyntaxException if json is not a valid representation for an object of type typeOfT | |
838 | * @since 1.3 | |
839 | */ | |
840 | public <T> T fromJson(JsonElement json, Class<T> classOfT) throws JsonSyntaxException { | |
841 | Object object = fromJson(json, (Type) classOfT); | |
842 | return Primitives.wrap(classOfT).cast(object); | |
843 | } | |
844 | ||
845 | /** | |
846 | * This method deserializes the Json read from the specified parse tree into an object of the | |
847 | * specified type. This method is useful if the specified object is a generic type. For | |
848 | * non-generic objects, use {@link #fromJson(JsonElement, Class)} instead. | |
849 | * | |
850 | * @param <T> the type of the desired object | |
851 | * @param json the root of the parse tree of {@link JsonElement}s from which the object is to | |
852 | * be deserialized | |
853 | * @param typeOfT The specific genericized type of src. You can obtain this type by using the | |
854 | * {@link com.google.gson.reflect.TypeToken} class. For example, to get the type for | |
855 | * {@code Collection<Foo>}, you should use: | |
856 | * <pre> | |
857 | * Type typeOfT = new TypeToken<Collection<Foo>>(){}.getType(); | |
858 | * </pre> | |
859 | * @return an object of type T from the json | |
860 | * @throws JsonSyntaxException if json is not a valid representation for an object of type typeOfT | |
861 | * @since 1.3 | |
862 | */ | |
863 | @SuppressWarnings("unchecked") | |
864 | public <T> T fromJson(JsonElement json, Type typeOfT) throws JsonSyntaxException { | |
865 | if (json == null) { | |
866 | return null; | |
867 | } | |
868 | return (T) fromJson(new JsonTreeReader(json), typeOfT); | |
869 | } | |
870 | ||
871 | static class FutureTypeAdapter<T> extends TypeAdapter<T> { | |
872 | private TypeAdapter<T> delegate; | |
873 | ||
874 | public void setDelegate(TypeAdapter<T> typeAdapter) { | |
875 | if (delegate != null) { | |
876 | throw new AssertionError(); | |
877 | } | |
878 | delegate = typeAdapter; | |
879 | } | |
880 | ||
881 | @Override public T read(JsonReader in) throws IOException { | |
882 | if (delegate == null) { | |
883 | throw new IllegalStateException(); | |
884 | } | |
885 | return delegate.read(in); | |
886 | } | |
887 | ||
888 | @Override public void write(JsonWriter out, T value) throws IOException { | |
889 | if (delegate == null) { | |
890 | throw new IllegalStateException(); | |
891 | } | |
892 | delegate.write(out, value); | |
893 | } | |
894 | } | |
895 | ||
896 | @Override | |
897 | public String toString() { | |
898 | return new StringBuilder("{serializeNulls:") | |
899 | .append(serializeNulls) | |
900 | .append("factories:").append(factories) | |
901 | .append(",instanceCreators:").append(constructorConstructor) | |
902 | .append("}") | |
903 | .toString(); | |
904 | } | |
905 | } |