※当サイトの記事には、広告・プロモーションが含まれます。

jackson-dataformat-csvでCSV形式からDTOやEntityの変換はCSVのフォーマットによっては難あり

nazology.net

⇧ 川で運搬できたとて、水平方向の移動は何とかなるとしても、垂直方向の移動はどうしていたのか気になりますな...

jackson-dataformat-csvCSV形式からDTOやEntityの変換はCSVのフォーマットによっては難あり

前前回、

ts0818.hatenablog.com

⇧ jackson-dataformat-csvで、JavaBean(DTOやEntity)からCSV形式の変換を行ったのだけど、その逆のことを実現するのに難があることが調査していて分かりましたと。

CSVファイルの全ての行が同じフォーマットになっていれば良いのですが、

cyzennt.co.jp

⇧ 上記サイト様のような、行によってフォーマットがバラバラなCSV形式のデータに対しては、jackson-dataformat-csvが対応しきれないっぽいので、CSVファイルの該当の行のみに絞り込みしてからでないと、JavaBean(DTOやEntity)への変換が厳しそうという...

試してみました。

前前回の記事の時に試したSpring Bootなプロジェクトにファイルを追加。

ソースコードは以下のような感じ。

■/dto-convert-to-csv/src/test/resources/testCsvFile.csv

1,20240521,0001,ほげほげ株式会社
2,A000001,ほげほげアメリカンプロテイン,10000,100
2,A000002,ほげほげアジアンプロテイン,8000,100
2,A000003,ほげほげヨーロピアンプロテイン,12000,100
2,A000004,ぴよぴよアメリカンプロテイン,11000,100
2,A000004,ぴよぴよアメリカンプロテイン,11000,100
2,A000005,ぽよぽよアメリカンプロテイン,13000,100
2,A000006,ぽよぽよアフリカンプロテイン,7000,100
9,8    

■/dto-convert-to-csv/src/main/java/com/example/demo/service/CreateDtoFromCsvData.java

package com.example.demo.service;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import org.springframework.stereotype.Service;

import com.example.demo.dto.ExaminationInfoData;
import com.fasterxml.jackson.databind.MappingIterator;
import com.fasterxml.jackson.dataformat.csv.CsvMapper;
import com.fasterxml.jackson.dataformat.csv.CsvSchema;

@Service
public class CreateDtoFromCsvData {

	public List<ExaminationInfoData> createDtoFromCsvData (File file) {
		
		List<ExaminationInfoData> examinationInfoDataList = new ArrayList<>();
		CsvMapper mapper = new CsvMapper();
		CsvSchema csvSchema = schemaForConvertCsvToBean(mapper, ExaminationInfoData.class);
		
		MappingIterator<ExaminationInfoData> iterator = null;
	    //BufferedReader reader = null;
		try (BufferedReader reader = new BufferedReader
			      (new InputStreamReader(new FileInputStream(file), "UTF-8"));) {
			
			String currentLine = null;
			while ((currentLine = reader.readLine()) != null) {
				if (Objects.nonNull(currentLine)) {
					String[] csvColumnForOneRow =  currentLine.split(",");
					// データ部の場合
					if (Objects.nonNull(csvColumnForOneRow[0])
						 &&	"2".equals(csvColumnForOneRow[0])) {
						ExaminationInfoData examinationInfoData = mapper.readerFor(ExaminationInfoData.class)
						.with(csvSchema)
						.readValue(currentLine);
						//.readValues(currentLine);
						examinationInfoDataList.add(examinationInfoData);
					}					
				}			
			}	
			
		} catch (IOException e) {
			// TODO 自動生成された catch ブロック
			e.printStackTrace();
		}
		
//		while (iterator.hasNext()) {
//			ExaminationInfoData examinationInfoData = iterator.next();
//			examinationInfoDataList.add(examinationInfoData);
//		}
		return examinationInfoDataList;
		
	}
	
	private static CsvSchema schemaForConvertCsvToBean(CsvMapper mapper, Class<?> clasz) {

		CsvSchema schema = mapper.schemaFor(clasz).withoutHeader();
		//CsvSchema schema = mapper.schemaFor(clasz).withHeader();

		return schema;
	}
	
}
    

動作確認用のソースコード

■/dto-convert-to-csv/src/test/java/com/example/demo/service/TestCreateDtoFromCsvData.java

package com.example.demo.service;

import java.io.File;
import java.net.URL;
import java.util.List;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import com.example.demo.dto.ExaminationInfoData;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.dataformat.csv.CsvMapper;
import com.fasterxml.jackson.dataformat.csv.CsvSchema;

@SpringBootTest
public class TestCreateDtoFromCsvData {

	@Autowired
	private CreateDtoFromCsvData createDtoFromCsvData;
	
	@Test
	public void test() {
//		ClassLoader cl = ClassLoader.getSystemClassLoader(); 
//		Thread.currentThread().setContextClassLoader(cl);
		URL url = Thread.currentThread().getContextClassLoader().getResource("testCsvFile.csv");
		//		URL url = this.getClass().getClassLoader().getResource("testCsvFile.csv");
		File file = new File(url.getPath());
		List<ExaminationInfoData> examinationInfoDataList = createDtoFromCsvData.createDtoFromCsvData(file);
		
		CsvMapper mapper = new CsvMapper();
		CsvSchema csvSchemaData = schemaForConvertBeanToCsvStr(mapper, ExaminationInfoData.class);

		StringBuilder sb = new StringBuilder();
		for (ExaminationInfoData examinationInfoData: examinationInfoDataList) {
			try {
				sb.append(mapper.writer(csvSchemaData).writeValueAsString(examinationInfoData));

			} catch (JsonProcessingException e) {
				// TODO 自動生成された catch ブロック
				e.printStackTrace();
			}
			
		}
		System.out.println(sb.toString());
	}
	
	private static CsvSchema schemaForConvertBeanToCsvStr(CsvMapper mapper, Class<?> clasz) {

		CsvSchema schema = mapper.schemaFor(clasz).withoutHeader();
		//CsvSchema schema = mapper.schemaFor(clasz).withHeader();

		return schema;
	}
	
	
}
   

⇧ 上記以外は、前々回の記事の時のものを利用。

で、JUnitで動作確認してみる。

CSVファイルの内容の内、データレコード部分のみ、JavaBean(DTOやEntity)に変換できたようです。

とりあえず、CSV形式の文字列からJavaBean(DTOやEntity)への変換もjackson-dataformat-csvで実現できそうではあると。

CSVのフォーマットが変則的な場合は、変換に難ありな気がしますかね...

毎度モヤモヤ感が半端ない…

今回はこのへんで。