JSONIC とは
JSONIC (Simple JSON encoder/decoder written in java) はシンプルなで使いやすい Java 用 json ライブラリです。ライセンスは Apache 2.0。
既に古くなっており、公式でも jackson への移行を推奨しています。が、いまだに多くのシステムで使われているとおもいます。
Java Object を JSON 化してみる
とりあえず、以下のような簡単な古典的な Java Object (POJO: Plain Old Java Object) を用意してみます。
public class User {
public int age;
private String name;
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
以下のようにインスタンスを生成して JSON.encode()
関数を呼び出すと、インスタンスを json テキストに変換してくれます。
import net.arnx.jsonic.JSON;
public class TestCode {
public static void main(String[] args) {
User user = new User();
user.setName("yamachan");
user.age = 17;
String json = JSON.encode(user);
System.out.println(json);
}
}
Eclipse 上はこんな感じ。
実行結果は以下になります。簡単ですよね。
{"age":17,"name":"yamachan"}
private inner class の扱い
某所で JSONIC を用いた Java アプリのコードを眺めたのですが、private inner class を用いたものがありました。面白いなと思って、自分でもちょっと試してみます。
さきほどの User クラスの中に、InnerUser という名前で、もうひとつの POJO クラスを private inner class として定義してみます。以下のような感じ。
public class User {
public User() {
this.innerUser = new InnerUser();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
this.innerUser.setName("#" + this.name);
}
public Object getInnerUser() {
return this.innerUser;
}
public int age;
private String name;
private InnerUser innerUser;
private class InnerUser {
public int age;
private String name;
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
}
実行コードはほとんど同じ。最後に innerClass の表示を追加しただけ。
import net.arnx.jsonic.JSON;
public class TestCode {
public static void main(String[] args) {
User user = new User();
user.setName("yamachan");
user.age = 17;
String json = JSON.encode(user);
System.out.println(json);
System.out.println(user.getInnerUser()); // コレを追加
}
}
実行結果は以下のようになりました。
private class として定義した InnerUser クラスを Object 型として返しただけなのに、ちゃんと中身が JSON 化されて表示されています。これは便利!でも、どうして?
{"age":17,"innerUser":{"age":0,"name":"#yamachan"},"name":"yamachan"}
jsonic.User$InnerUser@7a92922
この動作ですが、私としては以下のように理解しました。
- InnerClass は private class なので User class 以外からは利用できない
- しかし User class に
public Object getInnerUser()
関数が定義されているので、Object 型の参照として外部からアクセスすることはできる - 上記の得られた Object を String に変換すると
User$InnerUser@7a92922
と inner class 名とシグネチャがわかる、つまりこれらの情報は守られていない - InnerClass に定義された
age
属性値や、getName()
メソッドが public なので、これらの値にも外部からアクセスでき、結果として JSONIC により JSON テキスト化の対象となる
そして、InnerClass に格納した値を守るためには、以下の対応が必要のようです。
- InnerUser class 定義で
age
setName()
getName()
などの属性やメソッドを private に変更する - この private への変更後も定義した User class 内のロジックからは利用可能
private class InnerUser {
private int age;
private String name;
private String getName() {
return this.name;
}
private void setName(String name) {
this.name = name;
}
}
うん、はい。。なんか Java として当然なことを言っているだけの気がしてきました…
私はこれまで、あまり Java の private inner class を使ってこなかったので、見慣れないコードなだけでした。既存のクラスを private inner class として取り込む際には、public な setter/getter なども忘れずに private に変更すること。
そうじゃないとオブジェクトへの参照が外に漏れた途端、inner class そのものが守られているように見えても、JSONIC みたいなリフレクションを使った(?)コードから、中の値を見られてしまうよ、ということですね。気を付けよう。。
というわけで
JSONIC の動作が気になって試してみたら、自分自身の Java 知識と経験の浅さに改めて気がついた、という記録でした。
うーん、単に自己反省メモで、情報量がほとんどないですね。すみません。。
それではまた!