Looking for Schema Management Confluent Cloud docs? You are currently viewing Confluent Platform documentation. If you are looking for Confluent Cloud docs, check out Schema Management on Confluent Cloud.

JSON Schema のシリアライザーと逆シリアライザー

このドキュメントでは、Apache Kafka® の Java クライアントやコンソールツールで JSON Schema を使用する方法について説明します。

JSON Schema のシリアライザーとデシリアライザーはどちらも、指定されたスキーマに対してペイロードが有効でない場合にエラーが発生するように構成できます。この設定は、json.fail.invalid.schema=true を指定することによって行います。デフォルトでは、このプロパティが false に設定されています。

ちなみに

以下の例では、Kafka ブートストラップサーバーと Schema Registry にデフォルトのアドレスとポート(それぞれ localhost:9092 および localhost:8081)が使用されています。

JSON Schema シリアライザー

JSON スキーマ型のメッセージを Kafka に送信するには、KafkaProducerKafkaJsonSchemaSerializer をプラグインします。

Jackson アノテーションで修飾された次のような Java クラスがあるとします。

public static class User {
  @JsonProperty
  public String firstName;

  @JsonProperty
  public String lastName;

  @JsonProperty
  public short age;

  public User() {}

  public User(String firstName, String lastName, short age) {
    this(firstName, lastName, age, null);
  }
}

User オブジェクトをシリアル化するには、次のようにします。

Properties props = new Properties();
props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG,
  "org.apache.kafka.common.serialization.StringSerializer");
props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG,
  "io.confluent.kafka.serializers.json.KafkaJsonSchemaSerializer");
props.put("schema.registry.url", "http://127.0.0.1:8081");

Producer<String, User> producer = new KafkaProducer<String, User>(props);

String topic = "testjsonschema";
String key = "testkey";
User user = new User("John", "Doe", 33);

ProducerRecord<String, User> record
      = new ProducerRecord<String, User>(topic, key, user);
producer.send(record).get();
producer.close();

Java オブジェクトから派生した JSON スキーマでは、次の追加構成を使用できます。

  • json.schema.spec.version オブジェクトから派生した JSON スキーマに使用する仕様バージョンを示します。有効な値は、文字列 draft_4draft_6draft_7draft_2019_09 のいずれかです。デフォルトは draft_7 です。
  • json.oneof.for.nullables オブジェクトから派生した JSON スキーマで null 許容フィールドに oneOf を使用するかどうかを示します。このブール値のデフォルトは true です。
  • json.write.dates.iso8601 日付を ISO-8601 文字列として記述できるようにします。このブール値のデフォルトは false です。

JSON Schema 逆シリアライザー

JSON Schema 型のメッセージを Kafka から受信するには、KafkaConsumerKafkaJsonSchemaDeserializer をプラグインします。

Properties props = new Properties();
props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
props.put(ConsumerConfig.GROUP_ID_CONFIG, "group1");
props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringDeserializer");
props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, "io.confluent.kafka.serializers.json.KafkaJsonSchemaDeserializer");
props.put("schema.registry.url", "http://localhost:8081");
props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");
props.put(KafkaJsonDeserializerConfig.JSON_VALUE_TYPE, User.class.getName());

String topic = "testjsonschema";
final Consumer<String, JsonNode> consumer = new KafkaConsumer<String, JsonNode>(props);
consumer.subscribe(Arrays.asList(topic));

try {
  while (true) {
    ConsumerRecords<String, JsonNode> records = consumer.poll(100);
    User user= mapper.convertValue(record.value(), new TypeReference<User>(){});
    }
  }
} finally {
  consumer.close();
}

Avro デシリアライザーが具体的な Avro レコード型のインスタンスまたは GenericRecord を返すように、JSON Schema デシリアライザーも、具体的な Java クラスまたは JsonNode のインスタンスを返します。

