2013 年 5 月 2 日

アンドロイドアプリでJsonPullParserを使ってみる

アンドロイドアプリでJsonPullParserを使ってみる

JSONはXMLよりコンパクトでシンプルな構文で扱いやすいです。アンドロイドアプリでサーバとやりとりするときはJSONを利用することが多いです。
Android SDKにもJSONライブラリはありますが、JsonPullParserはサイズが小さく高速です。そして、APT(Annotation Processing Tool)を利用してアノテーションでJSONとPOJO(Plain Old Java Object)をマッピングするという特徴があります。

またXmlPullParserと同様に、全体を読み終わるまで待つのではなく、読み終わったJSONオブジェクトインスタンスを次々と受け取ることができます。

ダウンロード

ダウンロードは作者の@vvakameさんのgithubからダウンロードできます。

JsonPullParserはJSONからPOJOに変換してくれるユーティリティクラスを自動生成します。アノテーションを書くことが取っつきにくいかもしれませんが、なれれば、とっても簡単です。

今回は現時点で最新のjsonpullparser-1.4.zipをダウンロードしました。このzipファイルはソースコード含む4つのzipファイルが含まれており、利用するのは、以下の二つのjarファイルです。

  • jsonpullparser-apt-1.4.jar – コード生成時に必要なもの
  • jsonpullparser-core-1.4.jar – 実行時に利用するもの
  • プロジェクトのlibsに入れるのは、jsonpullparser-core-1.4.jarだけで、jsonpullparser-apt-1.4.jarはEclipseのannotation Factoryのパスで指定します。
    では、その設定を行っていきましょう。

    Elipseでの設定

    jsonpullparser-core-1.4.jarは、プロジェクトのlibsフォルダにDrag&Dropでコピーします。jsonpullparser-apt-1.4.jarは、c:\libs(好きな場所へ)に置いておきます。

    次にEclipseのプロジェクトプロパティからJava Complier->Annotation Processingを選択すると以下のような画面になります。

    ここで、Enable project specific settingsにチェックします。Generated source directoryは自動生成したJavaソースコードをどこに保存するかを指定します。アンドロイドなら、./genとしておくとよいでしょう。そして、Processor optionsに以下のものを追加します。

    • JsonPullParserClassPostfix – 自動生成するクラスの接尾語
    • JsonPullParserDebug – デバッグ出力の有無

    JsonPullParserClassPostfixは好きな語を指定します。私はGenとしています。JsonPullParserDebugはtrueとしておきます。

    次にAnnotation Processing->Factory Pathを選択します。ここで、先ほどのもう一つのライブラリを指定します。まず、Enable project specific settingsをチェックします。そして、Add External JARS…をクリックして、jsonpullparser-apt-1.4.jarを追加します。

    POJOを作成

    以下のようなJSONを読み込むことを想定します。

    {
      "id"           : "1",
      "name"         : "hoge",
      "version_code" : "1"
    }
    

    このJSONに対するPOJOを作成します。クラス宣言にJsonModelアノテーションを付加します。そして、JSONの各変数にひもづくメンバ変数にはJsonKeyアノテーションをつけます。

    さらにそれらのsetter,getterを追加します。

    この状態でビルドすると、genディレクトリ下にMyJsonGen.javaが生成されているはずです。されていなければ、一度クリーンを実行して、手動ビルドを実行してください。それでも生成されなければ再度Elipseの設定を見直してください。

    MyJson.java

    package com.example.jsonpullparser;
    
    import net.vvakame.util.jsonpullparser.annotation.JsonKey;
    import net.vvakame.util.jsonpullparser.annotation.JsonModel;
    
    // decamelize=true : xxx_yyy -> xxxYyyへ変換します。
    @JsonModel(decamelize=true)
    public class MyJson {
      
      @JsonKey
      private String id;
      
      @JsonKey
      private String name;
      
      // キャメルスタイルのメンバ変数の例
      // @JsonModel(decamelize=true)
      // またはメンバごとに @JsonKey("version_code")と書くこともできます。
      @JsonKey
      private String versionCode;
     
      public String getId() {
        return id;
      }
      
      public void setId(String id) {
        this.id = id;
      }
      
      public String getName() {
        return name;
      }
      
      public void setName(String name) {
        this.name = name;
      }
      
      public String getVersionCode() {
        return versionCode;
      }
      
      public void setVersionCode(String versionCode) {
        this.versionCode = versionCode;
      }
    }
    

    JSONをパースする

    では、実際にJSONをパースして、POJOを生成するところをみてみましょう。

    public class MainActivity extends Activity {
    
      static final String TAG = MainActivity.class.getSimpleName();
    
      @Override
      protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        new MyJsonDownloadTask().execute();
      }
    
      class MyJsonDownloadTask extends AsyncTask<Void, MyJson, Void> {
        
        @Override
        protected Void doInBackground(Void... params) {
    
          try {
            URL url = new URL("http://www.notice.co.jp/paads/myjson.json");
            HttpURLConnection conn = (HttpURLConnection)url.openConnection();
            
            try {
              InputStream in = new BufferedInputStream(conn.getInputStream());
              JsonPullParser parser = JsonPullParser.newParser(in);
              MyJson json = MyJsonGen.get(parser);
              Log.d(TAG, "id          = " + json.getId());
              Log.d(TAG, "name        = " + json.getName());
              Log.d(TAG, "versionCode = " + json.getVersionCode());
              
            } finally {
              conn.disconnect();
            }
          } catch (JsonFormatException e) {
            Log.e(TAG, "doInBackground", e);
          } catch (IOException e) {
            Log.e(TAG, "doInBackground", e);
          }
          return null;
        }
      }
    }
    

    一応、HTTPでJSONを取得するようにしてみました。今回は単体のJSONでしたが、getList()を利用すれば配列も取得できます。皆さんも是非利用してみてください。