Top / JSON / Json-libを使う / JSONからJavaへいろんな変換

以下のような親子モデルで、ネストしたオブジェクトが正しく変換されるか、配列やListやSetなどが正しく変換されるか試してみます。

public class Parent {
  private String name;
  private int id;
  private Child child;
  public Child getChild() { return child; }
  public void setChild(Child child) { this.child = child;}
  public int getId() { return id;}
  public void setId(int id) { this.id = id;}
  public String getName() { return name;}
  public void setName(String name) { this.name = name;}
  public String toString() {
    return new ToStringBuilder(this).
        append("id", getId()).append("name",
        getName()).append("child", getChild()).toString();
  }
}
public class Child {
  private String name;
  public String getName() { return name;}
  public void setName(String name) { this.name = name;}
  public String toString() {
    return new ToStringBuilder(this)
           .append("name", getName()).toString();
  }
}

ネストしたオブジェクト

Parent parent = new Parent();
parent.setId(0);
parent.setName("親の名前");

Child child = new Child();
child.setName("子の名前");
parent.setChild(child);

JSONObject jsonObject = JSONObject.fromObject(parent);
System.out.println(jsonObject);

Parent p = (Parent) JSONObject.toBean(jsonObject, Parent.class);
System.out.println(p);

結果

{"child":{"name":"子の名前"},"name":"親の名前","id":0}
Parent@6e70c7[id=0,name=親の名前,child=Child@1d63e39[name=子の名前]]

うまくいきました。

java.util.List

java.util.Listを追加しました。

public class Parent {
  private String name;
  private int id;

  private List list; //追加
  public List getList() {return list;} //追加
  public void setList(List list) {this.list = list;} //追加

  //private Child child;
  //public Child getChild() { return child; }
  //public void setChild(Child child) { this.child = child;}
  public int getId() { return id;}
  public void setId(int id) { this.id = id;}
  public String getName() { return name;}
  public void setName(String name) { this.name = name;}
  public String toString() {
    return new ToStringBuilder(this).append("id", getId())
               .append("name",getName())
               .append("list", list).toString();
  }
}

これでやってみると、、

Parent parent = new Parent();
parent.setId(0);
parent.setName("親の名前");

Child child = new Child();
child.setName("子の名前");
List<Child> list = new ArrayList<Child>();
list.add(child);
parent.setList(list);

JSONObject jsonObject = JSONObject.fromObject(parent);
System.out.println(jsonObject);

Parent p = (Parent) JSONObject.toBean(jsonObject, Parent.class);
System.out.println(p);

結果

{"list":[{"name":"子の名前"}],"name":"親の名前","id":0}
Parent@12a1e44[id=0,name=親の名前,list=[net.sf.json.util.JSONDynaBean@1ad77a7[
  {name=子の名前}
]]]

ChildをListに追加しているのですが、逆変換したオブジェクトはChildではなくnet.sf.json.util.JSONDynaBean? になっちゃいました。まあ

"list":[{"name":"子の名前"}]

とParentクラスだけだと、Listの中身がChildだって情報がないから、当たり前ですね。。

Listなどのマッピングについて 2009/03/18 追記

久しぶりに触ってみたら、モジュールが色々バージョンアップしてるみたいですね。今触ってるのは、2.2.3なのですが、戻り値のクラスがnet.sf.json.util.JSONDynaBean? からnet.sf.ezmorph.bean.MorphDynaBean?というのに変更になったりしています。*1

また色々ググってたら、フィールドの java.util.List をビシっと自分が指定したクラスにマップするようにライブラリに指示できることが分かりました。net.sf.json.JsonConfig? クラスというのがあり、これを使うことでJson-libの挙動を色々設定することができます。具体的には以下の通り:

private JsonConfig createConfig() {
  JsonConfig jsonConfig = new JsonConfig();
  jsonConfig.setRootClass(Parent.class);
  Map<String, Class> classMap = new HashMap<String, Class>();
  classMap.put("list", Child.class);
  jsonConfig.setClassMap(classMap);
  return jsonConfig;
}

としてJsonConfig?インスタンスを作成します。ポイントは

classMap.put("list", Child.class);

としてフィールドの変数名とそのフィールドにマッピングしたいクラス(List内にaddするクラス)のペアをJsonConfig?クラスに設定しておくところですね。あとは

JsonConfig jsonConfig = createConfig();
Parent p = (Parent) JSONObject.toBean(jsonObject, jsonConfig);

としてJsonConfig?をわたしながらtoBeanを実行するだけですね。ちなみにJsonConfig?を渡さなかったときは

Parent p = (Parent) JSONObject.toBean(jsonObject, Parent.class);

として引数にParent.classを指定してましたが、今回Parent.classはJsonConfig?経由で渡されてきています。

実行結果は以下の通り:

Parent@8ab08f[id=0,name=親の名前,list=[Child@a5af9f[name=子の名前]]]

