data) {
+ try (final SXSSFWorkbook workbook = new SXSSFWorkbook()) {
+ workbook.setCompressTempFiles(true);
+ addStyles(workbook);
+ try {
+ save(data, workbook);
+ } finally {
+ if (!workbook.dispose()) {
+ System.out.println("Warning! SXSSFWorkbook wasn't disposed correctly. See " + System.getProperty(
+ "java.io.tmpdir") + File.separator + "poifiles");
+ }
+ }
+ } catch (IOException e) {
+ throw new PoijiException(e.getMessage(), e);
+ }
+
+ }
+
+ private void addStyles(final SXSSFWorkbook workbook) {
+ final CellStyle dateCellStyle = workbook.createCellStyle();
+ final DataFormat dataFormat = workbook.createDataFormat();
+ dateCellStyle.setDataFormat(dataFormat.getFormat(options.datePattern()));
+ final CellStyle localDateCellStyle = workbook.createCellStyle();
+ localDateCellStyle.setDataFormat(dataFormat.getFormat(options.getLocalDatePattern()));
+ final CellStyle localDateTimeCellStyle = workbook.createCellStyle();
+ localDateTimeCellStyle.setDataFormat(dataFormat.getFormat(options.getLocalDateTimePattern()));
+ final POIXMLProperties.CustomProperties customProperties = workbook
+ .getXSSFWorkbook()
+ .getProperties()
+ .getCustomProperties();
+ customProperties.addProperty(DATE_CELL_STYLE_INDEX_PROPERTY_NAME, dateCellStyle.getIndex());
+ customProperties.addProperty(LOCAL_DATE_CELL_STYLE_INDEX_PROPERTY_NAME, localDateCellStyle.getIndex());
+ customProperties.addProperty(LOCAL_DATE_TIME_CELL_STYLE_INDEX_PROPERTY_NAME, localDateTimeCellStyle.getIndex());
+ }
+
+}
diff --git a/src/main/java/com/poiji/util/PoijiConstants.java b/src/main/java/com/poiji/util/PoijiConstants.java
index f147c47..2db5c37 100644
--- a/src/main/java/com/poiji/util/PoijiConstants.java
+++ b/src/main/java/com/poiji/util/PoijiConstants.java
@@ -8,10 +8,15 @@
public final class PoijiConstants {
public static final String DEFAULT_DATE_PATTERN = "dd/M/yyyy";
- public static final DateTimeFormatter DEFAULT_DATE_FORMATTER = DateTimeFormatter.ofPattern("dd/M/yyyy");
- public static final DateTimeFormatter DEFAULT_DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("dd/M/yyyy HH:mm:ss");
+ public static final String DEFAULT_DATE_TIME_PATTERN = "dd/M/yyyy HH:mm:ss";
+ public static final DateTimeFormatter DEFAULT_DATE_FORMATTER = DateTimeFormatter.ofPattern(DEFAULT_DATE_PATTERN);
+ public static final DateTimeFormatter DEFAULT_DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern(
+ DEFAULT_DATE_TIME_PATTERN);
public static final String XLS_EXTENSION = ".xls";
public static final String XLSX_EXTENSION = ".xlsx";
+ public static final String LOCAL_DATE_CELL_STYLE_INDEX_PROPERTY_NAME = "LocalDateCellStyleIndex";
+ public static final String LOCAL_DATE_TIME_CELL_STYLE_INDEX_PROPERTY_NAME = "LocalDateTimeCellStyleIndex";
+ public static final String DATE_CELL_STYLE_INDEX_PROPERTY_NAME = "DateCellStyleIndex";
private PoijiConstants() {
}
diff --git a/src/test/java/com/poiji/deserialize/ConcurrentTest.java b/src/test/java/com/poiji/deserialize/ConcurrentTest.java
new file mode 100644
index 0000000..ed66091
--- /dev/null
+++ b/src/test/java/com/poiji/deserialize/ConcurrentTest.java
@@ -0,0 +1,101 @@
+package com.poiji.deserialize;
+
+import com.poiji.bind.Poiji;
+import com.poiji.deserialize.model.ConcurrentEntity;
+import com.poiji.option.PoijiOptions;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import static java.util.Arrays.asList;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.junit.Assert.assertThat;
+
+/**
+ * For manual testing only.
+ */
+public class ConcurrentTest {
+
+ /**
+ * 1000000 records, Intel® Core™ i3-4160, 24GB, SSD
+ *
+ * Synchronized read:
+ * Generated in 370 ms
+ * Written in 8761 ms
+ * Read in 39167 ms
+ *
+ * Synchronized write:
+ * Generated in 309 ms
+ * Written in 16225 ms
+ * Read in 24233 ms
+ */
+ @Test
+ @Ignore("Test disabled to prevent huge xlsx files writing in CI")
+ public void writeThenRead() {
+ final long start = System.nanoTime();
+ final int size = 1000000;
+ final List entities1 = generateEntities(size, "1");
+ final List entities2 = generateEntities(size, "2");
+ final List entities3 = generateEntities(size, "3");
+ final List entities4 = generateEntities(size, "4");
+ final Set> expected = new HashSet<>(asList(entities1, entities2, entities3, entities4));
+ final String name1 = "src/test/resources/concurrent1.xlsx";
+ final String name2 = "src/test/resources/concurrent2.xlsx";
+ final String name3 = "src/test/resources/concurrent3.xlsx";
+ final String name4 = "src/test/resources/concurrent4.xlsx";
+ final List writeData = asList(
+ new WriteData(name1, entities1),
+ new WriteData(name2, entities2),
+ new WriteData(name3, entities3),
+ new WriteData(name4, entities4)
+ );
+
+ final PoijiOptions options = PoijiOptions.PoijiOptionsBuilder.settings().preferNullOverDefault(true).build();
+
+ final long generated = System.nanoTime();
+ System.out.println("Generated in " + (generated - start) / 1000000 + " ms");
+
+ writeData
+ .parallelStream()
+ .forEach(data -> Poiji.toExcel(new File(data.path), ConcurrentEntity.class, data.entities, options));
+
+ final long written = System.nanoTime();
+ System.out.println("Written in " + (written - generated) / 1000000 + " ms");
+
+ final Set> actual = asList(name1, name2, name3, name4)
+ .parallelStream()
+ .map(s -> Poiji.fromExcel(new File(s), ConcurrentEntity.class, options))
+ .collect(Collectors.toSet());
+
+ final long read = System.nanoTime();
+ System.out.println("Read in " + (read - written) / 1000000 + " ms");
+
+ assertThat(actual, equalTo(expected));
+
+
+ }
+
+ private List generateEntities(final int size, final String marker) {
+ final List result = new ArrayList<>();
+ for (int i = 0; i < size; i++) {
+ result.add(new ConcurrentEntity().setPrimitiveLong(i).setText(marker));
+ }
+ return result;
+ }
+
+ public static class WriteData {
+ private final String path;
+ private final List entities;
+
+ public WriteData(final String path, final List entities) {
+ this.path = path;
+ this.entities = entities;
+ }
+ }
+
+}
diff --git a/src/test/java/com/poiji/deserialize/WriteTest.java b/src/test/java/com/poiji/deserialize/WriteTest.java
new file mode 100644
index 0000000..1bcd103
--- /dev/null
+++ b/src/test/java/com/poiji/deserialize/WriteTest.java
@@ -0,0 +1,76 @@
+package com.poiji.deserialize;
+
+import com.poiji.bind.Poiji;
+import com.poiji.deserialize.model.WriteEntity;
+import com.poiji.option.PoijiOptions;
+import java.io.File;
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.junit.Assert.assertThat;
+
+@RunWith(Parameterized.class)
+public class WriteTest {
+
+ private final String path;
+
+ public WriteTest(String path) {
+ this.path = path;
+ }
+
+ @Parameterized.Parameters
+ public static List excel() {
+ return Arrays.asList("src/test/resources/write.xlsx", "src/test/resources/write.xls");
+ }
+
+ @Test
+ public void write() {
+ final Map unknown = new HashMap<>();
+ unknown.put("unKnown1", "unknown value 1");
+ unknown.put("unKnown2", "unknown value 2");
+ final List expected = new ArrayList<>();
+ final WriteEntity entity = new WriteEntity()
+ .setPrimitiveDouble(10.0)
+ .setWrappedDouble(11.0)
+ .setPrimitiveFloat(20.0f)
+ .setWrappedFloat(21.0f)
+ .setPrimitiveLong(1)
+ .setText("test")
+ .setPrimitiveBoolean(true)
+ .setWrappedBoolean(true)
+ .setDate(new Date(1234567890L))
+ .setLocalDate(LocalDate.of(2020, 1, 2))
+ .setLocalDateTime(LocalDateTime.of(2020, 1, 2, 12, 0))
+ .setBigDecimal(new BigDecimal("123.3456"))
+ .setPrimitiveByte((byte) -1)
+ .setWrappedByte((byte) -2)
+ .setPrimitiveShort((short) -3)
+ .setWrappedShort((short) -4)
+ .setAnotherUnknown(unknown);
+ expected.add(entity);
+ expected.add(new WriteEntity());
+ final PoijiOptions options = PoijiOptions.PoijiOptionsBuilder
+ .settings()
+ .datePattern("dd-MM-yyyy HH:mm:ss")
+ .preferNullOverDefault(true)
+ .build();
+ Poiji.toExcel(new File(path), WriteEntity.class, expected, options);
+
+ final List read = Poiji.fromExcel(new File(path), WriteEntity.class, options);
+ read.forEach(writeEntity -> writeEntity.setUnknown(new HashMap<>()));
+ assertThat(read.toString(), equalTo(expected.toString()));
+
+ }
+
+}
diff --git a/src/test/java/com/poiji/deserialize/model/ConcurrentEntity.java b/src/test/java/com/poiji/deserialize/model/ConcurrentEntity.java
new file mode 100644
index 0000000..cb389d0
--- /dev/null
+++ b/src/test/java/com/poiji/deserialize/model/ConcurrentEntity.java
@@ -0,0 +1,19 @@
+package com.poiji.deserialize.model;
+
+import com.poiji.annotation.ExcelCell;
+import com.poiji.annotation.ExcelCellName;
+import com.poiji.annotation.ExcelSheet;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+@Data
+@Accessors(chain = true)
+@ExcelSheet("test")
+public final class ConcurrentEntity {
+
+ @ExcelCell(0)
+ private long primitiveLong;
+ @ExcelCellName(value = "TexT")
+ private String text;
+
+}
diff --git a/src/test/java/com/poiji/deserialize/model/WriteEntity.java b/src/test/java/com/poiji/deserialize/model/WriteEntity.java
new file mode 100644
index 0000000..3271f54
--- /dev/null
+++ b/src/test/java/com/poiji/deserialize/model/WriteEntity.java
@@ -0,0 +1,58 @@
+package com.poiji.deserialize.model;
+
+import com.poiji.annotation.ExcelCell;
+import com.poiji.annotation.ExcelCellName;
+import com.poiji.annotation.ExcelSheet;
+import com.poiji.annotation.ExcelUnknownCells;
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.Date;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+@Data
+@Accessors(chain = true)
+@ExcelSheet("test")
+public final class WriteEntity {
+
+ @ExcelCell(0)
+ private long primitiveLong;
+ @ExcelCellName(value = "TexT", order = 5)
+ private String text;
+ @ExcelCell(4)
+ private Float wrappedFloat;
+ @ExcelCellName("float")
+ private float primitiveFloat;
+ @ExcelUnknownCells
+ private Map unknown = new ConcurrentHashMap<>();
+ @ExcelUnknownCells
+ private Map anotherUnknown = new ConcurrentHashMap<>();
+ @ExcelCellName("double")
+ private double primitiveDouble;
+ @ExcelCellName(value = "Double", order = 10)
+ private Double wrappedDouble;
+ @ExcelCellName("boolean")
+ private boolean primitiveBoolean;
+ @ExcelCellName("Boolean")
+ private Boolean wrappedBoolean;
+ @ExcelCellName("Date")
+ private Date date;
+ @ExcelCellName("LocalDate")
+ private LocalDate localDate;
+ @ExcelCellName("LocalDateTime")
+ private LocalDateTime localDateTime;
+ @ExcelCellName("BigDecimal")
+ private BigDecimal bigDecimal;
+ @ExcelCellName("byte")
+ private byte primitiveByte;
+ @ExcelCellName("Byte")
+ private Byte wrappedByte;
+ @ExcelCellName("short")
+ private short primitiveShort;
+ @ExcelCellName("Short")
+ private Short wrappedShort;
+
+}
diff --git a/src/test/java/com/poiji/option/PoijiOptionsTest.java b/src/test/java/com/poiji/option/PoijiOptionsTest.java
new file mode 100644
index 0000000..cf51e92
--- /dev/null
+++ b/src/test/java/com/poiji/option/PoijiOptionsTest.java
@@ -0,0 +1,46 @@
+package com.poiji.option;
+
+import com.poiji.save.CellCasting;
+import java.time.format.DateTimeFormatter;
+import org.junit.Test;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+/**
+ * Test for {@link PoijiOptions}.
+ */
+public final class PoijiOptionsTest {
+
+ @Test
+ public void getLocalDatePattern() {
+ final PoijiOptions options = PoijiOptions.PoijiOptionsBuilder.settings().localDatePattern("custom").build();
+ assertThat("custom", equalTo(options.getLocalDatePattern()));
+ }
+
+ @Test
+ public void getLocalDateTimePattern() {
+ final PoijiOptions options = PoijiOptions.PoijiOptionsBuilder.settings().localDateTimePattern("custom").build();
+ assertThat("custom", equalTo(options.getLocalDateTimePattern()));
+ }
+
+ @Test
+ public void dateTimeFormatter() {
+ final DateTimeFormatter expected = DateTimeFormatter.BASIC_ISO_DATE;
+ final PoijiOptions options = PoijiOptions.PoijiOptionsBuilder.settings().dateTimeFormatter(expected).build();
+ assertThat(expected, equalTo(options.dateTimeFormatter()));
+ }
+
+ @Test
+ public void getCellCasting() {
+ final CellCasting expected = new CellCasting();
+ final PoijiOptions options = PoijiOptions.PoijiOptionsBuilder.settings().withCellCasting(expected).build();
+ assertThat(expected, equalTo(options.getCellCasting()));
+ }
+
+ @Test
+ public void getCaseInsensitive() {
+ final PoijiOptions options = PoijiOptions.PoijiOptionsBuilder.settings().caseInsensitive(true).build();
+ assertThat(true, equalTo(options.getCaseInsensitive()));
+ }
+}
diff --git a/src/test/java/com/poiji/save/CellCastingTest.java b/src/test/java/com/poiji/save/CellCastingTest.java
new file mode 100644
index 0000000..c5596c7
--- /dev/null
+++ b/src/test/java/com/poiji/save/CellCastingTest.java
@@ -0,0 +1,43 @@
+package com.poiji.save;
+
+import java.util.function.BiConsumer;
+import org.apache.poi.ss.usermodel.Cell;
+import org.junit.Test;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+/**
+ * Test for {@link CellCasting}.
+ */
+public final class CellCastingTest {
+
+ @Test
+ public void getObjectCellCastingInsteadAbsent() {
+ final CellCasting cellCasting = new CellCasting();
+
+ assertThat(cellCasting.forType(CellCasting.class), is(cellCasting.forType(Object.class)));
+ }
+
+ @Test
+ public void addCellCasting() {
+ final CellCasting cellCasting = new CellCasting();
+ final BiConsumer rule = (cell, o) -> {};
+ cellCasting.addCellCasting(CellCasting.class, rule);
+
+ assertThat(cellCasting.forType(CellCasting.class), is(rule));
+ }
+
+ @Test
+ public void rewriteCellCasting() {
+ final CellCasting cellCasting = new CellCasting();
+ final BiConsumer rule = (cell, o) -> {};
+
+ assertThat(cellCasting.forType(Boolean.class), not(is(rule)));
+
+ cellCasting.addCellCasting(Boolean.class, rule);
+
+ assertThat(cellCasting.forType(Boolean.class), is(rule));
+ }
+}
| |