Gson usage documentation (collections must be generic, so new TypeToken, anonymous class, getType() must be used)

Original: http://www.jianshu.com/p/558844c96fc1

 

 

1. Overview
2. Goals
of Gson 3. Performance and scalability of Gson 4.
Users of
Gson 5. How to use Gson

  • Using Gson with Maven
  • Basic example
  • object example
  • The benefits of using objects
  • Nested classes (including inner classes)
  • array example
  • Collection example
  • Limitations of collections
  • Generic serialization and deserialization
  • Serialization and deserialization of collections of arbitrary types
  • Built-in serializer and deserializer
  • Custom serialization and deserialization
    • Write a serialization interpreter
    • Write a deserialization interpreter
  • Writing a Instance Creator
    • InstanceCreator for a Parameterized Type
  • Concise and beautiful Json formatted output
  • Support Null objects
  • Versioning supported
  • Ignore fields in serialization and deserialization
    • Java modifier ignored
    • Gson's @Expose
    • Custom ignore policy
  • JSON field naming help
  • Share state via classic serializers and deserializers
  • Flow
    6. Some problems in designing Gson
    7. Aspects that Gson needs to be strengthened in the future

Overview


Gson is a Java library that not only converts Java objects to Json format, but also converts a string of Json format into relative Java objects.
Gson works with all Java objects, even those for which you don't know the source code.

Gson's goal

  • Provides easy-to-use methods such as toString(), constructors to convert JAVA to JSON and back.
  • Provides conversion of existing immutable objects to JSON and inverse conversion.
  • Provides a conventional representation of an object
  • Support for arbitrarily complex objects
  • Generate robust and readable JSON output

Gson performance and scalability


Here is the computer configuration we ran the test on (dual opteron, 8GB RAM, 64-bit Ubuntu), you can run the test by using the PerformanceTest class

  • Can deserialize 25MB strings normally (refer to disabled_testStringDeserializationPerformance in PerformanceTest)
  • Extra large collection:
    • Can serialize 1.4 million objects normally (see disabled_testLargeCollectionSerialization in PerformanceTest)
    • Can deserialize collections of 87000 objects normally (see disabled_testLargeCollectionDeserialization in PerformanceTest)
  • Gson 1.4 increases the deserialized byte array and collection limit from 80KB to 11MB.
    Note: Remove the disabled_ prefix to run these TESTs, we use this prefix to prevent running these test cases when we run Junit's test cases.

Users of Gson


Gson was originally created to be used by a large number of projects within Google, and it is now used by many open source projects and companies.

Use Gson


You can use the new Gson() method to start using Gson. There is also a class GsonBuilder to create a Gson instance, through this class you can set various parameters including version control etc...

When you call a Json operation, the Gson instance does not maintain any state, so you can reuse the same object to repeat the Json serialization and deserialization operations.

Using Gson with Maven


To use Gson with Maven2/3, add the following dependencies to use Gson
<dependencies> <!-- Gson: Java to Json conversion --> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.5</version> <scope>compile</scope> </dependency> </dependencies>
with Maven Now your Maven project can use Gson

Basic example


// SerializationGson gson = new Gson();gson.toJson(1);// ==> 1 gson.toJson("abcd"); // ==> "abcd" gson.toJson(new Long(10)); // ==> 10 int[] values = { 1 }; gson.toJson(values); // ==> [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 example


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"}
Be careful not to use circular references in sequence objects, as it will lead to infinite recursion
// DeserializationBagOfPrimitives obj2 = gson.fromJson(json, BagOfPrimitives.class);// ==> obj2 is just like obj

Some details when working with objects

  • It is better to use the private modifier
  • No need to use annotations to indicate which fields need to be serialized and deserialized, all fields of the current class will be included by default
  • If a field is represented as transient (default) it will be ignored and not included in Json serialization or deserialization
  • nulls are handled correctly
  • When serializing a Null field is skipped on output
  • A missing entity in Json will automatically set the corresponding field to null when deserializing
  • If a field is synthetic, it will be ignored directly and will not be included in JSON serialization and deserialization.
  • Fields corresponding to the outer class in the local class of the anonymous class of the inner class will be ignored and will not be included in the serialization and deserialization of JSON.

Nested classes (including inner classes)

