読者です 読者をやめる 読者になる 読者になる

ナカザンドットネット

Android Developer's memo

GitHubでJPP用のオレオレTokenConverterを公開しました

あるkeyに対して、string値、string配列のどちらが割り振られるかわからない場合に利用します。
JPPUtils - Utilities for JsonPullParser

仕事で使うJSONが普通のJPP(JsonPullParser)だと対応しきれない感じだったので作ってみました。

概要

今回作ったオレオレTokenConverterのルールは以下になります。

  • string値 -> サイズ1の ArrayList
  • string配列 -> デフォルトと同じ挙動(のつもり)
  • 空配列 -> サイズ0の ArrayList(デフォルトと同じ(ry)
  • 該当のkeyが存在しない -> null

要は面倒だから全部Listにぶち込めヒャッハーってことですね!素敵!

詳細

まず、こんなPOJO(JPPアノテーション済み)があったとします。

@JsonModel(decamelize=true)
public class Item {

	@JsonKey
	List<String> valueList1;
	
	@JsonKey
	List<String> valueList2;

	public List<String> getValueList1() {
		return valueList1;
	}

	public void setValueList1(List<String> valueList) {
		this.valueList1 = valueList;
	}

	public List<String> getValueList2() {
		return valueList2;
	}

	public void setValueList2(List<String> valueList2) {
		this.valueList2 = valueList2;
	}
}

このPOJOでマッピングするJSONが以下のように複数パターンある場合、普通のJPPでは対処できません。

// パターン1 - 両方string配列(今回のPOJOならば問題ない)
{
	"value_list1": [
		"hoge1",
		"fuga1"
	],
	"value_list2": [
		"hoge2",
		"fuga2"
	]
}

// パターン2 - 片方string配列、片方string値(string値のパースでエラー発生)
{
	"value_list1":"hoge1",
	"value_list2": [
		"hoge2",
		"fuga2"
	]
}

// パターン3 - 両方ともstring値(string値のパースでエラー発生)
{
	"value_list1":"hoge1",
	"value_list2":"fuga2"
}

// パターン4 - 片方空配列、片方string配列(今回のPOJOならば問題ない)
{
	"value_list1": [],
	"value_list2": [
		"hoge2",
		"fuga2"
	]

}

// パターン5 - key自体が無い(これはJPPのデフォルトでnull値が割り当てられる)
{
	"value_list1":"hoge1",
}

今回の問題は、「受け皿であるPOJO側では一つの型でしか受け取れないのに、JSON側の型はstring配列、空配列、string値のいずれかに柔軟に変更される」ということでした。
幸い、JsonPullParserではパースのためのルールを自前でカスタマイズするTokenConverterの仕組みがありますので、そちらを使って今回の問題を解決することにしました。

使い方

  1. https://github.com/Nkzn/JPPUtils/downloads から最新版のjarを落としてくる
  2. jarにパス通す
  3. 以下のようにstring値が来るかstring配列が来るか分からないフィールドのアノテーションにconverterオプションで指定すればOK
@JsonModel(decamelize=true)
public class Item {

	@JsonKey(converter=String2ListConverter.class)
	List<String> valueList1;
	
	@JsonKey(converter=String2ListConverter.class)
	List<String> valueList2;

	public List<String> getValueList1() {
		return valueList1;
	}

	public void setValueList1(List<String> valueList) {
		this.valueList1 = valueList;
	}

	public List<String> getValueList2() {
		return valueList2;
	}

	public void setValueList2(List<String> valueList2) {
		this.valueList2 = valueList2;
	}
}

感想

@さんと@さんのTokenConverterを見よう見まねしながら作ってみましたが、まあ何とか作れるもんですね。
こっそりとMaven3とJUnit4によるテスト&ビルド環境も整えて作ってみました。むしろ今回はそちらのほうが勉強になったかも。
Integer2ListConverterとか作ってみるのも面白いかも知れませんね。(BooleanはJSの仕様上カオスなことになりそうな予感がするのでパス)
ご意見などありましたら@までどうぞ。ご要望はpull requestで!