1. 引言

在本文中,我们将学习如何使用 Jackson 库在 Java 中将 JSON 数据转换为 CSV 格式,以及反过来操作。

虽然也有其他工具可以实现类似功能(比如 org.json 提供的 CDL 类),但本文我们专注于使用 Jackson。

我们将结合 ObjectMapperCsvMapper 来完成 JSON 与 CSV 的转换,目标是提供一套简单粗暴的转换方案,避免踩坑。

2. 依赖配置

首先,我们需要在项目中添加 Jackson 的 CSV 支持模块:

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-csv</artifactId>
    <version>2.13.0</version>
</dependency>

另外,还需要 Jackson 的核心模块:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.13.0</version>
</dependency>

这两个依赖都可在 Maven Central 上找到最新版本。

3. 数据结构说明

在进行 JSON 到 CSV 转换前,我们需要理解两种格式之间的数据映射关系:

  • ✅ JSON 支持复杂结构,如嵌套对象、数组等
  • ✅ CSV 更适合表示“列表型”数据,每一行对应一个对象

因此,JSON 中的数组对象是最适合转换为 CSV 的结构。

我们以下面这个订单项列表为例:

[ {
  "item" : "No. 9 Sprockets",
  "quantity" : 12,
  "unitPrice" : 1.23
}, {
  "item" : "Widget (10mm)",
  "quantity" : 4,
  "unitPrice" : 3.45
} ]

转换后的 CSV 格式如下:

item,quantity,unitPrice
"No. 9 Sprockets",12,1.23
"Widget (10mm)",4,3.45

4. JSON 转 CSV

4.1 步骤概览

  1. 使用 ObjectMapper 将 JSON 文件解析为 JsonNode
  2. 构建 CsvSchema,基于 JSON 字段名设置列头
  3. 使用 CsvMapperJsonNode 写入 CSV 文件

4.2 示例代码

JsonNode jsonTree = new ObjectMapper().readTree(new File("src/main/resources/orderLines.json"));

Builder csvSchemaBuilder = CsvSchema.builder();
JsonNode firstObject = jsonTree.elements().next();
firstObject.fieldNames().forEachRemaining(fieldName -> {
    csvSchemaBuilder.addColumn(fieldName);
});
CsvSchema csvSchema = csvSchemaBuilder.build().withHeader();

CsvMapper csvMapper = new CsvMapper();
csvMapper.writerFor(JsonNode.class)
  .with(csvSchema)
  .writeValue(new File("src/main/resources/orderLines.csv"), jsonTree);

运行后即可得到预期的 CSV 文件。

5. CSV 转 JSON

5.1 步骤概览

  1. 定义 POJO 类 OrderLine 用于映射 CSV 数据
  2. 使用 CsvMapper 读取 CSV 文件为 OrderLine 对象列表
  3. 使用 ObjectMapper 将对象列表写回 JSON 文件

5.2 示例代码

定义 OrderLine 类:

public class OrderLine {
    private String item;
    private int quantity;
    private BigDecimal unitPrice;

    // Constructors, Getters, Setters and toString
}

读取 CSV 并转换为 JSON:

CsvSchema orderLineSchema = CsvSchema.emptySchema().withHeader();
CsvMapper csvMapper = new CsvMapper();
MappingIterator<OrderLine> orderLines = csvMapper.readerFor(OrderLine.class)
  .with(orderLineSchema)
  .readValues(new File("src/main/resources/orderLines.csv"));

new ObjectMapper()
  .configure(SerializationFeature.INDENT_OUTPUT, true)
  .writeValue(new File("src/main/resources/orderLinesFromCsv.json"), orderLines.readAll());

运行后即可得到结构清晰的 JSON 文件。

6. 自定义 CSV 格式

有时候我们希望控制输出 CSV 的列名、顺序或隐藏某些字段。这时可以使用 Jackson 提供的注解。

6.1 需求示例

我们希望输出的 CSV 格式如下:

count,name
12,"No. 9 Sprockets"
4,"Widget (10mm)"

即:

  • ✅ 将 item 映射为 name
  • ✅ 将 quantity 映射为 count
  • ❌ 忽略 unitPrice
  • count 列排在最前

6.2 实现方式

定义一个抽象类用于格式配置:

@JsonPropertyOrder({ "count", "name" })
public abstract class OrderLineForCsv {

    @JsonProperty("name")
    private String item;

    @JsonProperty("count")
    private int quantity;

    @JsonIgnore
    private BigDecimal unitPrice;
}

使用该类生成 CsvSchema 并注册为 Mixin:

CsvMapper csvMapper = new CsvMapper();
CsvSchema csvSchema = csvMapper
  .schemaFor(OrderLineForCsv.class)
  .withHeader();

csvMapper.addMixIn(OrderLine.class, OrderLineForCsv.class);

最后进行转换:

OrderLine[] orderLines = new ObjectMapper()
    .readValue(new File("src/main/resources/orderLines.json"), OrderLine[].class);

csvMapper.writerFor(OrderLine[].class)
    .with(csvSchema)
    .writeValue(new File("src/main/resources/orderLinesReformated.csv"), orderLines);

运行后即可得到符合预期的 CSV 文件。

7. 小结

本文我们介绍了如何使用 Jackson 的 CsvMapperObjectMapper 实现 JSON 与 CSV 的双向转换,并演示了如何通过注解灵活控制输出格式。

整个过程简单粗暴,适合需要快速实现数据格式转换的场景。

完整代码可在 GitHub 上找到:https://github.com/eugenp/tutorials(路径:jackson-modules/jackson-conversions-2


原始标题:Converting JSON to CSV in Java