Overview
Gson is a Java library that can be used to convert Java Objects into their JSON representation. It can also be used to convert a JSON string to an equivalent Java object. Gson is an open-source project hosted at http://code.google.com/p/google-gson.
Gson can work with arbitrary Java objects including pre-existing objects that you do not have source-code of.
Goals for Gson
∙Provide easy to use mechanisms like toString() and constructor (factory method) to convert Java to JSON and vice-versa
∙Allow pre-existing unmodifiable objects to be converted to and from JSON
∙Allow custom representations for objects
∙Support arbitrarily complex object
∙Generate compact and readability JSON output
Using Gson
The primary class to use is Gson which you can just create by calling new Gson(). There is also a class GsonBuilder available that can be used to create a Gson instance with various settings like version control and so on.
The Gson instance does not maintain any state while invoking Json operations. So, you are free to reuse the same object for multiple Json serialization and deserialization operations.
Primitives Examples
(Serialization)
Gson gson = new Gson();
gson.toJson(1); ==> prints 1
gson.toJson("abcd"); ==> prints "abcd"
gson.toJson(new Long(10)); ==> prints 10
int[] values = { 1 };
gson.toJson(values); ==> prints [1]
(Deserialization)
int one = gson.fromJson("1", int.class);
Integer one = gson.fromJson("1", Integer.class);
Long one = gson.fromJson("1", Long.class);
Boolean false = gson.fromJson("false", Boolean.class);
String str = gson.fromJson("\\"abc\\"", String.class);
String anotherStr = gson.fromJson("[\\"abc\\"]", String.class);
Object Examples
class BagOfPrimitives {
private int value1 = 1;
private String value2 = "abc";
private transient int value3 = 3;
BagOfPrimitives() {
// no-args constructor
}
}
(Serialization)
BagOfPrimitives obj = new BagOfPrimitives();
Gson gson = new Gson();
String json = gson.toJson(obj);
==> json is {"value1":1,"value2":"abc"}
Note that you can not serialize objects with circular references since that will result in infinite recursion.
(Deserialization)
BagOfPrimitives obj2 = gson.fromJson(json, BagOfPrimitives.class);
==> obj2 is just like obj
Finer Points with Objects
∙It is perfectly fine (and recommended) to use private fields
∙There is no need to use any annotations to indicate a field is to be included for serialization and deserialization. All fields in the current class (and from all super classes) are included by default.
∙If a field is marked transient, (by default) it is ignored and not included in the JSON serialization or deserialization.
∙This implementation handles nulls correctly
oWhile serialization, a null field is skipped from the output
oWhile deserialization, a missing entry in JSON results in setting the corresponding field in the object to null
∙If a field is synthetic, it is ignored and not included in JSON serialization or deserialization
∙Fields corresponding to the outer classes in inner classes, anonymous classes, and local classes are ignored and not included in serialization or deserialization
Array Examples
Gson gson = new Gson();
int[] ints = {1, 2, 3, 4, 5};
String[] strings = {"abc", "def", "ghi"};
(Serialization)
gson.toJson(ints); ==> prints [1,2,3,4,5]
gson.toJson(strings); ==> prints ["abc", "def", "ghi"]
(Deserialization)
int[] ints2 = gson.fromJson("[1,2,3,4,5]", int[].class);
==> ints2 will be same as ints
We also support multi-dimensional arrays, with arbitrarily complex element types
Collections Examples
Gson gson = new Gson();
Collection (Serialization) String json = gson.toJson(ints); ==> json is [1,2,3,4,5] (Deserialization) Type collectionType = new TypeToken Collection ints2 is same as ints Fairly hideous: note how we define the type of collection Unfortunately, no way to get around this in Java Collections Limitations ∙Can serialize collection of arbitrary objects but can not deserialize from it oBecause there is no way for the user to indicate the type of the resulting object ∙While deserializing, Collection must be of a specific generic type All of this makes sense, and is rarely a problem when following good Java coding practices Serializing and Deserializing Generic Types When you call toJson(obj), Gson calls obj.getClass() to get information on the fields to serialize. Similarly, you can typically pass MyClass.class object in the fromJson(json, MyClass.class) method. This works fine if the object is a non-generic type. However, if the object is of a generic type, then the Generic type information is lost because of Java Type Erasure. Here is an example illustrating the point: List gson.toJson(myStrings); // Will cause a runtime exception gson.fromJson(json, myStrings.getClass()); The above call results in a runtime exception because Gson invokes myStrings.getClass() to get its class information, but this method returns a raw class, List.class. This means that Gson has no way of knowing that this is a list of Strings, and not plain objects. You can solve this problem by specifying the correct parameterized type for your generic type. You can do this by using the TypeToken class. Type listType = new TypeToken gson.toJson(myStrings, listType); gson.fromJson(json, listType); The idiom used to get listType actually defines an anonymous local inner class containing a method getType() that returns the fully parameterized type. Built-in Serializers and Deserializers Gson has built-in serializers and deserializers for commonly used classes whose default representation may be inappropriate. Here is a list of such classes: 1.java.net.URL to match it with strings like "http://code.google.com/p/google-gson/". 2.java.net.URI to match it with strings like "/p/google-gson/". Custom Serialization and Deserialization Sometimes default representation is not what you want. This is often the case when dealing with library classes (DateTime, etc). Gson allows you to register your own custom serializers and deserializers. This is done by defining two parts: ∙Json Serialiers: Need to define custom serialization for an object ∙Json Deserializers: Needed to define custom deserialization for a type ∙Instance Creators: Not needed if no-args constructor is available GsonBuilder gson = new GsonBuilder(); gson.registerTypeAdapter(MyType.class, new MySerializer()); gson.registerDeserializer(MyType.class, new MyDeserializer()); gson.registerInstanceCreator(MyType.class, new MyInstanceCreator()); Writing a Serializer Here is an example of how to write a custom serializer for JodaTime DateTime class. private class DateTimeSerializer implements JsonSerializer public JsonElement serialize(DateTime src, Type typeOfSrc, JsonSerializationContext context) { new JsonPrimitive(src.toString()); } } Gson calls toJson() when it runs into a DateTime object during serialization. Writing a Deserializer Here is an example of how to write a custom deserializer for JodaTime DateTime class. private class DateTimeDeserializer implements JsonDeserializer public DateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { return new DateTime(json.getAsJsonPrimitive().getAsString()); } } Gson calls fromJson() when it needs to deserialize a JSON string fragment into a DateTime object Finer points with Serializers and Deserializers Often you want to register a single handler for all generic types corresponding to a raw type ∙For example, suppose you have an "Id" class for Id representation/translation (i.e. an internal vs. external representation). ∙Id oEssentially write out the id value ∙Deserialization is very similar but not exactly the same oNeed to call "new Id(Class Gson supports registering a single handler for this. You can also register a specific handler for a specific generic type (say Id The Type parameter for the toJson and fromJson contains the generic type information to help you write a single handler for all generic types corresponding to the same raw type Writing an Instance Creator While deserializing an Object, Gson needs to create a default instance of the class Well-behaved classes that are meant for serialization and deserialization should have a no-argument constructor ∙Doesn't matter whether public or private Typically, Instance Creators are needed when you are dealing with a library class that does NOT define a no-argument constructor Instance Creator Example private class MoneyInstanceCreator implements InstanceCreator public Money createInstance(Type type) { return new Money("1000000", CurrencyCode.USD); } } Type could be of a corresponding generic type ∙Very useful to invoke constructors which need specific generic type information ∙For example, if the Id class stores the class for which the Id is being created InstanceCreator for a Parameterized Type Sometimes that the type that you are trying to instantiate is a parameterized type. Generally, this is not a problem since the actual instance is of raw type. Here is an example: class MyList } class MyListInstanceCreator implements InstanceCreator @SuppressWarnings("unchecked") public MyList> createInstance(Type type) { // No need to use a parameterized list since the actual instance will have the raw type anyway. return new MyList(); } } However, sometimes you do need to create instance based on the actual parameterized type. In this case, you can use the type parameter being passed to the createInstance method. Here is an example: public class Id private final Class private final long value; public Id(Class this.classOfId = classOfId; this.value = value; } } class IdInstanceCreator implements InstanceCreator public Id> createInstance(Type type) { Type[] typeParameters = ((ParameterizedType)type).getActualTypeArguments(); Type idType = typeParameters[0]; // Id has only one parameterized type T return Id.get((Class)idType, 0L); } } In the above example, an instance of the Id class can not be created without actually passing in the actual type for the parameterized type. We solve this problem by using the passed method parameter, type. The type object in this case is the Java parameterized type representation of Id Compact Vs. Pretty Printing for JSON Output Format The default JSON output that is provide by Gson is a compact JSON format. This means that there will not be any whitespace in the output JSON structure. Therefore, there will be no whitespace between field names and its value, object fields, and objects within arrays in the JSON output. As well, "null" fields will be ignored in the output (NOTE: null values will still be included in collections/arrays of objects). See the Null Object Support section for information on configure Gson to output all null values. If you like to use the Pretty Print feature, you must configure your Gson instance using the GsonBuilder. The JsonFormatter is not exposed through our public API, so the client is unable to configure the default print settings/margins for the JSON output. For now, we only provide a default JsonPrintFormatter that has default line length of 80 character, 2 character indentation, and 4 character right margin. The following is an example shows how to configure a Gson instance to use the default JsonPrintFormatter instead of the JsonCompactFormatter: Gson gson = new GsonBuilder().setPrettyPrinting().create(); String jsonOutput = gson.toJson(someObject); Null Object Support The default behaviour that is implemented in Gson is that null object fields are ignored. This allows for a more compact output format; however, the client must define a default value for these fields as the JSON format is converted back into its Java. Here's how you would configure a Gson instance to output null: Gson gson = new GsonBuilder().serializeNulls().create(); NOTE: when serializing nulls with Gson, it will add a JsonNull element to the JsonElement structure. Therefore, this object can be used in custom serialization/deserialization. Here's an example: public class Foo { private final String s; private final int i; public Foo() { this(null, 5); } public Foo(String s, int i) { this.s = s; this.i = i; } } Gson gson = new GsonBuilder().serializeNulls().create(); Foo foo = new Foo(); String json = gson.toJson(foo); System.out.println(json); json = gson.toJson(null); System.out.println(json); ======== OUTPUT ======== {"s":null,"i":5} null Versioning Support Multiple versions of the same object can be maintained by using @Since annotation. This annotation can be used on Classes, Fields and, in a future release, Methods. In order to leverage this feature, you must configure your Gson instance to ignore any field/object that is greater than some version number. If no version is set on the Gson instance then it will serialize and deserialize all fields and classes regardless of the version. public class VersionedClass { @Since(1.1) private final String newerField; @Since(1.0) private final String newField; private final String field; public VersionedClass() { this.newerField = "newer"; this.newField = "new"; this.field = "old"; } } VersionedClass versionedObject = new VersionedClass(); Gson gson = new GsonBuilder().setVersion(1.0).create(); String jsonOutput = gson.toJson(someObject); System.out.println(jsonOutput); System.out.println(); gson = new Gson(); jsonOutput = gson.toJson(someObject); System.out.println(jsonOutput); ======== OUTPUT ======== {"newField":"new {"newerField":"newer Excluding Fields From Serialization and Deserialization Gson provides a feature where you can mark certain fields of your objects to be excluded for consideration for serialization and deserialization to JSON. By default, if you mark a field as transient, it will be excluded. If you are not willing to mark the field as transient, you can use the @Expose annotation instead. To use this annotation, you must create Gson by using GsonBuilder.excludeFieldsWithoutExposeAnnotation().create(). The Gson instance created will exclude all fields in a class that are not marked with @Expose annotation. JSON Field Naming Support Gson supports some pre-defined field naming policies to convert the standard Java field names (i.e. camel cased names starting with lower case --- "sampleFieldNameInJava") to a Json field name (i.e. sample_field_name_in_java or SampleFieldNameInJava). It also has an annotation based strategy to allows clients to define custom names on a per field basis. Note, that the annotation based strategy has field name validation which will raise "Runtime" exceptions if an invalid field name is provided as the annotation value. The following is an example of how to use both Gson naming policy features: private class SomeObject { @SerializedName("custom_naming") private final String someField; private final String someOtherField; public SomeObject(String a, String b) { this.someField = a; this.someOtherField = b; } } SomeObject someObject = new SomeObject("first", "second"); Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE).create(); String jsonRepresentation = gson.toJson(someObject); System.out.println(jsonRepresentation); ======== OUTPUT ======== {"custom_naming":"first If you have a need for custom naming policy (see this discussion), you can use the @SerializedName annotation. Sharing State Across Custom Serializers and Deserializers Sometimes you need to share state across custom serializers/deserializers (see this discussion). You can use the following three strategies to accomplish this: 1.Store shared state in static fields 2.Declare the serializer/deserializer as inner classes of a parent type, and use the instance fields of parent type to store shared state 3.Use Java ThreadLocal 1 and 2 are not thread-safe options, but 3 is. Issues in Designing Gson See the Gson design document for a discussion of issues we faced while designing Gson. It also include a comparison of Gson with other Java libraries that can be used for Json conversion. Future Enhancements to Gson For the latest list of proposed enhancements or if you'd like to suggest new ones, see the Issues section under the project website. 下载本文
>() {}.getType();