指定通りChildクラスにマップされました!賢いですねー。

ちなみにJsonConfig?にはJavaのフィールド名とJSON内のキー値をマッピングしたり、色々と便利な機能が備わっているようです。

参考

java.util.Set

java.util.Listをjava.util.Setに変えてみました。

public class Parent {
  private String name;
  private int id;
  private Set children;
  
  public Set getChildren() {return children;}
  public void setChildren(Set children) {this.children = children;}
  public int getId() { return id;}
  public void setId(int id) { this.id = id;}
  public String getName() { return name;}
  public void setName(String name) { this.name = name;}
  public String toString() {
    return new ToStringBuilder(this).append("id", getId())
               .append("name",getName())
               .append("children", children).toString();
  }
}

これでやってみると、、

Parent parent = new Parent();
parent.setId(0);
parent.setName("親の名前");

Child child = new Child();
child.setName("子の名前");
Set<Child> children = new HashSet<Child>();
children.add(child);
parent.setChildren(children);

JSONObject jsonObject = JSONObject.fromObject(parent);
System.out.println(jsonObject);

Parent p = (Parent) JSONObject.toBean(jsonObject, Parent.class);
System.out.println(p);

結果

2006/12/31 18:01:40 org.apache.commons.beanutils.PropertyUtilsBean invokeMethod
致命的: Method invocation failed.
java.lang.IllegalArgumentException: argument type mismatch

BeanUtils?が例外になっちゃいました。

Setのマッピングについて 2009/03/18 追記

先の例と同じでJsonConfig?

Map<String, Class> classMap = new HashMap<String, Class>();
classMap.put("children", Child.class);
jsonConfig.setClassMap(classMap);

とすることで、実行すると

Parent@4d921a[id=0,name=親の名前,children=[Child@4c6320[name=子の名前]]]

正しく動くことが確認できました。上の例外の件はとりあえず忘れちゃいましょう:-)。

配列

配列も同じですね。ダメですねぇ。

2009/03/18追記
配列も正しく動きます。実際実行してみると、
Parent@8ab08f[id=0,name=親の名前,children={Child@a5af9f[name=子の名前]}]
となりOKそうですね。

java.util.Map

java.util.Setをjava.util.Mapに変えてみました。

public class Parent {
  private String name;
  private int id;
  private Map children;
  
  public Map getChildren() {return children;}
  public void setChildren(Map children) {this.children = children;}
  public int getId() { return id;}
  public void setId(int id) { this.id = id;}
  public String getName() { return name;}
  public void setName(String name) { this.name = name;}
  public String toString() {
    return new ToStringBuilder(this).append("id", getId())
               .append("name",getName())
               .append("children", children).toString();
  }
}

これでやってみると、、

Parent parent = new Parent();
parent.setId(0);
parent.setName("親の名前");

Child child = new Child();
child.setName("子の名前");
Map children = new HashMap();
children.put("child1", child);
parent.setChildren(children);

JSONObject jsonObject = JSONObject.fromObject(parent);
System.out.println(jsonObject);

Parent p = (Parent) JSONObject.toBean(jsonObject, Parent.class);
System.out.println(p);

結果

{"name":"親の名前","id":0,"children":{"child1":{"name":"子の名前"}}}
Parent@b1b4c3[id=0,name=親の名前,children={child1=net.sf.json.util.JSONDynaBean@1efb836[
  {name=子の名前}
]}]

例によってkey=child1とともに代入されたChildはnet.sf.json.util.JSONDynaBean?になっちゃいましたが、一応正常終了ですね。

Mapのマッピングについて 2009/03/18 追記

先のJsonConfig?クラスを使用することでうまくマッピングすることができそうです。

private static JsonConfig createConfig() {
  JsonConfig jsonConfig = new JsonConfig();
  jsonConfig.setRootClass(Parent.class);
  Map<String, Class> classMap = new HashMap<String, Class>();
  classMap.put("child1", Child.class);
  jsonConfig.setClassMap(classMap);
  return jsonConfig;
}

このように、child1に対してChildクラスですよって指定をすることで、

Parent@672bbb[id=0,name=親の名前,children={child1=Child@dd75a4[name=子の名前]}]

となりました。。Mapのキーが増えていっても、

  classMap.put("child1", Child.class);
  classMap.put("child2", Child.class);

のようにそれぞれにマップするクラスを指定すれば良いみたいです。

関連リンク


この記事は

選択肢 投票
おもしろかった 11  
そうでもない 1  
  • やり方が悪いような気がするなあ。。でも時間切れ。。。 -- きの? 2006-12-31 23:10:37 (日)
  • Enumは? -- とおりすがり? 2007-03-09 (金) 09:16:17

Top / JSON / Json-libを使う / JSONからJavaへいろんな変換

現在のアクセス:38819


*1 だからナンなのかはよく分かってないのですが(´д`;)

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2012-12-28 (金) 12:59:58 (1732d)