I'm using the fantastic Univocity CSV Parser (thumbs up to the author!) but I'm struggling to find a solution for my problem.
Let's use a CSV with 10 fields. User uploads the CSV and chooses 2 columns, discarding the other 8. Upload is done to a Java Spring Rest Service with the file containing all 10 columns + a JSON object with the selected columns. The goal is to have the REST service get the file, parse it and generate POJO objects where:
i couldn't find a way to do it using the library. But maybe I missed something. Anyone knows if this is possible with Univocity CSV Parser libs ? How can this be implemented?
Thanks in advance
You can achieve this functionality using the Univocity CSV Parser in combination with Jackson, a JSON library for Java.
public class CsvData {
private String propertyA;
private String propertyB;
private Map<String, String> propertyC;
// Getters and setters
}
import com.univocity.parsers.csv.CsvParser;
import com.univocity.parsers.csv.CsvParserSettings;
import org.springframework.stereotype.Service;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Service
public class CsvParserService {
public List<CsvData> parseCsv(InputStream inputStream, Map<String, Object> selectedColumnsMap) {
List<CsvData> csvDataList = new ArrayList<>();
CsvParserSettings settings = new CsvParserSettings();
settings.detectFormatAutomatically();
CsvParser parser = new CsvParser(settings);
parser.beginParsing(new InputStreamReader(inputStream));
String[] headers = parser.parseNext();
String propertyAHeader = (String) selectedColumnsMap.get("propertyA");
String propertyBHeader = (String) selectedColumnsMap.get("propertyB");
int[] propertyCIndexes = new int[headers.length - 2];
int propertyCIndex = 0;
for (int i = 0; i < headers.length; i++) {
if (!headers[i].equals(propertyAHeader) && !headers[i].equals(propertyBHeader)) {
propertyCIndexes[propertyCIndex++] = i;
}
}
String[] row;
while ((row = parser.parseNext()) != null) {
CsvData csvData = new CsvData();
csvData.setPropertyA(row[propertyAIndex]);
csvData.setPropertyB(row[propertyBIndex]);
Map<String, String> propertyC = new HashMap<>();
for (int index : propertyCIndexes) {
propertyC.put(headers[index], row[index]);
}
csvData.setPropertyC(propertyC);
csvDataList.add(csvData);
}
return csvDataList;
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
@RestController
public class CsvUploadController {
@Autowired
private CsvParserService csvParserService;
@PostMapping("/upload")
public ResponseEntity<List<CsvData>> uploadCsv(@RequestParam("file") MultipartFile file,
@RequestParam("selectedColumns") String selectedColumns) {
try {
ObjectMapper objectMapper = new ObjectMapper();
Map<String, Object> selectedColumnsMap = objectMapper.readValue(selectedColumns, new TypeReference<Map<String, Object>>() {});
List<CsvData> csvDataList = csvParserService.parseCsv(file.getInputStream(), selectedColumnsMap);
return ResponseEntity.ok(csvDataList);
} catch (IOException e) {
e.printStackTrace();
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
}