Gson can serialize static inner classes very easily.
Gson can also deserialize static classes. Gson cannot automatically deserialize pure inner classes because their no-argument constructor requires a reference to the inner object, however this reference is in It is not available during deserialization. You can deal with this problem by either making the inner class static, or providing it with a static factory method (instanceCreator). For example:
public class A { public String a; class B { public String b; public B() { // No args constructor for B } } }
note that the above class B cannot be used by default Gson serialization
Gson can't deserialize {"a":"abc"} into B instance because class B is an inner class if it is defined as static class ClassB Gson can deserialize string another solution is for B
public class InstanceCreatorForB implements InstanceCreator<A.B> { private final A a; public InstanceCreatorForB(A a) { this.a = a; } public A.B createInstance(Type type) { return a.new B(); } }
The above solution is feasible to write a static factory method for the class , but it is not recommended to use it in this way

array example


Gson gson = new Gson(); int[] ints = {1, 2, 3, 4, 5}; String[] strings = {"abc", "def", "ghi"}; // Serialization gson.toJson(ints); // ==> [1,2,3,4,5] gson.toJson(strings); // ==> ["abc", "def", "ghi"] // Deserialization int[] ints2 = gson.fromJson("[1,2,3,4,5]", int[].class); // ==> ints2 will be same as ints
We also support multidimensional arrays, any complex element type.

Collection example

Gson gson = new Gson(); Collection<Integer> ints = Lists.immutableList(1,2,3,4,5); // SerializationString json = gson.toJson(ints); // ==> json is [1,2,3,4,5] // Deserialization Type collectionType = new TypeToken<Collection<Integer>>(){}.getType(); Collection<Integer> ints2 = gson.fromJson(json, collectionType); // ==> ints2 is same as ints
Terrible: notice how we define the type of the collection, but unfortunately there is no way to get it in Java.

Limitations of collections

  • Arbitrary objects of a collection can be serialized but not deserialized from them
  • Because the user has no way to declare the type of a result object
  • When serializing, the collection must be of a specific generic type
    when following a good JAVA encoding format, this all interprets and shouldn't be a problem.

Serialize and deserialize generic types

When you call toJson(obj) Gson calls obj.getClass to get information about the serialized fields. Similarly, you can specifically specify the MyClass.class object in the fromJson(json, MyClass.class) method, which works fine when it is not a generic type, however, when the object is a generic type, the generic type information will be lost because of Java type wipes, the following example shows this.
class Foo<T> { T value; } Gson gson = new Gson(); Foo<Bar> foo = new Foo<Bar>(); gson.toJson(foo); // May not serialize foo.value correctly gson.fromJson(json, foo.getClass()); // Fails to deserialize foo.value as Bar
The above code cannot resolve the value of type Bar, because when Gson calls list.getclass() to get the class information, this method returns an unhandled class Foo.class which means that Gson has no way of knowing that this is a Foo<Bar an object of type, not an unformatted Foo

You can get around this by specifying a proper parameter for your generic type, you can also handle this by using the TypeToken class.

Type fooType = new TypeToken<Foo<Bar>>() {}.getType(); gson.toJson(foo, fooType); gson.fromJson(json, fooType);
The way we usually get fooType is to define an anonymous inner class that contains a getType method that returns a full parameter type.

Serialization and deserialization of collections of arbitrary types


Sometimes you are dealing with JSON arrays that contain mixed types such as ['hello',5, {name:'GREETINGS',source:'guest'}]
collections to achieve this JSON format by:
Collection collection = new ArrayList(); collection.add("hello"); collection.add(5); collection.add(new Event("GREETINGS", "guest"));
Then the event class is defined like this:
class Event { private String name; private String source; private Event(String name, String source) { this.name = name; this.source = source; } }
You don't need to do extra operations when serializing the collection with Gson's toJson(collection) to get the desired output

However, deserialization using fromJson(json, Collection.class) fails because Gson has no way of knowing how to map the result to a type. Gson requires you to provide a generic version of the collection type in fromJson(), so you have three options :

  1. Use Gson's parsing API (low-level stream parsing or DOM parsing) to parse the array elements and then use Gson.fromJson() on the corresponding array elements. This is a better solution. An example shows how to use it.
  2. Register a type adapter for Collection.class to map each array member to the corresponding object. The disadvantage of this method is that it will confuse the deserialization of other collection types
  3. Register a type adapter for
    MyCollectionMemberType to use fromjson() via Collection<MyCollectionMemberType>
    This method is only used for arrays that appear as top-level elements or you can change the field type via Collection<MyCollectionMemberType>
    .

Built-in serializer and deserializer

Gson has built-in serializers and deserializers for common classes whose default display may not be appropriate. Here is a list of these classes:

