I want to return an object in CSV format with multi-line header & filter in Java

1.First of all

Since it was necessary to create a csv format that can filter output fields by multi-line header and field name, describe the program that was considered to be the library used.

2.CsvMapper/CsvSchema

You can easily convert an object (json) to csv with Jackson's library (jackson-dataformat-csv). I used this this time.

// getter/setter is required but omitted
class TestObj {
  private String field1 = "aaa";
  private String field2 = null;
  private String field3 = "ccc";
}
TestObj obj = new TestObj();
CsvMapper mapper = new CsvMapper();
CsvSchema schema = mapper.schemaFor(TestObj.class).withHeader();

try {
  System.out.println(mapper.writer(schema).writeValueAsString(obj));
} catch(JsonProcessingException e) {
  //Error handling (provisional)
  e.printStackTrace();
}

[output]

field1,field2,field3
aaa,,ccc

You can also do the following

CsvMapper mapper = new CsvMapper();
CsvSchema schema = mapper.schemaFor(TestObj.class).withHeader().withNullValue("<empty>");

[output]

field1,field2,field3
aaa,<empty>,ccc
CsvMapper mapper = new CsvMapper();
CsvSchema schema = mapper.schemaFor(TestObj.class).withHeader().withLineSeparator("|");

[output]

"field1","field2","field3"|"aaa",,"ccc"|
List<TestObj> objs = new ArrayList<TestObj>() {
  {
    add(new TestObj());
    add(new TestObj());
    add(new TestObj());
  }
};
CsvMapper mapper = new CsvMapper();
CsvSchema schema = mapper.schemaFor(TestObj.class).withHeader();

[output]

field1,field2,field3
aaa,,ccc
aaa,,ccc
aaa,,ccc

It should be noted that it does not support the following changes to nested objects.

//Can be converted to csv
class TestObj {
  private String field1 = "aaa";
  private String field2 = "bbb";
  private String field3 = "ccc";
}

//Cannot be converted to csv
class TestObj2 {
  TestObj obj = new TestObj();
  private String field4 = "aaa";
}

3. Filter by multi-line header & field and output

Create something that outputs the field name and type name of the object as a header (2 lines).

Unfortunately, jackson doesn't support multiple headers or filters, so I created it myself.


public static void main(String[] args) {
	TestObj obj = new TestObj();
	List<Field> fields = Arrays.asList(obj.getClass().getDeclaredFields());
	CsvMapper mapper = new CsvMapper();
	CsvSchema schema = mapper.schemaFor(TestObj.class);
	
	//Field to filter (originally external input)
	List<String> filterParam = new ArrayList<String>() {
		{
			add("field1");
			add("field3");
		}
	};
	//Create multiple headers & filters
	String header = createHeader(obj, filterParam, fields);
	List<String> bodies = new ArrayList<>();
	try {
		bodies = Arrays.asList(mapper.writer(schema).writeValueAsString(obj).split(","));
	} catch (JsonProcessingException e) {
		//Error handling (provisional)
		e.printStackTrace();
	}
	String body = filter(bodies, filterParam, fields);
	
	//Originally connected and returned
	System.out.println(header);
	System.out.println(body);
}

private static String createHeader(TestObj obj, List<String> param, List<Field> fields) {
	String fieldHeader = fields.stream().filter(o -> param.contains(o.getName())).map(o -> o.getName
)
			.collect(Collectors.joining(","));
	String typeHeader = fields.stream().filter(o -> param.contains(o.getName())).map(o -> {
		String typeName = o.getType().getName();
		return typeName.substring(typeName.lastIndexOf(".") + 1, typeName.length());
	}).collect(Collectors.joining(","));
	return fieldHeader + "\n" + typeHeader;
}

private static String filter(List<String> bodies, List<String> param, List<Field> fields) {
	if (param == null || param.isEmpty()) {
		return bodies.stream().collect(Collectors.joining(","));
	}
	List<String> res = new ArrayList<>();
	for (int i = 0; i < fields.size(); i++) {
		String fieldName = fields.get(i).getName();
		if (param.contains(fieldName)) {
			res.add(bodies.get(i));
		}
	}
	return res.stream().collect(Collectors.joining(","));
}

