2

Hi I am trying to convert a CSV file into a JSON array using A dependency called csvReader, but when I run the code it prints out the JSON response incorrectly and I ament sure why would anyone be able to point me in the right direction.

    @GetMapping("/convert")
    public List<List<String>> convertCSV() throws FileNotFoundException {
        List<List<String>> records = new ArrayList<List<String>>();
    try (CSVReader csvReader = new CSVReader(new FileReader("C:/Download/cities.csv"));) {
        String[] values = null;

    while ((values = csvReader.readNext()) != null) {
        records.add(Arrays.asList(values));
    }

} catch (IOException e) {
            e.printStackTrace();
        }
        return values;
    }
enter image description here
Conor Donohoe
  • 317
  • 1
  • 3
  • 18
  • 2
    What is wrong with the output? The output consists of array of arrays of strings, which I would expect looking at the code, because `convertCSV` returns `List>`. – Yury Nevinitsin Jan 29 '20 at 10:27
  • 1
    Can you explain this `prints out the JSON response incorrectly` ? What is incorrect? – KunLun Jan 29 '20 at 10:27
  • I need it to print "latD": "41", "LatM":"5", "LatS":"59", "NS":"N", etc... do I just have to change the type from list to array, for more context I need an Angular 7 frontend to be able to loop through the arrays – Conor Donohoe Jan 29 '20 at 10:32
  • Some of the answers parse the CSV by splitting on `\n` and `,`: this isn't recommended because it doesn't follow the RFC (4180 in this case, for example [_"Fields containing line breaks (CRLF), double quotes, and commas should be enclosed in double-quotes"_](https://datatracker.ietf.org/doc/html/rfc4180#section-2)). You should rather use a 3rd-party tool which handles this for you, for example [Opencsv](https://opencsv.sourceforge.net/) (just like what the OP seems to use). – sp00m Dec 14 '22 at 11:56

3 Answers3

3

That is because of your reading data in String and printing the List of String. If you want to map the CSV to Object ( JSON Object), You need to read the CSV as bean object please find below code snippet to print as JSON, override toString method as JSON format.

User.java

public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @NotNull
    private String name;

    @NotNull
    private String surname;

    //Getter and Setters
}

CsvReaderUtil.java

public static List<User> readCsvFile() throws IOException {
            List<User> list = null;
            CSVReader reader = null;
            InputStream is = null;
            try {
                File initialFile = new File("C:\\Users\\ER\\Desktop\\test.csv");
                is = new FileInputStream(initialFile);
                reader = new CSVReader(new InputStreamReader(is), ',', '"', 1);
                ColumnPositionMappingStrategy strat = new ColumnPositionMappingStrategy();
                strat.setType(User.class);
                String[] columns = new String[]{"id", "name", "surname"};
                strat.setColumnMapping(columns);
                CsvToBean csv = new CsvToBean();
                list = csv.parse(strat, reader);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                is.close();
                reader.close();
            }
            return list;
        }

Now print this List Of Users as a JSON object.

Yogeen Loriya
  • 589
  • 2
  • 5
  • Im getting this error: No serializer found for class com.poc.demo.models.Host and no properties discovered to create BeanSerializer – Conor Donohoe Jan 29 '20 at 12:41
  • Can you please post the code as well so that I can get more idea of it. – Yogeen Loriya Jan 29 '20 at 12:44
  • The problem was that jackson needs the getters and setters to be public Found the answer here -> https://stackoverflow.com/questions/8367312/serializing-with-jackson-json-getting-no-serializer-found the code hasn't changed from what you posted just renamed the file to Hosts from users now I just need to figure out why Im getting null – Conor Donohoe Jan 29 '20 at 12:50
1

Your case is not a big deal.

You can read that csv and build json.

Read first row and determine columns. The rest of rows are values.

public class Foo{

    public static void main(String[] args) throws Exception{

        List<String> csvRows = null;
        try(var reader = Files.lines(Paths.get("dataFile.csv"))){
            csvRows = reader.collect(Collectors.toList());
        }catch(Exception e){
            e.printStackTrace();
        }

        if(csvRows != null){

            String json = csvToJson(csvRows);
            System.out.println(json);

        }

    }

    public static String csvToJson(List<String> csv){

        //remove empty lines
        //this will affect permanently the list. 
        //be careful if you want to use this list after executing this method
        csv.removeIf(e -> e.trim().isEmpty());

        //csv is empty or have declared only columns
        if(csv.size() <= 1){
            return "[]";
        }

        //get first line = columns names
        String[] columns = csv.get(0).split(",");

        //get all rows
        StringBuilder json = new StringBuilder("[\n");
        csv.subList(1, csv.size()) //substring without first row(columns)
            .stream()
            .map(e -> e.split(","))
            .filter(e -> e.length == columns.length) //values size should match with columns size
            .forEach(row -> {

                json.append("\t{\n");

                    for(int i = 0; i < columns.length; i++){
                        json.append("\t\t\"")
                            .append(columns[i])
                            .append("\" : \"")
                            .append(row[i])
                            .append("\",\n"); //comma-1
                    }

                    //replace comma-1 with \n
                    json.replace(json.lastIndexOf(","), json.length(), "\n");

                json.append("\t},"); //comma-2

            });

        //remove comma-2
        json.replace(json.lastIndexOf(","), json.length(), "");

        json.append("\n]");

        return json.toString();

    }

}

Tested on:

fname,lname,note
Shaun,Curtis,a
Kirby,Beil,b

-----------------------

[
    {
        "fname" : "Shaun",
        "lname" : "Curtis",
        "note" : "a"
    },  {
        "fname" : "Kirby",
        "lname" : "Beil",
        "note" : "b"
    }
]

This method work on any structure of csv. Don't need to map columns.

KunLun
  • 3,109
  • 3
  • 18
  • 65
  • By any chance would you be able to tell me how to write this for java 1.8 I have to downgrade from 12 and var isant accepted? – Conor Donohoe Jan 30 '20 at 15:08
  • `var`(introduced in java10) it's like a shortcut and represent the type of the value it get when is declared. In this case `Stream`. Anything incompatible? – KunLun Jan 30 '20 at 15:17
  • Welcome. Tip: Even if you use a `dependency`, try to think your own solution for your problem, even if it's bad and it's a waste of time cause you don't use it. In time it will help you. – KunLun Jan 30 '20 at 16:35
  • Is this source ok to convert csv which contains boolean or integer values? – niddddddfier Apr 07 '22 at 09:06
  • @niddddddfier, It passed some time since I typed this solution. As a quick review, I say yes. Every type of data(actually everything from CSV is a `String`) from CSV will be `String` in JSON. – KunLun Apr 13 '22 at 15:37
-1

Here is a useful example of how to transform CSV to JSON using Java 11+:

private String fromCsvToJson(String csvFile) {
    String[] lines = file.split("\n");

    if (lines.length <= 1) {
        return List.of();
    }

    var headers = lines[0].split(",");
    var jsonFormat = Arrays.stream(lines)
                           .skip(1)
                           .map(line -> line.split(","))
                           .filter(line -> headers.length == line.length)
                           .map(line -> IntStream.range(0, headers.length).boxed().collect(toMap(i -> headers[i], i -> line[i], (a, b) -> b)))
                           .toList();

    return new ObjectMapper().writeValueAsString(jsonFormat);
}
Oleksandr
  • 450
  • 1
  • 6
  • 13