I am trying to write a means of serializing objects to CSV. As a part of the process, I need to know the column names for each field of the object. Consider the following:
public interface CsvExportable {
public List<String> getCsvHeaders();
public List<String> getCsvRow();
static String toCsv(@NotNull List<? extends CsvExportable> objs) {
StringJoiner sj = new StringJoiner("n");
sj.add(String.join(",", objs.get(0).getCsvHeaders())); // <- This might not work! What if objs is empty?
for (CsvExportable obj : objs) {
sj.add(String.join(",", obj.getCsvRow()));
}
return sj.toString();
}
}
public class A implments CsvExportable {
public int first;
public int second;
// This method could be static...
public List<String> getCsvHeaders() {
return Arrays.asList("first", "second");
}
public List<String> getCsvRow() {
return Arrays.asList(String.valueOf(first), String.valueOf(second));
}
}
The issue lies where I’m trying to get the column headers for the CSV. If I’m trying to serialize an empty list, I still want to print the column headers. But without a concrete object to call getCsvHeaders()
on, there’s no way to fetch them, even though we know that objects of type A
have the same headers no matter what (more specifically, we could make an assertion on the CsvExportable
interface that getCsvHeaders()
behaves like a pure, static method for all implementers). How can I access the headers of an object, which are basically a static property, without needing an instance of that object?
I thought about something like
static <T extends CsvExportable> String toCsv(List<T> objs, Class<T> clazz) {
List<String> headers = class.getCsvHeaders();
// ...
}
but obviously static methods can’t be enforced by an interface, and calling them from the class object through reflection is inefficient.
If it helps, there is a point somewhere before this method where the type of object to be serialized is known (like a List<A> objs = getFromDatabase(A.class)
method). However, that’s a fair distance away from where it gets turned into a CSV. If the headers were generated there, it would be a headache to carry that list all the way to the serialization.
I know that doing annotations similar to @JsonProperty
could help here, but importing/creating a module to handle that is not within scope.
3