Skip to content

Instantly share code, notes, and snippets.

@fabmars
Created March 4, 2024 12:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fabmars/678c2a690365f2687fe79e5890616517 to your computer and use it in GitHub Desktop.
Save fabmars/678c2a690365f2687fe79e5890616517 to your computer and use it in GitHub Desktop.
Java Json to CSV converter using Jackson
package whatever.converters;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
public class JsonToCsv {
public static void main(String[] args) throws IOException {
String homeDir = System.getProperty("user.home");
Path inFile = Paths.get(homeDir).resolve("Downloads").resolve("inputfile.json");
Path outFile = inFile.resolveSibling(inFile.getFileName() + ".csv");
flattenFile(inFile, outFile, ";", StandardCharsets.UTF_8);
}
public static void flattenFile(Path inFile, Path outFile, String delimiter, Charset charset) throws IOException {
try(InputStream is = Files.newInputStream(inFile);
OutputStream os = Files.newOutputStream(outFile, StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING)) {
flattenStream(is, os, delimiter, charset);
}
}
public static void flattenStream(InputStream is, OutputStream os, String delimiter, Charset charset) throws IOException {
List<Map<String, Object>> lines = readJson(is);
Set<String> headers = new LinkedHashSet<>();
lines.stream().flatMap(map -> map.keySet().stream()).forEach(headers::add);
writeCsv(os, headers, lines, charset, delimiter);
}
private static List<Map<String, Object>> readJson(InputStream is) throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
List<Map<String, Object>> lines = new ArrayList<>();
Object obj = objectMapper.readValue(is, Object.class);
if(obj instanceof List) {
for (Object elt : (List<?>) obj) {
lines.add(flatten(elt));
}
} else {
lines.add(flatten(obj));
}
return lines;
}
public static Map<String, Object> flatten(Object in) {
Map<String, Object> line = new LinkedHashMap<>();
flattenObj(in, line, "");
return line;
}
private static void flattenObj(Object in, Map<String, Object> out, String prefix) {
if(in instanceof Map) {
flattenMap((Map<?, ?>) in, out, prefix);
} else if(in instanceof List) {
flattenList((List<?>) in, out, prefix);
} else {
out.put(prefix, in);
}
}
private static void flattenMap(Map<?, ?> in, Map<String, Object> out, String prefix) {
in.forEach((k, v) -> {
String header = appendSuffix(prefix, k);
flattenObj(v, out, header);
});
}
private static void flattenList(List<?> in, Map<String, Object> out, String prefix) {
int i = 0;
for (Object e : in) {
String header = appendSuffix(prefix, i++);
flattenObj(e, out, header);
}
}
private static String appendSuffix(String header, Object suffix) {
if(header != null) {
return header + '.' + suffix;
} else {
return String.valueOf(suffix);
}
}
private static void writeCsv(OutputStream os, Collection<String> headers, Collection<Map<String, Object>> lines, Charset charset, String delimiter) throws IOException {
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os, charset));
bw.write(String.join(delimiter, headers));
bw.newLine();
for (Map<String, Object> kvs : lines) {
List<String> line = new ArrayList<>(headers.size());
for (String header : headers) {
line.add(toCsvString(kvs.get(header), delimiter));
}
bw.write(String.join(delimiter, line));
bw.newLine();
}
bw.flush();
}
private static String toCsvString(Object v, String delimiter) {
return Optional.ofNullable(v).map(o -> {
String s = o.toString();
if(s.contains(delimiter)) {
s = '"' + s + '"';
}
return s;
}).orElse("");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment