/* 
 | 
 * Copyright (C) 2011 Google Inc. 
 | 
 * 
 | 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 | 
 * you may not use this file except in compliance with the License. 
 | 
 * You may obtain a copy of the License at 
 | 
 * 
 | 
 *      http://www.apache.org/licenses/LICENSE-2.0 
 | 
 * 
 | 
 * Unless required by applicable law or agreed to in writing, software 
 | 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 | 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 | 
 * See the License for the specific language governing permissions and 
 | 
 * limitations under the License. 
 | 
 */ 
 | 
  
 | 
package cn.emay.sdk.util.json.gson; 
 | 
  
 | 
import java.io.IOException; 
 | 
import java.io.Reader; 
 | 
import java.io.StringReader; 
 | 
import java.io.StringWriter; 
 | 
import java.io.Writer; 
 | 
  
 | 
import cn.emay.sdk.util.json.gson.internal.bind.JsonTreeReader; 
 | 
import cn.emay.sdk.util.json.gson.internal.bind.JsonTreeWriter; 
 | 
import cn.emay.sdk.util.json.gson.stream.JsonReader; 
 | 
import cn.emay.sdk.util.json.gson.stream.JsonToken; 
 | 
import cn.emay.sdk.util.json.gson.stream.JsonWriter; 
 | 
  
 | 
/** 
 | 
 * Converts Java objects to and from JSON. 
 | 
 * 
 | 
 * <h3>Defining a type's JSON form</h3> By default Gson converts application 
 | 
 * classes to JSON using its built-in type adapters. If Gson's default JSON 
 | 
 * conversion isn't appropriate for a type, extend this class to customize the 
 | 
 * conversion. Here's an example of a type adapter for an (X,Y) coordinate 
 | 
 * point: 
 | 
 *  
 | 
 * <pre> 
 | 
 * { 
 | 
 *     @code 
 | 
 * 
 | 
 *     public class PointAdapter extends TypeAdapter<Point> { 
 | 
 *         public Point read(JsonReader reader) throws IOException { 
 | 
 *             if (reader.peek() == JsonToken.NULL) { 
 | 
 *                 reader.nextNull(); 
 | 
 *                 return null; 
 | 
 *             } 
 | 
 *             String xy = reader.nextString(); 
 | 
 *             String[] parts = xy.split(","); 
 | 
 *             int x = Integer.parseInt(parts[0]); 
 | 
 *             int y = Integer.parseInt(parts[1]); 
 | 
 *             return new Point(x, y); 
 | 
 *         } 
 | 
 *  
 | 
 *         public void write(JsonWriter writer, Point value) throws IOException { 
 | 
 *             if (value == null) { 
 | 
 *                 writer.nullValue(); 
 | 
 *                 return; 
 | 
 *             } 
 | 
 *             String xy = value.getX() + "," + value.getY(); 
 | 
 *             writer.value(xy); 
 | 
 *         } 
 | 
 *     } 
 | 
 * } 
 | 
 * </pre> 
 | 
 *  
 | 
 * With this type adapter installed, Gson will convert {@code Points} to JSON as 
 | 
 * strings like {@code "5,8"} rather than objects like {@code {"x":5,"y":8}}. In 
 | 
 * this case the type adapter binds a rich Java class to a compact JSON value. 
 | 
 * 
 | 
 * <p> 
 | 
 * The {@link #read(JsonReader) read()} method must read exactly one value and 
 | 
 * {@link #write(JsonWriter,Object) write()} must write exactly one value. For 
 | 
 * primitive types this is means readers should make exactly one call to 
 | 
 * {@code nextBoolean()}, {@code nextDouble()}, {@code nextInt()}, {@code 
 | 
 * nextLong()}, {@code nextString()} or {@code nextNull()}. Writers should make 
 | 
 * exactly one call to one of <code>value()</code> or <code>nullValue()</code>. 
 | 
 * For arrays, type adapters should start with a call to {@code beginArray()}, 
 | 
 * convert all elements, and finish with a call to {@code endArray()}. For 
 | 
 * objects, they should start with {@code beginObject()}, convert the object, 
 | 
 * and finish with {@code endObject()}. Failing to convert a value or converting 
 | 
 * too many values may cause the application to crash. 
 | 
 * 
 | 
 * <p> 
 | 
 * Type adapters should be prepared to read null from the stream and write it to 
 | 
 * the stream. Alternatively, they should use {@link #nullSafe()} method while 
 | 
 * registering the type adapter with Gson. If your {@code Gson} instance has 
 | 
 * been configured to {@link GsonBuilder#serializeNulls()}, these nulls will be 
 | 
 * written to the final document. Otherwise the value (and the corresponding 
 | 
 * name when writing to a JSON object) will be omitted automatically. In either 
 | 
 * case your type adapter must handle null. 
 | 
 * 
 | 
 * <p> 
 | 
 * To use a custom type adapter with Gson, you must <i>register</i> it with a 
 | 
 * {@link GsonBuilder}: 
 | 
 *  
 | 
 * <pre> 
 | 
 *    {@code 
 | 
 * 
 | 
 *   GsonBuilder builder = new GsonBuilder(); 
 | 
 *   builder.registerTypeAdapter(Point.class, new PointAdapter()); 
 | 
 *   // if PointAdapter didn't check for nulls in its read/write methods, you should instead use 
 | 
 *   // builder.registerTypeAdapter(Point.class, new PointAdapter().nullSafe()); 
 | 
 *   ... 
 | 
 *   Gson gson = builder.create(); 
 | 
 * } 
 | 
 * </pre> 
 | 
 * 
 | 
 * @since 2.1 
 | 
 */ 
 | 
