Islands in the byte stream

Technical notes by a software engineer

Gsonの処理を爆速にするStaticGsonをリリースした

コード生成でGsonをMoshiより高速化する - Islands in the byte stream の続きです。

GitHub - gfx/StaticGson: Static Gson binding library with annotation processing

三行まとめ

  • StaticGsonはannotation processingでコード生成してGsonを高速化する拡張で、結果はLoganSquareより少し遅い程度
  • 欠点はメソッド数+バイナリサイズのオーバーヘッド
  • 利点はGsonと互換性の高さ。モデルにアノテーションをつけてGson初期化でオプションを一つ与えるだけ

解説

リフレクションで処理していたところをコード生成にして高速化する手法は思ったより効果ありそうだな、ということでjcenterにリリースしました。以下のように依存指定すると使えます。

dependencies {
    apt 'com.github.gfx.static_gson:static-gson-processor:0.9.4'
    compile 'com.github.gfx.static_gson:static-gson:0.9.4'
}

使い方は簡単で、シリアライズ対象のモデルに @JsonSerializable をつけて:

@JsonSerializable
public class Book {
  // ...
}

GsonBuilderにtype adapter factoryを与えるだけ:

Gson gson = new GsonBuilder()
        .registerTypeAdapterFactory(StaticGsonTypeAdapterFactory.newInstance())
        .create();

setDateFormat()などのGsonBuilderのoptionはだいたい効きますが、FieldNamingPolicyなど一部のリフレクションの絡む機能は別途@JsonSerializableに与える必要があります。READMEにもあるとおりこんな感じ。

このシリアライズ名はコンパイル時に決定されるので、proguard避けのために@SerializedName を設定する必要はありません。速度よりもこっちのほうが個人的には嬉しい。

// LOWER_CASE_WITH_UNDERSCORES: 名前は各パーツをlower caseにしてアンダースコアで繋げるものとする
@JsonSerializable(
  fieldNamingPolicy = FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES
)
public class User {
    public String firstName; // serialized to "first_name"
    public Stirng lastName; // serialized to "last_name"
}

benchmarkはLoganSquare のものに手を加えてStaticGson対応させたもので測定してこんな感じ。Web APIのパースが多いだろうからパースに関する結果を載せています。Gsonよりも30%くらいは高速で、Jacksonより速くてLoganSquareより遅いという水準ですね。すでにGsonを使っているアプリに手軽に適用できるし、Gsonのオプションもほぼそのまま有効なので、導入が低コストという意味ではいいかもしれません。新規で使うならLoganSquareのほうが高速ではありますが、様々な場合にちゃんと対応できるかどうかまでは調べてないのでそこはよくわかりません。