[Output result]

field1,field3
String,String
aaa,ccc

Reference site

CsvSchema http://fasterxml.github.io/jackson-dataformat-csv/javadoc/2.8/com/fasterxml/jackson/dataformat/csv/CsvSchema.html#withoutColumns()

Several ways to concatenate strings separated by commas in Java https://qiita.com/shisama/items/b27d16b3aeb1baf055b1

String concatenation in Java 8 https://qiita.com/lonerydeveloper/items/9f7c977c039ad4d24d30

Recommended Posts

I want to return an object in CSV format with multi-line header & filter in Java
I want to send an email in Java.
I want to ForEach an array with a Lambda expression in Java
I want to return to the previous screen with kotlin and java!
Even in Java, I want to output true with a == 1 && a == 2 && a == 3 (PowerMockito edition)
I want to use java8 forEach with index
rsync4j --I want to touch rsync in Java.
Even in Java, I want to output true with a == 1 && a == 2 && a == 3 (black magic edition)
I want to do something like "cls" in Java
I want to transition screens with kotlin and java!
I want to get along with Map [Java beginner]
I want to build Java Applet without using an IDE
I want to push an app made with Rails 6 to GitHub
I want to manually send an authorization email with Devise
I want to implement various functions with kotlin and java!
Convert 2D array to csv format with Java 8 Stream API
[Java] I want to test standard input & standard output with JUnit
I want to simplify the conditional if-else statement in Java
After posting an article with Rails Simple Calendar, I want to reflect it in the calendar.
I want to write a loop that references an index with Java 8's Stream API
I want to return a type different from the input element with Java8 StreamAPI reduce ()
I sent an email in Java
I want to convert an array to Active Record Relation with Rails
[Ruby] I want to put an array in a variable. I want to convert to an array
I tried to interact with Java
I tried to make an Android application with MVC now (Java)
I made an annotation in Java.
[Java] Output the result of ffprobe -show_streams in JSON and map it to an object with Jackson
I want to display images with REST Controller of Java and Spring!
I want to select multiple items with a custom layout in Dialog
(Limited to Java 7 or later) I want you to compare objects in Objects.equals
[Note] I want to get in reverse order using afterLast with JdbcTemplate
I want to create a dark web SNS with Jakarta EE 8 with Java 11
I want to display a PDF in Chinese (Korean) with thin reports
I want to get the IP address when connecting to Wi-Fi in Java
I want to display an error message when registering in the database
[Java Spring MVC] I want to use DI in my own class
I want to make an ios.android app
I want to use DBViewer with Eclipse 2018-12! !!
Return custom object with @Query in spring-data-jpa
I want to stop Java updates altogether
I want to use @Autowired in Servlet
Let's create a TODO application in Java 2 I want to create a template with Spring Initializr and make a Hello world
How to store an object in PostgreSQL as JSON with MyBatis (Mapper XML)
Rails6 I want to make an array of values with a check box
I want to test Action Cable with RSpec test
Run R from Java I want to run rJava
I tried to make Basic authentication with Java
I want to use arrow notation in Ruby
Even in Java, I want to output true with a == 1 && a == 2 && a == 3 (gray magic that is not so much as black magic)
Deserialize CSV in Java based on header name
I tried to implement deep learning in Java
I want to pass APP_HOME to logback in Gradle
I wanted to make (a == 1 && a == 2 && a == 3) true in Java
Even if I want to convert the contents of a data object to JSON in Java, there is a circular reference ...
I tried to output multiplication table in Java
[Xcode] I want to manage images in folders
I want to be eventually even in kotlin
Even in Java, I want to output true with a == 1 && a == 2 && a == 3 (Royal road edition that is neither magic nor anything)
How to solve an Expression Problem in Java
I tried to develop an application in 2 languages