// non-Javadoc: 
 | 
// 
 | 
// <h3>JSON Conversion</h3> 
 | 
// <p>A type adapter registered with Gson is automatically invoked while 
 | 
// serializing 
 | 
// or deserializing JSON. However, you can also use type adapters directly to 
 | 
// serialize 
 | 
// and deserialize JSON. Here is an example for deserialization: <pre> {@code 
 | 
// 
 | 
// String json = "{'origin':'0,0','points':['1,2','3,4']}"; 
 | 
// TypeAdapter<Graph> graphAdapter = gson.getAdapter(Graph.class); 
 | 
// Graph graph = graphAdapter.fromJson(json); 
 | 
// }</pre> 
 | 
// And an example for serialization: <pre> {@code 
 | 
// 
 | 
// Graph graph = new Graph(...); 
 | 
// TypeAdapter<Graph> graphAdapter = gson.getAdapter(Graph.class); 
 | 
// String json = graphAdapter.toJson(graph); 
 | 
// }</pre> 
 | 
// 
 | 
// <p>Type adapters are <strong>type-specific</strong>. For example, a {@code 
 | 
// TypeAdapter<Date>} can convert {@code Date} instances to JSON and JSON to 
 | 
// instances of {@code Date}, but cannot convert any other types. 
 | 
// 
 | 
public abstract class TypeAdapter<T> { 
 | 
  
 | 
    /** 
 | 
     * Writes one JSON value (an array, object, string, number, boolean or null) for 
 | 
     * {@code value}. 
 | 
     * 
 | 
     * @param value 
 | 
     *            the Java object to write. May be null. 
 | 
     */ 
 | 
    public abstract void write(JsonWriter out, T value) throws IOException; 
 | 
  
