JavaでJSONをCSVに変換する

1. 前書き

この短いチュートリアルでは、Jacksonを使用してJSONをCSVに、またはその逆に変換する方法を説明します。
link:/java-org-json#cdl[org.jsonのCDLクラス]のような代替ライブラリが利用可能ですが、ここではJacksonライブラリに焦点を当てます。
サンプルのデータ構造を確認した後、https://www.baeldung.com/jackson-object-mapper-tutorial [_ObjectMapper_]とCSVMapperの組み合わせを使用してJSONとCSVを変換します。

2. 依存関係

Jackson CSVデータフォーマッタの依存関係を追加しましょう。
<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-csv</artifactId>
    <version>2.9.8</version>
</dependency>
この依存関係の最新バージョンは、https://search.maven.org/search?q = g:com.fasterxml.jackson.dataformat%20AND%20a:jackson-dataformat-csvでいつでも見つけることができます。
Jacksonのコアデータバインドの依存関係も追加します。
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.8</version>
</dependency>
繰り返しますが、この依存関係の最新バージョンはhttps://search.maven.org/search?q=g:com.fasterxml.jackson.core%20AND%20a:jackson-databindで見つけることができます

3. データ構造

JSONドキュメントをCSVに再フォーマットする前に、2つのフォーマット間でデータモデルがどの程度うまくマッピングされるかを考慮する必要があります。
最初に、さまざまな形式がサポートするデータを検討しましょう。
  • JSONを使用して、次のようなさまざまなオブジェクト構造を表します。
    配列とネストされたオブジェクトを含むもの

  • CSVを使用して、各オブジェクトのオブジェクトのリストからデータを表します
    新しい行に表示されるリストから

    つまり、JSONドキュメントにオブジェクトの配列がある場合、各オブジェクトをCSVファイルの新しい行に再フォーマットできます。 そのため、例として、注文からの次のアイテムリストを含むJSONドキュメントを使用します。
[ {
  "item" : "No. 9 Sprockets",
  "quantity" : 12,
  "unitPrice" : 1.23
}, {
  "item" : "Widget (10mm)",
  "quantity" : 4,
  "unitPrice" : 3.45
} ]
JSONドキュメントのフィールド名を列ヘッダーとして使用し、次のCSVファイルに再フォーマットします。
item,quantity,unitPrice
"No. 9 Sprockets",12,1.23
"Widget (10mm)",4,3.45

*4. JSONの読み取りとCSVの書き込み

*
最初に、Jacksonの_ObjectMapper_を使用して、サンプルJSONドキュメントを_JsonNode_オブジェクトのツリーに読み取ります。
JsonNode jsonTree = new ObjectMapper().readTree(new File("src/main/resources/orderLines.json"));
次に、_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();
*次に、_CsvSchema_で_CsvMapper_を作成し、最後に、CSVファイルに_jsonTree_を書き込みます*:
CsvMapper csvMapper = new CsvMapper();
csvMapper.writerFor(JsonNode.class)
  .with(csvSchema)
  .writeValue(new File("src/main/resources/orderLines.csv"), jsonTree);
このサンプルコードを実行すると、JSONドキュメントの例が期待されるCSVファイルに変換されます。

*5. CSVを読み取り、JSONを書き込む

*
それでは、Jacksonの_CsvMapper_を使用して、CSVファイルを_OrderLine_オブジェクトの_List_に読み込みます。 これを行うには、最初に_OrderLine_クラスを単純なPOJOとして作成します。
public class OrderLine {
    private String item;
    private int quantity;
    private BigDecimal unitPrice;

    // Constructors, Getters, Setters and toString
}
CSVファイルの列ヘッダーを使用して、_CsvSchema_を定義します。 *そして、* * CSVからのデータを_CsvMapper_を使用して* _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"));
次に、_MappingIterator_を使用して、_OrderLine_オブジェクトの_List_を取得します。 次に、Jacksonの_ObjectMapper_を使用して、リストをJSONドキュメントとして書き出します。
new ObjectMapper()
  .configure(SerializationFeature.INDENT_OUTPUT, true)
  .writeValue(new File("src/main/resources/orderLinesFromCsv.json"), orderLines.readAll());
このサンプルコードを実行すると、サンプルのCSVファイルは、予想されるJSONドキュメントに変換されます。

*6. CSVファイル形式の構成

*
Jacksonの注釈のいくつかを使用して、CSVファイルの形式を調整しましょう。 _â€〜item'_列見出しを_â€〜name'_に、_â€〜quantity'_列見出しを_âcountに変更し、_â€〜unitPrice'_列を削除して、 _â€〜count'_最初の列。
したがって、予想されるCSVファイルは次のようになります。
count,name
12,"No. 9 Sprockets"
4,"Widget (10mm)"
新しい抽象クラスを作成して、CSVファイルに必要な形式を定義します。
@JsonPropertyOrder({
    "count",
    "name"
})
public abstract class OrderLineForCsv {

    @JsonProperty("name")
    private String item;

    @JsonProperty("count")
    private int quantity;

    @JsonIgnore
    private BigDecimal unitPrice;

}
次に、_OrderLineForCsv_クラスを使用して_CsvSchema_を作成します。
CsvMapper csvMapper = new CsvMapper();
CsvSchema csvSchema = csvMapper
  .schemaFor(OrderLineForCsv.class)
  .withHeader();
また、_OrderLineForCsv_をJackson Mixinとして使用します。 これは、_OrderLine_オブジェクトを処理するときに、_OrderLineForCsv_クラスに追加した注釈を使用するようにJacksonに指示します。
csvMapper.addMixIn(OrderLine.class, OrderLineForCsv.class);
最後に、_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);
このサンプルコードを実行すると、JSONドキュメントの例が期待されるCSVファイルに変換されます。

*7. 結論

*
このクイックチュートリアルでは、Jacksonデータ形式ライブラリを使用してCSVファイルを読み書きする方法を学びました。 また、データを希望どおりに表示するのに役立ついくつかの構成オプションも検討しました。
いつものように、コードはhttps://github.com/eugenp/tutorials/tree/master/jackson-2[GitHubで]にあります。