当前位置: 首页 > 知识库问答 >
问题:

Avro向后模式演化抛出ClassCastException

赵晟睿
2023-03-14

当我试图用一个简单的Java程序测试Avro模式演化时,我得到了一个< code>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"}
  ]
}

序列化v1和反序列化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();
        }
    }
}

结果

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)

你能让我知道如何解决这个错误吗?

共有1个答案

韩禄
2023-03-14

您定义了两种数据类型CustomerCustomer2,由于它们不处于继承关系,因此不能进行任何强制转换。因此,Java无法进行强制转换,您将得到<code>ClassCastException</code>。在您的代码中,唯一的解决方案是捕获<code>ClassCastException

我假设您正在模仿Kafka环境中的模式变化。在这种情况下,您将通过添加新字段或删除旧字段来扩展现有的avro模式。

只要类名保持不变,avro模式更改将会起作用。

 类似资料:
  • 我有两个问题: > 我曾尝试使用模式V1编写记录,并使用模式V2读取记录,但出现以下错误: org.apache.avro。AvroTypeException:找到foo,应为foo 我使用avro-1.7.3和: 以下是这两种模式的示例(我也尝试过添加命名空间,但没有成功)。 架构V1: 架构V2: 提前谢谢。

  • 我正试图了解更多关于我们在Kafka主题中使用的Avro模式的信息,我对这一点相对来说比较陌生。 我想知道是否有一种方法可以在特定情况下发展模式。我们用一个不能为null的新字段或任何默认值来更新模式,因为这些新字段是标识符。解决这个问题的方法是创建新主题,但是有没有更好的方法来改进现有模式?

  • 我尝试使用avro-python3(向后兼容性)重新创建一个模式演变案例。 我有两个模式: 第二个模式没有字段,但有两个附加字段:和。 根据avro模式演化规则,如果我用schema_v1写入avro记录: …我可以使用schema_v2读取它,前提是不存在字段有默认值 但我得到了以下错误: 我知道这在Java中有效。这是一个视频课程的示例。有没有办法让它在python中工作?

  • 我在两个独立的AVCS模式文件中定义了记录的两个版本。我使用命名空间来区分版本SimpleV1.avsc 示例JSON 版本2只是有一个带有默认值的附加描述字段。 SimpleV2.avsc 示例JSON 这两个模式都序列化为Java类。在我的示例中,我将测试向后兼容性。V1写入的记录应由使用V2的读取器读取。我希望看到插入默认值。只要我不使用枚举,这就可以工作。 检查读者作家兼容性方法确认模式是

  • 如果我使用模式版本1序列化一个对象,然后将模式更新为版本2(比如添加一个字段),那么在以后反序列化该对象时是否需要使用模式版本2?理想情况下,我只希望使用模式版本2,并使反序列化对象具有在对象最初序列化后添加到模式中的字段的默认值。 也许一些代码会更好地解释... 架构 1: 方案2: 使用通用非代码生成方法: 导致EOFException。使用会导致AvroTypeException。 我知道如

  • 我是Hadoop和编程的新手,我对Avro模式演变有点困惑。我将解释到目前为止我对Avro的理解。 Avro是一种串行化工具,它存储二进制数据,其json模式位于顶部。模式如下所示。 现在我的问题是为什么我们需要进化?我已经了解到,我们可以在新字段的模式中使用<code>default</code>选项;但是,如果我们在文件中添加一个新的模式,早期的模式将被覆盖。一个文件不能有两个架构。 另一个问