1. Introduction
1.介绍
In this short tutorial, we’ll see how to use Jackson to convert JSON into CSV and vice versa.
在这个简短的教程中,我们将看到如何使用Jackson将JSON转换成CSV,反之亦然。
There are alternative libraries available, like the CDL class from org.json, but we’ll just focus on the Jackson library here.
还有其他可用的库,比如来自org.json的CDL类,但我们在这里只关注杰克逊库。
After we’ve looked at our example data structure, we’ll use a combination of ObjectMapper and CSVMapper to convert between JSON and CSV.
在我们看完我们的例子数据结构后,我们将使用ObjectMapper和CSVMapper的组合来在JSON和CSV之间进行转换。
2. Dependencies
2.依赖性
Let’s add the dependency for Jackson CSV data formatter:
让我们为Jackson CSV数据格式化器添加依赖性。
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-csv</artifactId>
<version>2.13.0</version>
</dependency>
We can always find the most recent version of this dependency on Maven Central.
我们总能在Maven Central上找到该依赖的最新版本。
We’ll also add the dependency for the core Jackson databind:
我们还将添加对核心Jackson databind的依赖。
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.0</version>
</dependency>
Again, we can find the most recent version of this dependency on Maven Central.
同样,我们可以在Maven Central上找到该依赖的最新版本。
3. Data Structure
3.数据结构
Before we reformat a JSON document to CSV, we need to consider how well our data model will map between the two formats.
在我们将JSON文档重新格式化为CSV之前,我们需要考虑我们的数据模型在两种格式之间的映射情况。
So first, let’s consider what data the different formats support:
因此,首先,让我们考虑不同的格式支持哪些数据。
- We use JSON to represent a variety of object structures, including ones that contain arrays and nested objects
- We use CSV to represent data from a list of objects, with each object from the list appearing on a new line
This means that if our JSON document has an array of objects, we can reformat each object into a new line of our CSV file. So, as an example, let’s use a JSON document containing the following list of items from an order:
这意味着,如果我们的JSON文档有一个对象数组,我们可以将每个对象重新格式化为我们CSV文件的一个新行。因此,作为一个例子,让我们使用一个JSON文档,其中包含一个订单的以下项目列表。
[ {
"item" : "No. 9 Sprockets",
"quantity" : 12,
"unitPrice" : 1.23
}, {
"item" : "Widget (10mm)",
"quantity" : 4,
"unitPrice" : 3.45
} ]
We’ll use the field names from the JSON document as column headers, and reformat it to the following CSV file:
我们将使用JSON文档中的字段名作为列标题,并将其重新格式化为以下CSV文件。
item,quantity,unitPrice
"No. 9 Sprockets",12,1.23
"Widget (10mm)",4,3.45
4. Read JSON and Write CSV
4.读取JSON和写入CSV
First, we use Jackson’s ObjectMapper to read our example JSON document into a tree of JsonNode objects:
首先,我们使用Jackson的ObjectMapper将我们的示例JSON文档读成一棵JsonNode对象。
JsonNode jsonTree = new ObjectMapper().readTree(new File("src/main/resources/orderLines.json"));
Next, let’s create a CsvSchema. This determines the column headers, types, and sequence of columns in the CSV file. To do this, we create a CsvSchema Builder and set the column headers to match the JSON field names:
接下来,让我们创建一个CsvSchema。这决定了CSV文件中的列头、类型和列的顺序。为此,我们创建一个CsvSchema Builder,并设置列头以匹配JSON字段名。
Builder csvSchemaBuilder = CsvSchema.builder();
JsonNode firstObject = jsonTree.elements().next();
firstObject.fieldNames().forEachRemaining(fieldName -> {csvSchemaBuilder.addColumn(fieldName);} );
CsvSchema csvSchema = csvSchemaBuilder.build().withHeader();
Then, we create a CsvMapper with our CsvSchema, and finally, we write the jsonTree to our CSV file:
然后,我们用我们的CsvSchema创建一个CsvMapper,最后,我们将jsonTree写入我们的CSV文件。
CsvMapper csvMapper = new CsvMapper();
csvMapper.writerFor(JsonNode.class)
.with(csvSchema)
.writeValue(new File("src/main/resources/orderLines.csv"), jsonTree);
When we run this sample code, our example JSON document is converted to the expected CSV file.
当我们运行这个示例代码时,我们的示例JSON文档被转换为预期的CSV文件。
5. Read CSV and Write JSON
5.读取CSV和写入JSON
Now, let’s use Jackson’s CsvMapper to read our CSV file into a List of OrderLine objects. To do this, we first create the OrderLine class as a simple POJO:
现在,让我们使用Jackson的CsvMapper来把我们的CSV文件读成List的OrderLine对象。要做到这一点,我们首先创建OrderLine类作为一个简单的POJO。
public class OrderLine {
private String item;
private int quantity;
private BigDecimal unitPrice;
// Constructors, Getters, Setters and toString
}
We’ll use the column headers in the CSV file to define our CsvSchema. Then, we use the CsvMapper to read the data from the CSV into a MappingIterator of OrderLine objects:
我们将使用CSV文件中的列标题来定义我们的CsvSchema。然后,我们使用CsvMapper从CSV中读取数据到OrderLine对象的MappingIterator。
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"));
Next, we’ll use the MappingIterator to get a List of OrderLine objects. Then, we use Jackson’s ObjectMapper to write the list out as a JSON document:
接下来,我们将使用MappingIterator来获得List的OrderLine对象。然后,我们使用Jackson的ObjectMapper将该列表写成JSON文档。
new ObjectMapper()
.configure(SerializationFeature.INDENT_OUTPUT, true)
.writeValue(new File("src/main/resources/orderLinesFromCsv.json"), orderLines.readAll());
When we run this sample code, our example CSV file is converted to the expected JSON document.
当我们运行这个示例代码时,我们的示例CSV文件被转换为预期的JSON文档。
6. Configuring the CSV File Format
6.配置CSV文件格式
Let’s use some of Jackson’s annotations to adjust the format of the CSV file. We’ll change the ‘item’ column heading to ‘name’, the ‘quantity’ column heading to ‘count’, remove the ‘unitPrice’ column, and make ‘count’ the first column.
让我们使用杰克逊的一些注释来调整CSV文件的格式。我们将把‘item’列标题改为‘name’,‘quantity’列标题改为‘count’,删除‘unitPrice’列,并将‘count’作为第一列。
So, our expected CSV file becomes:
因此,我们预期的CSV文件变成了。
count,name
12,"No. 9 Sprockets"
4,"Widget (10mm)"
We’ll create a new abstract class to define the required format for the CSV file:
我们将创建一个新的抽象类来定义CSV文件的所需格式。
@JsonPropertyOrder({
"count",
"name"
})
public abstract class OrderLineForCsv {
@JsonProperty("name")
private String item;
@JsonProperty("count")
private int quantity;
@JsonIgnore
private BigDecimal unitPrice;
}
Then, we use our OrderLineForCsv class to create a CsvSchema:
然后,我们使用我们的OrderLineForCsv类来创建一个CsvSchema。
CsvMapper csvMapper = new CsvMapper();
CsvSchema csvSchema = csvMapper
.schemaFor(OrderLineForCsv.class)
.withHeader();
We also use the OrderLineForCsv as a Jackson Mixin. This tells Jackson to use the annotations we added to the OrderLineForCsv class when it processes an OrderLine object:
我们还使用OrderLineForCsv作为Jackson混合器。这告诉Jackson在处理OrderLineForCsv类时使用我们添加到OrderLine的注释。
csvMapper.addMixIn(OrderLine.class, OrderLineForCsv.class);
Finally, we use an ObjectMapper to read our JSON document into an OrderLine array, and use our csvMapper to write the this to a CSV file:
最后,我们使用ObjectMapper将我们的JSON文档读入OrderLine数组,并使用我们的csvMapper将此写入CSV文件。
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);
When we run this sample code, our example JSON document is converted to the expected CSV file.
当我们运行这个示例代码时,我们的示例JSON文档被转换为预期的CSV文件。
7. Conclusion
7.结论
In this quick tutorial, we learned how to read and write CSV files using the Jackson data format library. We also looked at a few configuration options that help us get our data looking the way we want.
在这个快速教程中,我们学习了如何使用杰克逊数据格式库读写CSV文件。我们还看了一些配置选项,这些选项帮助我们以我们想要的方式获得数据。
As always, the code can be found over on GitHub.
一如既往,代码可以在GitHub上找到over。