JSON Schema デシリアライザーが具体的な型を特定できなかった場合は、汎用的な型が返されます。

具体的な型を返す 1 つの方法は、明示的なプロパティを使用することです。JSON Schema デシリアライザーの場合、KafkaJsonSchemaDeseriaizerConfig.JSON_VALUE_TYPE プロパティまたは KafkaJsonSchemaDeserializerConfig.JSON_KEY_TYPE プロパティを構成できます。

JSON Schema デシリアライザーで異種混合の型を含んだトピックを扱うためには、スキーマに追加情報を指定する必要があります。デシリアライザーを構成する際に、JSON Schema のトップレベルプロパティの名前を示す type.property の値を使用して Java の完全修飾型を指定してください。たとえば、type.property=javaType とした場合、JSON Schema のトップレベルには `` "javaType":"org.acme.MyRecord"`` を指定できます。

JSON ペイロードを逆シリアル化するとき、KafkaJsonSchemaDeserializer には、次の 3 とおりの動作が考えられます。

  • <json.key.type> または <json.value.type> が指定されている場合、デシリアライザーは、その指定された型を使用して逆シリアル化を実行します。

  • RecordNameStrategy では、複数の型の JSON メッセージがトピックに存在する可能性があり、先ほどの構成がうまく機能しません。このケースに対処するためには、デシリアライザーを構成する際に、JSON Schema のトップレベルプロパティの名前を示す <type.property> を使用して、逆シリアル化に使用する Java の完全修飾型を指定してください。たとえば、<type.property>=javaType とした場合、JSON Schema には別途、Java の完全修飾型を指定する javaType というトップレベルプロパティがあるとみなされます。たとえば、mbknor-jackson-jsonSchema ユーティリティを使用して POJO から JSON Schema を生成する場合、アノテーション @SchemaInject を使用して javaType を指定できます。

    // Generate javaType property
    @JsonSchemaInject(strings =
     {@JsonSchemaString(path="javaType", value="com.acme.User")})
    public static class User {
     @JsonProperty
     public String firstName;
     @JsonProperty
     public String lastName;
     @JsonProperty
     @Min(0)
     public short age;
     @JsonProperty
     public Optional<String> nickName;
    
     public User() {}
       ...
    }
    
  • json.value.type のデフォルトは Object.class.getName() です。したがって、タイプが指定されていない場合、またはタイプを決定できない場合、逆シリアライザーは JSON オブジェクトに対して LinkedHashMap を返し、JSON 配列に対して LinkedList を返します。

  • json.value.type=com.fasterxml.jackson.databind.JsonNode を設定すると、逆シリアライザーは Jackson JsonNode のインスタンスを返します。

以下の表は、返される具体的な型と汎用的な型をスキーマ形式ごとにまとめたものです。


Avro Protobuf JSON Schema
具体的な型 生成されたクラス(org.apache.avro.SpecificRecord を実装) 生成されたクラス(com.google.protobuf.Message を拡張) Java クラス(Jackson シリアル化との互換性あり)
汎用的な型 org.apache.avro.GenericRecord com.google.protobuf.DynamicMessage com.fasterxml.jackson.databind.JsonNode

JSON Schema の使用例

実際に JSON Schema を使ってみましょう。JSON Schema では、コマンドラインのプロデューサーとコンシューマーを使用できます。

注釈

  • 以下の例を実行するための前提条件は、 Schema Registry のチュートリアル に記載されている条件とほぼ同じです。ただし、ここでは Maven は必要ありません。また、ここでは Confluent Platform バージョン 5.5.0 以降が必要となります。
  • 以降の例では、Schema Registry の URL にデフォルト値(localhost:8081)が使用されています。これらの例を見ると、その URL をプロデューサーとコンシューマーのコマンドライン引数の --property フラグに引数として指定することにより、インラインでこの値を設定していることがわかります(--property schema.registry.url=<実際の Schema Registry のアドレス>)。別の方法として、このプロパティを $CONFLUENT_HOME/etc/kafka/server.properties で設定することもできます。そうすれば、プロデューサーとコンシューマーのコマンドで URL を指定する必要はありません。たとえば、「confluent.schema.registry.url=http://localhost:8081」のように指定します。

