Created
March 4, 2024 12:51
-
-
Save fabmars/678c2a690365f2687fe79e5890616517 to your computer and use it in GitHub Desktop.
Java Json to CSV converter using Jackson
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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