| 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 | } |