CodeGym /コース /JAVA 25 SELF /JSON の検証: JSON Schema と検証エラー

JSON の検証: JSON Schema と検証エラー

JAVA 25 SELF
レベル 46 , レッスン 4
使用可能

1. なぜ JSON の検証が必要か

想像してみましょう。あなたはクラス User を作り、入力として常に次のような JSON が来ると想定しています。

{
  "id": 42,
  "name": "Alice",
  "email": "alice@example.com"
}

ところが、こんなものが届くかもしれません。

{
  "id": "四十二",
  "name": 123,
  "email": null,
  "admin": true
}

あるいは、そもそも次のようなもの:

{
  "username": "Alice"
}

良くて JacksonGson がデシリアライズ時に例外を投げます。悪い場合はフィールドに既定値を黙って入れてしまい、ビジネスコードが不正に動作します。これがサービスの設定ファイルなら、チーム総出で追いかける羽目になる“愉快な”バグに繋がりかねません。

JSON の検証とは、JSON 内の構造・型・値が所定のルール(スキーマ)に適合しているかを確認するプロセスです。データのパスポートコントロールのようなものです。通過できなければ——搭乗は不可、というわけです。

2. JSON Schema: 何で、どういう見た目か

JSON の世界には、データ構造を記述する公式標準 — JSON Schema があります。プログラムの要件に JSON が合っているかをチェックできる「チェックリスト」のようなものです。

JSON Schema 自体も JSON で、特別なキー(typepropertiesrequired など)を使います。

最も簡単なスキーマの例

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "id":    { "type": "integer" },
    "name":  { "type": "string" },
    "email": { "type": "string", "format": "email" }
  },
  "required": ["id", "name"]
}

ここで行っていること:

  • オブジェクトを期待しています(type: "object")。
  • オブジェクトには "id""name""email" の各フィールドがあり得ます(properties で定義)。
  • "id" は必須の整数です(type: "integer")。
  • "name" は必須の文字列です(type: "string")。
  • "email" はメールアドレス形式の文字列です(キー format"email")。
  • required は必須フィールドの一覧を示します: "id""name"

JSON に "id""name" がない、または型が違う場合、検証は失敗します。

JSON Schema でできること(概要)

  • 型の指定(type: "string""integer""array""object""boolean""null")。
  • 入れ子のオブジェクトや配列の記述(propertiesitems)。
  • 必須/任意フィールド(required)。
  • 文字列長や数値範囲の検証(minLengthmaximum など)。
  • フォーマット検証(format: "email""date""uri" など)。
  • 列挙(enum: 許容値のリスト)。
  • 文字列に対する正規表現(pattern)。
  • 複合条件: anyOfoneOfallOf(高度なケース向け)。

3. Java における JSON 検証: ライブラリ概観

標準の Java ライブラリにはスキーマによる JSON 検証は含まれていません。しかし、人気のあるサードパーティ製ライブラリがあります。代表的なものは次の通りです。

  • everit-org/json-schema — シンプル、無料、そして広く使われています。
  • networknt/json-schema-validator — 高速で最新の仕様に対応。
  • Jackson-module-jsonSchemaJackson の拡張(ただし本格的な検証はサポートしていません)。
  • JustifyJava JSON Tools — そのほかもありますが出現頻度は低めです。

この講義では everit-org/json-schema を扱います。初心者にも簡単で、ドキュメントが充実しており、余計な儀式も必要ありません。

everit-org/json-schema の導入

pom.xmlMaven)に依存関係を追加します。

<dependency>
  <groupId>org.everit.json</groupId>
  <artifactId>org.everit.json.schema</artifactId>
  <version>1.14.2</version>
</dependency>

あるいは Gradle:

implementation 'org.everit.json:org.everit.json.schema:1.14.2'

4. 例: スキーマに基づく JSON 検証(手順)

実際に JSON を検証してみましょう。必要なのはスキーマ、JSON、そして少しのコードです。

スキーマの例(user-schema.json):

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "id":    { "type": "integer" },
    "name":  { "type": "string", "minLength": 2, "maxLength": 30 },
    "email": { "type": "string", "format": "email" }
  },
  "required": ["id", "name"]
}

有効な JSON の例(user.json):

{
  "id": 1,
  "name": "Alice",
  "email": "alice@example.com"
}

無効な JSON の例:

{
  "id": "一",
  "name": "",
  "email": "not-an-email"
}

検証用コード

import org.everit.json.schema.Schema;
import org.everit.json.schema.loader.SchemaLoader;
import org.json.JSONObject;
import org.json.JSONException;
import org.json.JSONTokener;
import org.everit.json.schema.ValidationException;

import java.nio.file.Files;
import java.nio.file.Paths;

