2

I'm trying to develop an application that convert JSON to CSV.

I'm using JACKSON to parse JSON and write CSV.

Here is an example of a JSON I'm trying to parse :

{ "_id" : 0, 
 "name" : "aimee Zank", 
 "scores" : 
           [ 
             { "type" : "exam", "score" :   1.463179736705023 }, 
             { "type" : "quiz", "score" : 11.78273309957772 },  
             { "type" : "homework", "score" : 6.676176060654615 },  
             { "type" : "homework", "score" : 35.8740349954354 } 
            ] 
     }

  { "_id" : 1, 
    "name" : "Aurelia Menendez", 
    "scores" : 
              [ 
                { "type" : "exam", "score" : 60.06045071030959 }, 
                { "type" : "quiz", "score" : 52.79790691903873 }, 
                { "type" : "homework", "score" : 71.76133439165544 }, 
                { "type" : "homework", "score" : 34.85718117893772 } 
             ] 
       }

 { "_id" : 2, 
  "name" : "Corliss Zuk", 
   "scores" : 
             [ 
              { "type" : "exam", "score" : 67.03077096065002 }, 
              { "type" : "quiz", "score" : 6.301851677835235 }, 
              { "type" : "homework", "score" : 20.18160621941858 }, 
              { "type" : "homework", "score" : 66.28344683278382 } 
             ] 
         }

The two Java Classes :

JsonNode class

public class JsonNode {

private String _id;
private String name;
private Collection<ScoreType> scores;

/**
 * @return the _id
 */
public String get_id() {
    return _id;
}
/**
 * @param _id the _id to set
 */
public void set_id(String _id) {
    this._id = _id;
}
/**
 * @return the name
 */
public String getName() {
    return name;
}
/**
 * @param name the name to set
 */
public void setName(String name) {
    this.name = name;
}
/**
  * @return the scores
 */
public Collection<ScoreType> getScores() {
    return scores;
}
/**
  * @param scores the scores to set
 */
public void setScores(Collection<ScoreType> scores) {
    this.scores = scores;
 }
 }

ScoreType class

public class ScoreType {
private String type;
private String score;
/**
 * @return the type
 */
public String getType() {
    return type;
}
/**
 * @param type the type to set
 */
public void setType(String type) {
    this.type = type;
}
/**
 * @return the score
 */
public String getScore() {
    return score;
}
/**
 * @param score the score to set
 */
public void setScore(String score) {
    this.score = score;
}

}

The method that convert JSON to CSV

  ObjectMapper mapper=new ObjectMapper();

    JsonNode jsonNode=mapper.readValue(new File("C:\\...\\...\\...\\test.json"), JsonNode.class);

    CsvMapper csvMapper=new CsvMapper();
    CsvSchema schema=csvMapper.schemaFor(JsonNode.class);

    schema=schema.withColumnSeparator(';');

    ObjectWriter myObjectWriter=csvMapper.writer(schema);

    FileOutputStream tempFileOutputStream=new FileOutputStream(out+"\\jsontocsv.csv");
    BufferedOutputStream bufferedOutputStream=new BufferedOutputStream(tempFileOutputStream);
    OutputStreamWriter writerOutputStream=new OutputStreamWriter(bufferedOutputStream,"UTF-8");

    myObjectWriter.writeValue(writerOutputStream,jsonNode);

The console output :

com.fasterxml.jackson.core.JsonGenerationException: CSV generator does not support 

Array values for properties

The CSV output :

"0";"aimee Zank";

That's what I have done so far.

So I'm facing two issues here :

1) The output CSV is not complete, it creates only one line and don't write scores.

2) The error in the console.

I'm using these JACKSON depandencies :

  <dependency>
        <groupId>com.fasterxml.jackson.dataformat</groupId>
        <artifactId>jackson-dataformat-csv</artifactId>
        <version>2.4.0</version>
    </dependency> 

Can anyone help me solving these issues ?

I hope I was clear enough.

Edits CSV I'm expecting :

_id;name;scores.type;scores.score;scores.type;scores.score;scores.type;scores.score
0;aimee Zank;exam;1.46;quiz;11.78;homework;6.67;homework;35.87

Ismail

5
  • Can you give an example how you want it in csv? i mean what a row in csv should look like Commented Jul 17, 2014 at 9:21
  • You are mixing 1.x and 2.x Jackson versions. Stick to 2.x. Commented Jul 17, 2014 at 9:26
  • @IsmailSen you have wrong library dependency. Refer to this page: github.com/FasterXML/jackson-core Commented Jul 17, 2014 at 9:38
  • @AlexeyGavrilov I've corrected the maven depandecies. I only use com.fasterxml.jackson.core Commented Jul 17, 2014 at 9:42
  • @pratim_b I've added CSV output I want in the Edits Commented Jul 17, 2014 at 10:15

2 Answers 2

1

Since a CSV is a tuple of simple values, it does indeed not support collections (JSON arrays) as column values. You have a Collection<ScoreType> as one of your bean's properties and this is causing your error.

Suggestion: add a String getter which turns your collection into a string, and build a CSV schema manually to avoid automatically using the Collection-valued column.

Sign up to request clarification or add additional context in comments.

2 Comments

could you please details more yout suggestion
While CSV does not indeed have a native array/list type, Jackson does allow use of "in-cell" separators for logical arrays. Default separator is semicolon (character ;), and as long as your property type is Java array or Collection, things should work with new enough Jackson CSV module version (at least 2.5 is needed I think).
0

Try using custom json serializer for Collection attribute in JsonNode class and convert list to string.

public class JsonNode {

private String _id;
private String name;
@JsonSerialize(using=CollectionSerializer.class)
private Collection<ScoreType> scores;

}


public class CollectionSerializer extends StdSerializer<Collection<Object>> {
    private static final long serialVersionUID = 1L;

    protected CollectionSerializer(Class<Collection<Object>> t) {
        super(t);
    }

    public CollectionSerializer() {
        this(null);
    }

    @Override
    public void serialize(Collection<Object> value, JsonGenerator gen, SerializerProvider provider) throws IOException {

        gen.writeString(value.stream().map(String::valueOf).collect(Collectors.joining(",")).toString());

    }

}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.