Javaとgsonでjsonを使う時詰まったとこ

4 min read読了の目安(約4000字

はじめに

https://qiita.com/advent-calendar/2020/code-polaris
codepolarisのアドベントカレンダーに参加するため記事を書きました!

Javaでgsonを使ってjsonを使う方法は別のサイトを参考にしました。

https://joytas.net/programming/webapi
こちらのサイトは星座の情報をJsonデータで受け取るものです。
これをベースに楽天ブックスのAPIとimslpのAPIを使ってみます。

ちなみに最終的に作りたいのはimslpのAPIを使ってドビュッシーが作曲したデータたちをまとめることです。imslpとはクラシックの楽譜がダウンロードできるサイトです。

https://imslp.org/wiki/Main_Page

詰まったとこ

参考サイトで使用されている星をみるひとAPIのjsonの構造と使いたいAPIのjsonの構造が違っていたのでちょっと考えないとだめでした。

使った項目だけ残して、もろもろ省いてます。
ほぼ参考サイトのコードになるので主に書き換えたところ(tryの中)だけ載せます。

星をみるひとAPIのjsonデータ

{
	"result": [
		{
			"enName": "Andromeda",
			"jpName": "アンドロメダ座",
			"origin": "エチオペアをケフェウス王とカシオペア王妃が支配していた時のこと、(略)",
			"starImage": "https://livlog.xyz/hoshimiru/img/and.png"
		}
	],
	"status": 0
}

楽天ブックスAPIの場合

楽天ブックスAPIのjsonデータ
長野まゆみ作の本で探した結果をもらいます。

{
	"Items": [
		{
			"Item": {
				"author": "長野 まゆみ",
				"title": "45° ここだけの話",
				"largeImageUrl": "https://thumbnail.image.rakuten.co.jp/@0_mall/book/cabinet/6117/9784065156117.jpg?_ex=200x200",
			}
		}
	]
}
try {
	URL url = new URL(urlString);
	con=(HttpURLConnection) url.openConnection();
	con.setRequestMethod("GET");

	InputStream is = con.getInputStream();
	InputStreamReader isr= new InputStreamReader(is, "UTF-8");
	jReader = new JsonReader(isr);

	JsonObject root = new Gson().fromJson(jReader, JsonObject.class);

	//rootを一番外側のキーにする
	JsonArray result = root.get("Items").getAsJsonArray();

	for (int i = 0; i < result.size(); i++) {
		//bookモデルのインスタンス生成
		Book book = new Book();
		
		//オブジェクトの中のキーを指定しオブジェクトとして取得(入れ子)
		//①
		JsonObject sObj = result.get(i).getAsJsonObject();
		//②
		JsonObject contain = sObj.get("Item").getAsJsonObject();

		//③
		String title = contain.get("title").getAsString();
		String author = contain.get("author").getAsString();
		String imageSrc = contain.get("largeImageUrl").getAsString();

		//bookモデル?にセット
		book.setTitle(title);
		book.setAuthor(author);
		book.setImageSrc(imageSrc);
		list.add(book);
	}
}

とりあえずルートにItemsを設定します。
①Itemsが配列になっており、キーのついていないオブジェクトがたくさん入ります。まずはそれを取得します。
②さらにその中にItemというキーのオブジェクトがあるのでそれをとります。
③ほしいデータのキーをgetのところにセットします。

imslpの場合

sort属性(?)をparentにして作曲者名(?)のアルファベット順に並べて、ドビュッシーがでてくるらへんをstartにしてます。ごり押し感強いのでいい方法あれば教えてほしいです。

https://imslp.org/imslpscripts/API.ISCR.php?account=worklist/disclaimer=accepted/sort=parent/type=2/start=41200/retformat=json/limit=2

imslpAPIのjsonデータ

{
	"0": {
		"id": "Fantasia for 2 Viols (De Pers)",
		"type": "2",
		"parent": "Category:De Pers",
		"intvals": {
			"composer": "De Pers",
			"worktitle": "Fantasia for 2 Viols"
		},
		"permlink": "https:\/\/imslp.org\/wiki\/Fantasia_for_2_Viols_(De_Pers)"
	}
}
try {
	URL url = new URL(urlString);
	con = (HttpURLConnection) url.openConnection();
	con.setRequestMethod("GET");

	InputStream is = con.getInputStream();
	InputStreamReader isr = new InputStreamReader(is, "UTF-8");
	reader = new JsonReader(isr);

	JsonObject root = new Gson().fromJson(reader, JsonObject.class);
	//rootはキーなし
	//連番のキーがついている
	//配列に入っていない
	for (int i = 0; i < root.size()-1; i++) {
		//連番のキーを文字にする
		String key = String.valueOf(i);
		//オブジェクトをとって来る
		JsonObject rootObj = root.get(key).getAsJsonObject();
		Work work = new Work();
		work.setParent(rootObj.get("parent").getAsString());
		work.setUrl(rootObj.get("permlink").getAsString());

		//階層が下(intvalsの中)
		JsonObject lowerObj = rootObj.get("intvals").getAsJsonObject();

		work.setComposer(lowerObj.get("composer").getAsString());
		work.setTitle(lowerObj.get("worktitle").getAsString());
		list.add(work);
	}
}	

root(一番外側で束ねている)のキーはありません。オブジェクトの配列{}の中に入っているデータに"0","1","2"...と数字のキーがついています。
なので、数字を文字に変換してキーにあてて、jsonオブジェクトとしてとってきます。
さらにinvalsというキーのオブジェクトのなかにタイトルなどのデータがあるので入れ子のようにしてデータをとってきます。

完成

これでドビュッシーの作品のリンク集ができました!
imslpのサイト内にも検索機能はあるのですがとても使いにくいので、これで少しはスムーズに欲しい曲が探せそうです。

これを作る際jsonのことを調べましたが全く分からなかったのでわかりそうでわからないサイト並みにわかりやすい書籍などあればコメントで教えていただけるとありがたいです。