  1. java.net.URL to match it with strings like "https://github.com/google/gson/"
  2. java.net.URI to match it with strings like "/google/gson/"
    You can also find the source code of some common classes like JodaTime

    Custom serialization and deserialization

    Sometimes the default representation may not be what you want, this often happens when dealing with library classes (DateTime, etc) Gson allows you to register your direct common serializers and deserializers, usually by defining these two parts .
  3. Json Serialiers: Serialization needs to be defined for objects
  4. Json Deserializers: Define deserialization for required types
  5. InstanceCreator: generally not required if no-argument constructors are available or deserialized and registered

GsonBuilder gson = new GsonBuilder(); gson.registerTypeAdapter(MyType2.class, new MyTypeAdapter()); gson.registerTypeAdapter(MyType.class, new MySerializer()); gson.registerTypeAdapter(MyType.class, new MyDeserializer()); gson.registerTypeAdapter(MyType.class, new MyInstanceCreator());

write a serializer


The following is to write a custom serializer for the JodaTime DateTime class.
private class DateTimeSerializer implements JsonSerializer<DateTime> { public JsonElement serialize(DateTime src, Type typeOfSrc, JsonSerializationContext context) { return new JsonPrimitive(src.toString()); } }
Gson calls the serialize method when there are DateTime objects that need to be serialized

write a deserializer

The following is to write a custom deserializer for the JodaTime DateTime class
private class DateTimeDeserializer implements JsonDeserializer<DateTime> { public DateTime deserialize(JsonElement json, Type typeOfT,JsonDeserializationContext context) throws JsonParseException { return new DateTime(json.getAsJsonPrimitive().getAsString()); } }
Gson calls deserialize when it needs to deserialize JSON string fragments into DateTime objects

Serializers and deserializers need attention

Usually you want to register a single handler to have one unhandled type for all introspected types

  • For example, suppose you have an ID class to represent or transform IDs (eg external to internal representation)
  • Id<T> types have the same serialization for all generic types
  • Deserialization is very similar but not identical
    • Need to call new Id(Class<T>, String) to return an instance of Id<T>

Writing static factory methods

When deserializing an object, Gson needs to create an instance of a default class, a good class means that both serialization and deserialization should have a no-argument constructor

  • public private is fine.
    Usually static factory methods do not define a no-argument constructor when you are dealing with library classes.` private class
    MoneyInstanceCreator
    implements InstanceCreator<Money> { public Money createInstance(Type type) {
     return new Money("1000000", CurrencyCode.USD);
    }
    }
    `
    The type needs to be the corresponding generic type
  • Useful when constructors need to specify generic type information
  • For example, if the Id class can store the class for which the Id was created