public class JsonValidationExample {
    public static void main(String[] args) throws Exception {
        // スキーマをファイルから読み込む
        String schemaString = new String(Files.readAllBytes(Paths.get("user-schema.json")));
        JSONObject rawSchema = new JSONObject(new JSONTokener(schemaString));
        Schema schema = SchemaLoader.load(rawSchema);

        // 検証用の JSON を読み込む
        String jsonString = new String(Files.readAllBytes(Paths.get("user.json")));
        JSONObject json = new JSONObject(new JSONTokener(jsonString));

        // 検証
        try {
            schema.validate(json); // すべて問題なければ何も起こりません
            System.out.println("JSON は有効です!");
        } catch (ValidationException e) {
            System.out.println("JSON は無効です!");
            for (String msg : e.getAllMessages()) {
                System.out.println("エラー: " + msg);
            }
        }
    }
}

コードに関する補足:

  • Schema クラスとローダー SchemaLoader.load(...) を使用しています。
  • メソッド schema.validate(json) はスキーマに合致しない場合に例外を投げます。
  • catch ブロックで getAllMessages() によりすべてのエラーを取得できます。

アプリへの統合方法は?

通常、スキーマはリソース(たとえば resources ディレクトリ)に置きます。Java オブジェクトにデシリアライズする前に JSON を検証します。問題なければデシリアライズして処理を続けます。

5. 検証エラーの扱い

JSON が検証に通らない場合、ライブラリは ValidationException を投げます。メッセージには、どこがスキーマに合致していないかの一覧が含まれます。

エラー出力の例

上の無効な JSON に対する出力は概ね次のようになります。

JSON は無効です!
エラー: #: required key [id] not found
エラー: #/name: expected minLength: 2, actual: 0
エラー: #/email: String [not-an-email] is invalid against requested format [email]
エラー: #/id: expected type: Integer, found: String

エラーの読み方:

  • required key [id] not found — 必須フィールドが欠けています。
  • expected minLength: 2, actual: 0 — 文字列が短すぎます。
  • String [...] is invalid against requested format [email] — メールアドレスの形式が不正です。
  • expected type: Integer, found: String — 型が一致しません。

重要: メッセージは英語の場合がありますが、内容は十分分かりやすいです。

エラーをユーザーにどう見せるか?

エラーを一覧にまとめて、たとえば REST API や GUI で返すことができます。これにより、入力データのどこが問題かを素早く把握できます。

6. 実践: オブジェクト配列の検証

1 つのオブジェクトではなく配列を検証することもよくあります。

[
  { "id": 1, "name": "Alice", "email": "alice@example.com" },
  { "id": 2, "name": "Bob" },
  { "id": "これは何?", "name": 123, "email": "not-an-email" }
]

スキーマ:

{
  "type": "array",
  "items": {
    "type": "object",
    "properties": {
      "id":    { "type": "integer" },
      "name":  { "type": "string", "minLength": 2, "maxLength": 30 },
      "email": { "type": "string", "format": "email" }
    },
    "required": ["id", "name"]
  }
}

検証のやり方は同じで、JSON には配列を渡すだけです。エラーには、問題がある要素のインデックスが含まれます(例: [#/2/id])。

7. JSON 検証でありがちなミス

誤り №1: データ型の不一致。 数値のはずが文字列("id": "123")で来ることがよくあります。スキーマは integer を期待しているため検証は通りません。データ源を制御できない場合は、スキーマを修正するか、事前にデータを変換してください。

誤り №2: 必須フィールドの欠落。 スキーマで必須("required": ["id","name"])なのに JSON に存在しない場合、エラーになります。フロントエンドが送信し忘れたり、API が変更されたりと、意外と起きがちです。

誤り №3: 余計なフィールド。 デフォルトでは JSON Schema は余分なフィールドを許容します。厳密にしたい場合は "additionalProperties": false を忘れずに。これがないと JSON にいくらでも「関係ない」フィールドが入ってしまいます。

誤り №4: スキーマのバージョン/文法の誤り。 使用しているスキーマのバージョンに存在しないキーを使ったり、タイプミスがあると、バリデータはスキーマを読み込めません。https://www.jsonschemavalidator.net/ などで検証しましょう。

誤り №5: エラー処理が不十分。 最初の例外だけを捕捉してユーザーに詳細を見せないと、JSON の何が悪いのか分かりにくくなります。getAllMessages() を使ってすべてのエラーを出力しましょう。

誤り №6: フォーマット検証に頼りすぎる。 "format": "email""date" のチェックは比較的「浅い」ことがあります。厳密な検証が必要なら、コード側で追加チェックを行ってください。

1
アンケート/クイズ
JSONのシリアライズ、レベル 46、レッスン 4
使用不可
JSONのシリアライズ
JSONのシリアライゼーション
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION