Niels Masdorp Niels Masdorp - 12 days ago 9
Java Question

Complex Java object to CSV

I'm trying to generate a CSV file from a rather complex Java object. The object is a Session with some attributes and a list of Strings and Messages who in turn have some attributes and a list of Comments that have some attributes.

The session class is as follows;

public class Session {

private Long id;

private Date startDate;

private Date endDate;

private List<Message> messages;

private List<String> participants;

public TweetSession() {
}

public TweetSession(Date startDate, List<Message> messages, List<String> participants) {
this.startDate = startDate;
this.messages = messages;
this.participants = participants;
}

public Long getId() {
return id;
}

public Date getStartDate() {
return startDate;
}

public void setStartDate(Date startDate) {
this.startDate = startDate;
}

public Date getEndDate() {
return endDate;
}

public void setEndDate(Date endDate) {
this.endDate = endDate;
}

public List<Message> getMessages() {
return messages;
}

public void setMessage(List<Message> messages) {
this.message = message;
}

public List<String> getParticipants() {
return participants;
}

public void setParticipants(List<String> participants) {
this.participants = participants;
}
}


The message class is as follows;

public class Message {

private Long id;

private Session session;

private Date date;

private String participant;

private String content;

private List<Comment> comments;

public Message() {
}

public Message(String participant, Session session, Date date, String content) {
this.participant = participant;
this.session = session;
this.content = content;
this.date = date;
this.comments = new ArrayList<>();
}

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getParticipant() {
return participant;
}

public void setParticipant(String participant) {
this.participant = participant;
}

public String getContent() {
return content;
}

public void setContent(String content) {
this.content = content;
}

public List<Comment> getComments() {
return comments;
}

public void setComments(List<Comment> comments) {
this.comments = comments;
}

public void addComment(Comment comment) {
this.comments.add(comment);
}

public Date getDate() {
return date;
}

public void setDate(Date date) {
this.date = date;
}

public TweetSession getSession() {
return session;
}

public void setSession(TweetSession session) {
this.session = session;
}
}


And the Comment class;

public class Comment {

private Long id;

private Message message;

private String participant;

private String message;

private Date date;

public Comment() {
}

public Comment(String participant, Message message, String content, Date date) {
this.participant = participant;
this.content = content;
this.message = message;
this.date = date;
}

public String getParticipant() {
return participant;
}

public void setParticipant(String participant) {
this.participant = participant;
}

public Message getMessage() {
return message;
}

public void setMessage(Message message) {
this.message = message;
}

public Date getDate() {
return date;
}

public void setDate(Date date) {
this.date = date;
}

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getContent() {
return content;
}

public void setContent(String content) {
this.content = content;
}
}


I'm wondering if it is possible to map this to a CSV file. When I convert the session object to JSON format and convert that JSON to CSV in an online generator I get the proper output so I think it must be possible. I just don't really know how.
I've tried using the net.sf.supercsv library like this;

public void generateCSV(Session session, HttpServletResponse response) throws IOException {
String csvFileName = "session.csv";
response.setContentType("text/csv");

String headerKey = "Content-Disposition";
String headerValue = String.format("attachment; filename=\"%s\"",
csvFileName);
response.setHeader(headerKey, headerValue);

ICsvBeanWriter csvWriter = new CsvBeanWriter(response.getWriter(),
CsvPreference.STANDARD_PREFERENCE);

// Generate header for the CSV
Field fields[] = session.getClass().getDeclaredFields();
String[] header = new String[fields.length];
for (int i = 0; i < fields.length; i++) {
header[i] = fields[i].getName();
}

csvWriter.writeHeader(header);

// Generate CSV content from data
csvWriter.write(session, header);

csvWriter.close();
}


But this will of course not give the desired result.

Can anyone point me in the right direction?

Thanks in advance,

Niels

Edit:

This is a sample session in JSON format:

{
"id": 22,
"startDate": 1447368081000,
"endDate": null,
"messages": [
{
"id": 10,
"date": 1447368159000,
"participant": "1",
"content": "This is a message",
"comments": []
},
{
"id": 11,
"date": 1447368168000,
"participant": "1",
"content": "This is also a message",
"comments": []
},
{
"id": 12,
"date": 1447368179000,
"participant": "1",
"content": "This is another message",
"comments": [
{
"id": 10,
"participant": "1",
"message": "This is a comment",
"date": 1447368227000
},
{
"id": 11,
"participant": "1",
"message": "This is also a comment",
"date": 1447368234000
}
]
}
],
"participants": [
"1",
"23"
]
}


When I convert this to CSV I get something like this:

CSV

Indeed starting to think (a single) CSV might not be the best approach to this problem.

Answer

The data you have has many 1:n dependencies in it and is not really fit for a single CSV file.

Approaches I've used or seen used for this:

  • One "hybrid" CSV with Session's own data, i.e. id, startDate, endDate in first columns and then two columns for messages and participants printed as a JSON

    "123", "2015-11-17", "2015-11-18", "[{id: 345, date: ...}, {id: 789, date: ...}]", "[...]"
    

    (notice you'll need to use a good CSV library that escapes the values containing , or "s)

  • Multiple CSV files - modeled like you'd model a relational database for your structure, i.e.

    • sessions.csv containing id, startDate, endDate
    • messages.csv containing id, session_id, date, ...
    • ...

    then ZIP them for a single file download

  • Ask your user for a more precise specification - work to find out what they intend to do with the data, then give them a "view" of the data in a format that will enable them to read them easily - just the way database views and reports are created to give users a task-oriented view of data.