    Static factory methods for parameterized types


Sometimes the type you need to instantiate is a parameterized type. Generally, this is not a problem because the actual instance created is a raw type. Here is an example
class MyList<T> extends ArrayList<T> {}class MyListInstanceCreator implements InstanceCreator<MyList<?>> { @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(); }}

Then, sometimes you do need to create a parameterized type based on an existing one, if so, you can pass the parameterized type to the createInstance method like this:
public class Id<T> { private final Class<T> classOfId; private final long value; public Id(Class<T> classOfId, long value) { this.classOfId = classOfId; this.value = value; }}class IdInstanceCreator implements InstanceCreator<Id<?>> { 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 cannot be created without Pass in the real type of the parameterized type. We solve this problem by passing in the method parameter type, the type object in this case is the representation of the Java parameterized type of Id<Foo>, the real instance should be bound to Id<Foo> since there is only one Id class The parameterized type parameter T we use is an array of types with zero elements held by getActualTypeArgument() of Foo.class.

Concise and elegant printing JSON output format


The default JSON output is the concise JSON format provided by Gson, which means that the JSON output format is without any spaces, so there are no spaces in names, values, object arrays, and objects. At the same time null fields will also be ignored when outputting (note: null values ​​will still exist in collection/array objects) in [Null Object Support] for more information on how to configure Gson to output all Null values

If you like to use the elegant printing function, you must configure your Gson instance by using GsonBuilder. The
JsonFormatter method is not exposed through our public api, so the client cannot output by configuring the default permission settings/spacing Formatted JSON Now, we just provide a default JsonPrintFormatter method. The default field length of this method is 80 bytes, 2 bytes indent, 4 bytes right margin

The following example shows how to configure a Gson instance to use the default JsonPrintFormatter
instead of JsonCompactFormatter
Gson gson = new GsonBuilder().setPrettyPrinting().create(); String jsonOutput = gson.toJson(someObject);

Null object support


The default handling method of Gson for null objects is to ignore it directly, which will provide a more concise output format, however the client must provide a default value when the JSON format needs to be transferred to the corresponding JAVA object.
You can configure the Gson instance to output null:
Gson gson = new GsonBuilder().serializeNulls().create();
Example As follows:
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);
The output is as follows:
{"s":null,"i":5} null

Version support


You can use the @Since annotation to maintain different versions of the same object. This annotation can be used for classes, fields, and Methods in future versions. To increase the impact of this feature, you must configure your Gson instance to ignore any A better version of the domain object. If the Gson instance does not have any version set then all fields and classes are serialized and deserialized regardless of 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
result`
{"newField":"new","field":"old"}

{"newerField":"newer","newField":"new","field":"old"}
`

Ignore fields in serialization and deserialization


Java Edit Exclusion

By default you can denote a field as transient and it will be ignored, and a field denoted as static will also be ignored, if you want to add some transient fields you can do as follows:
import java.lang.reflect.Modifier;Gson gson = new GsonBuilder() .excludeFieldsWithModifiers(Modifier.STATIC) .create();
Note that you can use as many modifier constants as you want Give the excludeFieldsWithModifiers method e.g.

Gson gson = new GsonBuilder() .excludeFieldsWithModifiers(Modifier.STATIC, Modifier.TRANSIENT, Modifier.VOLATILE) .create();

Gson's @Expose

If the above method of ignoring fields and classes doesn't work for you, you can also write your own ignore strategy and configure it in Gson, refer to the ExclusionStrategy JavaDoc for more information.
The following example shows if the ignore field is annotated as @Foo and ignored The top-level class String class.
@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.FIELD})public @interface Foo { // Field tag only annotation}public class SampleObjectForTest { @Foo private final int annotatedField; private final String stringField; private final long longField; private final Class<?> clazzField; public SampleObjectForTest() { annotatedField = 5; stringField = "someDefaultValue"; longField = 1234; }}public class MyExclusionStrategy implements ExclusionStrategy { private final Class<?> typeToSkip; private MyExclusionStrategy(Class<?> typeToSkip) { this.typeToSkip = typeToSkip; } public boolean shouldSkipClass(Class<?> clazz) { return (clazz == typeToSkip); } public boolean shouldSkipField(FieldAttributes f) { return f.getAnnotation(Foo.class) != null; }}public static void main(String[] args) { Gson gson = new GsonBuilder() .setExclusionStrategies(new MyExclusionStrategy(String.class)) .serializeNulls() .create(); SampleObjectForTest src = new SampleObjectForTest(); String json = gson.toJson(src); System.out.println(json);}
Output result:
{"longField":1234}

JSON field naming support

Gson supports a predefined field naming strategy, including standard JAVA field naming (Isn't the camel case name defined by Microsoft starting with a lowercase letter--- sampleFieldNameInJava), and use it to name the Json field. Refer to the FieldNamingPolicy class for more information on predefined naming policies.
It also provides a set of annotation-based policies to allow clients to customize their field bases. Note that there is a field naming determination mechanism based on annotation policies. If the field naming provided by the annotation value is invalid, it will be Package Runtime Exception
Here is an example of how to use:
`
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);

输出结果如下:
{"custom_naming":"first","SomeOtherField":"second"}
`
If you have the need for a custom naming strategy (see discussion), you can use the "serializedname" annotation.

Share state in custom serialization and deserialization


Sometimes you need to share state between custom serializers/deserializers (see discussion). You can accomplish this using three strategies:
1. Store the shared state in a static field
2. Declare a serializer or deserializer as an inner class of the supertype, and use the instance field of the supertype to store the shared
state3 . Using Java ThreadLocal
1.2 is not thread safe, 3 is thread safe

flow


In addition to gson's object model and data binding, you can use gson to read and write streams. You can also combine streaming and object model access to get the best of both worlds.

Some problems when designing gson

See the Gson design documentation for some discussion when we designed Gson. It also includes gson comparison with other Java libraries that can be used for JSON conversion.

Gson's future strengthening direction


See the latest list for details on areas that need strengthening, or if you want to suggest something new, see the Issues section on the project website.



Article/person disqualification (author of Jianshu)
Original link: http://www.jianshu.com/p/558844c96fc1
The copyright belongs to the author, please contact the author for authorization, and mark "author of Jianshu".

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=327033259&siteId=291194637