javacsvdata-bindingjacksonjackson-databind

CSV Parsing return null values for all fields when parsing CSV data


I'm trying to parse String CSV data into a Java object using CsvMapper. Here's the CSV schema and data format during debugging:

Parsing Method:

     @SuppressWarnings("unchecked")
    private <T> List<T> parseDataWithCsvMapper(String csvData, Class<?> modelClass) {
        try {
            CsvMapper csvMapper = CsvMapper.builder()
                    .enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES)
       .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
                    .build();

            CsvSchema schema = CsvSchema.builder()
                    .addColumn("FON KODU")
                    .addColumn("FON UNVANI")
                    ...
                    .build()
                    .withHeader();

            Reader reader = new StringReader(csvData);
            return (List<T>) csvMapper
                    .readerFor(modelClass)
                    .with(schema)
                    .readValues(reader)
                    .readAll();

        } catch (IOException e) {
            throw new RuntimeException("Failed to parse CSV data", e);
        }
    }

When I didn't manually add columns for headers, the CSV Schema during debugging::*

[CsvSchema: columns=[], header? true, skipFirst? false, comments? false, any-properties? N/A]

csvData during debugging:

FON KODU,FON UNVANI,FON ISIN KODU,FON OPERATÖR KODU,PARA BİRİMİ,İŞLEM BAŞLANGIÇ SAATİ,…
AAK,ATA PORTFÖY ÇOKLU VARLIK DEĞİŞKEN FON,TRMAF1WWWWW4,ATA,TL,09:00,17:30,…
AAL,ATA PORTFÖY PARA PİYASASI (TL) FONU,TRMAALWWWWW5,ATA,TL,09:00,13:30,…

Java Model Class:

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class TefasDataModel {
    @JsonProperty("FON KODU")
    private String fonKodu;
    @JsonProperty("FON UNVANI")
    private String fonUnvani;
    // Remaining fields match CSV headers.
}

Despite this, the output objects have all fields set to null. Example output:

[
    { "fonKodu": null, "fonUnvani": null, ... }
]

What I’ve Tried:

When I remove .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) method I'm getting this error:

com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "FON KODU" (class com.isuite.services.datajet.job.TefasDataModel), not marked as ignorable (24 known properties: "fonSatisValorAtlatmaSaati", "yarimGunIptalSaati", "fiyatMarjOrani", "fonSatisFiyatValor", "geriAlisAdetKati", "fonIsinKodu", "fonGeriAlisFiyatValor", "satisAdetKati", "iptalSonSaati", "minSatisAdet", "fonGeriAlisValor", "islemBaslangicSaati", "maksGeriAlisAdet", "fonSatisValor", "fonKodu", "islemBitisSaati", "fonGeriAlisValorAtlatmaSaati", "fonOperatorKodu", "fonUnvani", "maksSatisAdet", "minGeriAlisAdet", "yarimGunFonGeriAlisValorAtlSaati", "paraBirimi", "yarimGunFonSatisValorAtlSaati"])
 at [Source: (StringReader); line: 2, column: 5] (through reference chain: com.isuite.services.datajet.job.TefasDataModel["FON KODU"])

What might be causing this issue? How can I resolve it to correctly map the CSV data to the model?


Solution

  • After researching, I found that CsvSchema should be written like this, specifying the model we are converting and also defining the line and column separators:

    public static <T> List<T> parseCsvData(String csvData, Class<T> modelClass) {
        try {
            CsvMapper csvMapper = CsvMapper.builder()
                    .enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES)
                    .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
                    .build();
    
            CsvSchema schema = csvMapper.typedSchemaFor(modelClass)
                    .withHeader()
                    .withColumnSeparator(',')
                    .withColumnReordering(true);
    
            List<String> headers = schema.getColumnNames();
            System.out.println("CSV Headers: " + headers);
            
            Reader reader = new StringReader(csvData);
            return (List<T>) csvMapper
                    .readerFor(modelClass)
                    .with(schema)
                    .readValues(reader)
                    .readAll();
        } catch (IOException e) {
            throw new RuntimeException("Failed to parse CSV data", e);
        }
    }