2 * Copyright (C) 2011 Google Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com
.google
.gson
.internal
.bind
;
19 import com
.google
.gson
.TypeAdapterFactory
;
20 import java
.io
.IOException
;
21 import java
.math
.BigDecimal
;
22 import java
.math
.BigInteger
;
23 import java
.net
.InetAddress
;
25 import java
.net
.URISyntaxException
;
27 import java
.sql
.Timestamp
;
28 import java
.util
.BitSet
;
29 import java
.util
.Calendar
;
30 import java
.util
.Date
;
31 import java
.util
.GregorianCalendar
;
32 import java
.util
.HashMap
;
33 import java
.util
.Locale
;
35 import java
.util
.StringTokenizer
;
36 import java
.util
.UUID
;
38 import com
.google
.gson
.Gson
;
39 import com
.google
.gson
.JsonArray
;
40 import com
.google
.gson
.JsonElement
;
41 import com
.google
.gson
.JsonIOException
;
42 import com
.google
.gson
.JsonNull
;
43 import com
.google
.gson
.JsonObject
;
44 import com
.google
.gson
.JsonPrimitive
;
45 import com
.google
.gson
.JsonSyntaxException
;
46 import com
.google
.gson
.TypeAdapter
;
47 import com
.google
.gson
.annotations
.SerializedName
;
48 import com
.google
.gson
.internal
.LazilyParsedNumber
;
49 import com
.google
.gson
.reflect
.TypeToken
;
50 import com
.google
.gson
.stream
.JsonReader
;
51 import com
.google
.gson
.stream
.JsonToken
;
52 import com
.google
.gson
.stream
.JsonWriter
;
55 * Type adapters for basic types.
57 public final class TypeAdapters
{
58 private TypeAdapters() {}
60 @SuppressWarnings("rawtypes")
61 public static final TypeAdapter
<Class
> CLASS
= new TypeAdapter
<Class
>() {
63 public void write(JsonWriter out
, Class value
) throws IOException
{
67 throw new UnsupportedOperationException("Attempted to serialize java.lang.Class: "
68 + value
.getName() + ". Forgot to register a type adapter?");
72 public Class
read(JsonReader in
) throws IOException
{
73 if (in
.peek() == JsonToken
.NULL
) {
77 throw new UnsupportedOperationException(
78 "Attempted to deserialize a java.lang.Class. Forgot to register a type adapter?");
82 public static final TypeAdapterFactory CLASS_FACTORY
= newFactory(Class
.class, CLASS
);
84 public static final TypeAdapter
<BitSet
> BIT_SET
= new TypeAdapter
<BitSet
>() {
85 public BitSet
read(JsonReader in
) throws IOException
{
86 if (in
.peek() == JsonToken
.NULL
) {
91 BitSet bitset
= new BitSet();
94 JsonToken tokenType
= in
.peek();
95 while (tokenType
!= JsonToken
.END_ARRAY
) {
99 set
= in
.nextInt() != 0;
102 set
= in
.nextBoolean();
105 String stringValue
= in
.nextString();
107 set
= Integer
.parseInt(stringValue
) != 0;
108 } catch (NumberFormatException e
) {
109 throw new JsonSyntaxException(
110 "Error: Expecting: bitset number value (1, 0), Found: " + stringValue
);
114 throw new JsonSyntaxException("Invalid bitset value type: " + tokenType
);
120 tokenType
= in
.peek();
126 public void write(JsonWriter out
, BitSet src
) throws IOException
{
133 for (int i
= 0; i
< src
.length(); i
++) {
134 int value
= (src
.get(i
)) ?
1 : 0;
141 public static final TypeAdapterFactory BIT_SET_FACTORY
= newFactory(BitSet
.class, BIT_SET
);
143 public static final TypeAdapter
<Boolean
> BOOLEAN
= new TypeAdapter
<Boolean
>() {
145 public Boolean
read(JsonReader in
) throws IOException
{
146 if (in
.peek() == JsonToken
.NULL
) {
149 } else if (in
.peek() == JsonToken
.STRING
) {
150 // support strings for compatibility with GSON 1.7
151 return Boolean
.parseBoolean(in
.nextString());
153 return in
.nextBoolean();
156 public void write(JsonWriter out
, Boolean value
) throws IOException
{
166 * Writes a boolean as a string. Useful for map keys, where booleans aren't
167 * otherwise permitted.
169 public static final TypeAdapter
<Boolean
> BOOLEAN_AS_STRING
= new TypeAdapter
<Boolean
>() {
170 @Override public Boolean
read(JsonReader in
) throws IOException
{
171 if (in
.peek() == JsonToken
.NULL
) {
175 return Boolean
.valueOf(in
.nextString());
178 @Override public void write(JsonWriter out
, Boolean value
) throws IOException
{
179 out
.value(value
== null ?
"null" : value
.toString());
183 public static final TypeAdapterFactory BOOLEAN_FACTORY
184 = newFactory(boolean.class, Boolean
.class, BOOLEAN
);
186 public static final TypeAdapter
<Number
> BYTE
= new TypeAdapter
<Number
>() {
188 public Number
read(JsonReader in
) throws IOException
{
189 if (in
.peek() == JsonToken
.NULL
) {
194 int intValue
= in
.nextInt();
195 return (byte) intValue
;
196 } catch (NumberFormatException e
) {
197 throw new JsonSyntaxException(e
);
201 public void write(JsonWriter out
, Number value
) throws IOException
{
206 public static final TypeAdapterFactory BYTE_FACTORY
207 = newFactory(byte.class, Byte
.class, BYTE
);
209 public static final TypeAdapter
<Number
> SHORT
= new TypeAdapter
<Number
>() {
211 public Number
read(JsonReader in
) throws IOException
{
212 if (in
.peek() == JsonToken
.NULL
) {
217 return (short) in
.nextInt();
218 } catch (NumberFormatException e
) {
219 throw new JsonSyntaxException(e
);
223 public void write(JsonWriter out
, Number value
) throws IOException
{
228 public static final TypeAdapterFactory SHORT_FACTORY
229 = newFactory(short.class, Short
.class, SHORT
);
231 public static final TypeAdapter
<Number
> INTEGER
= new TypeAdapter
<Number
>() {
233 public Number
read(JsonReader in
) throws IOException
{
234 if (in
.peek() == JsonToken
.NULL
) {
240 } catch (NumberFormatException e
) {
241 throw new JsonSyntaxException(e
);
245 public void write(JsonWriter out
, Number value
) throws IOException
{
250 public static final TypeAdapterFactory INTEGER_FACTORY
251 = newFactory(int.class, Integer
.class, INTEGER
);
253 public static final TypeAdapter
<Number
> LONG
= new TypeAdapter
<Number
>() {
255 public Number
read(JsonReader in
) throws IOException
{
256 if (in
.peek() == JsonToken
.NULL
) {
261 return in
.nextLong();
262 } catch (NumberFormatException e
) {
263 throw new JsonSyntaxException(e
);
267 public void write(JsonWriter out
, Number value
) throws IOException
{
272 public static final TypeAdapter
<Number
> FLOAT
= new TypeAdapter
<Number
>() {
274 public Number
read(JsonReader in
) throws IOException
{
275 if (in
.peek() == JsonToken
.NULL
) {
279 return (float) in
.nextDouble();
282 public void write(JsonWriter out
, Number value
) throws IOException
{
287 public static final TypeAdapter
<Number
> DOUBLE
= new TypeAdapter
<Number
>() {
289 public Number
read(JsonReader in
) throws IOException
{
290 if (in
.peek() == JsonToken
.NULL
) {
294 return in
.nextDouble();
297 public void write(JsonWriter out
, Number value
) throws IOException
{
302 public static final TypeAdapter
<Number
> NUMBER
= new TypeAdapter
<Number
>() {
304 public Number
read(JsonReader in
) throws IOException
{
305 JsonToken jsonToken
= in
.peek();
311 return new LazilyParsedNumber(in
.nextString());
313 throw new JsonSyntaxException("Expecting number, got: " + jsonToken
);
317 public void write(JsonWriter out
, Number value
) throws IOException
{
322 public static final TypeAdapterFactory NUMBER_FACTORY
= newFactory(Number
.class, NUMBER
);
324 public static final TypeAdapter
<Character
> CHARACTER
= new TypeAdapter
<Character
>() {
326 public Character
read(JsonReader in
) throws IOException
{
327 if (in
.peek() == JsonToken
.NULL
) {
331 String str
= in
.nextString();
332 if (str
.length() != 1) {
333 throw new JsonSyntaxException("Expecting character, got: " + str
);
335 return str
.charAt(0);
338 public void write(JsonWriter out
, Character value
) throws IOException
{
339 out
.value(value
== null ?
null : String
.valueOf(value
));
343 public static final TypeAdapterFactory CHARACTER_FACTORY
344 = newFactory(char.class, Character
.class, CHARACTER
);
346 public static final TypeAdapter
<String
> STRING
= new TypeAdapter
<String
>() {
348 public String
read(JsonReader in
) throws IOException
{
349 JsonToken peek
= in
.peek();
350 if (peek
== JsonToken
.NULL
) {
354 /* coerce booleans to strings for backwards compatibility */
355 if (peek
== JsonToken
.BOOLEAN
) {
356 return Boolean
.toString(in
.nextBoolean());
358 return in
.nextString();
361 public void write(JsonWriter out
, String value
) throws IOException
{
366 public static final TypeAdapter
<BigDecimal
> BIG_DECIMAL
= new TypeAdapter
<BigDecimal
>() {
367 @Override public BigDecimal
read(JsonReader in
) throws IOException
{
368 if (in
.peek() == JsonToken
.NULL
) {
373 return new BigDecimal(in
.nextString());
374 } catch (NumberFormatException e
) {
375 throw new JsonSyntaxException(e
);
379 @Override public void write(JsonWriter out
, BigDecimal value
) throws IOException
{
384 public static final TypeAdapter
<BigInteger
> BIG_INTEGER
= new TypeAdapter
<BigInteger
>() {
385 @Override public BigInteger
read(JsonReader in
) throws IOException
{
386 if (in
.peek() == JsonToken
.NULL
) {
391 return new BigInteger(in
.nextString());
392 } catch (NumberFormatException e
) {
393 throw new JsonSyntaxException(e
);
397 @Override public void write(JsonWriter out
, BigInteger value
) throws IOException
{
402 public static final TypeAdapterFactory STRING_FACTORY
= newFactory(String
.class, STRING
);
404 public static final TypeAdapter
<StringBuilder
> STRING_BUILDER
= new TypeAdapter
<StringBuilder
>() {
406 public StringBuilder
read(JsonReader in
) throws IOException
{
407 if (in
.peek() == JsonToken
.NULL
) {
411 return new StringBuilder(in
.nextString());
414 public void write(JsonWriter out
, StringBuilder value
) throws IOException
{
415 out
.value(value
== null ?
null : value
.toString());
419 public static final TypeAdapterFactory STRING_BUILDER_FACTORY
=
420 newFactory(StringBuilder
.class, STRING_BUILDER
);
422 public static final TypeAdapter
<StringBuffer
> STRING_BUFFER
= new TypeAdapter
<StringBuffer
>() {
424 public StringBuffer
read(JsonReader in
) throws IOException
{
425 if (in
.peek() == JsonToken
.NULL
) {
429 return new StringBuffer(in
.nextString());
432 public void write(JsonWriter out
, StringBuffer value
) throws IOException
{
433 out
.value(value
== null ?
null : value
.toString());
437 public static final TypeAdapterFactory STRING_BUFFER_FACTORY
=
438 newFactory(StringBuffer
.class, STRING_BUFFER
);
440 public static final TypeAdapter
<URL
> URL
= new TypeAdapter
<URL
>() {
442 public URL
read(JsonReader in
) throws IOException
{
443 if (in
.peek() == JsonToken
.NULL
) {
447 String nextString
= in
.nextString();
448 return "null".equals(nextString
) ?
null : new URL(nextString
);
451 public void write(JsonWriter out
, URL value
) throws IOException
{
452 out
.value(value
== null ?
null : value
.toExternalForm());
456 public static final TypeAdapterFactory URL_FACTORY
= newFactory(URL
.class, URL
);
458 public static final TypeAdapter
<URI
> URI
= new TypeAdapter
<URI
>() {
460 public URI
read(JsonReader in
) throws IOException
{
461 if (in
.peek() == JsonToken
.NULL
) {
466 String nextString
= in
.nextString();
467 return "null".equals(nextString
) ?
null : new URI(nextString
);
468 } catch (URISyntaxException e
) {
469 throw new JsonIOException(e
);
473 public void write(JsonWriter out
, URI value
) throws IOException
{
474 out
.value(value
== null ?
null : value
.toASCIIString());
478 public static final TypeAdapterFactory URI_FACTORY
= newFactory(URI
.class, URI
);
480 public static final TypeAdapter
<InetAddress
> INET_ADDRESS
= new TypeAdapter
<InetAddress
>() {
482 public InetAddress
read(JsonReader in
) throws IOException
{
483 if (in
.peek() == JsonToken
.NULL
) {
487 // regrettably, this should have included both the host name and the host address
488 return InetAddress
.getByName(in
.nextString());
491 public void write(JsonWriter out
, InetAddress value
) throws IOException
{
492 out
.value(value
== null ?
null : value
.getHostAddress());
496 public static final TypeAdapterFactory INET_ADDRESS_FACTORY
=
497 newTypeHierarchyFactory(InetAddress
.class, INET_ADDRESS
);
499 public static final TypeAdapter
<UUID
> UUID
= new TypeAdapter
<UUID
>() {
501 public UUID
read(JsonReader in
) throws IOException
{
502 if (in
.peek() == JsonToken
.NULL
) {
506 return java
.util
.UUID
.fromString(in
.nextString());
509 public void write(JsonWriter out
, UUID value
) throws IOException
{
510 out
.value(value
== null ?
null : value
.toString());
514 public static final TypeAdapterFactory UUID_FACTORY
= newFactory(UUID
.class, UUID
);
516 public static final TypeAdapterFactory TIMESTAMP_FACTORY
= new TypeAdapterFactory() {
517 @SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal
518 public <T
> TypeAdapter
<T
> create(Gson gson
, TypeToken
<T
> typeToken
) {
519 if (typeToken
.getRawType() != Timestamp
.class) {
523 final TypeAdapter
<Date
> dateTypeAdapter
= gson
.getAdapter(Date
.class);
524 return (TypeAdapter
<T
>) new TypeAdapter
<Timestamp
>() {
525 @Override public Timestamp
read(JsonReader in
) throws IOException
{
526 Date date
= dateTypeAdapter
.read(in
);
527 return date
!= null ?
new Timestamp(date
.getTime()) : null;
530 @Override public void write(JsonWriter out
, Timestamp value
) throws IOException
{
531 dateTypeAdapter
.write(out
, value
);
537 public static final TypeAdapter
<Calendar
> CALENDAR
= new TypeAdapter
<Calendar
>() {
538 private static final String YEAR
= "year";
539 private static final String MONTH
= "month";
540 private static final String DAY_OF_MONTH
= "dayOfMonth";
541 private static final String HOUR_OF_DAY
= "hourOfDay";
542 private static final String MINUTE
= "minute";
543 private static final String SECOND
= "second";
546 public Calendar
read(JsonReader in
) throws IOException
{
547 if (in
.peek() == JsonToken
.NULL
) {
558 while (in
.peek() != JsonToken
.END_OBJECT
) {
559 String name
= in
.nextName();
560 int value
= in
.nextInt();
561 if (YEAR
.equals(name
)) {
563 } else if (MONTH
.equals(name
)) {
565 } else if (DAY_OF_MONTH
.equals(name
)) {
567 } else if (HOUR_OF_DAY
.equals(name
)) {
569 } else if (MINUTE
.equals(name
)) {
571 } else if (SECOND
.equals(name
)) {
576 return new GregorianCalendar(year
, month
, dayOfMonth
, hourOfDay
, minute
, second
);
580 public void write(JsonWriter out
, Calendar value
) throws IOException
{
587 out
.value(value
.get(Calendar
.YEAR
));
589 out
.value(value
.get(Calendar
.MONTH
));
590 out
.name(DAY_OF_MONTH
);
591 out
.value(value
.get(Calendar
.DAY_OF_MONTH
));
592 out
.name(HOUR_OF_DAY
);
593 out
.value(value
.get(Calendar
.HOUR_OF_DAY
));
595 out
.value(value
.get(Calendar
.MINUTE
));
597 out
.value(value
.get(Calendar
.SECOND
));
602 public static final TypeAdapterFactory CALENDAR_FACTORY
=
603 newFactoryForMultipleTypes(Calendar
.class, GregorianCalendar
.class, CALENDAR
);
605 public static final TypeAdapter
<Locale
> LOCALE
= new TypeAdapter
<Locale
>() {
607 public Locale
read(JsonReader in
) throws IOException
{
608 if (in
.peek() == JsonToken
.NULL
) {
612 String locale
= in
.nextString();
613 StringTokenizer tokenizer
= new StringTokenizer(locale
, "_");
614 String language
= null;
615 String country
= null;
616 String variant
= null;
617 if (tokenizer
.hasMoreElements()) {
618 language
= tokenizer
.nextToken();
620 if (tokenizer
.hasMoreElements()) {
621 country
= tokenizer
.nextToken();
623 if (tokenizer
.hasMoreElements()) {
624 variant
= tokenizer
.nextToken();
626 if (country
== null && variant
== null) {
627 return new Locale(language
);
628 } else if (variant
== null) {
629 return new Locale(language
, country
);
631 return new Locale(language
, country
, variant
);
635 public void write(JsonWriter out
, Locale value
) throws IOException
{
636 out
.value(value
== null ?
null : value
.toString());
640 public static final TypeAdapterFactory LOCALE_FACTORY
= newFactory(Locale
.class, LOCALE
);
642 public static final TypeAdapter
<JsonElement
> JSON_ELEMENT
= new TypeAdapter
<JsonElement
>() {
643 @Override public JsonElement
read(JsonReader in
) throws IOException
{
646 return new JsonPrimitive(in
.nextString());
648 String number
= in
.nextString();
649 return new JsonPrimitive(new LazilyParsedNumber(number
));
651 return new JsonPrimitive(in
.nextBoolean());
654 return JsonNull
.INSTANCE
;
656 JsonArray array
= new JsonArray();
658 while (in
.hasNext()) {
664 JsonObject object
= new JsonObject();
666 while (in
.hasNext()) {
667 object
.add(in
.nextName(), read(in
));
676 throw new IllegalArgumentException();
680 @Override public void write(JsonWriter out
, JsonElement value
) throws IOException
{
681 if (value
== null || value
.isJsonNull()) {
683 } else if (value
.isJsonPrimitive()) {
684 JsonPrimitive primitive
= value
.getAsJsonPrimitive();
685 if (primitive
.isNumber()) {
686 out
.value(primitive
.getAsNumber());
687 } else if (primitive
.isBoolean()) {
688 out
.value(primitive
.getAsBoolean());
690 out
.value(primitive
.getAsString());
693 } else if (value
.isJsonArray()) {
695 for (JsonElement e
: value
.getAsJsonArray()) {
700 } else if (value
.isJsonObject()) {
702 for (Map
.Entry
<String
, JsonElement
> e
: value
.getAsJsonObject().entrySet()) {
703 out
.name(e
.getKey());
704 write(out
, e
.getValue());
709 throw new IllegalArgumentException("Couldn't write " + value
.getClass());
714 public static final TypeAdapterFactory JSON_ELEMENT_FACTORY
715 = newTypeHierarchyFactory(JsonElement
.class, JSON_ELEMENT
);
717 private static final class EnumTypeAdapter
<T
extends Enum
<T
>> extends TypeAdapter
<T
> {
718 private final Map
<String
, T
> nameToConstant
= new HashMap
<String
, T
>();
719 private final Map
<T
, String
> constantToName
= new HashMap
<T
, String
>();
721 public EnumTypeAdapter(Class
<T
> classOfT
) {
723 for (T constant
: classOfT
.getEnumConstants()) {
724 String name
= constant
.name();
725 SerializedName annotation
= classOfT
.getField(name
).getAnnotation(SerializedName
.class);
726 if (annotation
!= null) {
727 name
= annotation
.value();
729 nameToConstant
.put(name
, constant
);
730 constantToName
.put(constant
, name
);
732 } catch (NoSuchFieldException e
) {
733 throw new AssertionError();
736 public T
read(JsonReader in
) throws IOException
{
737 if (in
.peek() == JsonToken
.NULL
) {
741 return nameToConstant
.get(in
.nextString());
744 public void write(JsonWriter out
, T value
) throws IOException
{
745 out
.value(value
== null ?
null : constantToName
.get(value
));
749 public static final TypeAdapterFactory ENUM_FACTORY
= newEnumTypeHierarchyFactory();
751 public static TypeAdapterFactory
newEnumTypeHierarchyFactory() {
752 return new TypeAdapterFactory() {
753 @SuppressWarnings({"rawtypes", "unchecked"})
754 public <T
> TypeAdapter
<T
> create(Gson gson
, TypeToken
<T
> typeToken
) {
755 Class
<?
super T
> rawType
= typeToken
.getRawType();
756 if (!Enum
.class.isAssignableFrom(rawType
) || rawType
== Enum
.class) {
759 if (!rawType
.isEnum()) {
760 rawType
= rawType
.getSuperclass(); // handle anonymous subclasses
762 return (TypeAdapter
<T
>) new EnumTypeAdapter(rawType
);
767 public static <TT
> TypeAdapterFactory
newFactory(
768 final TypeToken
<TT
> type
, final TypeAdapter
<TT
> typeAdapter
) {
769 return new TypeAdapterFactory() {
770 @SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal
771 public <T
> TypeAdapter
<T
> create(Gson gson
, TypeToken
<T
> typeToken
) {
772 return typeToken
.equals(type
) ?
(TypeAdapter
<T
>) typeAdapter
: null;
777 public static <TT
> TypeAdapterFactory
newFactory(
778 final Class
<TT
> type
, final TypeAdapter
<TT
> typeAdapter
) {
779 return new TypeAdapterFactory() {
780 @SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal
781 public <T
> TypeAdapter
<T
> create(Gson gson
, TypeToken
<T
> typeToken
) {
782 return typeToken
.getRawType() == type ?
(TypeAdapter
<T
>) typeAdapter
: null;
784 @Override public String
toString() {
785 return "Factory[type=" + type
.getName() + ",adapter=" + typeAdapter
+ "]";
790 public static <TT
> TypeAdapterFactory
newFactory(
791 final Class
<TT
> unboxed
, final Class
<TT
> boxed
, final TypeAdapter
<?
super TT
> typeAdapter
) {
792 return new TypeAdapterFactory() {
793 @SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal
794 public <T
> TypeAdapter
<T
> create(Gson gson
, TypeToken
<T
> typeToken
) {
795 Class
<?
super T
> rawType
= typeToken
.getRawType();
796 return (rawType
== unboxed
|| rawType
== boxed
) ?
(TypeAdapter
<T
>) typeAdapter
: null;
798 @Override public String
toString() {
799 return "Factory[type=" + boxed
.getName()
800 + "+" + unboxed
.getName() + ",adapter=" + typeAdapter
+ "]";
805 public static <TT
> TypeAdapterFactory
newFactoryForMultipleTypes(final Class
<TT
> base
,
806 final Class
<?
extends TT
> sub
, final TypeAdapter
<?
super TT
> typeAdapter
) {
807 return new TypeAdapterFactory() {
808 @SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal
809 public <T
> TypeAdapter
<T
> create(Gson gson
, TypeToken
<T
> typeToken
) {
810 Class
<?
super T
> rawType
= typeToken
.getRawType();
811 return (rawType
== base
|| rawType
== sub
) ?
(TypeAdapter
<T
>) typeAdapter
: null;
813 @Override public String
toString() {
814 return "Factory[type=" + base
.getName()
815 + "+" + sub
.getName() + ",adapter=" + typeAdapter
+ "]";
820 public static <TT
> TypeAdapterFactory
newTypeHierarchyFactory(
821 final Class
<TT
> clazz
, final TypeAdapter
<TT
> typeAdapter
) {
822 return new TypeAdapterFactory() {
823 @SuppressWarnings("unchecked")
824 public <T
> TypeAdapter
<T
> create(Gson gson
, TypeToken
<T
> typeToken
) {
825 return clazz
.isAssignableFrom(typeToken
.getRawType()) ?
(TypeAdapter
<T
>) typeAdapter
: null;
827 @Override public String
toString() {
828 return "Factory[typeHierarchy=" + clazz
.getName() + ",adapter=" + typeAdapter
+ "]";