diff --git a/json/src/main/java/tech/tablesaw/io/json/JsonWriteOptions.java b/json/src/main/java/tech/tablesaw/io/json/JsonWriteOptions.java index 2154ab34f..a9def7893 100644 --- a/json/src/main/java/tech/tablesaw/io/json/JsonWriteOptions.java +++ b/json/src/main/java/tech/tablesaw/io/json/JsonWriteOptions.java @@ -1,6 +1,9 @@ package tech.tablesaw.io.json; import java.io.Writer; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import tech.tablesaw.io.Destination; import tech.tablesaw.io.WriteOptions; @@ -8,11 +11,13 @@ public class JsonWriteOptions extends WriteOptions { private final boolean asObjects; private final boolean header; + private final ObjectMapper mapper; private JsonWriteOptions(Builder builder) { super(builder); this.asObjects = builder.asObjects; this.header = builder.header; + this.mapper = builder.mapper; } public boolean asObjects() { @@ -23,6 +28,8 @@ public boolean header() { return header; } + public ObjectMapper mapper() { return mapper; } + public static Builder builder(Writer writer) { return new Builder(new Destination(writer)); } @@ -35,6 +42,7 @@ public static class Builder extends WriteOptions.Builder { private boolean asObjects = true; private boolean header = false; + private ObjectMapper mapper = new ObjectMapper().registerModule(new JavaTimeModule()); protected Builder(Destination destination) { super(destination); @@ -52,6 +60,11 @@ public JsonWriteOptions.Builder header(boolean header) { return this; } + public JsonWriteOptions.Builder mapper(ObjectMapper mapper) { + this.mapper = mapper; + return this; + } + public JsonWriteOptions build() { return new JsonWriteOptions(this); } diff --git a/json/src/main/java/tech/tablesaw/io/json/JsonWriter.java b/json/src/main/java/tech/tablesaw/io/json/JsonWriter.java index 1997b0b7e..97e50021e 100644 --- a/json/src/main/java/tech/tablesaw/io/json/JsonWriter.java +++ b/json/src/main/java/tech/tablesaw/io/json/JsonWriter.java @@ -30,8 +30,6 @@ public class JsonWriter implements DataWriter { private static final JsonWriter INSTANCE = new JsonWriter(); - private static final ObjectMapper mapper = - new ObjectMapper().registerModule(new JavaTimeModule()); static { register(Table.defaultWriterRegistry); @@ -43,33 +41,33 @@ public static void register(WriterRegistry registry) { } public void write(Table table, JsonWriteOptions options) { - ArrayNode output = mapper.createArrayNode(); + ArrayNode output = options.mapper().createArrayNode(); if (options.asObjects()) { for (int r = 0; r < table.rowCount(); r++) { - ObjectNode row = mapper.createObjectNode(); + ObjectNode row = options.mapper().createObjectNode(); for (int c = 0; c < table.columnCount(); c++) { - row.set(table.column(c).name(), mapper.convertValue(table.get(r, c), JsonNode.class)); + row.set(table.column(c).name(), options.mapper().convertValue(table.get(r, c), JsonNode.class)); } output.add(row); } } else { if (options.header()) { - ArrayNode row = mapper.createArrayNode(); + ArrayNode row = options.mapper().createArrayNode(); for (int c = 0; c < table.columnCount(); c++) { - row.add(mapper.convertValue(table.column(c).name(), JsonNode.class)); + row.add(options.mapper().convertValue(table.column(c).name(), JsonNode.class)); } output.add(row); } for (int r = 0; r < table.rowCount(); r++) { - ArrayNode row = mapper.createArrayNode(); + ArrayNode row = options.mapper().createArrayNode(); for (int c = 0; c < table.columnCount(); c++) { - row.add(mapper.convertValue(table.get(r, c), JsonNode.class)); + row.add(options.mapper().convertValue(table.get(r, c), JsonNode.class)); } output.add(row); } } try (Writer writer = options.destination().createWriter()) { - String str = mapper.writeValueAsString(output); + String str = options.mapper().writeValueAsString(output); writer.write(str); } catch (IOException e) { throw new RuntimeIOException(e); diff --git a/json/src/test/java/tech/tablesaw/io/json/JsonWriterTest.java b/json/src/test/java/tech/tablesaw/io/json/JsonWriterTest.java index 5475b193a..c1570de39 100644 --- a/json/src/test/java/tech/tablesaw/io/json/JsonWriterTest.java +++ b/json/src/test/java/tech/tablesaw/io/json/JsonWriterTest.java @@ -16,10 +16,20 @@ import static org.junit.jupiter.api.Assertions.assertEquals; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.StringWriter; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; import org.junit.jupiter.api.Test; import tech.tablesaw.api.Table; +import tech.tablesaw.io.Destination; public class JsonWriterTest { @@ -54,4 +64,23 @@ public void arrayOfObjects() { String output = table.write().toString("json"); assertEquals(json, output); } + + @Test + public void withCustomMapper() { + var json = "[{\"a\":\"2021-01-01\"}, {\"a\":\"2021-02-01\"}]"; + var table = Table.read().string(json, "json"); + var mapper = new ObjectMapper(); + mapper.registerModule(new SimpleModule().addSerializer(new StdSerializer(LocalDate.class) { + final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy/MM/dd"); + @Override + public void serialize(LocalDate localDate, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) + throws IOException { + jsonGenerator.writeString(FORMATTER.format(localDate)); + } + })); + + var baos = new ByteArrayOutputStream(); + new JsonWriter().write(table, new JsonWriteOptions.Builder(new Destination(baos)).mapper(mapper).build()); + assertEquals(new String(baos.toByteArray()), "[{\"a\":\"2021/01/01\"},{\"a\":\"2021/02/01\"}]"); + } }