1 /*
2  * Copyright (C) 2011 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.internal.bind;
18
19 import com.google.gson.Gson;
20 import com.google.gson.JsonDeserializationContext;
21 import com.google.gson.JsonDeserializer;
22 import com.google.gson.JsonElement;
23 import com.google.gson.JsonParseException;
24 import com.google.gson.JsonSerializationContext;
25 import com.google.gson.JsonSerializer;
26 import com.google.gson.TypeAdapter;
27 import com.google.gson.TypeAdapterFactory;
28 import com.google.gson.internal.$Gson$Preconditions;
29 import com.google.gson.internal.Streams;
30 import com.google.gson.reflect.TypeToken;
31 import com.google.gson.stream.JsonReader;
32 import com.google.gson.stream.JsonWriter;
33 import java.io.IOException;
34 import java.lang.reflect.Type;
35
36 /**
37  * Adapts a Gson 1.x tree-style adapter as a streaming TypeAdapter. Since the
38  * tree adapter may be serialization-only or deserialization-only, this class
39  * has a facility to lookup a delegate type adapter on demand.
40  */

41 public final class TreeTypeAdapter<T> extends TypeAdapter<T> {
42   private final JsonSerializer<T> serializer;
43   private final JsonDeserializer<T> deserializer;
44   final Gson gson;
45   private final TypeToken<T> typeToken;
46   private final TypeAdapterFactory skipPast;
47   private final GsonContextImpl context = new GsonContextImpl();
48
49   /** The delegate is lazily created because it may not be needed, and creating it may fail. */
50   private TypeAdapter<T> delegate;
51
52   public TreeTypeAdapter(JsonSerializer<T> serializer, JsonDeserializer<T> deserializer,
53       Gson gson, TypeToken<T> typeToken, TypeAdapterFactory skipPast) {
54     this.serializer = serializer;
55     this.deserializer = deserializer;
56     this.gson = gson;
57     this.typeToken = typeToken;
58     this.skipPast = skipPast;
59   }
60
61   @Override public T read(JsonReader in) throws IOException {
62     if (deserializer == null) {
63       return delegate().read(in);
64     }
65     JsonElement value = Streams.parse(in);
66     if (value.isJsonNull()) {
67       return null;
68     }
69     return deserializer.deserialize(value, typeToken.getType(), context);
70   }
71
72   @Override public void write(JsonWriter out, T value) throws IOException {
73     if (serializer == null) {
74       delegate().write(out, value);
75       return;
76     }
77     if (value == null) {
78       out.nullValue();
79       return;
80     }
81     JsonElement tree = serializer.serialize(value, typeToken.getType(), context);
82     Streams.write(tree, out);
83   }
84
85   private TypeAdapter<T> delegate() {
86     TypeAdapter<T> d = delegate;
87     return d != null
88         ? d
89         : (delegate = gson.getDelegateAdapter(skipPast, typeToken));
90   }
91
92   /**
93    * Returns a new factory that will match each type against {@code exactType}.
94    */

95   public static TypeAdapterFactory newFactory(TypeToken<?> exactType, Object typeAdapter) {
96     return new SingleTypeFactory(typeAdapter, exactType, falsenull);
97   }
98
99   /**
100    * Returns a new factory that will match each type and its raw type against
101    * {@code exactType}.
102    */

103   public static TypeAdapterFactory newFactoryWithMatchRawType(
104       TypeToken<?> exactType, Object typeAdapter) {
105     // only bother matching raw types if exact type is a raw type
106     boolean matchRawType = exactType.getType() == exactType.getRawType();
107     return new SingleTypeFactory(typeAdapter, exactType, matchRawType, null);
108   }
109
110   /**
111    * Returns a new factory that will match each type's raw type for assignability
112    * to {@code hierarchyType}.
113    */

114   public static TypeAdapterFactory newTypeHierarchyFactory(
115       Class<?> hierarchyType, Object typeAdapter) {
116     return new SingleTypeFactory(typeAdapter, nullfalse, hierarchyType);
117   }
118
119   private static final class SingleTypeFactory implements TypeAdapterFactory {
120     private final TypeToken<?> exactType;
121     private final boolean matchRawType;
122     private final Class<?> hierarchyType;
123     private final JsonSerializer<?> serializer;
124     private final JsonDeserializer<?> deserializer;
125
126     SingleTypeFactory(Object typeAdapter, TypeToken<?> exactType, boolean matchRawType,
127         Class<?> hierarchyType) {
128       serializer = typeAdapter instanceof JsonSerializer
129           ? (JsonSerializer<?>) typeAdapter
130           : null;
131       deserializer = typeAdapter instanceof JsonDeserializer
132           ? (JsonDeserializer<?>) typeAdapter
133           : null;
134       $Gson$Preconditions.checkArgument(serializer != null || deserializer != null);
135       this.exactType = exactType;
136       this.matchRawType = matchRawType;
137       this.hierarchyType = hierarchyType;
138     }
139
140     @SuppressWarnings("unchecked"// guarded by typeToken.equals() call
141     @Override
142     public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
143       boolean matches = exactType != null
144           ? exactType.equals(type) || matchRawType && exactType.getType() == type.getRawType()
145           : hierarchyType.isAssignableFrom(type.getRawType());
146       return matches
147           ? new TreeTypeAdapter<T>((JsonSerializer<T>) serializer,
148               (JsonDeserializer<T>) deserializer, gson, type, this)
149           : null;
150     }
151   }
152
153   private final class GsonContextImpl implements JsonSerializationContext, JsonDeserializationContext {
154     @Override public JsonElement serialize(Object src) {
155       return gson.toJsonTree(src);
156     }
157     @Override public JsonElement serialize(Object src, Type typeOfSrc) {
158       return gson.toJsonTree(src, typeOfSrc);
159     }
160     @SuppressWarnings("unchecked")
161     @Override public <R> R deserialize(JsonElement json, Type typeOfT) throws JsonParseException {
162       return (R) gson.fromJson(json, typeOfT);
163     }
164   };
165 }
166