$30 off During Our Annual Pro Sale. View Details »

JJUG Java仕様勉強会「JSON Processing / JSON Binding」

JJUG Java仕様勉強会「JSON Processing / JSON Binding」

2023/02/16に開催されたJJUG(日本Javaユーザーグループ)Java仕様勉強会「JSON Processing / JSON Binding」の発表資料です。
https://jjug.doorkeeper.jp/events/149818

当日の録画はこちらです。
https://www.youtube.com/watch?v=E-rPycGxG8E

Takakiyo Tanaka

February 16, 2023
Tweet

More Decks by Takakiyo Tanaka

Other Decks in Technology

Transcript

  1. 1
    JJUG(⽇本Javaユーザー会) Java仕様勉強会 2023年2⽉
    JSON Processing
    JSON Binding
    ⽇本IBM ⽥中 孝清 (Twitter @TTakakiyo)

    View Slide

  2. 2
    ⾃⼰紹介
    2
    n
    ⽥中 孝清
    n ⽇本アイ・ビー・エム株式会社
    オートメーションソフトウェア テクニカルセールス
    n WebSphere Application Serverなどの
    テクニカルセールスを20年以上担当
    n Twitter @TTakakiyo

    View Slide

  3. 3
    3
    JSON
    JavaScript Object Notation

    View Slide

  4. 4
    JSONとは(1)
    n JavaScript Object Notation
    – JavaScriptにおけるオブジェクトの表記法をベースとした軽量なデータ記述⾔語
    – あらゆるプログラミング⾔語で容易に扱うことができ,汎⽤のデータ交換フォーマットとして多⽤
    – RESTfulなWebサービスで,主要なデータ型として使⽤されている
    n JSONの構⽂
    – JSONのデータ構造はオブジェクトと配列の2つだけ定義されている
    • { } オブジェクト { "key" : "value" }
    • [ ] 配列
    – 7つのvalue typeが定義されている
    • string, number, true, false, null, object, array
    4
    {
    "firstName": "John", "lastName": "Smith", "age": 25,
    "address" : {
    "streetAddress": "21 2nd Street",
    "city": "New York",
    "state": "NY",
    "postalCode": "10021"
    },
    "phoneNumber": [
    { "type": "home", "number": "212 555-1234" },
    { "type": "fax", "number": "646 555-4567" }
    ]
    }

    View Slide

  5. 5
    JSONとは(2)
    n ⽶国Yahoo!でSenior JavaScript Architectをしていた
    Douglas Crockford⽒が2001年頃に命名
    – Douglas 「私はJSONの考案者ではなく発⾒者だ」
    – それ以前からも,似たようなデータ型の使⽤例がある
    – 単純かつ⾃然なデータ構造
    – 2006年にRFC 4627で仕様が規定
    – 左図のBNF記法が,ほぼ仕様の全て
    – 外部参照も実体参照も16進数値の仕組みもなし
    (コメント構⽂すらなし)
    n XMLの仕様が
    – 6章の本編仕様,8章の名前空間仕様,
    スキーマが三部(5章×3)の仕様群
    n YAMLの仕様が
    – 10章,4階層の仕様書
    などと⽐べると,圧倒的な単純さ
    5
    json
    element
    value
    object
    array
    string
    number
    "true"
    "false"
    "null"
    object
    '{' ws '}'
    '{' members '}'
    members
    member
    member ',' members
    member
    ws string ws ':' element
    array
    '[' ws ']'
    '[' elements ']'
    elements
    element
    element ',' elements
    element
    ws value ws
    string
    '"' characters '"'
    characters
    ""
    character characters
    character
    '0020' . '10FFFF' - '"' - '¥'
    '¥' escape
    escape
    '"'
    '¥'
    '/'
    'b'
    'f'
    'n'
    'r'
    't'
    'u' hex hex hex hex
    hex
    digit
    'A' . 'F'
    'a' . 'f'
    number
    integer fraction exponent
    integer
    digit
    onenine digits
    '-' digit
    '-' onenine digits
    digits
    digit
    digit digits
    digit
    '0'
    onenine
    onenine
    '1' . '9'
    fraction
    ""
    '.' digits
    exponent
    ""
    'E' sign digits
    'e' sign digits
    sign
    ""
    '+'
    '-'
    ws
    ""
    '0020' ws
    '000A' ws
    '000D' ws
    '0009' ws

    View Slide

  6. 6
    エンタープライズJavaにおけるJSONの標準仕様
    n SOAP通信の仕様を参考にする形でRESTfulの仕様が策定
    6
    SOAP通信(主にXLMを使⽤) RESTful通信(主にJSONを使⽤)
    システム間連携・Webサービス
    JAX-RPC
    ⇒ Jakarta XML RPC
    JAX-WS
    ⇒ Jakarta XML Web Services
    JAX-RS
    ⇒ Jakarta RESTful Web Services
    オブジェクトモデルでデータを操作 JAX-P(Java SE仕様)
    JSON-P
    ⇒ Jakarta JSON Processing
    ストリームモデルでデータを操作 StAX(Java SE仕様)
    データとJavaのオブジェクトを
    相互変換
    JAX-B
    ⇒ Jakarta XML Binding
    JSON-B
    ⇒ Jakarta JSON Binding
    Java EE仕様 ⇒ Jakarta EE仕様

    View Slide

  7. 7
    各仕様でのJSONの対応
    n Java EE
    – Java EE 7以降のFull Platform,Web ProfileでJSON-Pを使⽤可能
    – Java EE 8のFull Platform,Web ProfileでJSON-Bを使⽤可能
    n Jakarta EE
    – Full Platform,Web Profile,Core Profileの全てで,
    Jakarta JSON Processingおよび
    Jakarta JSON Bindingが使⽤可能
    7

    View Slide

  8. 8
    8
    JSON-P
    Java EE: JSON-P (Java API for JSON Processing)
    Jakarta EE: Jakarta JSON Processing

    View Slide

  9. 9
    JSON Processing
    n JSONを直接あつかい,
    ⽣成,解析,照会,変換を⾏うためのAPIを提供する
    n Java EE 7の⼀部としてJSR 353で仕様化
    n JSON-Pとも略されるが,
    ハイフンなしのJSONPだと別の意味になるので検索時に注意
    – JSONP(JSON with padding)は,
    JavaScriptでクロスサイトオリジンの境界を越えるためのテクニック
    n プログラミングモデルとして下記2つのモデルが定義されている
    – Object Model (javax.json / jakarta.jsonパッケージ)
    • メモリ上にJSONデータを表すツリー構造のオブジェクトを作成する
    • XMLのDocument Object Model(DOM) APIに類似したAPI
    – Streaming Model (javax.json.stream / jakarta.json.streamパッケージ)
    • イベントベースで1度に1エレメントずつJSONデータを解析する
    • 1度に1エレメントずつストリームへ書き込む
    • XMLのStreaming API for XML(StAX)に類似したAPI
    9

    View Slide

  10. 10
    Object Model APIにおけるJSONデータの表現
    10
    § JSONデータを表現するインターフェース
    § EnumとしてJsonValueのタイプが定義されている
    インターフェース 説明
    JsonValue JSONデータのエレメントを表現する。JsonStructure,JsonString,JsonNumberのスーパータイプ。
    JsonStructure JsonValueのサブタイプ。JSONデータのオブジェクトあるいは配列を表す。
    JsonObject
    JsonArray
    JsonStructureのサブタイプ。
    JsonObjectはオブジェクト、JsonArrayは配列を表す。
    JsonString
    JsonNumber
    JsonValueのサブタイプ。
    JsonStringは⽂字列、JsonNumberは数値を表す。
    Enum 説明
    JsonValue.ValueType JsonValueオブジェクトのタイプ
    を⽰す。
    • OBJECT
    • ARRAY
    • STRING
    • NUMBER
    • TRUE
    • FALSE
    • NULL
    JsonStructure
    JsonValue
    JsonNumber
    JsonString
    JsonArray
    JsonObject

    View Slide

  11. 11
    Object Modelの作成やストリームへの読み取り/書き込みのためのAPI
    11
    § ストリームからの読み取り、Object Modelの作成、ストリームへの書き込みに関するクラスおよびインターフェース
    § 例外に関するインターフェース
    API 説明
    JsonException JSON処理中に例外が発⽣したことを⽰す。
    API 説明
    Json JSON Processingのオブジェクトを作成するためのファクトリークラス。
    createReaderやcreateWriter、createObjectBuilderなどの静的メソッドが定義されている。
    JsonReader ストリームからJSONデータを読み込み、メモリ上にObject Modelを作成する。
    JsonWriter メモリ上のObject Modelをストリームに書き出す。
    JsonObjectBuilder アプリケーションコードからエレメントを追加していくことでJsonObjectを作成する。
    JsonArrayBuilder アプリケーションコードからエレメントを追加していくことでJsonArrayを作成する。

    View Slide

  12. 12
    Object Model API: アプリケーションコードでObject Modelを作成
    n Json.createObjectBuilder()およびJson.createArrayBuilder()メソッドを使⽤して
    JsonObject/JsonArrayを作成できる
    n OjbectでもArrayでもないJsonValueはJson.createValue(...)で作成できる
    12
    import javax.json.Json;
    import javax.json.JsonObject;
    ...
    JsonObject jsonobj = Json.createObjectBuilder()
    .add("firstName", "John")
    .add("lastName", "Smith")
    .add("age", 25)
    .add("address", Json.createObjectBuilder()
    .add("streetAddress", "21 2nd Street")
    .add("city", "New York")
    .add("state", "NY")
    .add("postalCode", "10021"))
    .add("phoneNumber", Json.createArrayBuilder()
    .add(Json.createObjectBuilder()
    .add("type", "home")
    .add("number", "212 555-1234"))
    .add(Json.createObjectBuilder()
    .add("type", "fax")
    .add("number", "646 555-4567")))
    .build();
    {
    "firstName": "John", "lastName": "Smith", "age": 25,
    "address" : {
    "streetAddress": "21 2nd Street",
    "city": "New York",
    "state": "NY",
    "postalCode": "10021"
    },
    "phoneNumber": [
    { "type": "home", "number": "212 555-1234" },
    { "type": "fax", "number": "646 555-4567" }
    ]
    }

    View Slide

  13. 13
    Object Model API: JSONデータを読み込んでObject Modelを作成
    n テキストファイル内のJSONデータを読み込み,メモリ上にObject Modelを作成
    – JsonReaderインターフェースを利⽤する
    13
    import java.io.FileReader;
    import javax.json.Json;
    import javax.json.JsonReader;
    import javax.json.JsonStructure;
    ...
    //テキストファイルからJSONデータを読み込むためにFileReaderクラスをインスタンス化する
    //jsondata.txtにJSONデータが格納されている
    FileReader fr = new FileReader("jsondata.txt");
    //JsonReaderを作成する
    JsonReader reader = Json.createReader(fr));
    //JSONデータを読み込み、JsonValueを作成する
    JsonValue jsonval = reader.readValue();
    //作成したJsonValueをJSONテキストにして標準出⼒に出⼒する
    System.out.println(jsonval.toString());
    {
    "firstName": "John", "lastName": "Smith", "age": 25,
    "address" : {
    "streetAddress": "21 2nd Street",
    "city": "New York",
    "state": "NY",
    "postalCode": "10021"
    },
    "phoneNumber": [
    { "type": "home", "number": "212 555-1234" },
    { "type": "fax", "number": "646 555-4567" }
    ]
    }
    jsondata.txt

    View Slide

  14. 14
    Object Model API: Object Modelのツリー構造をナビゲーション(1)
    n メモリ上に作成されたObject Modelはツリー構造になっており、
    ツリー内の各要素にランダムアクセスが可能
    14
    public static void navigateTree(JsonValue tree, String key) {
    if (key != null)
    System.out.print("Key " + key + ": ");
    //JsonValueインターフェースのgetValueType()メソッドは
    //JsonValue型(Enum JsonValue.ValueType)を戻す
    switch(tree.getValueType()) {
    case OBJECT:
    System.out.println("OBJECT");
    JsonObject object = (JsonObject) tree;
    //java.util.Mapインターフェースから継承されたKeySet()メソッドで
    //JSONオブジェクトのkeyのセットを取得する
    for (String name : object.keySet())
    //get()メソッドでJSONオブジェクトのkeyの名前を取得する
    navigateTree(object.get(name), name);
    break;
    case ARRAY:
    System.out.println("ARRAY");
    JsonArray array = (JsonArray) tree;
    for (JsonValue val : array)
    navigateTree(val, null);
    break;
    //つづく→
    // ←つづき
    case STRING:
    JsonString st = (JsonString) tree;
    System.out.println("STRING " + st.getString());
    break;
    case NUMBER:
    JsonNumber num = (JsonNumber) tree;
    System.out.println("NUMBER " + num.toString());
    break;
    case TRUE:
    case FALSE:
    case NULL:
    System.out.println(tree.getValueType().toString());
    break;
    }
    }

    View Slide

  15. 15
    Object Model API: Object Modelのツリー構造をナビゲーション(2)
    OBJECT
    Key firstName: STRING John
    Key lastName: STRING Smith
    Key age: NUMBER 25
    Key address: OBJECT
    Key streetAddress: STRING 21 2nd Street
    Key city: STRING New York
    Key state: STRING NY
    Key postalCode: STRING 10021
    Key phoneNumber: ARRAY
    OBJECT
    Key type: STRING home
    Key number: STRING 212 555-1234
    OBJECT
    Key type: STRING fax
    Key number: STRING 646 555-4567
    {
    "firstName": "John", "lastName": "Smith", "age": 25,
    "address" : {
    "streetAddress": "21 2nd Street",
    "city": "New York",
    "state": "NY",
    "postalCode": "10021"
    },
    "phoneNumber": [
    { "type": "home", "number": "212 555-1234" },
    { "type": "fax", "number": "646 555-4567" }
    ]
    }
    jsondata.txt
    標準出⼒
    //jsondata.txtからJSONデータからJsonValueオブジェクトを作成し、navigateTreeメソッドの引数に指定する
    navigateTree((JsonValue)Json.createReader(new FileReader("jsondata.txt")).read(),null);

    View Slide

  16. 16
    Streaming APIで利⽤する主なAPI
    § インターフェース
    § Enum
    § 例外
    API 説明
    JsonParser ストリームやObject ModelからJSONデータを読むことができるイベントベースのParserを表す
    JsonGenerator ⼀度にひとつのエレメントをストリームに書き出す
    API 説明
    JsonParser.Event JsonParserのイベント。以下10個のイベントが定義されている
    START_OBJECT/START_ARRAY/END_OBJECT/END_ARRAY/KEY_NAME/VALUE_STRING/
    VALUE_NUMBER/VALUE_TRUE/VALUE_FALSE/VALUE_NULL
    API 説明
    JsonGenerationException 不適当なJSONが⽣成されたことを⽰す
    JsonParsingException 不適当なJSONを解析したことを⽰す

    View Slide

  17. 17
    Streaming API: JsonParserによるJSONデータの解析
    n イベントベースのJsonParserによって
    ストリームおよびObject ModelからJSONデータを解析することができる
    17
    JsonParser parser = Json.createParser(new StringReader(jsondata)); //JsonParserインスタンスを取得
    while (parser.hasNext()){ //parser.hasNext()メソッドで繰り返し処理を⾏う
    JsonParser.Event event = parser.next(); //次の解析のためのイベントを返す
    switch(event){
    case START_ARRAY:
    case END_ARRAY:
    case START_OBJECT:
    case END_OBJECT:
    case VALUE_FALSE:
    case VALUE_NULL:
    case VALUE_TRUE:
    //イベント名を返す
    System.out.println(event.toString());
    break;
    case KEY_NAME:
    //KEY_NAMEの名前を返す
    System.out.print(event.toString() + " " + parser.getString() + " - ");
    break;
    case VALUE_STRING:
    case VALUE_NUMBER:
    //string値あるいはnumber値を返す
    System.out.println(event.toString() + " " + parser.getString());
    break;
    }
    START_OBJECT
    KEY_NAME firstName - VALUE_STRING John
    KEY_NAME lastName - VALUE_STRING Smith
    KEY_NAME age - VALUE_NUMBER 25
    KEY_NAME address - START_OBJECT
    KEY_NAME streetAddress - VALUE_STRING 21 2nd Street
    KEY_NAME city - VALUE_STRING New York
    KEY_NAME state - VALUE_STRING NY
    KEY_NAME postalCode - VALUE_STRING 10021
    END_OBJECT
    KEY_NAME phoneNumber - START_ARRAY
    START_OBJECT
    KEY_NAME type - VALUE_STRING home
    KEY_NAME number - VALUE_STRING 212 555-1234
    END_OBJECT
    START_OBJECT
    KEY_NAME type - VALUE_STRING fax
    KEY_NAME number - VALUE_STRING 646 555-4567
    END_OBJECT
    END_ARRAY
    END_OBJECT

    View Slide

  18. 18
    Streaming API: JsonGeneratorによるJSONデータの⽣成
    n JsonGeneratorを使⽤してJSONデータを
    ストリームに書き込むことかできる
    – 1度に1要素ずつ書く
    – writeStartObject()
    ・・・Objectを開始する⽂字を書く
    – writeStartArray()
    ・・・配列を開始する⽂字を書く
    – write()
    ・・・現在のオブジェクトあるいは配列コンテキストに書く
    – writeEnd()
    ・・・現在のコンテキストの終了を書く
    18
    FileWriter writer = new FileWriter("test.txt");
    JsonGenerator gen = Json.createGenerator(writer);
    gen.writeStartObject()
    .write("firstName", "John")
    .write("lastName", "Smith")
    .write("age", 25)
    .write("streetAddress", "21 2nd Street")
    .write("city", "New York")
    .write("state", "NY")
    .write("postalCode", "10021")
    .writeStartArray("phoneNumbers")
    .writeStartObject()
    .write("type", "home")
    .write("number", "212 555-1234")
    .writeEnd()
    .writeStartObject()
    .write("type", "fax")
    .write("number", " 646 555-4567")
    .writeEnd()
    .writeEnd()
    .writeEnd();
    gen.close();

    View Slide

  19. 19
    Object Model APIとStreaming APIの⽐較
    n Object Model APIとStreaming APIを⽐較すると以下のような特徴がある
    19
    ⽐較軸 Object Model API Streaming API
    柔軟性 ○ -
    効率性 - ○
    ストリームからの
    読み込み/書き込み
    オブジェクト単位 1度に1エレメントずつ
    コードの記述量 少ない 多い
    処理速度 若⼲遅い 若⼲早い
    メモリ使⽤量 若⼲多い 若⼲少ない
    XMLの類似API Document Object Model(DOM) API Streaming API for XML(StAX)
    ⽤途
    ツリー内のコンテンツに
    ランダムアクセスが必要な処理に
    適している
    エレメントの処理に
    残りのデータを必要としないような
    ローカル処理に適している

    View Slide

  20. 20
    20
    JSON-B
    Java EE: JSON-B (Java API for JSON Binding)
    Jakarta EE: Jakarta JSON Binding

    View Slide

  21. 21
    JSON Binding
    n JavaオブジェクトからJSONドキュメントへの変換(シリアライズ)
    JSONドキュメントからJavaオブジェクトへの逆変換(デシリアライズ)を
    単純かつ統⼀的に⾏うためのAPI
    n Java EE 8の⼀部としてJSR 367で仕様化「Java API for JSON Binding」
    – 各種仕様書では「JSON-B」と省略されることが多い
    n Jakarta EEでも「Jakarta JSON Binding」として継続し,仕様の改善が続く
    – Jakartaでは,あまり省略されない
    21
    json
    {
    "xx": "yy"
    }
    Java Data
    シリアライズ︓toJson()
    デシリアライズ︓fromJson()
    メソッドが統⼀的
    クラス

    View Slide

  22. 22
    JSON Bindingのパッケージ構成
    n Java EE(Jakarta EE 8)では,下記のようなパッケージで構成
    (Jakarta EE 9以降はjakartaパッケージ)
    22
    Package API(Exceptionは省略) Description
    javax.json.bind Interface: Jsonb, JsonbBuilder toJson()やfromJson()といった
    シリアライズ、デシリアライズするためのInterface
    javax.json.bind.adapter Interface: JsonbAdapter JsonbAdapter Interfaceを継承し実装することで、
    カスタムマッピングを⾏う
    javax.json.bind.annotation Interface: JsonbAnnotation アノテーションを付与することで
    出⼒形式をカスタマイズする
    javax.json.bind.config Interface: PropertyNamingStrategy,
    PropertyVisibility Strategy
    出⼒順序やフィールドの可視性をカスタマイズする
    javax.json.bind.serializer Interface: DeserializeContext,
    JsonbDeserializer
    JsonbSerializer,
    SerializationContext
    JsonbSerializerまたは
    JsonbDeserializer Interfaceを継承し、
    実装することでカスタムマッピングを実現
    javax.json.bind.spi JsonbProvider
    (本資料では解説省略)
    JsonbBuilderの機能を補完するためのプラグイン

    View Slide

  23. 23
    JSON Bindingの実装イメージ
    n 基本的にJsonb、JsonbBuilderインターフェースを⽤いて
    シリアライズ(toJson()),デシリアライズ(fromJson())を⾏う
    n 出⼒形式をカスタマイズしたい時はadapter, serializer, annotation, configパッケージを⽤いる
    Java
    Class
    JSON
    Doc
    javax.json.bind.Jsonb
    javax.json.bind.JsonbBuilder
    toJson()
    fromJson()
    javax.json.bind.annotation
    javax.json.bind.config
    javax.json.bind.adapter
    javax.json.bind.serializer
    カスタマイズ
    シリアライズ
    アノテーションによるカスタマイズ
    デシリアライズ
    JsonbConfigインスタンスの利⽤
    JsonbAdapterの実装
    JsonbSerializerの実装

    View Slide

  24. 24
    JSON Bindingによるシリアライズ
    24
    Empoloyee クラス
    フィールド インスタンス化
    String id a1234
    String name fukui
    Stiring department cloud
    ① シリアライズするJavaクラス、インスタンスを作成
    ② JsonbBuilder のstatic メソッド, create()を利⽤しJsonb型のインスタンスを作成
    Jsonb jsonb = JsonbBuilder.create()
    ③ ②で作成したJsonbインスタンスが持つtoJson()メソッドの引数に①のインスタンスを与える
    jsonb.toJson( )
    Empoloyee インスタンス
    {
    "department": "cloud",
    "id": "a1234",
    "name": "fukui"
    }
    ex)Employeeクラスのインスタンスをシリアライズする
    デフォルトのストラテジーでは
    • JSONのkeyはフィールド名が引き継がれる
    • 値がnullのフィールドは無視される(JSONに出⼒されない)

    View Slide

  25. 25
    JSON Bindingによるシリアライズの実装例
    25
    ① シリアライズするためのJavaクラス、インスタンスを作成
    ② Jsonbインスタンスを作成し、JsonBuilderのcreate()を使⽤
    ③ toJson(obj)を使⽤(obj はシリアライズ対象のオブジェクト)
    public class Employee {
    private String id;
    private String name;
    private String department;
    public Employee() {
    }
    public Employee(String id, String name, String department) {
    this.id = id;
    this.name = name;
    this.department = department;
    }
    ...
    (セッター、ゲッターは省略(privateフィールドでは必須))
    クラス メソッド定義
    import javax.json.bind.Jsonb;
    import javax.json.bind.JsonbBuilder;
    ...
    public class SampleMethod {
    public String serializeEmployee(Employee emp) {
    Jsonb jsonb = JsonbBuilder.create();
    String json = jsonb.toJson(emp);
    return json;
    }
    }
    シリアライズを⾏うメソッド定義



    インスタンス格納

    View Slide

  26. 26
    JSON Bindingによるデシリアライズ
    26
    ①, シリアライズするJSONを⽤意
    ②, JsonbBuilder のstatic メソッド, create()を利⽤したJsonb型のインスタンスを作成する。
    ->デシリアライズと同様
    Jsonb jsonb = JsonbBuilder.create()
    ③, ②で作成したJsonbインスタンスが持つfromJson()メソッドの第⼀引数にJSONドキュメント、第⼆引数に該当クラスを指定
    jsonb.fromJson( , Employee.class )
    JSON ドキュメント
    {
    "department": "cloud",
    "id": "a1234",
    "name": "fukui"
    }
    • JSONのkeyと⼀致するフィールド名が読み込まれる(デフォルトでは⼤⽂字⼩⽂字は区別されるので注意)

    View Slide

  27. 27
    JSON Bindingによるデシリアライズの実装例
    27
    ① Javaクラス、インスタンスを作成、デシリアライズするJson⽂字列を取得
    ② Jsonbインスタンスを作成し、JsonBuilderのcreate()を使⽤
    ③ fromJson(json, Obj.class)を使⽤(json は⽂字列, Objは帰属されるクラス)
    public class Employee {
    private String id;
    private String name;
    private String department;
    public Emp() {}
    ...(コンストラクタ、セッター、ゲッター省略)
    }
    デフォルトコンストラクタ必須!
    import javax.json.bind.Jsonb;
    import javax.json.bind.JsonbBuilder;
    ...
    public class Sample {
    public Employee deserializeEmployee(String jsonEmployee) {
    Jsonb jsonb = JsonbBuilder.create();
    Employee empClass =
    jsonb.fromJson(jsonEmployee, Employee.class);
    return empClass;
    }
    }


    ③ JSON⽂字列 帰属されるクラス
    クラス メソッド定義

    View Slide

  28. 28
    JSON Bindingのデフォルトのマッピング(1)
    28
    § 基本型のマッピング
    – 基本データ型についてはデフォルトで下記のようにマッピング
    • String, char型はJSONで⽂字列に解釈される
    • Float, double, int, AtomicInteger, Byte型は数値として解釈される
    • boolean型は真偽値で解釈される
    public class BasicTypes {
    private String name;
    private char initial;
    private Float height;
    private double weight;
    private int age;
    private boolean isPassed;
    private AtomicInteger count;
    private Byte version;
    (セッター・ゲッター省略)
    }
    {
    "name":"Fukui",
    "initial":"F",
    "height":169.99,
    "weight":60.0,
    "age":20,
    "isPassed":true
    "count":4,
    "version":5,
    }
    BasicTypes basic = new BasicTypes();
    basic.setName("Fukui");
    basic.setInitial('F');
    basic.setHeight(169.99f);
    basic.setWeight(60.000);
    basic.setAge(20);
    basic.setIsPassed(true);
    basic.setCount(new AtomicInteger(4));
    basic.setVersion((byte) 5);
    クラス 値を格納 出⼒(実際には辞書式で出⼒)

    View Slide

  29. 29
    JSON Bindingのデフォルトのマッピング(2)
    29
    § 配列・コレクション型のシリアライズ
    – List型, 固定⻑配列ともに、JSONドキュメントとしては配列として解釈される
    – Mapはネストされたオブジェクトとして{"key": "value"}が⽣成される
    – MapやList型のインスタンスにnull値が含まれる場合は、配列にnullと表⽰される
    {
    "ints": [1,2,3,4,5],
    "ints2d": [[1,2],[3,4],[5,6],[7,8]],
    "strs": ["aaa","bbb",null]
    "list": ["Java EE","Python"],
    "map": {
    "Fukui": 26,
    "Problem": null
    },
    "set": ["Red"],
    }
    public class ArraysAndCollections {
    private int[] ints = new int[5];
    private int[][] ints2d = new int[5][];
    private String[] strs = new String[3];
    private List list;
    private Map map;
    private Set set;
    (セッター・ゲッター省略)
    }
    ArraysAndCollections ac = new ArraysAndCollections();
    ac.setInts(new int[]{1, 2, 3, 4, 5});
    ac.setInts2d(new int[][]{{1, 2}, {3, 4}, {5, 6}, {7, 8}});
    ac.setStrs(new String[]{"aaa", "bbb" , null});
    ac.setList(new ArrayList() {{
    add("Java EE");
    add("Python");
    }});
    ac.setMap(new HashMap() {{
    put("Fukui", 26);
    put("Problem", null);
    }});
    ac.setSet(new HashSet() {{
    add("Red");
    }});

    View Slide

  30. 30
    JSON Bindingのカスタマイズ
    ⼤きく⼆つの⽅法(詳細は時間の関係で割愛)
    n シリアライズ・デシリアライズするJavaクラスに
    アノテーションをつけてカスタマイズする
    n Jsonbをビルドする際にJsonConfigでカスタマイズする
    – 変換の際の命名ストラテジーや順序ストラテジーなどの指定
    – 数値,⽇付のフォーマットなどの指定
    – 独⾃に実装したJsonbAdapterやJsonbSerializerの指定 etc.
    30
    @JsonbProperty("ID")
    public String userId; // JSONでのkeyを指定
    @JsonbTransient
    public boolean internalFlag; // JSONへの出⼒を抑⽌
    @JsonbDateFormat(value = "yyyy年MM⽉dd⽇", locale = "Locale.JAPANESE")
    public LocalDate when; // JSONへ出⼒する⽇付フォーマットを指定
    Jsonb jsonb = JsonbBuilder.create(jsonbConfig);
    String json = jsonb.toJson(emp);

    View Slide

  31. 31
    JSON BindingとJSON Processingの統合
    n JSON Bindingの実装は,
    必ずJSON Processingをサポートしなければならないと
    仕様で規定されている
    n つまり,JsonValueやJsonObjectなどののJSON Processingの型は,
    toJson() にかけるとJSON⽂字列が得られるし,
    JSON⽂字列からfromJson()でJsonValueなどを得ることができる
    31
    シリアライズ︓toJson()
    デシリアライズ︓fromJson()
    {
    "xx": "yy"
    }
    "xx": "yy"
    JsonObject
    ⽂字列

    View Slide

  32. 32
    参考情報︓JSON Binding 3.0の新機能
    n JSON Binding 3.0の新機能については,寺⽥佳央さんの
    JakartaOne LiveStream Japan 2022のセッションを参照
    「CN4J Studio Jakarta JSON Binding の概要と便利な使い⽅について」
    https://www.youtube.com/watch?v=rj-NAGYlZRI
    – Polymorphic型
    – Recordのサポート
    – JSON Bindingsのカスタマイズ
    32

    View Slide

  33. 33
    33
    JAX-RSとJSON
    Jakarta RESTful Web Service + JSON

    View Slide

  34. 34
    MediaType.APPLICATION_JSONでStringを返しても...
    34
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/bad")
    public String badJson() {
    return "This is a ¥"test¥".";
    }
    curl -v http://192.168.140.1:9080/JsonTest/jsonb/bad
    ...
    < HTTP/1.1 200 OK
    < X-Powered-By: Servlet/4.0
    < Date: Wed, 15 Feb 2023 21:48:22 GMT
    < Content-Type: application/json
    < Content-Language: en-US
    < Content-Length: 17
    <
    * Connection #0 to host 192.168.140.1 left intact
    This is a "test".
    ⽂字列はJSONのvalueだが,
    " "でクオートされていないと
    正しいJSONではない

    View Slide

  35. 35
    正しくJSONにするには
    35
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/good")
    public JsonValue goodJson() {
    return Json.createValue("This is a ¥"test¥".");
    }
    curl -v http://192.168.140.1:9080/JsonTest/jsonb/good
    ...
    < HTTP/1.1 200 OK
    < X-Powered-By: Servlet/4.0
    < Date: Wed, 15 Feb 2023 21:55:21 GMT
    < Content-Type: application/json
    < Content-Language: en-US
    < Content-Length: 21
    <
    * Connection #0 to host 192.168.140.1 left intact
    "This is a ¥"test¥"."
    " "でクオートされ
    ⽂字列中の"もエスケープされ
    正しいJSONになっている

    View Slide

  36. 36
    何が起こっている︖
    n JAX-RSでは以下のような処理を⾏うProviderが提供され,
    状況に応じて選択されて利⽤されている
    – 要求ストリームを処理してJavaのオブジェクトに変換するMessageBodyReader
    – Javaのオブジェクトを変換して応答ストリームに書き込むMessageBodyWriter
    – 発⽣した例外を応答にマッピングするExceptionMapper
    – コンテキスト情報を提供するContextResolver
    n 独⾃のMessageBodyWriterなどを実装して,Providerとして組み込むこともできる
    n 現在の状況(Context)で,どのProviderが選択されるかを調べるProvidersという
    インターフェースが提供されている
    n 以上のしくみは,javax.ws.rs.ext / jakarta.ws.rs.ext パッケージで提供されている
    36

    View Slide

  37. 37
    どのようなMessageBodyWriterが選択されるか調べてみる(1)
    37
    @javax.ws.rs.core.Context
    private javax.ws.rs.ext.Providers providers;
    private String getWiterName(Class c) {
    return providers
    .getMessageBodyWriter(c, null, null, MediaType.APPLICATION_JSON_TYPE)
    .toString();
    }
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/providers")
    public JsonValue providers() {
    return Json.createObjectBuilder()
    .add("int", getWiterName(Integer.TYPE))
    .add("byte[]", getWiterName(byte[].class))
    .add("String", getWiterName(String.class))
    .add("JsonValue", getWiterName(javax.json.JsonValue.class))
    .add("Properties", getWiterName(java.util.Properties.class))
    .build();
    }

    View Slide

  38. 38
    どのようなMessageBodyWriterが選択されるか調べてみる(2)
    n 実⾏結果
    (Open Libertyでjaxrs-2.1フィーチャーを有効にして実⾏)
    n ほとんどJSON-BのProviderが使⽤されているが,
    byte[]やStringでは,別のProviderが利⽤されてる
    38
    $ curl http://localhost:9080/JsonTest/jsonb/providers | jq
    % Total % Received % Xferd Average Speed Time Time Time Current
    Dload Upload Total Spent Left Speed
    100 346 100 346 0 0 15477 0 --:--:-- --:--:-- --:--:-- 19222
    {
    "int": "com.ibm.ws.jaxrs21.providers.json.JsonBProvider@ecce30b8",
    "byte[]": "org.apache.cxf.jaxrs.provider.BinaryDataProvider@b192ae45",
    "String": "org.apache.cxf.jaxrs.provider.StringTextProvider@ec4ab4c",
    "JsonValue": "com.ibm.ws.jaxrs21.providers.json.JsonBProvider@ecce30b8",
    "Properties": "com.ibm.ws.jaxrs21.providers.json.JsonBProvider@ecce30b8"
    }

    View Slide

  39. 39
    MessageBodyWriter
    n JSON-B(JSON Binding)が利⽤できる環境で
    MediaType.APPLICATION_JSONなどが指定されたら,
    JSON-BをつかったMessageBodyWriterが選択される
    n JAX-B(XML Binding)が利⽤できる環境で
    MediaType.APPLICATION_XMLなどが指定されたら,
    JAX-BをつかったMessageBodyWriterが選択される
    n ただし,メソッドが以下のような型を返す場合には,
    標準のMessageBodyWriter(何も変換しないでそのまま出⼒)が使⽤される
    – byte[], String
    – java.io.InputStream, java.io.Reader, java.io.File
    – javax.ws.rs.core.StreamingOutput, javax.activation.DataSouce
    – ⼀部のMediaTypeについては,これ以外の型についても標準のMessageBodyWriterが規定
    (JSONは関わってこないので今回は割愛)
    n これらはMediaTypeなどにあわせて整形済みの情報が⼊っていることが想定されている
    – なので,MediaType.APPLICATION_JSONでStringを返すメソッドは,整形済みのJSONをかえすこと︕
    39

    View Slide

  40. 40
    JAX-RSでのJSON-Bのカスタマイズ(1)
    n カスタマイズしたJsonbでシリアライズ・デシリアライズしたい時は
    Jsonbを提供するContextResolverを実装してProviderとして登録する
    – アプリケーションで@Providerでアノテーションされたクラスは⾃動的に組み込まれる
    40
    @javax.ws.rs.ext.Provider
    public class MyJsonbContentResolver
    implements javax.ws.rs.ext.ContextResolver {
    @Override
    public Jsonb getContext(Class> c) {
    JsonbConfig config = new JsonbConfig()
    .withPropertyNamingStrategy(PropertyNamingStrategy.UPPER_CAMEL_CASE_WITH_SPACES);
    return JsonbBuilder.newBuilder().withConfig(config).build();
    }
    }

    View Slide

  41. 41
    JAX-RSでのJSON-Bのカスタマイズ(2)
    41
    @Path("/user")
    @Produces(MediaType.APPLICATION_JSON)
    public class MyJsonbResource {
    public static class User {
    public String userId = "A0001";
    public String firstName = "Takakiyo";
    public String lastName = "Tanaka";
    }
    @GET
    public User getUser() {
    return new User();
    }
    }
    {
    "First Name": "Takakiyo",
    "Last Name": "Tanaka",
    "User Id": "A0001"
    }
    {
    "firstName": "Takakiyo",
    "lastName": "Tanaka",
    "userId": "A0001"
    }
    前⾴のContextResolverがないと 前⾴のContextResolverがあると
    PropertyNamingStrategy.UPPER_CAMEL_CASE_WITH_SPACESの効果

    View Slide

  42. 42
    42
    最後に
    お知らせと宣伝

    View Slide

  43. 43
    Open Liberty / WebSphere Libertyとは
    n IBMが開発・公開しているOSSのJava EE / Jakarta EE / MicroProfileのランタイム
    n Eclipse Public Licenseで提供 / 無償で利⽤可能
    n Open Libertyの成果を取り込み,IBMが販売する製品
    n アプリや構成はOpen Libertyと同じものを利⽤可能 / バージョンはOpen Libertyと完全に同期
    43
    Open Liberty

    View Slide

  44. 44
    WebSphere Liberty / Open Liberty コミュニティサイト
    nhttps://ibm.biz/JapanWebSphereUG
    – Japan WebSphere User Group
    – ログイン無しでどなたでも参照できます
    – 無料のIBM IDを登録いただければ
    ディスカッション・Q&Aなどの
    書き込みもできます
    – IBMからの技術情報
    – イベントの案内
    25周年イベントの情報もお伝えします︕
    44

    View Slide

  45. 45
    本⽇のセッションの内容は・・・
    こちらで公開されている
    以下の資料から抜粋し追記したものです
    n Java EE 7アプリケーション設計ガイド
    JSON-P編
    n Java EE 8アプリケーション設計ガイド
    JSON-B編
    45

    View Slide