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
;
19 import com
.google
.gson
.internal
.bind
.JsonTreeWriter
;
20 import com
.google
.gson
.internal
.bind
.JsonTreeReader
;
21 import com
.google
.gson
.stream
.JsonReader
;
22 import com
.google
.gson
.stream
.JsonToken
;
23 import com
.google
.gson
.stream
.JsonWriter
;
24 import java
.io
.IOException
;
25 import java
.io
.Reader
;
26 import java
.io
.StringReader
;
27 import java
.io
.StringWriter
;
28 import java
.io
.Writer
;
31 * Converts Java objects to and from JSON.
33 * <h3>Defining a type's JSON form</h3>
34 * By default Gson converts application classes to JSON using its built-in type
35 * adapters. If Gson's default JSON conversion isn't appropriate for a type,
36 * extend this class to customize the conversion. Here's an example of a type
37 * adapter for an (X,Y) coordinate point: <pre> {@code
39 * public class PointAdapter extends TypeAdapter<Point> {
40 * public Point read(JsonReader reader) throws IOException {
41 * if (reader.peek() == JsonToken.NULL) {
45 * String xy = reader.nextString();
46 * String[] parts = xy.split(",");
47 * int x = Integer.parseInt(parts[0]);
48 * int y = Integer.parseInt(parts[1]);
49 * return new Point(x, y);
51 * public void write(JsonWriter writer, Point value) throws IOException {
52 * if (value == null) {
56 * String xy = value.getX() + "," + value.getY();
60 * With this type adapter installed, Gson will convert {@code Points} to JSON as
61 * strings like {@code "5,8"} rather than objects like {@code {"x":5,"y":8}}. In
62 * this case the type adapter binds a rich Java class to a compact JSON value.
64 * <p>The {@link #read(JsonReader) read()} method must read exactly one value
65 * and {@link #write(JsonWriter,Object) write()} must write exactly one value.
66 * For primitive types this is means readers should make exactly one call to
67 * {@code nextBoolean()}, {@code nextDouble()}, {@code nextInt()}, {@code
68 * nextLong()}, {@code nextString()} or {@code nextNull()}. Writers should make
69 * exactly one call to one of <code>value()</code> or <code>nullValue()</code>.
70 * For arrays, type adapters should start with a call to {@code beginArray()},
71 * convert all elements, and finish with a call to {@code endArray()}. For
72 * objects, they should start with {@code beginObject()}, convert the object,
73 * and finish with {@code endObject()}. Failing to convert a value or converting
74 * too many values may cause the application to crash.
76 * <p>Type adapters should be prepared to read null from the stream and write it
77 * to the stream. Alternatively, they should use {@link #nullSafe()} method while
78 * registering the type adapter with Gson. If your {@code Gson} instance
79 * has been configured to {@link GsonBuilder#serializeNulls()}, these nulls will be
80 * written to the final document. Otherwise the value (and the corresponding name
81 * when writing to a JSON object) will be omitted automatically. In either case
82 * your type adapter must handle null.
84 * <p>To use a custom type adapter with Gson, you must <i>register</i> it with a
85 * {@link GsonBuilder}: <pre> {@code
87 * GsonBuilder builder = new GsonBuilder();
88 * builder.registerTypeAdapter(Point.class, new PointAdapter());
89 * // if PointAdapter didn't check for nulls in its read/write methods, you should instead use
90 * // builder.registerTypeAdapter(Point.class, new PointAdapter().nullSafe());
92 * Gson gson = builder.create();
99 // <h3>JSON Conversion</h3>
100 // <p>A type adapter registered with Gson is automatically invoked while serializing
101 // or deserializing JSON. However, you can also use type adapters directly to serialize
102 // and deserialize JSON. Here is an example for deserialization: <pre> {@code
104 // String json = "{'origin':'0,0','points':['1,2','3,4']}";
105 // TypeAdapter<Graph> graphAdapter = gson.getAdapter(Graph.class);
106 // Graph graph = graphAdapter.fromJson(json);
108 // And an example for serialization: <pre> {@code
110 // Graph graph = new Graph(...);
111 // TypeAdapter<Graph> graphAdapter = gson.getAdapter(Graph.class);
112 // String json = graphAdapter.toJson(graph);
115 // <p>Type adapters are <strong>type-specific</strong>. For example, a {@code
116 // TypeAdapter<Date>} can convert {@code Date} instances to JSON and JSON to
117 // instances of {@code Date}, but cannot convert any other types.
119 public abstract class TypeAdapter
<T
> {
122 * Writes one JSON value (an array, object, string, number, boolean or null)
125 * @param value the Java object to write. May be null.
127 public abstract void write(JsonWriter out
, T value
) throws IOException
;
130 * Converts {@code value} to a JSON document and writes it to {@code out}.
131 * Unlike Gson's similar {@link Gson#toJson(JsonElement, Appendable) toJson}
132 * method, this write is strict. Create a {@link
133 * JsonWriter#setLenient(boolean) lenient} {@code JsonWriter} and call
134 * {@link #write(com.google.gson.stream.JsonWriter, Object)} for lenient
137 * @param value the Java object to convert. May be null.
140 public final void toJson(Writer out
, T value
) throws IOException
{
141 JsonWriter writer
= new JsonWriter(out
);
142 write(writer
, value
);
146 * This wrapper method is used to make a type adapter null tolerant. In general, a
147 * type adapter is required to handle nulls in write and read methods. Here is how this
148 * is typically done:<br>
151 * Gson gson = new GsonBuilder().registerTypeAdapter(Foo.class,
152 * new TypeAdapter<Foo>() {
153 * public Foo read(JsonReader in) throws IOException {
154 * if (in.peek() == JsonToken.NULL) {
158 * // read a Foo from in and return it
160 * public void write(JsonWriter out, Foo src) throws IOException {
165 * // write src as JSON to out
169 * You can avoid this boilerplate handling of nulls by wrapping your type adapter with
170 * this method. Here is how we will rewrite the above example:
173 * Gson gson = new GsonBuilder().registerTypeAdapter(Foo.class,
174 * new TypeAdapter<Foo>() {
175 * public Foo read(JsonReader in) throws IOException {
176 * // read a Foo from in and return it
178 * public void write(JsonWriter out, Foo src) throws IOException {
179 * // write src as JSON to out
181 * }.nullSafe()).create();
183 * Note that we didn't need to check for nulls in our type adapter after we used nullSafe.
185 public final TypeAdapter
<T
> nullSafe() {
186 return new TypeAdapter
<T
>() {
187 @Override public void write(JsonWriter out
, T value
) throws IOException
{
191 TypeAdapter
.this.write(out
, value
);
194 @Override public T
read(JsonReader reader
) throws IOException
{
195 if (reader
.peek() == JsonToken
.NULL
) {
199 return TypeAdapter
.this.read(reader
);
205 * Converts {@code value} to a JSON document. Unlike Gson's similar {@link
206 * Gson#toJson(Object) toJson} method, this write is strict. Create a {@link
207 * JsonWriter#setLenient(boolean) lenient} {@code JsonWriter} and call
208 * {@link #write(com.google.gson.stream.JsonWriter, Object)} for lenient
211 * @param value the Java object to convert. May be null.
214 public final String
toJson(T value
) throws IOException
{
215 StringWriter stringWriter
= new StringWriter();
216 toJson(stringWriter
, value
);
217 return stringWriter
.toString();
221 * Converts {@code value} to a JSON tree.
223 * @param value the Java object to convert. May be null.
224 * @return the converted JSON tree. May be {@link JsonNull}.
227 public final JsonElement
toJsonTree(T value
) {
229 JsonTreeWriter jsonWriter
= new JsonTreeWriter();
230 write(jsonWriter
, value
);
231 return jsonWriter
.get();
232 } catch (IOException e
) {
233 throw new JsonIOException(e
);
238 * Reads one JSON value (an array, object, string, number, boolean or null)
239 * and converts it to a Java object. Returns the converted object.
241 * @return the converted Java object. May be null.
243 public abstract T
read(JsonReader in
) throws IOException
;
246 * Converts the JSON document in {@code in} to a Java object. Unlike Gson's
247 * similar {@link Gson#fromJson(java.io.Reader, Class) fromJson} method, this
248 * read is strict. Create a {@link JsonReader#setLenient(boolean) lenient}
249 * {@code JsonReader} and call {@link #read(JsonReader)} for lenient reading.
251 * @return the converted Java object. May be null.
254 public final T
fromJson(Reader in
) throws IOException
{
255 JsonReader reader
= new JsonReader(in
);
260 * Converts the JSON document in {@code json} to a Java object. Unlike Gson's
261 * similar {@link Gson#fromJson(String, Class) fromJson} method, this read is
262 * strict. Create a {@link JsonReader#setLenient(boolean) lenient} {@code
263 * JsonReader} and call {@link #read(JsonReader)} for lenient reading.
265 * @return the converted Java object. May be null.
268 public final T
fromJson(String json
) throws IOException
{
269 return fromJson(new StringReader(json
));
273 * Converts {@code jsonTree} to a Java object.
275 * @param jsonTree the Java object to convert. May be {@link JsonNull}.
278 public final T
fromJsonTree(JsonElement jsonTree
) {
280 JsonReader jsonReader
= new JsonTreeReader(jsonTree
);
281 return read(jsonReader
);
282 } catch (IOException e
) {
283 throw new JsonIOException(e
);