気になる開発プロダクツ

第2回JSON-lib 1.1 - JSON文字列とJavaオブジェクトとの相互変換

JSON-libの概要

JSON-libは、JavaオブジェクトからJSON形式の文字列を生成したり、その逆の処理を行うJavaライブラリです。Ajaxアプリケーションにおいて、Webブラウザで動作しているJavaScriptのプログラムとサーバ側のプログラムとの間でオブジェクトをやり取りする際に利用できます。JAR形式のファイルをSourceForgeからダウンロード可能です。ライセンスはThe Apache Software License, Version 2.0です。

JDK1.3用(json-lib-1.1-jdk13.jar)とJDK1.5用(json-lib-1.1-jdk15.jar)がありますので、使用するJDKのバージョンに合ったものをダウンロードし、ファイルのパスをクラスパス(CLASSPATH)に設定してください。ここではJDK1.5用による実行例を紹介します。

実際の処理では、これ以外にも以下のライブラリも必要になりますので、合わせてダウンロードし、JARファイルをクラスパスに設定しておいてください。

JSON-libの実行に必要なライブラリ

JSONの概要

JSON-libを紹介する前に、JSON形式の文字列についてふれておきましょう。

Web APIで採用されるJSON

JSON(JavaScript Object Notation)とは、JavaScriptにおいて、オブジェクトの定義を行う際に用いられる表記方法です。RFC4627でも規定されています。このところWeb APIを公開する動きが加速していますが、その処理結果を返す際の形式として、JSONが採用されることが増えてきています。ちなみに、JavaScript関数の引数でJSON形式を用いる場合はJSONP(JSON with Padding)と呼ばれます。

JSON形式で処理結果を返すWeb APIの例

●国内サイト
●海外サイト

JSON形式によるオブジェクトの定義

Ajaxの広がりに伴い公開されるようになったWeb APIは、XML形式で処理結果を返すのが現在は主流です。XMLデータから必要とする部分を取得するには、DOM APIを用いる必要がありますが、メソッドなどの記述がどうしても複雑になりがちです。しかしJSONであれば、文字列からそのままオブジェクトを定義できるため、必要なデータをDOM APIよりも簡便な記述で取得できます。

たとえば、ID番号(id)、画像ファイル名(filename)と画像のタイトル(title)という3つのプロパティを持つオブジェクト(data)をJSONで定義すると、以下のようになります。

data = { "id" : 1, "title" : "東京ミッドタウン", "filename" : "midtown01.JPG" };

1つのオブジェクト定義は{}で囲み、: (コロン)を挟む左右のデータで1つのプロパティを表します。プロパティは, (カンマ)で区切られます。この場合はidプロパティの値が1、titleプロパティの値が"東京ミッドタウン"となります。それぞれのプロパティの値を取得するときは、data.id、data.titleなどのように記述します。

1つのオブジェクト定義を, (カンマ)で区切り、複数の定義を[ ]で囲めば、配列を定義できます。以下は2つのオブジェクトを要素とする配列dataを定義する例です。

data = [
  { "id" : 1, "title" : "東京ミッドタウン", "filename" : "midtown01.JPG" },
  { "id" : 2, "title":"新丸ビル", "filename" : "shinmaru01.JPG" }
];

JSONには関数の定義を含めることもできます。以下のcalcオブジェクトには、足し算をするplus関数と、引き算をするminus関数を定義しています。実行結果は、calc.plus(5,3)が8、calc.minus(5,3)が2となります。

calc = {
  "plus"  : function(a, b) {  return a + b;  },
  "minus" : function(a, b) {  return a - b;  }
};

JSON形式の文字列からオブジェクトを生成する場合は、文字列の両端に()を追加してeval関数の引数とし、これを実行します。Ajaxアプリケーションにおいて、Web APIからJSON形式のデータを取得する際に、よく用いられます。

json = '{ "id" : 1, "title" : "東京ミッドタウン" }';
data = eval( '(' + json + ')' );
alert( '画像ID = ' + data.id + ', タイトル = ' + data.title );

