LoginSignup
14
10

More than 1 year has passed since last update.

JSONGeneratorクラス調査メモ(Apex)

Last updated at Posted at 2017-09-19

概要

  • WebAPIへデータをJSONで渡すにあたってApexのJSONGeneratorを調査し、試したことや思ったことを順番に記録しました
  • ありていにいえば、やってみたメモ記事です

やりたいこと

  • ApexでJSON文字列を生成します
  • WebAPIへJSON形式で情報を渡すことが目的です
  • 最終的に文字列なので、頑張って編集することもできますが、ApexではJSONサポート機能が含まれているのでこれ利用し、スマートに実装したいと思っています
  • Apex開発者ガイド JSONサポート

使い方

使い方パターン1

  • key/valueをセットする方法です
  • writeNumberField()writeStringField()のように、write~Field()メソッドが該当します
sample1
JSONGenerator g = JSON.createGenerator(false);
g.writeStartObject();
g.writeNumberField('number', 12345);
g.writeEndObject();
System.debug(g.getAsString());
sample1-result
{"number":12345}

使い方パターン2

  • keyとvalueを別々にセットする方法です
  • witeFieldName()してからwrite~()します
sample2
JSONGenerator g = JSON.createGenerator(false);
g.writeStartObject();
g.writeFieldName('number');
g.writeNumber(7890);
g.writeEndObject();
System.debug(g.getAsString());
sample2-result
{"number":7890}

利用イメージまとめ

  • writeStartObject(){を挿入
  • 必要なキーと値をセット
  • 配列の場合はwriteStartArray()[を挿入
  • 全部セットしたらgetAsString()でテキストとして取り出してWebAPIをコール

疑問(脱線)

  • JSONGeneratorクラスにはメソッドがたくさんありますが、上記パターン1と2のメソッドが型(プリミティブ型)ごとにたくさんある感じですね
  • オーバーロードしてwriteValue()とかにまとめられそうな気配は感じますが、String、Number、Booleanなど型ごとにメソッド名が分けられています
  • writeNumber()writeNumberField()については別型でオーバーロードしていますが)

オブジェクト型

  • プリミティブ型の他に、オブジェクト型を取り扱えます
  • これは良いです

リスト型のサンプル

sample-list
List<Integer> numbers = new List<Integer>();
numbers.add(100);
numbers.add(200);

JSONGenerator g = JSON.createGenerator(false);
g.writeStartObject();
g.writeObjectField('numbers', numbers);
g.writeEndObject();
System.debug(g.getAsString());
sample-list-result
{"numbers":[100,200]}

オブジェクト型のサンプル

  • ここまでの例ではwriteStartObject()という呪文が必要でした(要は {を挿入するステートですね)
  • オブジェクトの場合は、いきなりwriteObject()が可能です。オブジェクトですから、{が含まれているんですね
  • WebAPIで渡すパラメータなんてたいてい一番外側がオブジェクトな気がするので、JSON全体を大きなオブジェクトにしてしまえば良さそう、つまり、まるごとオブジェクトJSONパターンです
  • サンプルは省略しますが、メンバ変数にオブジェクトのリスト型(配列)も定義可能です
sample-object
Hoge h = new Hoge();
h.code = '0001';
h.name = 'Hoge-0001';
h.price = 1200;

JSONGenerator g = JSON.createGenerator(false);
g.writeObject(h);
System.debug(g.getAsString());

public class Hoge {
    public String code;
    public String name;
    public Decimal price;
}
sample-object-result
{"price":1200,"name":"Hoge-0001","code":"0001"}

これだけで良いのでは

  • 上記、まるごとオブジェクトパターンがあれば、もはやこれだけでいいのでは?と、さっきまで思っていました
  • {を挿入するためにwriteStartObject()を記述するということは、実装者は文字列編集を意識する必要があるということです
  • まるごとオブジェクトパターンでは、クラス定義が必要になりますが、むしろ構造が明確になり、編集機能はJSONGeneratorに任せるという、あるべき実装の姿ではないでしょうか

予約キーワード(予約語)の壁

  • 結論としては「これだけでは良くない」です
  • 予約語をkeyして指定したい場合、そのまま記述できません
  • オブジェクトの場合、メンバ変数名がkeyとして採用される振る舞いになっています
  • WebAPI連携する場合、keyは相手システムが提示する訳ですが、要求されたkey文字列がApexで予約キーワードだったりして記述できないケースがありました
  • 下記サンプルはkeyとしてnumberを要求されていたため、そのようにクラス定義したものですが、numberはApex予約キーワードのため、コンパイルエラーになります
  • すごくキレイに記述できそうなのにできない。おしい。残念です。
sample-error
Hoge h = new Hoge();
h.number = '0001';
h.name = 'Hoge-0001';
h.price = 1200;

JSONGenerator g = JSON.createGenerator(false);
g.writeObject(h);
System.debug(g.getAsString());

public class Hoge {
    public String number;
    public String name;
    public Decimal price;
}
sample-error-result
Line: 11, Column: 20
Identifier name is reserved: number
14
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
10