1. 概述

Apache Avro 是一个数据序列化框架,提供强大的数据结构和轻量级、快速的二进制数据格式。

在本教程中,我们将探索如何创建一个 Avro schema,当它转换为对象时,包含其他对象的列表。

2. 目标

假设我们需要开发一个表示父子关系的 Avro schema。因此,我们需要一个包含多个 Child 对象列表的 Parent 类。

在 Java 代码中可能长这样:

public class Child {
    String name;
}

public class Parent {
    List<Child> children;
}

我们的目标是创建一个能自动转换为这些对象的 Avro schema

在看解决方案前,快速回顾几个 Avro 基础概念:

  • Avro schema 使用 JSON 定义
  • type 字段表示数据类型(如 record, array, string
  • fields 数组定义记录的结构

3. 创建 Avro Schema

要在 Avro 中正确表示父子关系,我们需要组合使用 recordarray 类型。

schema 如下所示:

{
    "namespace": "com.baeldung.apache.avro.generated",
    "type": "record",
    "name": "Parent",
    "fields": [
        {
            "name": "children",
            "type": {
                "type": "array",
                "items": {
                    "type": "record",
                    "name": "Child",
                    "fields": [
                        {"name": "name", "type": "string"}
                    ]
                }
            }
        }
    ]
}

我们首先定义了一个 Parent 类型的记录。在 Parent 记录中,我们定义了一个 children 字段。这个字段是 数组 类型,允许我们存储多个 Child 对象。数组类型的 items 属性详细描述了数组中每个元素的结构。在我们的例子中,这是一个 Child 记录。可以看到,Child 记录只有一个属性 name,类型为 string

4. 在 Java 中使用 Schema

定义好 Avro schema 后,我们将用它生成 Java 类。当然,这需要通过 Avro Maven 插件完成。以下是 parent pom 文件中的配置:

<plugin>
    <groupId>org.apache.avro</groupId>
    <artifactId>avro-maven-plugin</artifactId>
    <version>1.11.3</version>
    <executions>
        <execution>
            <phase>generate-sources</phase>
            <goals>
                <goal>schema</goal>
            </goals>
            <configuration>
                <sourceDirectory>src/main/java/com/baeldung/apache/avro/schemas</sourceDirectory>
                <outputDirectory>src/main/java</outputDirectory>
            </configuration>
        </execution>
    </executions>
</plugin>

要让 Avro 生成类,我们需要运行 Maven 生成源码命令(mvn clean generate-sources),或者到 Maven 工具窗口的 Plugins 部分运行 avro 插件的 avro:schema 目标:

maven avro plugin

这样,Avro 会根据提供的 schema 在指定的 namespace 中创建 Java 类。namespace 属性还会在生成类的顶部添加包名。

5. 使用生成的类

新生成的类提供了设置和获取 children 列表的方法。具体如下:

@Test
public void whenAvroSchemaWithListOfObjectsIsUsed_thenObjectsAreSuccessfullyCreatedAndSerialized() throws IOException {
    Parent parent = new Parent();
    List<Child> children = new ArrayList();

    Child child1 = new Child();
    child1.setName("Alice");
    children.add(child1);

    Child child2 = new Child();
    child2.setName("Bob");
    children.add(child2);

    parent.setChildren(children);

    SerializationDeserializationLogic.serializeParent(parent);
    Parent deserializedParent = SerializationDeserializationLogic.deserializeParent();

    assertEquals("Alice", deserializedParent.getChildren().get(0).getName());
}

从上面的测试可以看到,我们创建了一个新的 Parent 对象。也可以使用提供的 builder() 方法创建(这篇关于 Avro 默认值 的文章展示了如何使用 builder() 模式)。

然后,我们创建了两个 Child 对象并添加到 Parentchildren 属性中。最后,我们序列化和反序列化对象,并比较其中一个名字。

6. 总结

本文介绍了如何创建包含对象列表的 Avro schema。我们详细说明了如何定义一个带有 Child 记录列表属性的 Parent 记录。这是在 Avro 中表示复杂数据结构的一种方式。当我们需要处理对象集合或分层数据时,这种方法特别有用。

最后,Avro schema 非常灵活,我们可以配置它们来设置更复杂的数据结构。通过组合不同类型和嵌套结构,可以复制我们的数据模型。