JSON-libによるJSON文字列の生成

それでは、JSON-libの使い方を紹介しましょう。ここで説明しきれない内容については、SourceForgeのドキュメントJavadocなどを参照してください。

シンプルなオブジェクト定義の生成(JSONObject)

はじめに、シンプルなオブジェクト定義を生成する方法を紹介します。用いるのはJSONObjectクラスです。このインスタンスにput()メソッドでプロパティの名称と値を設定し、toString()メソッドでJSON文字列を設定します。以下はコンソールアプリケーションの例ですが、同じ処理をサーブレットやJSPで実行すれば、Ajaxアプリケーションにすることもできます。

// JSON文字列の生成(シンプルなオブジェクト定義)
JSONObject obj = new JSONObject();
// プロパティを登録
obj.put( "id", 1 );
obj.put( "title", "東京ミッドタウン" );
// JSON文字列を生成
System.out.println( obj.toString() );

実行結果

{"id":1,"title":"東京ミッドタウン"}

JavaBeanからの生成(JSONObject)

Ajaxアプリケーションでは、データベースから取得した値をJavaScriptで利用する場合も多いでしょう。一方で、Javaアプリケーションでデータベースからデータを取得する場合は、データをDTO(Data Transfer Object)となるJavaBeanのインスタンスに格納して扱われます。こうした場合は、JSONObjectクラスのfromBean()メソッドでJavaBeanからJSON文字列を生成します。

DataBean bean = new DataBean( 1, "東京ミッドタウン" );
// JavaBeanからJSON文字列を生成
JSONObject obj = JSONObject.fromBean( bean );
System.out.println( obj.toString() );

// プロパティが格納されるJavaBeanクラス
public class DataBean  {
  private int    id;
  private String title;

  public DataBean( int id, String title )  {
    this.id    = id;
    this.title = title;
  }

  /*****  セッター/ゲッターメソッド *****/
}

配列やコレクションからの生成(JSONArray)

JavaBeanが配列になっている場合はfromObject()メソッド、ArrayListなどコレクションの要素となっている場合はfromCollection()メソッドからJSON文字列を生成できます。

// 配列からJSON文字列を生成
DataBean db1 = new DataBean( 1, "東京ミッドタウン" );
DataBean db2 = new DataBean( 2, "新丸ビル" );
DataBean[] data = new DataBean[] { db1, db2 };
JSONArray array = JSONArray.fromObject( data );

// コレクションからJSON文字列を生成
ArrayList list = new ArrayList();
list.add( new DataBean( 1, "東京ミッドタウン" ) );
list.add( new DataBean( 2, "新丸ビル" ) );
JSONArray array = JSONArray.fromCollection( list );

関数が設定されるプロパティの場合は? (JSONFunction)

プロパティに関数を設定する場合は、JSONFunctionクラスで関数を定義するか、functionのブロック全体を1つの文字列にしてオブジェクトを定義します。

// 関数を設定するJSON文字列を生成
JSONFunction plus = new JSONFunction( new String[] { "a", "b" }, "return a + b;" );
String minus = "function minus(a,b) { return a - b; }";
JSONObject obj = new JSONObject();
obj.put( "plus", plus );
obj.put( "minus", minus );
System.out.println( obj.toString() );

実行結果

{"plus":function(a,b){ return a + b; }, "minus":"function minus(a,b) { return a - b; }"}

JSON文字列からJavaオブジェクトの生成

JavaScriptからサーバ側にデータを送信する際、POSTメソッドを用いる方法もありますが、JSON文字列でデータを扱うほうがJavaScriptプログラマには理解しやすいかもしれません。また、URLパラメータよりもデバッグもしやすいかもしれません。そうした場合は、JSON文字列からJavaオブジェクトを生成できると便利です。

ちなみに、JavaScriptでJSON文字列を生成するには、JSON in JavaScriptにアップされているファイルjson.jsに定義されているtoJSONString()メソッドを用います。

