0

Is there a way to convert the map to json string by json schema? I need to do that by json schema because I don't know if the object in the map is a string or a number. For example, I have csv that look like this:

name, year
1   , 1

I need to convert it to json string "{'name': '1', 'year': 1}" and I can know if 1 is a string (in a case of the name) or number (in a case of the year) only by json schema.

Tanveer Munir
  • 1,956
  • 1
  • 12
  • 27
pera.coyote
  • 41
  • 1
  • 10

5 Answers5

2

Jackson has a module to parse CSV documents. Assuming that you already have Jackson dependencies in your project, you jusy need to add the following depending:

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-csv</artifactId>
    <version>${jackson.version}</version>
</dependency>

Then create a class to define your schema and hold the values (pay attention to the @JsonPropertyOrder annotation, as it defines the order of the CSV columns):

@JsonPropertyOrder({"name", "year"})
public class Person {

    private String name;
    private Integer year;

    // Getters and setters   
}

Parse the CSV document to a list and finally write the list to a JSON string:

CsvMapper mapper = new CsvMapper();
CsvSchema schema = mapper.schemaFor(Person.class).withHeader();

MappingIterator<Object> iterator = mapper.readerFor(Person.class)
        .with(schema).readValues(new FileInputStream("/path/to/the/csv/file"));

String json = new ObjectMapper().writeValueAsString(iterator.readAll());
cassiomolin
  • 124,154
  • 35
  • 280
  • 359
1

You could try something like this using Jackson:

The only thing you need to implement by yourself is the second method to convert your CsvSchema.json to a Map containing the column name and the column type.

     public String generateJsonFromCSV() throws IOException {
        File csvFile = new File("path/to/csv/mycsv.csv");
        File schemaJson = new File("path/to/json/schema.json");
        Map<String, CsvSchema.ColumnType> map = getSchemaMapFromJson(schemaJson);
        CsvSchema.Builder schemaBuilder = new CsvSchema.Builder();
        map.forEach(schemaBuilder::addColumn);
        CsvSchema schema = schemaBuilder.build();
        CsvMapper csvMapper = new CsvMapper();
        MappingIterator<Map<?, ?>> mappingIterator = csvMapper.readerFor(Map.class).with(schema).readValues(csvFile);
        String json = new ObjectMapper().writeValueAsString(mappingIterator.readAll());
        return json;
    }

    //Convert your JsonSchema to Map<String,CsvSchema.ColumnType>
    private Map<String, CsvSchema.ColumnType> getSchemaMapFromJson(File file) {
        return new HashMap<>();
    }

Dependency:

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-csv</artifactId>
    <version>${jackson.version}</version>
</dependency>
DCO
  • 1,222
  • 12
  • 24
  • yes, this can be solution, thanks. I tried it but I had another problem with it, maybe you know the answer? https://stackoverflow.com/questions/55067378/jackson-csv-mapper-doesnt-work-for-custom-schema – pera.coyote Mar 11 '19 at 09:53
  • Tried around two hours and did not found a solution. Seems like Jackson ignores the schema. Another solution could be to transform the json to a new one respecting the schema – DCO Mar 11 '19 at 12:48
0

You can use org.json library:

Map<String, Object> map = new HashMap<>();
map.put("name", "1");
map.put("year", 1);
org.json.JSONObject obj = new org.json.JSONObject(map);
System.out.println(obj.toString());

Output:

{"year":1,"name":"1"}
devmind
  • 344
  • 2
  • 10
  • yep, but my map is: map.put("name", "1"); map.put("year", "1"); both values are strings, and in json schema is configuration that name is string, and year is number – pera.coyote Mar 08 '19 at 15:44
  • You gonna read it always as string. Then you can check it by StringUtils.isNumeric(year) and cast it to integer if it is numeric . – DCO Mar 08 '19 at 16:24
  • Here: https://stackoverflow.com/questions/1102891/how-to-check-if-a-string-is-numeric-in-java – DCO Mar 08 '19 at 16:29
  • It's not solution for name property, it should stay string – pera.coyote Mar 08 '19 at 16:32
  • I read it with com.fasterxml.jackson.dataformat.csv.CsvMapper – pera.coyote Mar 11 '19 at 08:26
0

You can use GSON for it. It is very easy to use und very powerful. For now I was able to solve every problem this lib. (https://github.com/google/gson)

// your map
Map<String, Object> map = new HashMap<>();
map.put("name", "1");
map.put("year", 1);

// create Gson instance
Gson gson = new GsonBuilder().create();

// convert to JSON
String jsonString = gson.toJson(map);

// convert back to map
Map map = gson.fromJson(jsonString, Map.class);
DCO
  • 1,222
  • 12
  • 24
-1

After I read your comments I suggest this is what you need. This is a simple Java Solution. I guess there are libraries which can help you parsing csv. I hope I was able to help you

Given CSV:

name,year
1,1
test,38
foo,78

Java Code:

    try {
        File file = ResourceUtils.getFile(this.getClass().getResource("/import.csv"));
        List<List<String>> lines = new ArrayList<>();
        try (BufferedReader br = new BufferedReader(new FileReader(file))) {
            String line;
            while ((line = br.readLine()) != null) {
                String[] values = line.split(",");
                lines.add(Arrays.asList(values));
            }
        }

        Map<String,Integer> resultMap = new HashMap<>();
        for (int i = 1; i < lines.size(); i++) {
            List<String> currentLine = lines.get(i);
            String name = currentLine.get(0);
            String year = currentLine.get(1);
            if(StringUtils.isNoneEmpty(name,year) && StringUtils.isNumeric(year)){
                resultMap.put(name,Integer.valueOf(year));
            }
        }

        Gson gson = new GsonBuilder().create();
        String jsonString = gson.toJson(resultMap);
        System.out.println(jsonString);

    } catch (IOException e) {
        System.out.println(e);
    }

The output will be:

{"1":1,"test":38,"foo":78}
DCO
  • 1,222
  • 12
  • 24