 | 
    /** 
 | 
     * Converts {@code value} to a JSON document and writes it to {@code out}. 
 | 
     * Unlike Gson's similar {@link Gson#toJson(JsonElement, Appendable) toJson} 
 | 
     * method, this write is strict. Create a {@link JsonWriter#setLenient(boolean) 
 | 
     * lenient} {@code JsonWriter} and call 
 | 
     * {@link #write(com.google.gson.stream.JsonWriter, Object)} for lenient 
 | 
     * writing. 
 | 
     * 
 | 
     * @param value 
 | 
     *            the Java object to convert. May be null. 
 | 
     * @since 2.2 
 | 
     */ 
 | 
    public final void toJson(Writer out, T value) throws IOException { 
 | 
        JsonWriter writer = new JsonWriter(out); 
 | 
        write(writer, value); 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * This wrapper method is used to make a type adapter null tolerant. In general, 
 | 
     * a type adapter is required to handle nulls in write and read methods. Here is 
 | 
     * how this is typically done:<br> 
 | 
     *  
 | 
     * <pre> 
 | 
     * { 
 | 
     *     @code 
 | 
     * 
 | 
     *     Gson gson = new GsonBuilder().registerTypeAdapter(Foo.class, new TypeAdapter<Foo>() { 
 | 
     *         public Foo read(JsonReader in) throws IOException { 
 | 
     *             if (in.peek() == JsonToken.NULL) { 
 | 
     *                 in.nextNull(); 
 | 
     *                 return null; 
 | 
     *             } 
 | 
     *             // read a Foo from in and return it 
 | 
     *         } 
 | 
     *  
 | 
     *         public void write(JsonWriter out, Foo src) throws IOException { 
 | 
     *             if (src == null) { 
 | 
     *                 out.nullValue(); 
 | 
     *                 return; 
 | 
     *             } 
 | 
     *             // write src as JSON to out 
 | 
     *         } 
 | 
     *     }).create(); 
 | 
     * } 
 | 
     * </pre> 
 | 
     *  
 | 
     * You can avoid this boilerplate handling of nulls by wrapping your type 
 | 
     * adapter with this method. Here is how we will rewrite the above example: 
 | 
     *  
 | 
     * <pre> 
 | 
     * { 
 | 
     *     @code 
 | 
     * 
 | 
     *     Gson gson = new GsonBuilder().registerTypeAdapter(Foo.class, new TypeAdapter<Foo>() { 
 | 
     *         public Foo read(JsonReader in) throws IOException { 
 | 
     *             // read a Foo from in and return it 
 | 
     *         } 
 | 
     *  
 | 
     *         public void write(JsonWriter out, Foo src) throws IOException { 
 | 
     *             // write src as JSON to out 
 | 
     *         } 
 | 
     *     }.nullSafe()).create(); 
 | 
     * } 
 | 
     * </pre> 
 | 
     *  
 | 
     * Note that we didn't need to check for nulls in our type adapter after we used 
 | 
     * nullSafe. 
 | 
     */ 
 | 
    public final TypeAdapter<T> nullSafe() { 
 | 
        return new TypeAdapter<T>() { 
 | 
            @Override 
 | 
            public void write(JsonWriter out, T value) throws IOException { 
 | 
                if (value == null) { 
 | 
                    out.nullValue(); 
 | 
                } else { 
 | 
                    TypeAdapter.this.write(out, value); 
 | 
                } 
 | 
            } 
 | 
  
 | 
            @Override 
 | 
            public T read(JsonReader reader) throws IOException { 
 | 
                if (reader.peek() == JsonToken.NULL) { 
 | 
                    reader.nextNull(); 
 | 
                    return null; 
 | 
                } 
 | 
                return TypeAdapter.this.read(reader); 
 | 
            } 
 | 
        }; 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * Converts {@code value} to a JSON document. Unlike Gson's similar 
 | 
     * {@link Gson#toJson(Object) toJson} method, this write is strict. Create a 
 | 
     * {@link JsonWriter#setLenient(boolean) lenient} {@code JsonWriter} and call 
 | 
     * {@link #write(com.google.gson.stream.JsonWriter, Object)} for lenient 
 | 
     * writing. 
 | 
     * 
 | 
     * @param value 
 | 
     *            the Java object to convert. May be null. 
 | 
     * @since 2.2 
 | 
     */ 
 | 
    public final String toJson(T value) { 
 | 
        StringWriter stringWriter = new StringWriter(); 
 | 
        try { 
 | 
            toJson(stringWriter, value); 
 | 
        } catch (IOException e) { 
 | 
            throw new AssertionError(e); // No I/O writing to a StringWriter. 
 | 
        } 
 | 
        return stringWriter.toString(); 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * Converts {@code value} to a JSON tree. 
 | 
     * 
 | 
     * @param value 
 | 
     *            the Java object to convert. May be null. 
 | 
     * @return the converted JSON tree. May be {@link JsonNull}. 
 | 
     * @since 2.2 
 | 
     */ 
 | 
    public final JsonElement toJsonTree(T value) { 
 | 
        try { 
 | 
            JsonTreeWriter jsonWriter = new JsonTreeWriter(); 
 | 
            write(jsonWriter, value); 
 | 
            return jsonWriter.get(); 
 | 
        } catch (IOException e) { 
 | 
            throw new JsonIOException(e); 
 | 
        } 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * Reads one JSON value (an array, object, string, number, boolean or null) and 
 | 
     * converts it to a Java object. Returns the converted object. 
 | 
     * 
 | 
     * @return the converted Java object. May be null. 
 | 
     */ 
 | 
    public abstract T read(JsonReader in) throws IOException; 
 | 
  
 | 
    /** 
 | 
     * Converts the JSON document in {@code in} to a Java object. Unlike Gson's 
 | 
     * similar {@link Gson#fromJson(java.io.Reader, Class) fromJson} method, this 
 | 
     * read is strict. Create a {@link JsonReader#setLenient(boolean) lenient} 
 | 
     * {@code JsonReader} and call {@link #read(JsonReader)} for lenient reading. 
 | 
     * 
 | 
     * @return the converted Java object. May be null. 
 | 
     * @since 2.2 
 | 
     */ 
 | 
    public final T fromJson(Reader in) throws IOException { 
 | 
        JsonReader reader = new JsonReader(in); 
 | 
        return read(reader); 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * Converts the JSON document in {@code json} to a Java object. Unlike Gson's 
 | 
     * similar {@link Gson#fromJson(String, Class) fromJson} method, this read is 
 | 
     * strict. Create a {@link JsonReader#setLenient(boolean) lenient} {@code 
 | 
     * JsonReader} and call {@link #read(JsonReader)} for lenient reading. 
 | 
     * 
 | 
     * @return the converted Java object. May be null. 
 | 
     * @since 2.2 
 | 
     */ 
 | 
    public final T fromJson(String json) throws IOException { 
 | 
        return fromJson(new StringReader(json)); 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * Converts {@code jsonTree} to a Java object. 
 | 
     * 
 | 
     * @param jsonTree 
 | 
     *            the Java object to convert. May be {@link JsonNull}. 
 | 
     * @since 2.2 
 | 
     */ 
 | 
    public final T fromJsonTree(JsonElement jsonTree) { 
 | 
        try { 
 | 
            JsonReader jsonReader = new JsonTreeReader(jsonTree); 
 | 
            return read(jsonReader); 
 | 
        } catch (IOException e) { 
 | 
            throw new JsonIOException(e); 
 | 
        } 
 | 
    } 
 | 
} 
 |