以下の例では、$CONFLUENT_HOME/bin にある kafka-json-schema-console-producerkafka-json-schema-console-consumer を利用しています。

コマンドラインのプロデューサーとコンシューマーは、Confluent Platform における組み込みの JSON Schema 機能の働きを理解するうえで役立ちます。

実際にプロデューサーとコンシューマーのコードにシリアライザーとデシリアライザーを組み込んだときにも、コンソールから実行したときと同じようにメッセージおよび関連するスキーマが処理されます。

プロデューサーを実行した直後にコンシューマーを実行できなかった場合でも確実にメッセージを取り込むために、コンシューマーコマンドには、先頭から読み取るためのフラグ(--from-beginning)を指定することをお勧めします。--from-beginning フラグを省略した場合、コンシューマーは、現在のセッション中に生成された最後のメッセージしか読み取りません。

  1. 次のコマンドを使用して Confluent Platform を起動します。

    confluent local services start
    

    ちなみに

    • 単に confluent local schema-registry を実行してもかまいません。その場合は、依存関係として kafkazookeeper も起動されます。このデモでは、Connect や Control Center など、他のサービスを直接参照することはしていません。もっとも、さらに理解を深めるために(トピックやメッセージが Control Center にどのように表示されるかなど)、フルスタックを実行したい場合もあるでしょう。confluent local の詳細については、「Confluent Platform のクイックスタート(ローカルインストール)」および Confluent CLI コマンドリファレンスの「confluent local」を参照してください。
    • confluent local のコマンドはバックグラウンドで実行されるので、そのコマンドウィンドウを再利用することができます。プロデューサーとコンシューマーのセッションは独立している必要があります。
  2. 登録されているスキーマタイプを確認します。

    Confluent Platform 5.5.0 以降では、Schema Registry で任意のスキーマタイプがサポートされます。どのタイプのスキーマが現在 Schema Registry に登録されているかを確認する必要があります。

    そこで、次のコマンドを入力します(Schema Registry の URL とポートには、デフォルトの localhost:8081 が使用されているものとします)。

    curl http://localhost:8081/schemas/types
    

    次のいずれかまたは複数の項目が応答として返されます。さらに、スキーマ形式プラグインがインストールされている場合は、それらも候補となります。

    ["JSON", "PROTOBUF", "AVRO"]
    

    または、curl --silent フラグを使用し、コマンドをパイプで jq に連結すれば( curl --silent http://localhost:8081/schemas/types | jq)、整った書式の出力結果を得ることができます。

    "JSON",
    "PROTOBUF",
    "AVRO"
    
  3. プロデューサーを使用して、JSON 形式の JSON Schema レコードをメッセージの値として送信します。

    トピック t1-j がまだ存在しない場合、このプロデューサーコマンドの実行過程で新たに作成されます。

    kafka-json-schema-console-producer --broker-list localhost:9092  --property schema.registry.url=http://localhost:8081 --topic t1-j \
    --property value.schema='{"type":"object","properties":{"f1":{"type":"string"}}}'
    

    ちなみに

    現在の JSON Schema 用プロデューサーには、> プロンプトが表示 "されません"。単に空白の行が表示され、そこにプロデューサーのメッセージを入力します。

  4. シェルに次のコマンドを入力し、Return キーを押します。

    {"f1": "value1-j"}
    

    このプロデューサーセッションは実行したままにしてください。

  5. コマンドラインの JSON Schema コンシューマーを使用して、先ほどこのトピックに生成した値を読み取ります。

    kafka-json-schema-console-consumer --bootstrap-server localhost:9092 --from-beginning --topic t1-j --property schema.registry.url=http://localhost:8081
    

    コンソールには次のように表示されます。

    {"f1": "value1-j"}
    

    このコンシューマーセッションは実行したままにしてください。

  6. プロデューサーを使用して、もう 1 つのレコードをメッセージの値として送信します。このメッセージには、スキーマには明示的に宣言されていない新しいプロパティを含めます。

    JSON Schema には、"オープンコンテンツモデル" が採用されています。このモデルでは、JSON ドキュメントにいくつでもプロパティを追加することができます。それらのプロパティが JSON Schema に指定されている必要はありません。これを使用するには、additionalPropertiestrue (デフォルト)に設定します。additionalProperties を明示的に無効化(false に設定)した場合を除き、レコードに含まれている未宣言のプロパティが許可されます。これは JSON Schema のみに見られる特徴です。この点について、以降の手順で見ていきましょう。

    既に実行中のプロデューサーセッションに戻って、次のメッセージを送信します。このメッセージには、新しいプロパティ "f2" が含まれています。このプロデューサーを起動する際に使用したスキーマに、このプロパティは宣言されていません。

    {"f2": "value2-j"}
    
  7. コマンドラインの JSON Schema コンシューマーを使用して、先ほど生成した値を読み取ります。

    既に実行されている(トピック t1-j を読み取っている)コンシューマーに戻ります。コンソールには、次のような新しいメッセージが表示されます。

    {"f2": "value2-j"}
    

    新しいプロパティ(f2)を含んだメッセージが正常に生成されて読み取られます。同じことを他のスキーマ形式(Avro、Protobuf)で行った場合、プロデューサーコマンドでエラーが発生します。その仕様上、すべてのプロパティがスキーマに明示的に宣言されている必要があるためです。

    このコンシューマーは実行したままにしてください。

  8. プロデューサーを起動し、additionalProperties が明示的に false に設定された JSON Schema を渡します。

    プロデューサーのコマンドウィンドウに戻り、Ctrl キーを押しながら C キーを押してプロデューサーを停止します。

    シェルに次のコマンドを入力し、Return キーを押します。これは、前の手順で使用したものと同じプロデューサーとトピック(t1-j)です。スキーマは前回と "ほぼ" 同じですが、この例では、スキーマ内の additionalProperties が明示的に false に設定されています。

    kafka-json-schema-console-producer --broker-list localhost:9092  --property schema.registry.url=http://localhost:8081 --topic t1-j \
    --property value.schema='{"type":"object","properties":{"f1":{"type":"string"}}, "additionalProperties": false}'
    
  9. トップレベルの互換性構成を取得します。

    curl -X GET http://localhost:8081/config
    

    たとえば、次の結果が返されます(これがデフォルトです)。

    {"compatibility":"BACKWARD"}
    
  10. 互換性の要件をグローバルにアップデートします。

    curl -X PUT -H "Content-Type: application/vnd.schemaregistry.v1+json" \
      --data '{"compatibility": "NONE"}' \
      http://localhost:8081/config
    

    たとえば、次の結果が返されます(これがデフォルトです)。

    {"compatibility":"NONE"}
    

    ちなみに

    互換性の要件をアップデートしなかった場合、次の手順で発生するエラーが、ここで紹介しているものとは "異なります"。互換性設定が BACKWARD になっているためです。API に対し curl を使用して構成のテストや設定を行うその他の例については、「Schema Registry API の使用例」を参照してください。

  11. プロデューサーを使用して、もう 1 つのレコードをメッセージの値として送信してみます。このメッセージには、スキーマには明示的に宣言されていない新しいプロパティを含めます。

    先ほど起動したプロデューサーのプロンプトで次のように入力し、Return キーを押します。

    {"f2": "value3-j-this-will-break"}
    

    additionalPropertiesfalse に設定されているので、これを送信しようとするとエラーが発生します。プロデューサーは、次のエラーメッセージでクラッシュします。

    org.apache.kafka.common.errors.SerializationException: Error serializing JSON message
    Caused by: org.apache.kafka.common.errors.SerializationException: JSON {"f2":"value3-j-this-will-break"} does not match schema {"type":"object","properties":{"f1":{"type":"string"}},"additionalProperties":false}
    Caused by: org.everit.json.schema.ValidationException: #: extraneous key [f2] is not permitted
    ...
    

    コンシューマーは引き続き実行されますが、新しいメッセージは表示されません。

    これは、このシナリオで Avro または Protobuf を使用した場合にデフォルトで発生するものと同じ動作です。

    ちなみに

    アプリケーションの JSON Schema プロデューサーのコードにこの動作を組み込む場合は、スキーマに "additionalProperties": false を追加してください。この例は、『Understanding JSON Schema 』のプロパティに関する解説の中で紹介されています。

  12. これまでのようにデフォルトモードでプロデューサーを再実行し、未宣言のプロパティを含んだ後続のメッセージを送信します。

    プロデューサーのコマンドウィンドウで、Ctrl キーを押しながら C キーを押してプロデューサーを停止します。

    元のプロデューサーコマンドを実行します。additionalProperties は明示的に true として宣言してもかまいませんが、デフォルト値が true であるため、明示的に true として宣言する必要はありません。

    kafka-json-schema-console-producer --broker-list localhost:9092  --property schema.registry.url=http://localhost:8081 --topic t1-j \
    --property value.schema='{"type":"object","properties":{"f1":{"type":"string"}}}'
    
  13. プロデューサーを使用して、もう 1 つのレコードをメッセージの値として送信します。このメッセージには、スキーマには明示的に宣言されていない新しいプロパティを含めます。

    {"f2": "value3-j-this-will-work-again"}
    
  14. コンシューマーセッションに戻って、新しいメッセージを読み取ります。

    コンシューマーは引き続き実行され、トピック t1-j からの読み取りを行っているはずです。コンソールには、次のような新しいメッセージが表示されます。

    {"f2": "value3-j-this-will-work-again"}
    

    具体的には、上のすべての手順に忠実に従い、前述した --from-beginning フラグを指定してコンシューマーを起動した場合、コンシューマーには、送信したすべてのメッセージの履歴が表示されます。

    {"f1":"value1-j"}
    {"f2":"value2-j"}
    {"f2":"value3-j-this-will-work-again"}
    
  15. 別のシェルで、次の curl コマンド(読みやすくするためにパイプで jq に連結)を使用し、Schema Registry にバージョン 1 およびバージョン 2 として登録されているスキーマを照会します。

    バージョン 1 のスキーマを照会するには、次のように入力します。

    curl --silent -X GET http://localhost:8081/subjects/t1-j-value/versions/1/schema | jq
    

    バージョン 1 については、次の出力が返されるはずです。

    "type": "object",
    "properties": {
      "f1": {
        "type": "string"
      }
    

    同じコマンドを使用してバージョン 2 のスキーマを照会します。

    curl --silent -X GET http://localhost:8081/subjects/t1-j-value/versions/2/schema | jq
    

    バージョン 2 については、次の出力が返されるはずです。

    "type": "object",
    "properties": {
      "f1": {
        "type": "string"
      }
    },
    "additionalProperties": false
    
  16. 次のコマンドを実行して、より詳細に最新バージョンのスキーマを表示します。

    curl --silent -X GET http://localhost:8081/subjects/t1-j-value/versions/latest | jq
    

    上のコマンドを実行すると、次のような結果が出力されます。

    "subject": "t1-j-value",
     "version": 2,
     "id": 2,
     "schemaType": "JSON",
     "schema": "{\"type\":\"object\",\"properties\":{\"f1\":{\"type\":\"string\"}},\"additionalProperties\":false}"
    
  17. Confluent Control Center を使用して、スキーマとメッセージを調査します。

    正常に生成されたメッセージは、Control Center (http://localhost:9021/)の Topics > <トピック名> > Messages にも表示されます。以前に送信されたメッセージを表示するには、パーティションを選択するか、タイムスタンプに移動しなければならない場合があります。(タイムスタンプに移動するには、数値を入力して Return キーを押します。デフォルトのパーティションは 1/Partition: 0 です。ここに示されているようなメッセージビューを取得するには、右上の カード アイコンを選択します。)

    ../../_images/serdes-json-c3-messages.png

    作成するスキーマには、選択したトピックの Schemas タブからアクセスできます。

    ../../_images/serdes-json-c3-schema.png
  18. シャットダウンとクリーンアップのタスクを実行します。

    • コンシューマーとプロデューサーを停止するには、それぞれのコマンドウィンドウで Ctrl キーを押しながら C キーを押します。
    • Confluent Platform を停止するには、「confluent local stop」と入力します。
    • 別のテストを最初から実行する前に既存のデータ(トピック、スキーマ、メッセージ)を削除する場合は、「confluent local destroy」と入力します。

JSON Schema のスキーマ参照

Confluent Platform は、 スキーマ参照 (スキーマから別のスキーマを参照する機能)という概念をフルサポートします。

ちなみに

Confluent Cloud でも、Avro、Protobuf、JSON Schema の各形式でスキーマ参照がサポートされます。Confluent Cloud CLI から、ccloud schema-registry schema create--refs <file> フラグを使用することで他のスキーマを参照できます。

JSON Schema の場合、参照先スキーマを呼び出すには $ref キーワードに続けて、参照するスキーマの URL またはアドレスを指定します。

{ "$ref": "<参照先スキーマの URL パス>" }

スキーマ参照の例については、JSON Schema ウェブサイトの「Structuring a complex schema」を参照してください。以下の「同じトピック内の複数のイベントタイプ」に記載の例や、関連する ブログ記事 でも詳しく取り上げています。

同じトピック内の複数のイベントタイプ

スキーマ参照 が提供するのは、あるスキーマから他のスキーマを呼び出すしくみだけではありません。スキーマ参照を使用することで、複数のイベントタイプを同じトピックの中で効率よく組み合わせ ながらも、サブジェクト-トピック制約を維持することができます。

JSON Schema でこれを実現するには、次のようにします。

  • デフォルトの サブジェクト命名方法 である TopicNameStrategy を使用します。この命名方法では、スキーマのルックアップに使用されるサブジェクトがトピック名を使用して決定されます。また、この命名方法によって、サブジェクト-トピック制約の適用が促されます。

  • JSON Schema の構文である oneOf を使用して、スキーマ参照のリストを定義します。その例を次に示します。

    {
      "oneOf": [
         { "$ref": "Customer.schema.json" },
         { "$ref": "Product.schema.json" },
         { "$ref": "Order.schema.json }
      ]
    }
    

    スキーマが登録されるときに、参照バージョンの配列を送信します。以下に例を示します。

    [
      {
        "name": "Customer.schema.json",
        "subject": "customer",
        "version": 1
      },
      {
        "name": "Product.schema.json",
        "subject": "product",
        "version": 1
      },
      {
        "name": "Order.schema.json",
        "subject": "order",
        "version": 1
      }
    ]
    
  • プロデューサーアプリケーションで次のプロパティを構成し、イベントタイプではなく oneOf を使用してシリアル化を行うように JSON Schema シリアライザーを構成します。

    auto.register.schemas=false
    use.latest.version=true
    

    以下に例を示します。

    props.put(KafkaJsonSchemaSerializerConfig.AUTO_REGISTER_SCHEMAS, "false");
    props.put(KafkaJsonSchemaSerializerConfig.USE_LATEST_VERSION, "true");
    

    ちなみに

    • auto.register.schemas を false に設定すると、イベントタイプの自動登録が無効になるので、oneOf がサブジェクト内の最新のスキーマとしてオーバーライドされることはありません。use.latest.version が true に設定されている場合、JSON Schema シリアライザーは、(oneOf となる)サブジェクトから最新のスキーマバージョンを検索し、それをシリアル化に使用します。それ以外の(false に設定されている)場合、シリアライザーは、サブジェクトからイベントタイプを探しますが、その検出に失敗します
    • 「Schema Registry のチュートリアル」の「スキーマの自動登録」と Kafka Connect に対する Schema Registry の「構成オプション」も参照してください。

JSON Schema の互換性ルール

JSON Schema の互換性ルールは、おおよそ Avro の同様のルール に基づいていますが、後方互換性のルールはより複雑です。以降のセクションに加えて、詳細については『Understanding JSON Schema Compatibility』を参照してください。

プリミティブ型の互換性

JSON Schema は Avro ほど型の数は多くありません。しかし、Avro についての次のルールは、JSON Schema にも当てはまります。

  • ライターのスキーマの integer は、リーダーのスキーマの number に昇格させることができます。

JSON のプリミティブ型スキーマに加えることができる変更は数多くあります。こうした変更によってスキーマの制約を緩和し、新しいスキーマを使用するクライアントが古いスキーマで作成された JSON ドキュメントを読み取ることができるようにします。以下に、いくつかの例を示します。

  • 文字列型に関して、ライターのスキーマにある minLength の値は、リーダーのスキーマの minLength の値より大きくすることができ、また、リーダーのスキーマに存在していなくてもかまいません。また、maxLength の値は、リーダーのスキーマの maxLength の値よりも小さくすることができ、また、リーダーのスキーマに存在していなくてもかまいません。
  • 文字列型に関して、ライターのスキーマには、リーダーのスキーマに存在しない pattern 値を含めることができます。
  • 数値型に関して、ライターのスキーマにある minimum の値は、リーダーのスキーマの minimum の値より大きくすることができ、また、存在していなくてもかまいません。また、minimum の値は、リーダーのスキーマの minimum の値よりも小さくすることができ、また、リーダーのスキーマに存在していなくてもかまいません。
  • 整数型に関して、ライターのスキーマにある multipleOf 値は、リーダーのスキーマにある multipleOf 値の倍数にすることができます。また、リーダーのスキーマに存在していなくてもかまいません。

オブジェクトの互換性

オブジェクトのスキーマに関して、JSON Schema は、オープンコンテンツモデルとクローズドコンテンツモデル、および部分的なオープンコンテンツモデルをサポートしています。

  • オープンコンテンツモデルでは、JSON ドキュメントにいくつでもプロパティを追加することができます。それらのプロパティが JSON スキーマに指定されている必要はありません。これを使用するには、additionalProperties を true(デフォルト)に設定します。
  • クローズドコンテンツモデルでは、JSON スキーマに指定されていないプロパティが JSON ドキュメントに出現する場合、エラーが通知されます。これを使用するには、additionalProperties を false に設定します。
  • 部分的なオープンコンテンツモデルでは、JSON スキーマに指定されていないプロパティが JSON ドキュメントに出現していてもかまいませんが、そうした追加のプロパティの型や名前は特定のものに限定されます。これを使用するには、additionalProperties のスキーマを指定するか、正規表現をスキーマにマッピングする patternProperties の値を指定します。

たとえば、リーダーのスキーマはライターのスキーマのプロパティに myProperty というプロパティを追加できますが、それはライターのスキーマにクローズドコンテンツモデルが使用されている場合に後方互換という形でのみ可能となります。なぜなら、ライターのスキーマにオープンコンテンツモデルが使用されている場合、ライターによって生成される JSON ドキュメントには、リーダーのスキーマの myProperty に想定される型とは異なる型を使用した myProperty が存在する可能性があるためです。

これらのコンテンツモデルの概念を踏まえて、Avro のルールを次のように調整して当てはめることができます。

  • フィールドの順序が異なっていてかまいません。つまり、フィールドは名前で照合されます。
  • 両方のレコードで同じ名前を持つフィールドのスキーマは再帰的に解決されます。
  • ライターのスキーマに含まれているフィールドの名前がリーダーのスキーマに存在しない場合、リーダーのスキーマに使用されるモデルは、欠落しているフィールドが取り込まれるオープンコンテンツモデルまたは部分的なオープンコンテンツモデルであることが必要です。
  • リーダーのスキーマに、デフォルト値を持つ必須フィールドがあり、なおかつ、ライターのスキーマにクローズドコンテンツモデルが使用されていて、同じ名前のフィールドが存在しないか、または、同じ名前のフィールドはあるが省略可能である場合、リーダーは、そのフィールドのデフォルト値を使用する必要があります。
  • リーダーのスキーマに、デフォルト値を持たない必須フィールドがあり、なおかつライターのスキーマに同じ名前のフィールドが存在しないか、または同じ名前のフィールドはあるが省略可能である場合、エラーが通知されます。
  • リーダーのスキーマに省略可能なフィールドがあり、なおかつ、ライターのスキーマにクローズドコンテンツモデルが使用されていて、同じ名前のフィールドが存在しない場合、リーダーはそのフィールドを無視する必要があります。

その他、JSON Schema に固有の互換性ルールを次に示します。

  • ライターのスキーマにある minProperties の値は、リーダーのスキーマの minProperties の値より大きくすることができ、また、リーダーのスキーマに存在していなくてもかまいません。また、maxProperties の値は、リーダーのスキーマの maxProperties の値よりも小さくすることができ、また、リーダーのスキーマに存在していなくてもかまいません。
  • ライターのスキーマにある必須の値は、リーダーのスキーマにある必須の値の上位集合とすることができます。また、リーダーのスキーマに存在していなくてもかまいません。
  • ライターのスキーマにある依存関係の値は、リーダーのスキーマにある依存関係の値の上位集合とすることができます。また、リーダーのスキーマに存在していなくてもかまいません。
  • ライターのスキーマでは additionalProperties の値を false とする一方、リーダーのスキーマでは、その値を true にすることができます。

列挙型の互換性

列挙型に関する Avro のルールは、JSON Schema にもそのまま当てはまります。

  • ライターのシンボルがリーダーの enum に存在しない場合、エラーが通知されます。

配列の互換性

JSON Schema は配列に関して 2 種類の検証をサポートしています。配列の要素がすべて同じ型であるリストの検証と、配列の各要素の型が異なるタプルの検証です。

  • この解決アルゴリズムは、リーダーとライターの配列要素スキーマに再帰的に適用されます。

その他、JSON Schema に固有の互換性ルールを次に示します。

  • ライターのスキーマにある minItems の値は、リーダーのスキーマの minItems の値より大きくすることができ、また、リーダーのスキーマに存在していなくてもかまいません。また、maxItems の値は、リーダーのスキーマの maxItems の値よりも小さくすることができ、また、リーダーのスキーマに存在していなくてもかまいません。
  • ライターのスキーマでは uniqueItems の値を true とする一方、リーダーのスキーマでは、その値を false にすることができ、また存在していなくてもかまいません。

共用体の互換性

JSON Schema では、共用体が oneOf キーワードを使用して実装されます。Avro のルールを次のように調整して当てはめることができます。

  • リーダーとライターのスキーマがどちらも共用体である場合、ライターのスキーマは、リーダーのスキーマの部分集合である必要があります。
  • リーダーのスキーマは共用体だが、ライターのスキーマは共用体ではない場合、リーダーの共用体に含まれるスキーマのうち、ライターのスキーマと一致する最初のスキーマが再帰的に解決されます。一致するスキーマがない場合は、エラーが通知されます。

おすすめの関連情報