Avro 向后模式演化抛出 ClassCastException
Avro backward schema evolution throws ClassCastException
我在尝试使用简单的 Java 程序测试 Avro 模式演化时收到 ClassCastException
。
Avro 版本:1.10.0
customer-v1.avsc
{
"type": "record",
"namespace": "com.practice.kafka",
"name": "Customer",
"doc": "Avro schema for Customer",
"fields": [
{"name": "first_name", "type": "string", "doc": "Customer first name"},
{"name": "last_name", "type": "string", "doc": "Customer last name"},
{"name": "automated_email", "type": "boolean", "default": true, "doc": "Receive marketing emails or not"}
]
}
customer-v2.avsc
{
"type": "record",
"namespace": "com.practice.kafka",
"name": "CustomerV2",
"doc": "Avro schema for Customer",
"fields": [
{"name": "first_name", "type": "string", "doc": "Customer first name"},
{"name": "last_name", "type": "string", "doc": "Customer last name"},
{"name": "phone_number", "type": ["null","boolean"], "default": null, "doc": "Optional phone number"},
{"name": "email", "type": "string", "default": "missing@example.com", "doc": "Optional email address"}
]
}
Program to serialize v1 and deserialize v2
package com.practice.kafka;
import org.apache.avro.file.DataFileReader;
import org.apache.avro.file.DataFileWriter;
import org.apache.avro.io.DatumReader;
import org.apache.avro.io.DatumWriter;
import org.apache.avro.specific.SpecificDatumReader;
import org.apache.avro.specific.SpecificDatumWriter;
import java.io.File;
import java.io.IOException;
public class BackwardSchemaEvolutionSample {
public static void main(String[] args) {
// Step 1 - Create specific record
Customer customer = Customer.newBuilder().setFirstName("John").setLastName("Doe").setAutomatedEmail(false).build();
// Step 2 - Write specific record to a file
final DatumWriter<Customer> datumWriter = new SpecificDatumWriter<>();
try (DataFileWriter<Customer> dataFileWriter = new DataFileWriter<>(datumWriter)) {
dataFileWriter.create(customer.getSchema(), new File("customer-v1.avro"));
dataFileWriter.append(customer);
} catch (IOException e) {
e.printStackTrace();
}
// Step 3 - Read specific record from a file
final File file = new File("customer-v1.avro");
final DatumReader<CustomerV2> datumReader = new SpecificDatumReader<>();
CustomerV2 customerRecord;
try (DataFileReader<CustomerV2> dataFileReader = new DataFileReader<>(file, datumReader)) {
customerRecord = dataFileReader.next();
System.out.println(customerRecord.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
}
Result
Exception in thread "main" java.lang.ClassCastException: class com.practice.kafka.Customer cannot be cast to class com.practice.kafka.CustomerV2 (com.practice.kafka.Customer and com.practice.kafka.CustomerV2 are in unnamed module of loader 'app')
at com.practice.kafka.SchemaEvolutionSample.main(SchemaEvolutionSample.java:34)
你能告诉我如何解决这个错误吗?
您定义了 2 种数据类型 Customer
和 Customer2
,并且您不能进行任何转换,因为它们没有继承关系。
所以 Java 无法进行转换,你得到的是 ClassCastException
。
在您的代码中,唯一的解决方案是捕获 ClassCastException
并在捕获块中将 Customer 转换为 Customer2.
我假设您正在 Kafka 环境中模拟架构的更改。
在这种情况下,您将通过添加新字段或删除旧字段来扩展现有的 avro 架构。
只要 class 的名称保持不变,avro 架构更改将起作用。
我在尝试使用简单的 Java 程序测试 Avro 模式演化时收到 ClassCastException
。
Avro 版本:1.10.0
customer-v1.avsc
{
"type": "record",
"namespace": "com.practice.kafka",
"name": "Customer",
"doc": "Avro schema for Customer",
"fields": [
{"name": "first_name", "type": "string", "doc": "Customer first name"},
{"name": "last_name", "type": "string", "doc": "Customer last name"},
{"name": "automated_email", "type": "boolean", "default": true, "doc": "Receive marketing emails or not"}
]
}
customer-v2.avsc
{
"type": "record",
"namespace": "com.practice.kafka",
"name": "CustomerV2",
"doc": "Avro schema for Customer",
"fields": [
{"name": "first_name", "type": "string", "doc": "Customer first name"},
{"name": "last_name", "type": "string", "doc": "Customer last name"},
{"name": "phone_number", "type": ["null","boolean"], "default": null, "doc": "Optional phone number"},
{"name": "email", "type": "string", "default": "missing@example.com", "doc": "Optional email address"}
]
}
Program to serialize v1 and deserialize v2
package com.practice.kafka;
import org.apache.avro.file.DataFileReader;
import org.apache.avro.file.DataFileWriter;
import org.apache.avro.io.DatumReader;
import org.apache.avro.io.DatumWriter;
import org.apache.avro.specific.SpecificDatumReader;
import org.apache.avro.specific.SpecificDatumWriter;
import java.io.File;
import java.io.IOException;
public class BackwardSchemaEvolutionSample {
public static void main(String[] args) {
// Step 1 - Create specific record
Customer customer = Customer.newBuilder().setFirstName("John").setLastName("Doe").setAutomatedEmail(false).build();
// Step 2 - Write specific record to a file
final DatumWriter<Customer> datumWriter = new SpecificDatumWriter<>();
try (DataFileWriter<Customer> dataFileWriter = new DataFileWriter<>(datumWriter)) {
dataFileWriter.create(customer.getSchema(), new File("customer-v1.avro"));
dataFileWriter.append(customer);
} catch (IOException e) {
e.printStackTrace();
}
// Step 3 - Read specific record from a file
final File file = new File("customer-v1.avro");
final DatumReader<CustomerV2> datumReader = new SpecificDatumReader<>();
CustomerV2 customerRecord;
try (DataFileReader<CustomerV2> dataFileReader = new DataFileReader<>(file, datumReader)) {
customerRecord = dataFileReader.next();
System.out.println(customerRecord.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
}
Result
Exception in thread "main" java.lang.ClassCastException: class com.practice.kafka.Customer cannot be cast to class com.practice.kafka.CustomerV2 (com.practice.kafka.Customer and com.practice.kafka.CustomerV2 are in unnamed module of loader 'app')
at com.practice.kafka.SchemaEvolutionSample.main(SchemaEvolutionSample.java:34)
你能告诉我如何解决这个错误吗?
您定义了 2 种数据类型 Customer
和 Customer2
,并且您不能进行任何转换,因为它们没有继承关系。
所以 Java 无法进行转换,你得到的是 ClassCastException
。
在您的代码中,唯一的解决方案是捕获 ClassCastException
并在捕获块中将 Customer 转换为 Customer2.
我假设您正在 Kafka 环境中模拟架构的更改。 在这种情况下,您将通过添加新字段或删除旧字段来扩展现有的 avro 架构。
只要 class 的名称保持不变,avro 架构更改将起作用。