GSONは、JSONオブジェクトとJavaオブジェクト間の相互変換を実装するために使用されるJavaライブラリです。 GSONは、https://github.com/google/gsonでホストされているオープンソースプロジェクトです。
GSONのメインクラスはGSONです。また、GSONオブジェクトの作成中にクラスGSONBUILDERを使用していくつかのオプションを設定することもできます。
GSONオブジェクトは、JSONを処理するときに状態を節約しないため、ユーザーは同じGSONオブジェクトで複数のシリアル化、脱審、その他の操作を簡単に実行できます。
例:基本的な使用
// serializationgson gson = new gson(); gson.tojson(1); // ==> prints 1gson.tojson( "abcd"); // ==> "abcd" gson.tojson(new long(10)); // ==> prints 10int [] values = {1}; gson.tojson(values); // ==> prints [1] // deserializationint one = gson.fromjson( "1"、int.class); integer one = gson.fromjson( "1"、integer.class); long one = gson.fromjson( "1"、integer.class); long one = gson.fromjson.fromjson(booulen); gson.fromjson( "false"、boolean.class); string str = gson.fromjson( "/" abc/""、string.class); string anotherstr = gson.fromjson( "[/" abc/"]、string.class); // serializationbagofprimitives obj = new gson gson(); gson.tojson(obj); // ==> jsonは{"value1":1、 "value2": "abc"}です例:オブジェクトとJSON間の変換
Bagofprimitivesクラスを定義します。
クラスbagofprimitives {private int value1 = 1; private string value2 = "abc";プライベートトランジェントINT値3 = 3; bagofprimitives(){// no-args constructor}}JSONにシリアル化:
// serializationbagofprimitives obj = new bagofprimitives(); gson gson = new gson(); string json = gson.tojson(obj); // ==> jsonは{"value1":1、 "value2": "abc"}です円形の参照を含むオブジェクトをシリアル化しないでください。そうしないと、無限の再帰が発生します。
Desarialization:
// DeserializationBagofprimitives obj2 = gson.fromjson(json、bagofprimitives.class); // ==> obj2はobjに似ています
オブジェクトを処理するときの詳細:
ネストされたクラスの処理(内部クラスを含む)
GSONは、ネストされたクラスを簡単にシリアル化し、静的なネストされたクラスを脱派化できます。 GSONは、内側のクラスのパラメーターのないコンストラクターがそれを含むオブジェクト(つまり、外側クラスのインスタンス)を参照する必要があるため、純粋な内部クラスを自動的に脱却することはできません。静的クラスをゆるくするために、内側のクラスを静的に、またはカスタムインスタンス作成者を提供することができます。これが例です:
パブリッククラスA {public string a;クラスB {public String B; public b(){// b}}}}}のargsコンストラクターはありません上記のクラスBは、GSONによってシリアル化することはできません。クラスBは(非静的な)内部クラスであるため、GSONは{"b": "abc"}をクラスBのインスタンスに偏りにすることもできません。Bが静的クラスBとして宣言されている場合、GSONは文字列をゆるくすることができます。
別の解決策は、Bのインスタンス作成者を作成することです。
Public Class InstanceCreatorForBは、InstanceCreator <ab> {private final a a; public InstanceCreatorforb(a){this.a = a; } public ab createInstance(type type){return a.new b(); }}この方法は実現可能ですが、推奨されません。 (翻訳者は、このインスタンスの作成者を理解しておらず、それを使用する方法を知らなかったと言いました)
例:配列
gson gson = new gson(); int [] ints = {1、2、3、4、5}; strings = {"abc"、 "def"、 "ghi"}; // serializationgson.tojson(ints); ==> prints [1,2,3,4,5] gson.tojson(文字列); ==> prints ["abc"、 "def"、 "ghi"] // deserializationint [] ints2 = gson.fromjson( "[1,2,3,4,5]"、int []。class); ==> ints2はintsと同じですGSONは、複雑なデータ型を持つ多次元配列もサポートしています。
例:コレクション
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] // DeserializationType CollectionType = new Typetoken <collection <collection <integer >>(){}。getType(); collection <integer> ints2 = gson.fromjson(json、collectiontype);コレクションの処理時の制限:
ジェネリックをシリアル化/降下します
Tojson(OBJ)を使用する場合、GSONはobj.getClass()を呼び出して、シリアル化で使用するフィールド情報を取得します。同様に、オブジェクトmyClass.classは、fromjson(json、myclass.class)メソッドのパラメーターとして渡すことができます。これは、オブジェクトが汎用ではない場合に使用できます。ただし、オブジェクトが汎用型オブジェクトである場合、Javaの型消去メカニズムにより、一般的なタイプ情報が失われます。次の例はこれを示しています:
クラスfoo <t> {t value;} gson gson = new gson(); foo <bar> foo = new foo <bar>(); gson.tojson(foo); // foo.value reclygson.fromjson(json、foo.getclass())をシリアル化することはできません。 // foo.valueをbarとしてゆるくすることに失敗します上記のコードは、gsonがfoo.getclass()を呼び出してクラスの情報を取得するため、値をバータイプとして解釈しますが、この方法は原始クラス、つまりfoo.classを返します。これは、GSONがfoo <bar>のタイプのオブジェクトであることを知ることができないことを意味します。
この問題を解決するために、ジェネリックの正しいパラメーター化されたタイプを指定できます。 Typetokenクラスを使用して:
タイプフットタイプ=新しいtypetoken <foo <bar >>(){} .getType(); gson.tojson(foo、footype); gson.fromjson(json、footype);Footypeは実際に、すべてのパラメーター化された型を返すことができるgetType()メソッドを含む匿名の内部クラスを定義します。
あらゆるタイプのオブジェクトのコレクションをシリアル化/脱必要にします
処理されたJSONには、次のような混合タイプが含まれる場合があります。
['hello'、5、{name: 'Greetings'、source: 'guest'}]対応するセットは次のとおりです。
collection collection = new arrayList(); collection.add( "hello"); collection.add(5); collection.add(new event( "Greetings"、 "guest"));
イベントクラスは次のように定義されています。
クラスイベント{プライベート文字列名;プライベートストリングソース;プライベートイベント(文字列名、文字列ソース){this.name = name; this.source = source; }}GSONを使用すると、コレクションをシリアル化するために特別なことをする必要はありません。Tojson(Collection)は満足のいく結果を出力します。
ただし、GSON(JSON、collection.class)を介した降下は不可能です。これは、GSONがJSONのコンテンツに対応できないためです。 GSONでは、FromJsonでコレクションタイプの共通バージョンを提供する必要があります。 3つの選択肢があります。
ソリューション1:GSONパーサーのAPI(低レベルのストリームパーサーまたはDomパーサーjsonParser)を使用して配列要素を解析し、gson.fromjson()を使用して各配列要素を処理します。これが好ましいソリューションです。
スキーム2:collection.class用のタイプアダプターを登録して、配列内の要素を適切なオブジェクトにマッピングします。この方法の欠点は、他のコレクションタイプを扱う際に不便を引き起こすことです。
スキーム3:MyCollectionMemberTypeのタイプアダプターを登録し、fromJsonでコレクション<myCollectionMemberType>を使用します。この方法は、配列が高レベルの要素のように見える場合、またはフィールドタイプをCollection <myCollectionMemberType>に変更できる場合にのみ可能です。
組み込みのシリアイザー/デシリアライザー
GSONは、デフォルトの表現には適していない場合がある一般的に使用されるクラスにシリアナー/デシリアライザーを提供します。
これらのクラスのリストは次のとおりです。
カスタムシリアル化/脱介入
GSONのデフォルトの実装はあなたが望むものではなく、いくつかのクラスライブラリ(DateTimeなど)を扱うときにより一般的なものである場合があります。
GSONを使用すると、カスタムシリアイザー/デシリアライザーを登録できます。これを行うには、次の部分を実装する必要があります。
JSON Serializer:オブジェクトのシリアル化をカスタマイズする必要があります
JSON Deserializer:タイプのDeserialialization Class Creatorをカスタマイズする必要があります。パラメーターのないコンストラクターが登録されている場合、またはDeserializerが登録されている場合、必要ありません。
gsonBuilder gson = new gsonbuilder(); gson.registertypeadapter(mytype2.class、new mytypeadapter()); gson.registertypeadapter(class、new myserializer()); gson.registertypeadapter(mytype.class、new mydeserializer()); gson.registertypeadapter(mytype.class、new myinstancecreator());
RegisterTyPeadapterタイプアダプターが複数のインターフェイスを実装し、これらのインターフェイスのタイプアダプターを登録するかどうかを確認します。
シリアナーを書きます
以下は、DateTimeのシリアイザーをカスタマイズする例です。
プライベートクラスのDateTimeRializerは、JSonserializer <DateTime> {public jsonelement serialize(datetime src、type ofsrc、jsonserializationcontextコンテキスト){return new jsonprimitive(src.tostring()); }}GSONは、DateTimeインスタンスをシリアル化するときにtojson()を呼び出します。
Deserializerを書いてください
次の例は、DateTimeクラスの脱登記の書き方を示しています。
プライベートクラスのDateTimedeSerializerを実装するJSONDESERIALIZER <DATETIME> {public DateTime Deserialize(jsonelement json、Type Typeoft、jsondeRializationContextコンテキスト)Throws jsonParseexception {return new DateTime(json.getasjsonprimitive()。 }}GSONがJSON文字列をDateTimeオブジェクトにゆるくする必要がある場合、fromjson()が呼び出されます。
シリアル化師/脱介入者の場合、次のように注意を払う必要があります。
インスタンス作成者を書いてください
オブジェクトを脱出するとき、GSONはクラスのインスタンスを作成する必要があります。シリアル化/敏lasialization化中にうまく機能するクラスは、このクラスにパラメーターのないコンストラクターがあることを意味します。通常、クラスライブラリにパラメーターのないコンストラクターのないクラスを扱う場合、インスタンス作成者が必要です。
例作成者の例:
プライベートクラスのMoneyinstanceCreator InstanceCreator <Money> {public Money CreateInstance(Type Type){return new Money( "1000000"、currencycode.usd); }}パラメーター化されたタイプインスタンス作成者
インスタンス化されるタイプがパラメーター化されたタイプになる場合があります。全体として、実際のインスタンスは原始的なタイプであるため、これは問題ではありません。これが例です:
クラスmylist <t> arraylist <t> {} class mylistinstancecreatorはinstancecreator <mylist <?新しいmylist()を返します。 }}ただし、実際のパラメーター化されたタイプに基づいてインスタンスを作成する必要がある場合があります。この場合、型パラメーターをcreateinstanceメソッドに渡すことができます。これが例です:
パブリッククラスID <t> {プライベートファイナルクラス<t> classofid;プライベートファイナルロングバリュー。 public ID(class <t> classofid、long value){this.classofid = classofid; this.value = value; }} class idinStanceCreator InstanceCreator <id <?>> {public id <?> createInstance(type type){typeparameters =((parameterizedType)Type).getActualTypearguments();タイプidtype = typeparameters [0]; // idには1つのパラメーター化されたタイプt return id.get((class)idtype、0l)のみです。 }}上記の例では、真のタイプをパラメーター化されたタイプに渡さずにIDクラスのインスタンスを作成することはできません。パラメータータイプをメソッドに渡すことで、この問題を解決できます。ここでは、タイプオブジェクトは、Javaパラメーター化されたタイプのID <foo>の表現と見なすことができ、対応するインスタンスはid <foo>にバインドする必要があります。クラスIDにはパラメーターのパラメーターtが1つしかないため、getActualTypeargument()を使用して、この例ではfoo.classのタイプ配列の0番目の要素を返します。
コンパクトな出力と美しい出力
GSONのJSONのデフォルトの出力は、コンパクトJSON形式です。つまり、JSONには余分な空白のキャラクターはありません。したがって、フィールド名とフィールド値、フィールド間、およびJSONの出力の配列要素間の間に空白のスペースはありません。また、nullフィールドは出力されません(注:nullはコレクションおよび配列オブジェクトに保存されます)。
より美しく出力する場合は、GSONBuilderを使用してGSONインスタンスを構成する必要があります。 jsonformatterはパブリックAPIには存在しないため、クライアントはデフォルトの出力設定を構成できません。現在、JSONPrintFormatterのみを提供します。デフォルトでは1行あたり80文字で、インデントは2文字を使用し、右マージンは4文字です。
次の例は、デフォルトのjsoncompactformatterを使用する代わりに、jsonprintformatterを使用してGSONインスタンスを取得する方法を示しています。
gson gson = new gsonbuilder()。setprettyprinting()。create(); string jsonoutput = gson.tojson(someobject);
空のオブジェクト
GSONのデフォルト実装では、NULLオブジェクトは無視されます。これにより、出力形式(シリアル化の結果と見なすことができます)をよりタイトにすることができます。ただし、クライアントは、JSONが正常に降下できるように、デフォルト値を定義する必要があります。
GSONインスタンスのシリアル化可能なnullを作成したい場合は、次のことができます。
gson gson = new gsonbuilder()。serializenulls()。create();
NULLをシリアル化する場合、JSONNULL要素がJSONELEMENT構造に追加されることに注意してください。したがって、このオブジェクト(GSON)をカスタムシリアイザー/デシリアライザーで使用できます。
これが例です:
パブリッククラスfoo {private final string s;プライベートファイナルイント。 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); out.out.out.out.out.out.out.out.out.出力:
{"s":null、 "i":5} nullバージョンサポート
@Since Annotationを使用して、同じオブジェクトの複数のバージョンを維持できます。この注釈は、クラスやフィールドで使用でき、将来の方法でもサポートされます。この機能を使用するには、特定のバージョン番号よりも大きいフィールドとオブジェクトを無視するようにGSONインスタンスを構成する必要があります。バージョンがGSONオブジェクトに設定されていない場合、シリアル化/脱着時にすべてのフィールドとクラスが使用されます。
public class versionedclass {@since(1.1)private final string newerfield; @Since(1.0)プライベートファイナルストリングニューフィールド。プライベートファイナルストリングフィールド。 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(some object); system.out.println(jsonoutput); system.out.print = gson = new gson( gson.tojson(someobject); system.out.println(jsonoutput);出力:
{"newfield": "new"、 "field": "old"} {"newerfield": "newer"、 "newfield": "new"、 "field": "old"}シリアル化/脱介入からフィールドを除外します
GSONは、クラス、フィールド、およびフィールドタイプを削除するための多くの方法の使用をサポートしています。次の方法でニーズを満たしていない場合は、カスタムシリアル化/デシリアライザー法を使用できます。
1.Java修飾子除外
デフォルトでは、フィールドが一時的に宣言されている場合、フィールドは除外されます。さらに、フィールドが静的と宣言されている場合、このフィールドもデフォルトで除外されます。一時的であると宣言されたいくつかのフィールドを含めたい場合は、これを行うことができます。
Import java.lang.Reflect.Modifier; gson gson = new gsonbuilder().excludefieldswithModifiers(modifier.static).create();
expludefieldswithModifiersメソッドでは、できるだけ多くの修飾子定数を使用できることに注意してください。例えば:
gson gson = new gsonbuilder().excludefieldswithmodifiers(modifier.static、modifier.transient、modifier.volatile).create();
2。 @exposeフィールドを使用して除外します
この機能を使用すると、クラス内の特定のフィールドにタグを付けることができ、シリアル化/脱介入で除外/除外されないようにします。このアノテーションを使用するには、new gsonBuilder()を使用してGSONを作成する必要があります。 GSONインスタンスは、 @exposeでマークされていないクラス内のすべてのフィールドを除外します。
3。ユーザー定義の除外ポリシー
上記の除外方法がニーズを満たすことができない場合は、除外戦略をカスタマイズすることもできます。詳細については、除外trategy javadocを参照してください。
次の例は、@FOOでマークされたフィールドを除外し、トップレベルの種類の文字列クラスまたは宣言されたフィールドタイプを除外する方法を示しています。
@retention(retentionPolicy.runtime)@target({elementType.field})public @interface foo {//フィールドタグのみアノテーション} public class sample objectfortest {@foo private final int annotatedfield;プライベートファイナルストリングストリングフィールド。プライベートファイナルロングロングフィールド。プライベートファイナルクラス<?> Clazzfield; public sample objectfortest(){annotatedfield = 5; stringfield = "SomedefaultValue"; Longfield = 1234; }} public class myexclusionstrategyは除外trategy {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); }出力:
{"Longfield":1234}JSONフィールドネーミングのサポート
GSONの事前定義されたフィールド命名戦略の一部は、標準のJavaフィールド名(つまり、SamplefieldNameInjavaなどのラクダの命名法)をJSONフィールド名(つまり、Sample_field_name_in_javaまたはsamplefieldnameinjava)に変換できます。詳細については、FieldNamingPolicyを参照してください。
GSONには、クライアントがフィールドの名前をカスタマイズできるようにするための注釈ベースのポリシーもあります。この戦略の下で、違法なフィールド名が注釈付き値として提供される場合、GSONはランタイム例外をスローします。
次の例は、これら2つのGSONネーミング戦略の使用方法を示しています。
プライベートクラスSomeObject {@serializedName( "custom_naming")プライベートファイナルストリングSomefield;プライベートファイナルストリングSomeotherfield; public someobject(string a、string b){this.somefield = a; this.someotherfield = b; }} some object some object = new someObject( "first"、 "second"); gson gson = new gsonbuilder()。setfieldnamingpolicy(fieldnamingpolicy.upper_camel_case)。出力:
{"custom_naming": "first"、 "someotherfield": "second"}名前をカスタマイズする場合は、@SerializedName Annotationを使用できます。
SerializerとDeserializerの間で状態を共有します
シリアルとデシリアライザーの間で状態を共有する必要がある場合があり、次の3つの方法を使用して目標を達成できます。
最初の2つの方法はスレッドセーフではなく、3つ目はです。
nullエラーを解析するGSONの解決策
GSONの欠点の1つは、ヌルの交換を設定できないことです。
バッチでサーバーによって返されたnullを手動で交換することができます。通常のインターフェイスが定義されている場合、サーバーは間違いなくnullを返すことは許可されませんが、背景の結果は常にnullに見えます!
検索すると、よくある答えがあります。
gson gson = new gsonbuilder()。serializenulls()。create();
しかし、これは略奪の問題を解決することはできません、それを解決する方法は?
解決策は次のとおりです。
gson gson = new gsonbuilder()。RegisterTypeadapterfactory(new NullstringToEmptyAdapterFactory()) nullStringToEmptyAdapterFactory <t>は、typeadapterfactory {@suppresswarnings( "unchecked")public <t> typeadapter <t> create(gson gson、typetoken <t> type){class <t> rawtype =(class <t>)type.getrawtype(); if(rawType!= string.class){return null; } return(typeadapter <t>)new StringNulladapter(); }} // stringnulladapter code public class stringnulladapter拡張typeadapter <string> {@override public string read(jsonreader reader)throws ioexception {// dodo auto-generated method stub(reader.peek()== jsontoken.null){reader.nextnull();戻る ""; } return reader.nextString(); } @Override public void write(jsonwriter writer、string value)throws ioexception {// todo auto-fenatedメソッドスタブif(value == null){writer.nullvalue();戻る; } writer.value(value); }}