JSON文字列が単独のオブジェクトを表す場合はJSONObjectクラスのtoBean()メソッド、配列を表している場合はJSONArrayクラスのtoArray()メソッドを実行します。JSONArrayクラスのtoList()メソッドでは、配列の要素を詰めたリストを生成することもできます。

JSONのオブジェクト定義からJavaオブジェクトの生成(JSONObject)

// オブジェクト定義からJavaBeanを生成
String json = JavaScriptから取得したオブジェクト定義のJSON文字列;
JSONObject obj  = new JSONObject( json );
DataBean   bean = (DataBean)JSONObject.toBean( obj, DataBean.class );
System.out.println( bean.toString() );

JSONの配列からJava配列(Object[])の生成(JSONArray)

// 配列定義からJava配列(要素はDataBeanクラス)を生成
String json = JavaScriptから取得した配列定義のJSON文字列;
JSONArray obj  = new JSONArray( json );
Object[] data = JSONArray.toArray( obj, DataBean.class );
// 配列定義からリストを生成する場合はtoList()メソッドを実行
List list = JSONArray.toList( obj, DataBean.class );
for( Object o : data )  System.out.println( (DataBean)o );

JSON文字列の送受信のポイント(JavaScript-サーバサイド間)

JSON-libによって、JSON文字列とJavaオブジェクトとを相互に変換する方法を紹介したところで、JavaScriptのプログラムと、サーブレットやJSPなどサーバサイドのプログラムとの間でJSON文字列を送受信する際にポイントとなることを以下に挙げておきます。

a) 文字コードはUTF-8とする

JSON文字列の送受信はUTF-8で行うようにします。ブラウザによっては、JavaScriptでの処理で他の文字コードを扱えない場合があるためです。ですから、サーバサイドでもJSON文字列の送受信に関してはUTF-8を想定したプログラミングをしておく必要があります。具体的には、送信する文字列をUTF-8にエンコードするのはもちろん、Content-Typeヘッダのうしろに「charset=UTF-8」を追加します。

// JSON文字列をサーバサイドから受信(JavaScript)
var req = XMLHttpRequestオブジェクト;
req.onreadystatechange = function() {
  data = eval( '(' + req.responseText + ')' );
  // json.jsを利用する場合
  // data = req.responseText.parseJSON();
}

// JSON文字列をXMLHttpRequestに送信する(サーバサイド)
response.setContentType( "application/json; charset=UTF-8" );
out.print( JSON文字列 );   // JSON文字列はUTF-8に変換済みとする
out.close();

// JSON文字列を受信してJavaオブジェクトに変換(サーバサイド)
String json = request.getParameter( "data" );
if ( json != null )  {
  json = new String( json.getBytes( "ISO-8859-1" ), "UTF-8" );
  JSONObject obj = JSONObject.fromString( json );
  DataBean data = (DataBean)JSONObject.toBean( obj, DataBean.class );
}

b) 悪意のあるJavaScriptコードをWebブラウザに送信される可能性がある

JavaScriptで受信したJSON文字列はeval関数によって解釈し、オブジェクトとできるようになっていますが、悪意のあるWebサイトにアクセスしてしまうと、この仕組みを悪用してセキュリティを脅かすコードがユーザのWebブラウザに送信されてしまうおそれがあります。

前述のjson.jsに定義されているparseJSON()メソッドをeval関数の代わりに用いることもできますが、それでもセキュリティを完全に確保できるとは限りません。アプリケーションの開発時、そして稼動後もどんなデータが送信されるかをきちんと確認することが肝要です。


JSON-libは小さなライブラリですが、JavaアプリケーションでつくられたサービスをWeb APIによって公開する際に、きっと役に立つことでしょう。もしかすると、広がりつつあるAjaxアプリケーションやWeb API公開の裏で、すでに活躍しているのかもしれません。

おすすめ記事

記事・ニュース一覧