Browse Source

Merge branch '3.x' into 2.1.x

developing
Jiaju Zhuang 4 years ago committed by GitHub
parent
commit
33bb5556e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      .github/ISSUE_TEMPLATE/bug.md
  2. 4
      .github/ISSUE_TEMPLATE/question.md
  3. 2
      .github/ISSUE_TEMPLATE/suggest.md
  4. 8
      CONTRIBUTING.md
  5. 39
      README.md
  6. 50
      pom.xml
  7. 4
      src/main/java/com/alibaba/excel/ExcelReader.java
  8. 20
      src/main/java/com/alibaba/excel/ExcelWriter.java
  9. 2
      src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java
  10. 13
      src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java
  11. 13
      src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java
  12. 24
      src/main/java/com/alibaba/excel/analysis/v03/handlers/EofRecordHandler.java
  13. 23
      src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java
  14. 11
      src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java
  15. 2
      src/main/java/com/alibaba/excel/analysis/v03/handlers/StringRecordHandler.java
  16. 58
      src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java
  17. 12
      src/main/java/com/alibaba/excel/analysis/v07/handlers/AbstractCellValueTagHandler.java
  18. 2
      src/main/java/com/alibaba/excel/analysis/v07/handlers/CellInlineStringValueTagHandler.java
  19. 16
      src/main/java/com/alibaba/excel/analysis/v07/handlers/CellTagHandler.java
  20. 5
      src/main/java/com/alibaba/excel/analysis/v07/handlers/CellValueTagHandler.java
  21. 12
      src/main/java/com/alibaba/excel/analysis/v07/handlers/RowTagHandler.java
  22. 15
      src/main/java/com/alibaba/excel/annotation/ExcelProperty.java
  23. 92
      src/main/java/com/alibaba/excel/cache/Ehcache.java
  24. 10
      src/main/java/com/alibaba/excel/cache/MapCache.java
  25. 8
      src/main/java/com/alibaba/excel/constant/BuiltinFormats.java
  26. 13
      src/main/java/com/alibaba/excel/constant/OrderConstant.java
  27. 77
      src/main/java/com/alibaba/excel/context/WriteContextImpl.java
  28. 8
      src/main/java/com/alibaba/excel/converters/AutoConverter.java
  29. 78
      src/main/java/com/alibaba/excel/converters/Converter.java
  30. 14
      src/main/java/com/alibaba/excel/converters/ConverterKeyBuild.java
  31. 40
      src/main/java/com/alibaba/excel/converters/DefaultConverterLoader.java
  32. 10
      src/main/java/com/alibaba/excel/converters/bigdecimal/BigDecimalBooleanConverter.java
  33. 12
      src/main/java/com/alibaba/excel/converters/bigdecimal/BigDecimalNumberConverter.java
  34. 8
      src/main/java/com/alibaba/excel/converters/bigdecimal/BigDecimalStringConverter.java
  35. 8
      src/main/java/com/alibaba/excel/converters/booleanconverter/BooleanBooleanConverter.java
  36. 10
      src/main/java/com/alibaba/excel/converters/booleanconverter/BooleanNumberConverter.java
  37. 8
      src/main/java/com/alibaba/excel/converters/booleanconverter/BooleanStringConverter.java
  38. 6
      src/main/java/com/alibaba/excel/converters/bytearray/BoxingByteArrayImageConverter.java
  39. 5
      src/main/java/com/alibaba/excel/converters/bytearray/ByteArrayImageConverter.java
  40. 10
      src/main/java/com/alibaba/excel/converters/byteconverter/ByteBooleanConverter.java
  41. 12
      src/main/java/com/alibaba/excel/converters/byteconverter/ByteNumberConverter.java
  42. 8
      src/main/java/com/alibaba/excel/converters/byteconverter/ByteStringConverter.java
  43. 47
      src/main/java/com/alibaba/excel/converters/date/DateDateConverter.java
  44. 10
      src/main/java/com/alibaba/excel/converters/date/DateNumberConverter.java
  45. 10
      src/main/java/com/alibaba/excel/converters/date/DateStringConverter.java
  46. 10
      src/main/java/com/alibaba/excel/converters/doubleconverter/DoubleBooleanConverter.java
  47. 13
      src/main/java/com/alibaba/excel/converters/doubleconverter/DoubleNumberConverter.java
  48. 8
      src/main/java/com/alibaba/excel/converters/doubleconverter/DoubleStringConverter.java
  49. 6
      src/main/java/com/alibaba/excel/converters/file/FileImageConverter.java
  50. 10
      src/main/java/com/alibaba/excel/converters/floatconverter/FloatBooleanConverter.java
  51. 15
      src/main/java/com/alibaba/excel/converters/floatconverter/FloatNumberConverter.java
  52. 8
      src/main/java/com/alibaba/excel/converters/floatconverter/FloatStringConverter.java
  53. 6
      src/main/java/com/alibaba/excel/converters/inputstream/InputStreamImageConverter.java
  54. 10
      src/main/java/com/alibaba/excel/converters/integer/IntegerBooleanConverter.java
  55. 14
      src/main/java/com/alibaba/excel/converters/integer/IntegerNumberConverter.java
  56. 8
      src/main/java/com/alibaba/excel/converters/integer/IntegerStringConverter.java
  57. 10
      src/main/java/com/alibaba/excel/converters/longconverter/LongBooleanConverter.java
  58. 14
      src/main/java/com/alibaba/excel/converters/longconverter/LongNumberConverter.java
  59. 8
      src/main/java/com/alibaba/excel/converters/longconverter/LongStringConverter.java
  60. 10
      src/main/java/com/alibaba/excel/converters/shortconverter/ShortBooleanConverter.java
  61. 13
      src/main/java/com/alibaba/excel/converters/shortconverter/ShortNumberConverter.java
  62. 8
      src/main/java/com/alibaba/excel/converters/shortconverter/ShortStringConverter.java
  63. 8
      src/main/java/com/alibaba/excel/converters/string/StringBooleanConverter.java
  64. 8
      src/main/java/com/alibaba/excel/converters/string/StringErrorConverter.java
  65. 6
      src/main/java/com/alibaba/excel/converters/string/StringImageConverter.java
  66. 8
      src/main/java/com/alibaba/excel/converters/string/StringNumberConverter.java
  67. 8
      src/main/java/com/alibaba/excel/converters/string/StringStringConverter.java
  68. 8
      src/main/java/com/alibaba/excel/converters/url/UrlImageConverter.java
  69. 8
      src/main/java/com/alibaba/excel/enums/CellDataTypeEnum.java
  70. 2
      src/main/java/com/alibaba/excel/event/AnalysisEventListener.java
  71. 38
      src/main/java/com/alibaba/excel/exception/ExcelDataConvertException.java
  72. 9
      src/main/java/com/alibaba/excel/metadata/AbstractHolder.java
  73. 15
      src/main/java/com/alibaba/excel/metadata/BasicParameter.java
  74. 157
      src/main/java/com/alibaba/excel/metadata/CellData.java
  75. 2
      src/main/java/com/alibaba/excel/metadata/ConfigurationHolder.java
  76. 14
      src/main/java/com/alibaba/excel/metadata/GlobalConfiguration.java
  77. 119
      src/main/java/com/alibaba/excel/metadata/format/DataFormatter.java
  78. 81
      src/main/java/com/alibaba/excel/metadata/format/ExcelGeneralNumberFormat.java
  79. 113
      src/main/java/com/alibaba/excel/metadata/property/ExcelHeadProperty.java
  80. 13
      src/main/java/com/alibaba/excel/read/builder/AbstractExcelReaderParameterBuilder.java
  81. 51
      src/main/java/com/alibaba/excel/read/listener/ModelBuildEventListener.java
  82. 2
      src/main/java/com/alibaba/excel/read/listener/ReadListener.java
  83. 29
      src/main/java/com/alibaba/excel/read/metadata/holder/AbstractReadHolder.java
  84. 8
      src/main/java/com/alibaba/excel/read/metadata/holder/ReadSheetHolder.java
  85. 12
      src/main/java/com/alibaba/excel/read/metadata/holder/xls/XlsReadSheetHolder.java
  86. 13
      src/main/java/com/alibaba/excel/read/metadata/holder/xls/XlsReadWorkbookHolder.java
  87. 4
      src/main/java/com/alibaba/excel/read/processor/DefaultAnalysisEventProcessor.java
  88. 75
      src/main/java/com/alibaba/excel/util/BooleanUtils.java
  89. 194
      src/main/java/com/alibaba/excel/util/ClassUtils.java
  90. 22
      src/main/java/com/alibaba/excel/util/CollectionUtils.java
  91. 49
      src/main/java/com/alibaba/excel/util/ConverterUtils.java
  92. 32
      src/main/java/com/alibaba/excel/util/DateUtils.java
  93. 145
      src/main/java/com/alibaba/excel/util/FieldUtils.java
  94. 24
      src/main/java/com/alibaba/excel/util/FileUtils.java
  95. 39
      src/main/java/com/alibaba/excel/util/IntUtils.java
  96. 121
      src/main/java/com/alibaba/excel/util/ListUtils.java
  97. 63
      src/main/java/com/alibaba/excel/util/MapUtils.java
  98. 54
      src/main/java/com/alibaba/excel/util/MemberUtils.java
  99. 15
      src/main/java/com/alibaba/excel/util/NumberDataFormatterUtils.java
  100. 25
      src/main/java/com/alibaba/excel/util/NumberUtils.java
  101. Some files were not shown because too many files have changed in this diff Show More

2
.github/ISSUE_TEMPLATE/bug.md

@ -7,6 +7,8 @@ assignees: zhuangjiaju
--- ---
**建议先去看文档**
[快速开始](https://www.yuque.com/easyexcel/doc/easyexcel) 、[常见问题](https://www.yuque.com/easyexcel/faq)
**触发场景描述** **触发场景描述**
**触发Bug的代码** **触发Bug的代码**

4
.github/ISSUE_TEMPLATE/question.md

@ -1,12 +1,14 @@
--- ---
name: question name: question
about: 有使用疑问,请先阅读“快速使用”,上面无法解决再提交问题。处理完请关闭问题。 about: 有使用疑问,请先阅读“快速开始”,上面无法解决再提交问题。处理完请关闭问题。
title: '' title: ''
labels: help wanted labels: help wanted
assignees: '' assignees: ''
--- ---
**建议先去看文档**
[快速开始](https://www.yuque.com/easyexcel/doc/easyexcel) 、[常见问题](https://www.yuque.com/easyexcel/faq)
**异常代码** **异常代码**
```java ```java
这里写你的代码 这里写你的代码

2
.github/ISSUE_TEMPLATE/suggest.md

@ -7,4 +7,6 @@ assignees: ''
--- ---
**建议先去看文档**
[快速开始](https://www.yuque.com/easyexcel/doc/easyexcel) 、[常见问题](https://www.yuque.com/easyexcel/faq)
**建议描述** **建议描述**

8
CONTRIBUTING.md

@ -0,0 +1,8 @@
## 前言
非常感谢您愿意协助EasyExcel的开发,EasyExcel成长离不开大家的贡献。但是为了合作的更有效率,希望我们在贡献代码的时候能按照如下约定。
## 提前沟通
尽量把自己的想法和实现思路提前沟通,可以通过issue,钉钉,QQ都可以,可能很多问题我们内部已经讨论过,由于各种原因后续不会支持,但是您这边又开发好了,这样容易浪费您的时间。
## 代码规范
目前代码规范已经集成了自动校验,然后源代码尽量不要有中文注释。在新增功能的时候,尽量注意补充junit。core代表每次travis-ci都会跑的测试案例,然后demo用于对外看到,temp里面随便写。
## 提交分支
建议提交到最新的版本号.x上面,比如 3.x之类的版本,为了方便其他同学阅读源代码,所以目前的思路是master和maven center的最新版本代码保持一致,然后您提交过来的代码我们可能会稍微做一些修改。所以提交到开发分支会比较好。fork也可以直接fork该分支。

39
README.md

@ -1,26 +1,32 @@
easyexcel EasyExcel
====================== ======================
[![Build Status](https://travis-ci.org/alibaba/easyexcel.svg?branch=master)](https://travis-ci.org/alibaba/easyexcel) [![Build Status](https://travis-ci.org/alibaba/easyexcel.svg?branch=master)](https://travis-ci.org/alibaba/easyexcel)
[![Maven central](https://maven-badges.herokuapp.com/maven-central/com.alibaba/easyexcel/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.alibaba/easyexcel) [![Maven central](https://maven-badges.herokuapp.com/maven-central/com.alibaba/easyexcel/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.alibaba/easyexcel)
[![License](http://img.shields.io/:license-apache-brightgreen.svg)](http://www.apache.org/licenses/LICENSE-2.0.html) [![License](http://img.shields.io/:license-apache-brightgreen.svg)](http://www.apache.org/licenses/LICENSE-2.0.html)
[QQ群: 662022184](//shang.qq.com/wpa/qunwpa?idkey=53d9d821b0833e3c14670f007488a61e300f00ff4f1b81fd950590d90dd80f80) [QQ1群(已满): 662022184](https://jq.qq.com/?_wv=1027&k=1T21jJxh)
[钉钉群: 21960511](https://qr.dingtalk.com/action/joingroup?code=v1,k1,cchz6k12ci9B08NNqhNRFGXocNVHrZtW0kaOtTKg/Rk=&_dt_no_comment=1&origin=11) [QQ2群: 1097936804](https://jq.qq.com/?_wv=1027&k=j5zEy6Xl)
[官方网站: https://alibaba-easyexcel.github.io/](https://alibaba-easyexcel.github.io/) [钉钉1群(已满): 21960511](https://qr.dingtalk.com/action/joingroup?code=v1,k1,cchz6k12ci9B08NNqhNRFGXocNVHrZtW0kaOtTKg/Rk=&_dt_no_comment=1&origin=11)
[钉钉2群(已满): 32796397](https://qr.dingtalk.com/action/joingroup?code=v1,k1,jyU9GtEuNU5S0QTyklqYcYJ8qDZtUuTPMM7uPZTS8Hs=&_dt_no_comment=1&origin=11)
[钉钉3群(已满): 33797247](https://qr.dingtalk.com/action/joingroup?code=v1,k1,3UGlEScTGQaHpW2cIRo+gkxJ9EVZ5fz26M6nW3uFP30=&_dt_no_comment=1&origin=11)
[钉钉4群: 33491624](https://qr.dingtalk.com/action/joingroup?code=v1,k1,V14Pb65Too70rQkEaJ9ohb6lZBZbtp6jIL/q9EWh9vA=&_dt_no_comment=1&origin=11)
[官方网站: https://yuque.com/easyexcel](https://www.yuque.com/easyexcel/doc/easyexcel)
[常见问题](https://www.yuque.com/easyexcel/faq)
#### 因为公司不方便用QQ,所以建议加钉钉群 #### 因为公司不方便用QQ,所以建议加钉钉群
# JAVA解析Excel工具easyexcel # JAVA解析Excel工具EasyExcel
Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。easyexcel重写了poi对07版Excel的解析,能够原本一个3M的excel用POI sax依然需要100M左右内存降低到几M,并且再大的excel不会出现内存溢出,03版依赖POI的sax模式。在上层做了模型转换的封装,让使用者更加简单方便 Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。easyexcel重写了poi对07版Excel的解析,一个3M的excel用POI sax解析依然需要100M左右内存,改用easyexcel可以降低到几M,并且再大的excel也不会出现内存溢出;03版依赖POI的sax模式,在上层做了模型转换的封装,让使用者更加简单方便
## 64M内存1分钟内读取75M(46W行25列)的Excel ## 64M内存1分钟内读取75M(46W行25列)的Excel
当然还有速模式能更快,但是内存占用会在100M多一点 当然还有速模式能更快,但是内存占用会在100M多一点
![img](img/readme/large.png) ![img](img/readme/large.png)
## 相关文档 ## 相关文档
* [快速使用](https://alibaba-easyexcel.github.io/) * [快速开始](https://www.yuque.com/easyexcel/doc/easyexcel)
* [关于软件](/abouteasyexcel.md) * [关于软件](/abouteasyexcel.md)
* [更新记事](/update.md) * [更新记事](/update.md)
* [贡献代码](https://alibaba-easyexcel.github.io/support/contribute.html) * [贡献代码](https://www.yuque.com/easyexcel/doc/contribute)
## 维护者 ## 维护者
玉霄、庄家钜、怀宇 玉霄、庄家钜、怀宇
@ -65,18 +71,21 @@ DEMO代码地址:[https://github.com/alibaba/easyexcel/blob/master/src/test/ja
```java ```java
/** /**
* 文件下载(失败了会返回一个有部分数据的Excel) * 文件下载(失败了会返回一个有部分数据的Excel)
* <p>1. 创建excel对应的实体对象 参照{@link DownloadData} * <p>
* <p>2. 设置返回的 参数 * 1. 创建excel对应的实体对象 参照{@link DownloadData}
* <p>3. 直接写,这里注意,finish的时候会自动关闭OutputStream,当然你外面再关闭流问题不大 * <p>
* 2. 设置返回的 参数
* <p>
* 3. 直接写,这里注意,finish的时候会自动关闭OutputStream,当然你外面再关闭流问题不大
*/ */
@GetMapping("download") @GetMapping("download")
public void download(HttpServletResponse response) throws IOException { public void download(HttpServletResponse response) throws IOException {
// 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman // 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman
response.setContentType("application/vnd.ms-excel"); response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8"); response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系 // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
String fileName = URLEncoder.encode("测试", "UTF-8"); String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx"); response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
EasyExcel.write(response.getOutputStream(), DownloadData.class).sheet("模板").doWrite(data()); EasyExcel.write(response.getOutputStream(), DownloadData.class).sheet("模板").doWrite(data());
} }

50
pom.xml

@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>com.alibaba</groupId> <groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId> <artifactId>easyexcel</artifactId>
<version>2.2.0-beta2</version> <version>3.0.0-beta1</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>easyexcel</name> <name>easyexcel</name>
@ -16,7 +16,7 @@
<properties> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<jdk.version>1.6</jdk.version> <jdk.version>1.8</jdk.version>
<gpg.skip>true</gpg.skip> <gpg.skip>true</gpg.skip>
<maven.javadoc.skip>true</maven.javadoc.skip> <maven.javadoc.skip>true</maven.javadoc.skip>
</properties> </properties>
@ -60,22 +60,22 @@
<dependency> <dependency>
<groupId>org.apache.poi</groupId> <groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId> <artifactId>poi</artifactId>
<version>3.17</version> <version>4.1.2</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.poi</groupId> <groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId> <artifactId>poi-ooxml</artifactId>
<version>3.17</version> <version>4.1.2</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.poi</groupId> <groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId> <artifactId>poi-ooxml-schemas</artifactId>
<version>3.17</version> <version>4.1.2</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>cglib</groupId> <groupId>cglib</groupId>
<artifactId>cglib</artifactId> <artifactId>cglib</artifactId>
<version>3.1</version> <version>3.3.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
@ -85,8 +85,15 @@
<dependency> <dependency>
<groupId>org.ehcache</groupId> <groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId> <artifactId>ehcache</artifactId>
<version>3.4.0</version> <version>3.8.1</version>
</dependency> </dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
<scope>provided</scope>
</dependency>
<!--test--> <!--test-->
<dependency> <dependency>
<groupId>ch.qos.logback</groupId> <groupId>ch.qos.logback</groupId>
@ -97,13 +104,7 @@
<dependency> <dependency>
<groupId>com.alibaba</groupId> <groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId> <artifactId>fastjson</artifactId>
<version>1.2.58</version> <version>1.2.71</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
@ -121,7 +122,7 @@
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
<artifactId>junit</artifactId> <artifactId>junit</artifactId>
<version>4.12</version> <version>4.13.1</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>
@ -162,6 +163,8 @@
<exclude>com/alibaba/excel/event/AnalysisEventListener.java</exclude> <exclude>com/alibaba/excel/event/AnalysisEventListener.java</exclude>
<exclude>com/alibaba/excel/metadata/DataFormatter.java</exclude> <exclude>com/alibaba/excel/metadata/DataFormatter.java</exclude>
<exclude>com/alibaba/excel/util/DateUtils.java</exclude> <exclude>com/alibaba/excel/util/DateUtils.java</exclude>
<exclude>com/alibaba/excel/metadata/format/DataFormatter.java</exclude>
<exclude>com/alibaba/excel/metadata/format/ExcelGeneralNumberFormat.java</exclude>
</excludes> </excludes>
</configuration> </configuration>
<executions> <executions>
@ -185,8 +188,8 @@
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<configuration> <configuration>
<source>1.6</source> <source>1.8</source>
<target>1.6</target> <target>1.8</target>
</configuration> </configuration>
</plugin> </plugin>
<plugin> <plugin>
@ -230,6 +233,19 @@
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
<plugin>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-maven-plugin</artifactId>
<version>1.18.20.0</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>delombok</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins> </plugins>
</build> </build>
</project> </project>

4
src/main/java/com/alibaba/excel/ExcelReader.java

@ -136,6 +136,8 @@ public class ExcelReader {
readWorkbook.setReadCache(new MapCache()); readWorkbook.setReadCache(new MapCache());
readWorkbook.setConvertAllFiled(Boolean.FALSE); readWorkbook.setConvertAllFiled(Boolean.FALSE);
readWorkbook.setDefaultReturnMap(Boolean.FALSE); readWorkbook.setDefaultReturnMap(Boolean.FALSE);
// The previous logic was that Article 0 started reading
readWorkbook.setHeadRowNumber(0);
excelAnalyser = new ExcelAnalyserImpl(readWorkbook); excelAnalyser = new ExcelAnalyserImpl(readWorkbook);
} }
@ -274,8 +276,10 @@ public class ExcelReader {
* Complete the entire read file.Release the cache and close stream. * Complete the entire read file.Release the cache and close stream.
*/ */
public void finish() { public void finish() {
if (excelAnalyser != null) {
excelAnalyser.finish(); excelAnalyser.finish();
} }
}
/** /**
* Prevents calls to {@link #finish} from freeing the cache * Prevents calls to {@link #finish} from freeing the cache

20
src/main/java/com/alibaba/excel/ExcelWriter.java

@ -3,6 +3,8 @@ package com.alibaba.excel;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List; import java.util.List;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -142,7 +144,7 @@ public class ExcelWriter {
* Write to this sheet * Write to this sheet
* @return this current writer * @return this current writer
*/ */
public ExcelWriter write(List data, WriteSheet writeSheet) { public ExcelWriter write(Collection<?> data, WriteSheet writeSheet) {
return write(data, writeSheet, null); return write(data, writeSheet, null);
} }
@ -157,7 +159,7 @@ public class ExcelWriter {
* Write to this table * Write to this table
* @return this * @return this
*/ */
public ExcelWriter write(List data, WriteSheet writeSheet, WriteTable writeTable) { public ExcelWriter write(Collection<?> data, WriteSheet writeSheet, WriteTable writeTable) {
excelBuilder.addContent(data, writeSheet, writeTable); excelBuilder.addContent(data, writeSheet, writeTable);
return this; return this;
} }
@ -194,7 +196,7 @@ public class ExcelWriter {
* @param sheet * @param sheet
* Write to this sheet * Write to this sheet
* @return this current writer * @return this current writer
* @deprecated please use {@link ExcelWriter#write(List, WriteSheet)} * @deprecated please use {@link ExcelWriter#write(Collection, WriteSheet)}
*/ */
@Deprecated @Deprecated
public ExcelWriter write(List data, Sheet sheet) { public ExcelWriter write(List data, Sheet sheet) {
@ -211,7 +213,7 @@ public class ExcelWriter {
* @param table * @param table
* Write to this table * Write to this table
* @return this * @return this
* @deprecated * @deprecated please use {@link ExcelWriter#write(List, WriteSheet,WriteTable)} * @deprecated * @deprecated please use {@link ExcelWriter#write(Collection, WriteSheet,WriteTable)}
*/ */
@Deprecated @Deprecated
public ExcelWriter write(List data, Sheet sheet, Table table) { public ExcelWriter write(List data, Sheet sheet, Table table) {
@ -246,7 +248,7 @@ public class ExcelWriter {
* @param sheet * @param sheet
* Write to this sheet * Write to this sheet
* @return this current writer * @return this current writer
* @deprecated please use {@link ExcelWriter#write(List, WriteSheet)} * @deprecated please use {@link ExcelWriter#write(Collection, WriteSheet)}
*/ */
@Deprecated @Deprecated
public ExcelWriter write0(List data, Sheet sheet) { public ExcelWriter write0(List data, Sheet sheet) {
@ -263,7 +265,7 @@ public class ExcelWriter {
* @param table * @param table
* Write to this table * Write to this table
* @return this * @return this
* @deprecated * @deprecated please use {@link ExcelWriter#write(List, WriteSheet,WriteTable)} * @deprecated * @deprecated please use {@link ExcelWriter#write(Collection, WriteSheet,WriteTable)}
*/ */
@Deprecated @Deprecated
public ExcelWriter write0(List data, Sheet sheet, Table table) { public ExcelWriter write0(List data, Sheet sheet, Table table) {
@ -278,7 +280,7 @@ public class ExcelWriter {
* @param sheet * @param sheet
* Write to this sheet * Write to this sheet
* @return this current writer * @return this current writer
* @deprecated please use {@link ExcelWriter#write(List, WriteSheet)} * @deprecated please use {@link ExcelWriter#write(Collection, WriteSheet)}
*/ */
@Deprecated @Deprecated
public ExcelWriter write1(List data, Sheet sheet) { public ExcelWriter write1(List data, Sheet sheet) {
@ -295,7 +297,7 @@ public class ExcelWriter {
* @param table * @param table
* Write to this table * Write to this table
* @return this * @return this
* @deprecated * @deprecated please use {@link ExcelWriter#write(List, WriteSheet,WriteTable)} * @deprecated * @deprecated please use {@link ExcelWriter#write(Collection, WriteSheet,WriteTable)}
*/ */
@Deprecated @Deprecated
public ExcelWriter write1(List data, Sheet sheet, Table table) { public ExcelWriter write1(List data, Sheet sheet, Table table) {
@ -325,8 +327,10 @@ public class ExcelWriter {
* Close IO * Close IO
*/ */
public void finish() { public void finish() {
if (excelBuilder != null) {
excelBuilder.finish(false); excelBuilder.finish(false);
} }
}
/** /**
* Prevents calls to {@link #finish} from freeing the cache * Prevents calls to {@link #finish} from freeing the cache

2
src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java

@ -3,6 +3,7 @@ package com.alibaba.excel.analysis;
import java.io.InputStream; import java.io.InputStream;
import java.util.List; import java.util.List;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey; import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey;
import org.apache.poi.poifs.crypt.Decryptor; import org.apache.poi.poifs.crypt.Decryptor;
import org.apache.poi.poifs.filesystem.DocumentFactoryHelper; import org.apache.poi.poifs.filesystem.DocumentFactoryHelper;
@ -26,7 +27,6 @@ import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder;
import com.alibaba.excel.read.metadata.holder.xls.XlsReadWorkbookHolder; import com.alibaba.excel.read.metadata.holder.xls.XlsReadWorkbookHolder;
import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadWorkbookHolder; import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadWorkbookHolder;
import com.alibaba.excel.support.ExcelTypeEnum; import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.util.CollectionUtils;
import com.alibaba.excel.util.DateUtils; import com.alibaba.excel.util.DateUtils;
import com.alibaba.excel.util.FileUtils; import com.alibaba.excel.util.FileUtils;
import com.alibaba.excel.util.NumberDataFormatterUtils; import com.alibaba.excel.util.NumberDataFormatterUtils;

13
src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java

@ -70,12 +70,12 @@ import com.alibaba.excel.read.metadata.holder.xls.XlsReadWorkbookHolder;
* <p> * <p>
* * To turn an excel file into a CSV or similar, then see * the XLS2CSVmra example * * * To turn an excel file into a CSV or similar, then see * the XLS2CSVmra example *
* </p> * </p>
* * * @see <a href= * * * @see <a href= "http://svn.apache.org/repos/asf/poi/trunk/src/examples/src/org/apache/poi/hssf/eventusermodel/examples/XLS2CSVmra.java">XLS2CSVmra</a>
* "http://svn.apache.org/repos/asf/poi/trunk/src/examples/src/org/apache/poi/hssf/eventusermodel/examples/XLS2CSVmra.java">XLS2CSVmra</a>
* *
* @author jipengfei * @author jipengfei
*/ */
public class XlsSaxAnalyser implements HSSFListener, ExcelReadExecutor { public class XlsSaxAnalyser implements HSSFListener, ExcelReadExecutor {
private static final Logger LOGGER = LoggerFactory.getLogger(XlsSaxAnalyser.class); private static final Logger LOGGER = LoggerFactory.getLogger(XlsSaxAnalyser.class);
private static final short DUMMY_RECORD_SID = -1; private static final short DUMMY_RECORD_SID = -1;
private XlsReadContext xlsReadContext; private XlsReadContext xlsReadContext;
@ -138,11 +138,6 @@ public class XlsSaxAnalyser implements HSSFListener, ExcelReadExecutor {
} catch (IOException e) { } catch (IOException e) {
throw new ExcelAnalysisException(e); throw new ExcelAnalysisException(e);
} }
// Sometimes tables lack the end record of the last column
if (!xlsReadContext.xlsReadSheetHolder().getCellMap().isEmpty()) {
// Forge a termination data
processRecord(new LastCellOfRowDummyRecord(xlsReadContext.xlsReadSheetHolder().getRowIndex() + 1, -1));
}
} }
@Override @Override
@ -151,8 +146,8 @@ public class XlsSaxAnalyser implements HSSFListener, ExcelReadExecutor {
if (handler == null) { if (handler == null) {
return; return;
} }
boolean ignoreRecord = (handler instanceof IgnorableXlsRecordHandler) boolean ignoreRecord =
&& xlsReadContext.xlsReadSheetHolder() != null && xlsReadContext.xlsReadSheetHolder().getIgnoreRecord(); (handler instanceof IgnorableXlsRecordHandler) && xlsReadContext.xlsReadWorkbookHolder().getIgnoreRecord();
if (ignoreRecord) { if (ignoreRecord) {
// No need to read the current sheet // No need to read the current sheet
return; return;

13
src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java

@ -22,10 +22,11 @@ public class BofRecordHandler extends AbstractXlsRecordHandler {
@Override @Override
public void processRecord(XlsReadContext xlsReadContext, Record record) { public void processRecord(XlsReadContext xlsReadContext, Record record) {
BOFRecord br = (BOFRecord)record; BOFRecord br = (BOFRecord) record;
XlsReadWorkbookHolder xlsReadWorkbookHolder = xlsReadContext.xlsReadWorkbookHolder(); XlsReadWorkbookHolder xlsReadWorkbookHolder = xlsReadContext.xlsReadWorkbookHolder();
if (br.getType() == BOFRecord.TYPE_WORKBOOK) { if (br.getType() == BOFRecord.TYPE_WORKBOOK) {
xlsReadWorkbookHolder.setReadSheetIndex(null); xlsReadWorkbookHolder.setReadSheetIndex(null);
xlsReadWorkbookHolder.setIgnoreRecord(Boolean.FALSE);
return; return;
} }
if (br.getType() != BOFRecord.TYPE_WORKSHEET) { if (br.getType() != BOFRecord.TYPE_WORKSHEET) {
@ -38,15 +39,15 @@ public class BofRecordHandler extends AbstractXlsRecordHandler {
readSheetIndex = 0; readSheetIndex = 0;
xlsReadWorkbookHolder.setReadSheetIndex(readSheetIndex); xlsReadWorkbookHolder.setReadSheetIndex(readSheetIndex);
} }
ReadSheet readSheet = xlsReadWorkbookHolder.getActualSheetDataList().get(readSheetIndex); ReadSheet actualReadSheet = xlsReadWorkbookHolder.getActualSheetDataList().get(readSheetIndex);
assert readSheet != null : "Can't find the sheet."; assert actualReadSheet != null : "Can't find the sheet.";
// Copy the parameter to the current sheet // Copy the parameter to the current sheet
readSheet = SheetUtils.match(readSheet, xlsReadContext); ReadSheet readSheet = SheetUtils.match(actualReadSheet, xlsReadContext);
if (readSheet != null) { if (readSheet != null) {
xlsReadContext.currentSheet(readSheet); xlsReadContext.currentSheet(readSheet);
xlsReadContext.xlsReadSheetHolder().setIgnoreRecord(Boolean.FALSE); xlsReadContext.xlsReadWorkbookHolder().setIgnoreRecord(Boolean.FALSE);
} else { } else {
xlsReadContext.xlsReadSheetHolder().setIgnoreRecord(Boolean.TRUE); xlsReadContext.xlsReadWorkbookHolder().setIgnoreRecord(Boolean.TRUE);
} }
// Go read the next one // Go read the next one
xlsReadWorkbookHolder.setReadSheetIndex(xlsReadWorkbookHolder.getReadSheetIndex() + 1); xlsReadWorkbookHolder.setReadSheetIndex(xlsReadWorkbookHolder.getReadSheetIndex() + 1);

24
src/main/java/com/alibaba/excel/analysis/v03/handlers/EofRecordHandler.java

@ -1,9 +1,16 @@
package com.alibaba.excel.analysis.v03.handlers; package com.alibaba.excel.analysis.v03.handlers;
import java.util.LinkedHashMap;
import org.apache.poi.hssf.eventusermodel.dummyrecord.LastCellOfRowDummyRecord;
import org.apache.poi.hssf.record.Record; import org.apache.poi.hssf.record.Record;
import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler;
import com.alibaba.excel.context.xls.XlsReadContext; import com.alibaba.excel.context.xls.XlsReadContext;
import com.alibaba.excel.enums.RowTypeEnum;
import com.alibaba.excel.metadata.Cell;
import com.alibaba.excel.read.metadata.holder.ReadRowHolder;
import com.alibaba.excel.read.metadata.holder.xls.XlsReadSheetHolder;
/** /**
* Record handler * Record handler
@ -14,8 +21,21 @@ public class EofRecordHandler extends AbstractXlsRecordHandler implements Ignora
@Override @Override
public void processRecord(XlsReadContext xlsReadContext, Record record) { public void processRecord(XlsReadContext xlsReadContext, Record record) {
if (xlsReadContext.readSheetHolder() != null) { if (xlsReadContext.readSheetHolder() == null) {
xlsReadContext.analysisEventProcessor().endSheet(xlsReadContext); return;
}
// Sometimes tables lack the end record of the last column
if (!xlsReadContext.xlsReadSheetHolder().getCellMap().isEmpty()) {
XlsReadSheetHolder xlsReadSheetHolder = xlsReadContext.xlsReadSheetHolder();
// Forge a termination data
xlsReadContext.readRowHolder(new ReadRowHolder(xlsReadContext.xlsReadSheetHolder().getRowIndex() + 1,
xlsReadSheetHolder.getTempRowType(),
xlsReadContext.readSheetHolder().getGlobalConfiguration(), xlsReadSheetHolder.getCellMap()));
xlsReadContext.analysisEventProcessor().endRow(xlsReadContext);
xlsReadSheetHolder.setCellMap(new LinkedHashMap<Integer, Cell>());
xlsReadSheetHolder.setTempRowType(RowTypeEnum.EMPTY);
} }
xlsReadContext.analysisEventProcessor().endSheet(xlsReadContext);
} }
} }

23
src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java

@ -3,20 +3,21 @@ package com.alibaba.excel.analysis.v03.handlers;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Map; import java.util.Map;
import org.apache.poi.hssf.model.HSSFFormulaParser;
import org.apache.poi.hssf.record.FormulaRecord;
import org.apache.poi.hssf.record.Record;
import org.apache.poi.ss.usermodel.CellType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler;
import com.alibaba.excel.constant.BuiltinFormats; import com.alibaba.excel.constant.BuiltinFormats;
import com.alibaba.excel.context.xls.XlsReadContext; import com.alibaba.excel.context.xls.XlsReadContext;
import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.enums.RowTypeEnum;
import com.alibaba.excel.metadata.Cell; import com.alibaba.excel.metadata.Cell;
import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.CellData;
import org.apache.poi.hssf.model.HSSFFormulaParser;
import org.apache.poi.hssf.record.FormulaRecord;
import org.apache.poi.hssf.record.Record;
import org.apache.poi.ss.usermodel.CellType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** /**
* Record handler * Record handler
* *
@ -30,7 +31,7 @@ public class FormulaRecordHandler extends AbstractXlsRecordHandler implements Ig
public void processRecord(XlsReadContext xlsReadContext, Record record) { public void processRecord(XlsReadContext xlsReadContext, Record record) {
FormulaRecord frec = (FormulaRecord)record; FormulaRecord frec = (FormulaRecord)record;
Map<Integer, Cell> cellMap = xlsReadContext.xlsReadSheetHolder().getCellMap(); Map<Integer, Cell> cellMap = xlsReadContext.xlsReadSheetHolder().getCellMap();
CellData tempCellData = new CellData(); CellData<?> tempCellData = new CellData<>();
tempCellData.setRowIndex(frec.getRow()); tempCellData.setRowIndex(frec.getRow());
tempCellData.setColumnIndex((int)frec.getColumn()); tempCellData.setColumnIndex((int)frec.getColumn());
CellType cellType = CellType.forInt(frec.getCachedResultType()); CellType cellType = CellType.forInt(frec.getCachedResultType());
@ -43,6 +44,7 @@ public class FormulaRecordHandler extends AbstractXlsRecordHandler implements Ig
} }
tempCellData.setFormula(Boolean.TRUE); tempCellData.setFormula(Boolean.TRUE);
tempCellData.setFormulaValue(formulaValue); tempCellData.setFormulaValue(formulaValue);
xlsReadContext.xlsReadSheetHolder().setTempRowType(RowTypeEnum.DATA);
switch (cellType) { switch (cellType) {
case STRING: case STRING:
// Formula result is a string // Formula result is a string
@ -55,8 +57,9 @@ public class FormulaRecordHandler extends AbstractXlsRecordHandler implements Ig
tempCellData.setNumberValue(BigDecimal.valueOf(frec.getValue())); tempCellData.setNumberValue(BigDecimal.valueOf(frec.getValue()));
Integer dataFormat = Integer dataFormat =
xlsReadContext.xlsReadWorkbookHolder().getFormatTrackingHSSFListener().getFormatIndex(frec); xlsReadContext.xlsReadWorkbookHolder().getFormatTrackingHSSFListener().getFormatIndex(frec);
tempCellData.setDataFormat(dataFormat); Short dataFormatShort = dataFormat.shortValue();
tempCellData.setDataFormatString(BuiltinFormats.getBuiltinFormat(dataFormat, tempCellData.setDataFormat(dataFormatShort);
tempCellData.setDataFormatString(BuiltinFormats.getBuiltinFormat(dataFormatShort,
xlsReadContext.xlsReadWorkbookHolder().getFormatTrackingHSSFListener().getFormatString(frec), xlsReadContext.xlsReadWorkbookHolder().getFormatTrackingHSSFListener().getFormatString(frec),
xlsReadContext.readSheetHolder().getGlobalConfiguration().getLocale())); xlsReadContext.readSheetHolder().getGlobalConfiguration().getLocale()));
cellMap.put((int)frec.getColumn(), tempCellData); cellMap.put((int)frec.getColumn(), tempCellData);

11
src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java

@ -2,15 +2,15 @@ package com.alibaba.excel.analysis.v03.handlers;
import java.math.BigDecimal; import java.math.BigDecimal;
import org.apache.poi.hssf.record.NumberRecord;
import org.apache.poi.hssf.record.Record;
import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler;
import com.alibaba.excel.constant.BuiltinFormats; import com.alibaba.excel.constant.BuiltinFormats;
import com.alibaba.excel.context.xls.XlsReadContext; import com.alibaba.excel.context.xls.XlsReadContext;
import com.alibaba.excel.enums.RowTypeEnum; import com.alibaba.excel.enums.RowTypeEnum;
import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.CellData;
import org.apache.poi.hssf.record.NumberRecord;
import org.apache.poi.hssf.record.Record;
/** /**
* Record handler * Record handler
* *
@ -21,8 +21,9 @@ public class NumberRecordHandler extends AbstractXlsRecordHandler implements Ign
@Override @Override
public void processRecord(XlsReadContext xlsReadContext, Record record) { public void processRecord(XlsReadContext xlsReadContext, Record record) {
NumberRecord nr = (NumberRecord)record; NumberRecord nr = (NumberRecord)record;
CellData cellData = CellData.newInstance(BigDecimal.valueOf(nr.getValue()), nr.getRow(), (int)nr.getColumn()); CellData<?>cellData = CellData.newInstance(BigDecimal.valueOf(nr.getValue()), nr.getRow(), (int)nr.getColumn());
Integer dataFormat = xlsReadContext.xlsReadWorkbookHolder().getFormatTrackingHSSFListener().getFormatIndex(nr); short dataFormat = (short)xlsReadContext.xlsReadWorkbookHolder().getFormatTrackingHSSFListener().getFormatIndex(
nr);
cellData.setDataFormat(dataFormat); cellData.setDataFormat(dataFormat);
cellData.setDataFormatString(BuiltinFormats.getBuiltinFormat(dataFormat, cellData.setDataFormatString(BuiltinFormats.getBuiltinFormat(dataFormat,
xlsReadContext.xlsReadWorkbookHolder().getFormatTrackingHSSFListener().getFormatString(nr), xlsReadContext.xlsReadWorkbookHolder().getFormatTrackingHSSFListener().getFormatString(nr),

2
src/main/java/com/alibaba/excel/analysis/v03/handlers/StringRecordHandler.java

@ -23,7 +23,7 @@ public class StringRecordHandler extends AbstractXlsRecordHandler implements Ign
// String for formula // String for formula
StringRecord srec = (StringRecord)record; StringRecord srec = (StringRecord)record;
XlsReadSheetHolder xlsReadSheetHolder = xlsReadContext.xlsReadSheetHolder(); XlsReadSheetHolder xlsReadSheetHolder = xlsReadContext.xlsReadSheetHolder();
CellData tempCellData = xlsReadSheetHolder.getTempCellData(); CellData<?>tempCellData = xlsReadSheetHolder.getTempCellData();
if (tempCellData == null) { if (tempCellData == null) {
LOGGER.warn("String type formula but no value found."); LOGGER.warn("String type formula but no value found.");
return; return;

58
src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java

@ -9,9 +9,26 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory; import javax.xml.parsers.SAXParserFactory;
import com.alibaba.excel.analysis.ExcelReadExecutor;
import com.alibaba.excel.analysis.v07.handlers.sax.SharedStringsTableHandler;
import com.alibaba.excel.analysis.v07.handlers.sax.XlsxRowHandler;
import com.alibaba.excel.cache.ReadCache;
import com.alibaba.excel.context.xlsx.XlsxReadContext;
import com.alibaba.excel.enums.CellExtraTypeEnum;
import com.alibaba.excel.exception.ExcelAnalysisException;
import com.alibaba.excel.metadata.CellExtra;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadWorkbookHolder;
import com.alibaba.excel.util.FileUtils;
import com.alibaba.excel.util.SheetUtils;
import com.alibaba.excel.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackageAccess; import org.apache.poi.openxml4j.opc.PackageAccess;
import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.openxml4j.opc.PackagePart;
@ -25,26 +42,13 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbookPr;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.WorkbookDocument; import org.openxmlformats.schemas.spreadsheetml.x2006.main.WorkbookDocument;
import org.xml.sax.ContentHandler; import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource; import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader; import org.xml.sax.XMLReader;
import com.alibaba.excel.analysis.ExcelReadExecutor;
import com.alibaba.excel.analysis.v07.handlers.sax.SharedStringsTableHandler;
import com.alibaba.excel.analysis.v07.handlers.sax.XlsxRowHandler;
import com.alibaba.excel.cache.ReadCache;
import com.alibaba.excel.context.xlsx.XlsxReadContext;
import com.alibaba.excel.enums.CellExtraTypeEnum;
import com.alibaba.excel.exception.ExcelAnalysisException;
import com.alibaba.excel.metadata.CellExtra;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadWorkbookHolder;
import com.alibaba.excel.util.CollectionUtils;
import com.alibaba.excel.util.FileUtils;
import com.alibaba.excel.util.SheetUtils;
import com.alibaba.excel.util.StringUtils;
/** /**
* @author jipengfei * @author jipengfei
*/ */
@Slf4j
public class XlsxSaxAnalyser implements ExcelReadExecutor { public class XlsxSaxAnalyser implements ExcelReadExecutor {
private XlsxReadContext xlsxReadContext; private XlsxReadContext xlsxReadContext;
@ -78,7 +82,9 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor {
XSSFReader xssfReader = new XSSFReader(pkg); XSSFReader xssfReader = new XSSFReader(pkg);
analysisUse1904WindowDate(xssfReader, xlsxReadWorkbookHolder); analysisUse1904WindowDate(xssfReader, xlsxReadWorkbookHolder);
xlsxReadWorkbookHolder.setStylesTable(xssfReader.getStylesTable()); // set style table
setStylesTable(xlsxReadWorkbookHolder, xssfReader);
sheetList = new ArrayList<ReadSheet>(); sheetList = new ArrayList<ReadSheet>();
sheetMap = new HashMap<Integer, InputStream>(); sheetMap = new HashMap<Integer, InputStream>();
commentsTableMap = new HashMap<Integer, CommentsTable>(); commentsTableMap = new HashMap<Integer, CommentsTable>();
@ -101,6 +107,17 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor {
} }
} }
private void setStylesTable(XlsxReadWorkbookHolder xlsxReadWorkbookHolder, XSSFReader xssfReader) {
try {
xlsxReadWorkbookHolder.setStylesTable(xssfReader.getStylesTable());
} catch (Exception e) {
log.warn(
"Currently excel cannot get style information, but it doesn't affect the data analysis.You can try to"
+ " save the file with office again or ignore the current error.",
e);
}
}
private void defaultReadCache(XlsxReadWorkbookHolder xlsxReadWorkbookHolder, private void defaultReadCache(XlsxReadWorkbookHolder xlsxReadWorkbookHolder,
PackagePart sharedStringsTablePackagePart) { PackagePart sharedStringsTablePackagePart) {
ReadCache readCache = xlsxReadWorkbookHolder.getReadCacheSelector().readCache(sharedStringsTablePackagePart); ReadCache readCache = xlsxReadWorkbookHolder.getReadCacheSelector().readCache(sharedStringsTablePackagePart);
@ -147,9 +164,10 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor {
xlsxReadWorkbookHolder.setTempFile(readTempFile); xlsxReadWorkbookHolder.setTempFile(readTempFile);
File tempFile = new File(readTempFile.getPath(), UUID.randomUUID().toString() + ".xlsx"); File tempFile = new File(readTempFile.getPath(), UUID.randomUUID().toString() + ".xlsx");
if (decryptedStream != null) { if (decryptedStream != null) {
FileUtils.writeToFile(tempFile, decryptedStream); FileUtils.writeToFile(tempFile, decryptedStream, false);
} else { } else {
FileUtils.writeToFile(tempFile, xlsxReadWorkbookHolder.getInputStream()); FileUtils.writeToFile(tempFile, xlsxReadWorkbookHolder.getInputStream(),
xlsxReadWorkbookHolder.getAutoCloseStream());
} }
return OPCPackage.open(tempFile, PackageAccess.READ); return OPCPackage.open(tempFile, PackageAccess.READ);
} }
@ -177,9 +195,7 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor {
xmlReader.setContentHandler(handler); xmlReader.setContentHandler(handler);
xmlReader.parse(inputSource); xmlReader.parse(inputSource);
inputStream.close(); inputStream.close();
} catch (ExcelAnalysisException e) { } catch (IOException | ParserConfigurationException | SAXException e) {
throw e;
} catch (Exception e) {
throw new ExcelAnalysisException(e); throw new ExcelAnalysisException(e);
} finally { } finally {
if (inputStream != null) { if (inputStream != null) {

12
src/main/java/com/alibaba/excel/analysis/v07/handlers/AbstractCellValueTagHandler.java

@ -7,6 +7,7 @@ import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadSheetHolder; import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadSheetHolder;
import com.alibaba.excel.util.BooleanUtils; import com.alibaba.excel.util.BooleanUtils;
import com.alibaba.excel.util.StringUtils;
/** /**
* Cell Value Handler * Cell Value Handler
@ -20,6 +21,7 @@ public abstract class AbstractCellValueTagHandler extends AbstractXlsxTagHandler
XlsxReadSheetHolder xlsxReadSheetHolder = xlsxReadContext.xlsxReadSheetHolder(); XlsxReadSheetHolder xlsxReadSheetHolder = xlsxReadContext.xlsxReadSheetHolder();
CellData tempCellData = xlsxReadSheetHolder.getTempCellData(); CellData tempCellData = xlsxReadSheetHolder.getTempCellData();
StringBuilder tempData = xlsxReadSheetHolder.getTempData(); StringBuilder tempData = xlsxReadSheetHolder.getTempData();
String tempDataString = tempData.toString();
CellDataTypeEnum oldType = tempCellData.getType(); CellDataTypeEnum oldType = tempCellData.getType();
switch (oldType) { switch (oldType) {
case DIRECT_STRING: case DIRECT_STRING:
@ -28,10 +30,18 @@ public abstract class AbstractCellValueTagHandler extends AbstractXlsxTagHandler
tempCellData.setStringValue(tempData.toString()); tempCellData.setStringValue(tempData.toString());
break; break;
case BOOLEAN: case BOOLEAN:
if(StringUtils.isEmpty(tempDataString)){
tempCellData.setType(CellDataTypeEnum.EMPTY);
break;
}
tempCellData.setBooleanValue(BooleanUtils.valueOf(tempData.toString())); tempCellData.setBooleanValue(BooleanUtils.valueOf(tempData.toString()));
break; break;
case NUMBER: case NUMBER:
case EMPTY: case EMPTY:
if(StringUtils.isEmpty(tempDataString)){
tempCellData.setType(CellDataTypeEnum.EMPTY);
break;
}
tempCellData.setType(CellDataTypeEnum.NUMBER); tempCellData.setType(CellDataTypeEnum.NUMBER);
tempCellData.setNumberValue(new BigDecimal(tempData.toString())); tempCellData.setNumberValue(new BigDecimal(tempData.toString()));
break; break;
@ -44,7 +54,7 @@ public abstract class AbstractCellValueTagHandler extends AbstractXlsxTagHandler
if (tempCellData.getStringValue() != null if (tempCellData.getStringValue() != null
&& xlsxReadContext.currentReadHolder().globalConfiguration().getAutoTrim()) { && xlsxReadContext.currentReadHolder().globalConfiguration().getAutoTrim()) {
tempCellData.setStringValue(tempCellData.getStringValue()); tempCellData.setStringValue(tempCellData.getStringValue().trim());
} }
tempCellData.checkEmpty(); tempCellData.checkEmpty();

2
src/main/java/com/alibaba/excel/analysis/v07/handlers/CellInlineStringValueTagHandler.java

@ -15,7 +15,7 @@ public class CellInlineStringValueTagHandler extends AbstractCellValueTagHandler
@Override @Override
protected void setStringValue(XlsxReadContext xlsxReadContext) { protected void setStringValue(XlsxReadContext xlsxReadContext) {
// This is a special form of string // This is a special form of string
CellData tempCellData = xlsxReadContext.xlsxReadSheetHolder().getTempCellData(); CellData<?> tempCellData = xlsxReadContext.xlsxReadSheetHolder().getTempCellData();
XSSFRichTextString richTextString = new XSSFRichTextString(tempCellData.getStringValue()); XSSFRichTextString richTextString = new XSSFRichTextString(tempCellData.getStringValue());
tempCellData.setStringValue(richTextString.toString()); tempCellData.setStringValue(richTextString.toString());
} }

16
src/main/java/com/alibaba/excel/analysis/v07/handlers/CellTagHandler.java

@ -1,8 +1,5 @@
package com.alibaba.excel.analysis.v07.handlers; package com.alibaba.excel.analysis.v07.handlers;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.xml.sax.Attributes;
import com.alibaba.excel.constant.BuiltinFormats; import com.alibaba.excel.constant.BuiltinFormats;
import com.alibaba.excel.constant.ExcelXmlConstants; import com.alibaba.excel.constant.ExcelXmlConstants;
import com.alibaba.excel.context.xlsx.XlsxReadContext; import com.alibaba.excel.context.xlsx.XlsxReadContext;
@ -12,6 +9,10 @@ import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadSheetHolder;
import com.alibaba.excel.util.PositionUtils; import com.alibaba.excel.util.PositionUtils;
import com.alibaba.excel.util.StringUtils; import com.alibaba.excel.util.StringUtils;
import org.apache.poi.xssf.model.StylesTable;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.xml.sax.Attributes;
/** /**
* Cell Handler * Cell Handler
* *
@ -46,9 +47,12 @@ public class CellTagHandler extends AbstractXlsxTagHandler {
} else { } else {
dateFormatIndexInteger = Integer.parseInt(dateFormatIndex); dateFormatIndexInteger = Integer.parseInt(dateFormatIndex);
} }
XSSFCellStyle xssfCellStyle = StylesTable stylesTable = xlsxReadContext.xlsxReadWorkbookHolder().getStylesTable();
xlsxReadContext.xlsxReadWorkbookHolder().getStylesTable().getStyleAt(dateFormatIndexInteger); if (stylesTable == null) {
int dataFormat = xssfCellStyle.getDataFormat(); return;
}
XSSFCellStyle xssfCellStyle = stylesTable.getStyleAt(dateFormatIndexInteger);
short dataFormat = xssfCellStyle.getDataFormat();
xlsxReadSheetHolder.getTempCellData().setDataFormat(dataFormat); xlsxReadSheetHolder.getTempCellData().setDataFormat(dataFormat);
xlsxReadSheetHolder.getTempCellData().setDataFormatString(BuiltinFormats.getBuiltinFormat(dataFormat, xlsxReadSheetHolder.getTempCellData().setDataFormatString(BuiltinFormats.getBuiltinFormat(dataFormat,
xssfCellStyle.getDataFormatString(), xlsxReadSheetHolder.getGlobalConfiguration().getLocale())); xssfCellStyle.getDataFormatString(), xlsxReadSheetHolder.getGlobalConfiguration().getLocale()));

5
src/main/java/com/alibaba/excel/analysis/v07/handlers/CellValueTagHandler.java

@ -3,6 +3,7 @@ package com.alibaba.excel.analysis.v07.handlers;
import com.alibaba.excel.context.xlsx.XlsxReadContext; import com.alibaba.excel.context.xlsx.XlsxReadContext;
import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.util.StringUtils;
/** /**
* Cell Value Handler * Cell Value Handler
@ -17,6 +18,10 @@ public class CellValueTagHandler extends AbstractCellValueTagHandler {
CellData tempCellData = xlsxReadContext.xlsxReadSheetHolder().getTempCellData(); CellData tempCellData = xlsxReadContext.xlsxReadSheetHolder().getTempCellData();
switch (tempCellData.getType()) { switch (tempCellData.getType()) {
case STRING: case STRING:
// In some cases, although cell type is a string, it may be an empty tag
if(StringUtils.isEmpty(tempCellData.getStringValue())){
break;
}
String stringValue = xlsxReadContext.readWorkbookHolder().getReadCache() String stringValue = xlsxReadContext.readWorkbookHolder().getReadCache()
.get(Integer.valueOf(tempCellData.getStringValue())); .get(Integer.valueOf(tempCellData.getStringValue()));
if (stringValue != null && xlsxReadContext.currentReadHolder().globalConfiguration().getAutoTrim()) { if (stringValue != null && xlsxReadContext.currentReadHolder().globalConfiguration().getAutoTrim()) {

12
src/main/java/com/alibaba/excel/analysis/v07/handlers/RowTagHandler.java

@ -2,8 +2,6 @@ package com.alibaba.excel.analysis.v07.handlers;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import org.xml.sax.Attributes;
import com.alibaba.excel.constant.ExcelXmlConstants; import com.alibaba.excel.constant.ExcelXmlConstants;
import com.alibaba.excel.context.xlsx.XlsxReadContext; import com.alibaba.excel.context.xlsx.XlsxReadContext;
import com.alibaba.excel.enums.RowTypeEnum; import com.alibaba.excel.enums.RowTypeEnum;
@ -12,6 +10,9 @@ import com.alibaba.excel.read.metadata.holder.ReadRowHolder;
import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadSheetHolder; import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadSheetHolder;
import com.alibaba.excel.util.PositionUtils; import com.alibaba.excel.util.PositionUtils;
import org.apache.commons.collections4.MapUtils;
import org.xml.sax.Attributes;
/** /**
* Cell Handler * Cell Handler
* *
@ -25,7 +26,6 @@ public class RowTagHandler extends AbstractXlsxTagHandler {
int rowIndex = PositionUtils.getRowByRowTagt(attributes.getValue(ExcelXmlConstants.ATTRIBUTE_R), int rowIndex = PositionUtils.getRowByRowTagt(attributes.getValue(ExcelXmlConstants.ATTRIBUTE_R),
xlsxReadSheetHolder.getRowIndex()); xlsxReadSheetHolder.getRowIndex());
Integer lastRowIndex = xlsxReadContext.readSheetHolder().getRowIndex(); Integer lastRowIndex = xlsxReadContext.readSheetHolder().getRowIndex();
if (lastRowIndex != null) {
while (lastRowIndex + 1 < rowIndex) { while (lastRowIndex + 1 < rowIndex) {
xlsxReadContext.readRowHolder(new ReadRowHolder(lastRowIndex + 1, RowTypeEnum.EMPTY, xlsxReadContext.readRowHolder(new ReadRowHolder(lastRowIndex + 1, RowTypeEnum.EMPTY,
xlsxReadSheetHolder.getGlobalConfiguration(), new LinkedHashMap<Integer, Cell>())); xlsxReadSheetHolder.getGlobalConfiguration(), new LinkedHashMap<Integer, Cell>()));
@ -34,18 +34,18 @@ public class RowTagHandler extends AbstractXlsxTagHandler {
xlsxReadSheetHolder.setCellMap(new LinkedHashMap<Integer, Cell>()); xlsxReadSheetHolder.setCellMap(new LinkedHashMap<Integer, Cell>());
lastRowIndex++; lastRowIndex++;
} }
}
xlsxReadSheetHolder.setRowIndex(rowIndex); xlsxReadSheetHolder.setRowIndex(rowIndex);
} }
@Override @Override
public void endElement(XlsxReadContext xlsxReadContext, String name) { public void endElement(XlsxReadContext xlsxReadContext, String name) {
XlsxReadSheetHolder xlsxReadSheetHolder = xlsxReadContext.xlsxReadSheetHolder(); XlsxReadSheetHolder xlsxReadSheetHolder = xlsxReadContext.xlsxReadSheetHolder();
xlsxReadContext.readRowHolder(new ReadRowHolder(xlsxReadSheetHolder.getRowIndex(), RowTypeEnum.DATA, RowTypeEnum rowType = MapUtils.isEmpty(xlsxReadSheetHolder.getCellMap()) ? RowTypeEnum.EMPTY : RowTypeEnum.DATA;
xlsxReadContext.readRowHolder(new ReadRowHolder(xlsxReadSheetHolder.getRowIndex(), rowType,
xlsxReadSheetHolder.getGlobalConfiguration(), xlsxReadSheetHolder.getCellMap())); xlsxReadSheetHolder.getGlobalConfiguration(), xlsxReadSheetHolder.getCellMap()));
xlsxReadContext.analysisEventProcessor().endRow(xlsxReadContext); xlsxReadContext.analysisEventProcessor().endRow(xlsxReadContext);
xlsxReadSheetHolder.setColumnIndex(null); xlsxReadSheetHolder.setColumnIndex(null);
xlsxReadSheetHolder.setCellMap(new LinkedHashMap<Integer, Cell>()); xlsxReadSheetHolder.setCellMap(new LinkedHashMap<>());
} }
} }

15
src/main/java/com/alibaba/excel/annotation/ExcelProperty.java

@ -23,7 +23,7 @@ public @interface ExcelProperty {
* <p> * <p>
* write: It automatically merges when you have more than one head * write: It automatically merges when you have more than one head
* <p> * <p>
* read: When you have multiple heads, take the first one * read: When you have multiple heads, take the last one
* *
* @return The name of the sheet header * @return The name of the sheet header
*/ */
@ -32,12 +32,23 @@ public @interface ExcelProperty {
/** /**
* Index of column * Index of column
* *
* Read or write it on the index of column,If it's equal to -1, it's sorted by Java class * Read or write it on the index of column,If it's equal to -1, it's sorted by Java class.
*
* priority: index &gt; order &gt; default sort
* *
* @return Index of column * @return Index of column
*/ */
int index() default -1; int index() default -1;
/**
* Defines the sort order for an column.
*
* priority: index &gt; order &gt; default sort
*
* @return Order of column
*/
int order() default Integer.MAX_VALUE;
/** /**
* Force the current field to use this converter. * Force the current field to use this converter.
* *

92
src/main/java/com/alibaba/excel/cache/Ehcache.java vendored

@ -1,50 +1,49 @@
package com.alibaba.excel.cache; package com.alibaba.excel.cache;
import java.io.File; import java.io.File;
import java.util.HashMap; import java.util.ArrayList;
import java.util.UUID; import java.util.UUID;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.util.FileUtils;
import com.alibaba.excel.util.ListUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.ehcache.CacheManager; import org.ehcache.CacheManager;
import org.ehcache.config.CacheConfiguration; import org.ehcache.config.CacheConfiguration;
import org.ehcache.config.builders.CacheConfigurationBuilder; import org.ehcache.config.builders.CacheConfigurationBuilder;
import org.ehcache.config.builders.CacheManagerBuilder; import org.ehcache.config.builders.CacheManagerBuilder;
import org.ehcache.config.builders.ResourcePoolsBuilder; import org.ehcache.config.builders.ResourcePoolsBuilder;
import org.ehcache.config.units.MemoryUnit; import org.ehcache.config.units.MemoryUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.util.CollectionUtils;
import com.alibaba.excel.util.FileUtils;
/** /**
* Default cache * Default cache
* *
* @author Jiaju Zhuang * @author Jiaju Zhuang
*/ */
@Slf4j
public class Ehcache implements ReadCache { public class Ehcache implements ReadCache {
public static final int BATCH_COUNT = 1000;
private static final Logger LOGGER = LoggerFactory.getLogger(Ehcache.class);
private static final int BATCH_COUNT = 1000;
private static final int DEBUG_WRITE_SIZE = 100 * 10000;
private static final int DEBUG_CACHE_MISS_SIZE = 1000;
/** /**
* Key index * Key index
*/ */
private int index = 0; private int activeIndex = 0;
private HashMap<Integer, String> dataMap = new HashMap<Integer, String>(BATCH_COUNT * 4 / 3 + 1); public static final int DEBUG_CACHE_MISS_SIZE = 1000;
private static CacheManager fileCacheManager; public static final int DEBUG_WRITE_SIZE = 100 * 10000;
private static CacheConfiguration<Integer, HashMap> fileCacheConfiguration; private ArrayList<String> dataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
private static CacheManager activeCacheManager; private static final CacheManager FILE_CACHE_MANAGER;
private CacheConfiguration<Integer, HashMap> activeCacheConfiguration; private static final CacheConfiguration<Integer, ArrayList> FILE_CACHE_CONFIGURATION;
private static final CacheManager ACTIVE_CACHE_MANAGER;
private final CacheConfiguration<Integer, ArrayList> activeCacheConfiguration;
/** /**
* Bulk storage data * Bulk storage data
*/ */
private org.ehcache.Cache<Integer, HashMap> fileCache; private org.ehcache.Cache<Integer, ArrayList> fileCache;
/** /**
* Currently active cache * Currently active cache
*/ */
private org.ehcache.Cache<Integer, HashMap> activeCache; private org.ehcache.Cache<Integer, ArrayList> activeCache;
private String cacheAlias; private String cacheAlias;
/** /**
* Count the number of cache misses * Count the number of cache misses
@ -53,7 +52,7 @@ public class Ehcache implements ReadCache {
public Ehcache(int maxCacheActivateSize) { public Ehcache(int maxCacheActivateSize) {
activeCacheConfiguration = CacheConfigurationBuilder activeCacheConfiguration = CacheConfigurationBuilder
.newCacheConfigurationBuilder(Integer.class, HashMap.class, .newCacheConfigurationBuilder(Integer.class, ArrayList.class,
ResourcePoolsBuilder.newResourcePoolsBuilder().heap(maxCacheActivateSize, MemoryUnit.MB)) ResourcePoolsBuilder.newResourcePoolsBuilder().heap(maxCacheActivateSize, MemoryUnit.MB))
.withSizeOfMaxObjectGraph(1000 * 1000L).withSizeOfMaxObjectSize(maxCacheActivateSize, MemoryUnit.MB) .withSizeOfMaxObjectGraph(1000 * 1000L).withSizeOfMaxObjectSize(maxCacheActivateSize, MemoryUnit.MB)
.build(); .build();
@ -61,11 +60,11 @@ public class Ehcache implements ReadCache {
static { static {
File cacheFile = FileUtils.createCacheTmpFile(); File cacheFile = FileUtils.createCacheTmpFile();
fileCacheManager = FILE_CACHE_MANAGER =
CacheManagerBuilder.newCacheManagerBuilder().with(CacheManagerBuilder.persistence(cacheFile)).build(true); CacheManagerBuilder.newCacheManagerBuilder().with(CacheManagerBuilder.persistence(cacheFile)).build(true);
activeCacheManager = CacheManagerBuilder.newCacheManagerBuilder().build(true); ACTIVE_CACHE_MANAGER = CacheManagerBuilder.newCacheManagerBuilder().build(true);
fileCacheConfiguration = CacheConfigurationBuilder FILE_CACHE_CONFIGURATION = CacheConfigurationBuilder
.newCacheConfigurationBuilder(Integer.class, HashMap.class, .newCacheConfigurationBuilder(Integer.class, ArrayList.class,
ResourcePoolsBuilder.newResourcePoolsBuilder().disk(10, MemoryUnit.GB)) ResourcePoolsBuilder.newResourcePoolsBuilder().disk(10, MemoryUnit.GB))
.withSizeOfMaxObjectGraph(1000 * 1000L).withSizeOfMaxObjectSize(10, MemoryUnit.GB).build(); .withSizeOfMaxObjectGraph(1000 * 1000L).withSizeOfMaxObjectSize(10, MemoryUnit.GB).build();
} }
@ -73,21 +72,22 @@ public class Ehcache implements ReadCache {
@Override @Override
public void init(AnalysisContext analysisContext) { public void init(AnalysisContext analysisContext) {
cacheAlias = UUID.randomUUID().toString(); cacheAlias = UUID.randomUUID().toString();
fileCache = fileCacheManager.createCache(cacheAlias, fileCacheConfiguration); fileCache = FILE_CACHE_MANAGER.createCache(cacheAlias, FILE_CACHE_CONFIGURATION);
activeCache = activeCacheManager.createCache(cacheAlias, activeCacheConfiguration); activeCache = ACTIVE_CACHE_MANAGER.createCache(cacheAlias, activeCacheConfiguration);
} }
@Override @Override
public void put(String value) { public void put(String value) {
dataMap.put(index, value); dataList.add(value);
if ((index + 1) % BATCH_COUNT == 0) { if (dataList.size() >= BATCH_COUNT) {
fileCache.put(index / BATCH_COUNT, dataMap); fileCache.put(activeIndex, dataList);
dataMap = new HashMap<Integer, String>(BATCH_COUNT * 4 / 3 + 1); activeIndex++;
dataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
} }
index++; if (log.isDebugEnabled()) {
if (LOGGER.isDebugEnabled()) { int alreadyPut = activeIndex * BATCH_COUNT + dataList.size();
if (index % DEBUG_WRITE_SIZE == 0) { if (alreadyPut % DEBUG_WRITE_SIZE == 0) {
LOGGER.debug("Already put :{}", index); log.debug("Already put :{}", alreadyPut);
} }
} }
} }
@ -98,31 +98,31 @@ public class Ehcache implements ReadCache {
return null; return null;
} }
int route = key / BATCH_COUNT; int route = key / BATCH_COUNT;
HashMap<Integer, String> dataMap = activeCache.get(route); ArrayList<String> dataList = activeCache.get(route);
if (dataMap == null) { if (dataList == null) {
dataMap = fileCache.get(route); dataList = fileCache.get(route);
activeCache.put(route, dataMap); activeCache.put(route, dataList);
if (LOGGER.isDebugEnabled()) { if (log.isDebugEnabled()) {
if (cacheMiss++ % DEBUG_CACHE_MISS_SIZE == 0) { if (cacheMiss++ % DEBUG_CACHE_MISS_SIZE == 0) {
LOGGER.debug("Cache misses count:{}", cacheMiss); log.debug("Cache misses count:{}", cacheMiss);
} }
} }
} }
return dataMap.get(key); return dataList.get(key % BATCH_COUNT);
} }
@Override @Override
public void putFinished() { public void putFinished() {
if (CollectionUtils.isEmpty(dataMap)) { if (CollectionUtils.isEmpty(dataList)) {
return; return;
} }
fileCache.put(index / BATCH_COUNT, dataMap); fileCache.put(activeIndex, dataList);
} }
@Override @Override
public void destroy() { public void destroy() {
fileCacheManager.removeCache(cacheAlias); FILE_CACHE_MANAGER.removeCache(cacheAlias);
activeCacheManager.removeCache(cacheAlias); ACTIVE_CACHE_MANAGER.removeCache(cacheAlias);
} }
} }

10
src/main/java/com/alibaba/excel/cache/MapCache.java vendored

@ -1,26 +1,24 @@
package com.alibaba.excel.cache; package com.alibaba.excel.cache;
import java.util.HashMap; import java.util.ArrayList;
import java.util.Map; import java.util.List;
import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.context.AnalysisContext;
/** /**
*
* Putting temporary data directly into a map is a little more efficient but very memory intensive * Putting temporary data directly into a map is a little more efficient but very memory intensive
* *
* @author Jiaju Zhuang * @author Jiaju Zhuang
*/ */
public class MapCache implements ReadCache { public class MapCache implements ReadCache {
private Map<Integer, String> cache = new HashMap<Integer, String>(); private List<String> cache = new ArrayList<>();
private int index = 0;
@Override @Override
public void init(AnalysisContext analysisContext) {} public void init(AnalysisContext analysisContext) {}
@Override @Override
public void put(String value) { public void put(String value) {
cache.put(index++, value); cache.add(value);
} }
@Override @Override

8
src/main/java/com/alibaba/excel/constant/BuiltinFormats.java

@ -17,7 +17,9 @@ import java.util.Locale;
**/ **/
public class BuiltinFormats { public class BuiltinFormats {
private static final String[] BUILTIN_FORMATS_CN = { public static short GENERAL = 0;
public static final String[] BUILTIN_FORMATS_CN = {
// 0 // 0
"General", "General",
// 1 // 1
@ -189,7 +191,7 @@ public class BuiltinFormats {
// end // end
}; };
private static final String[] BUILTIN_FORMATS_US = { public static final String[] BUILTIN_FORMATS_US = {
// 0 // 0
"General", "General",
// 1 // 1
@ -361,7 +363,7 @@ public class BuiltinFormats {
// end // end
}; };
public static String getBuiltinFormat(Integer index, String defaultFormat, Locale locale) { public static String getBuiltinFormat(Short index, String defaultFormat, Locale locale) {
String[] builtinFormat = switchBuiltinFormats(locale); String[] builtinFormat = switchBuiltinFormats(locale);
if (index == null || index < 0 || index >= builtinFormat.length) { if (index == null || index < 0 || index >= builtinFormat.length) {
return defaultFormat; return defaultFormat;

13
src/main/java/com/alibaba/excel/constant/OrderConstant.java

@ -0,0 +1,13 @@
package com.alibaba.excel.constant;
/**
* Order constant.
*
* @author Jiaju Zhuang
*/
public class OrderConstant {
/**
* Sorting of styles written to cells.
*/
public static final int FILL_DATA_FORMAT = 10000;
}

77
src/main/java/com/alibaba/excel/context/WriteContextImpl.java

@ -6,22 +6,6 @@ import java.io.OutputStream;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackageAccess;
import org.apache.poi.poifs.crypt.EncryptionInfo;
import org.apache.poi.poifs.crypt.EncryptionMode;
import org.apache.poi.poifs.crypt.Encryptor;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.excel.enums.WriteTypeEnum; import com.alibaba.excel.enums.WriteTypeEnum;
import com.alibaba.excel.exception.ExcelGenerateException; import com.alibaba.excel.exception.ExcelGenerateException;
import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.CellData;
@ -42,6 +26,22 @@ import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
import com.alibaba.excel.write.property.ExcelWriteHeadProperty; import com.alibaba.excel.write.property.ExcelWriteHeadProperty;
import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackageAccess;
import org.apache.poi.poifs.crypt.EncryptionInfo;
import org.apache.poi.poifs.crypt.EncryptionMode;
import org.apache.poi.poifs.crypt.Encryptor;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** /**
* A context is the main anchorage point of a excel writer. * A context is the main anchorage point of a excel writer.
* *
@ -50,6 +50,7 @@ import com.alibaba.excel.write.property.ExcelWriteHeadProperty;
public class WriteContextImpl implements WriteContext { public class WriteContextImpl implements WriteContext {
private static final Logger LOGGER = LoggerFactory.getLogger(WriteContextImpl.class); private static final Logger LOGGER = LoggerFactory.getLogger(WriteContextImpl.class);
private static final String NO_SHEETS="no sheets";
/** /**
* The Workbook currently written * The Workbook currently written
@ -111,15 +112,25 @@ public class WriteContextImpl implements WriteContext {
if (selectSheetFromCache(writeSheet)) { if (selectSheetFromCache(writeSheet)) {
return; return;
} }
initCurrentSheetHolder(writeSheet); initCurrentSheetHolder(writeSheet);
// Workbook handler need to supplementary execution
WriteHandlerUtils.beforeWorkbookCreate(this, true);
WriteHandlerUtils.afterWorkbookCreate(this, true);
// Initialization current sheet // Initialization current sheet
initSheet(writeType); initSheet(writeType);
} }
private boolean selectSheetFromCache(WriteSheet writeSheet) { private boolean selectSheetFromCache(WriteSheet writeSheet) {
writeSheetHolder = null; writeSheetHolder = null;
if (writeSheet.getSheetNo() != null) { Integer sheetNo = writeSheet.getSheetNo();
writeSheetHolder = writeWorkbookHolder.getHasBeenInitializedSheetIndexMap().get(writeSheet.getSheetNo()); if (sheetNo == null && StringUtils.isEmpty(writeSheet.getSheetName())) {
sheetNo = 0;
}
if (sheetNo != null) {
writeSheetHolder = writeWorkbookHolder.getHasBeenInitializedSheetIndexMap().get(sheetNo);
} }
if (writeSheetHolder == null && !StringUtils.isEmpty(writeSheet.getSheetName())) { if (writeSheetHolder == null && !StringUtils.isEmpty(writeSheet.getSheetName())) {
writeSheetHolder = writeWorkbookHolder.getHasBeenInitializedSheetNameMap().get(writeSheet.getSheetName()); writeSheetHolder = writeWorkbookHolder.getHasBeenInitializedSheetNameMap().get(writeSheet.getSheetName());
@ -153,17 +164,27 @@ public class WriteContextImpl implements WriteContext {
Sheet currentSheet; Sheet currentSheet;
try { try {
if (writeSheetHolder.getSheetNo() != null) { if (writeSheetHolder.getSheetNo() != null) {
// When the add default sort order of appearance
if (WriteTypeEnum.ADD.equals(writeType) && writeWorkbookHolder.getTempTemplateInputStream() == null) {
currentSheet = createSheet();
} else {
currentSheet = writeWorkbookHolder.getWorkbook().getSheetAt(writeSheetHolder.getSheetNo()); currentSheet = writeWorkbookHolder.getWorkbook().getSheetAt(writeSheetHolder.getSheetNo());
writeSheetHolder writeSheetHolder
.setCachedSheet(writeWorkbookHolder.getCachedWorkbook().getSheetAt(writeSheetHolder.getSheetNo())); .setCachedSheet(
writeWorkbookHolder.getCachedWorkbook().getSheetAt(writeSheetHolder.getSheetNo()));
}
} else { } else {
// sheet name must not null // sheet name must not null
currentSheet = writeWorkbookHolder.getWorkbook().getSheet(writeSheetHolder.getSheetName()); currentSheet = writeWorkbookHolder.getWorkbook().getSheet(writeSheetHolder.getSheetName());
writeSheetHolder writeSheetHolder
.setCachedSheet(writeWorkbookHolder.getCachedWorkbook().getSheet(writeSheetHolder.getSheetName())); .setCachedSheet(writeWorkbookHolder.getCachedWorkbook().getSheet(writeSheetHolder.getSheetName()));
} }
} catch (Exception e) { } catch (IllegalArgumentException e) {
if (e.getMessage() != null && e.getMessage().contains(NO_SHEETS)) {
currentSheet = createSheet(); currentSheet = createSheet();
} else {
throw e;
}
} }
if (currentSheet == null) { if (currentSheet == null) {
currentSheet = createSheet(); currentSheet = createSheet();
@ -201,8 +222,8 @@ public class WriteContextImpl implements WriteContext {
if (currentWriteHolder.automaticMergeHead()) { if (currentWriteHolder.automaticMergeHead()) {
addMergedRegionToCurrentSheet(excelWriteHeadProperty, newRowIndex); addMergedRegionToCurrentSheet(excelWriteHeadProperty, newRowIndex);
} }
for (int relativeRowIndex = 0, i = newRowIndex; i < excelWriteHeadProperty.getHeadRowNumber() + newRowIndex; for (int relativeRowIndex = 0, i = newRowIndex; i < excelWriteHeadProperty.getHeadRowNumber()
i++, relativeRowIndex++) { + newRowIndex; i++, relativeRowIndex++) {
WriteHandlerUtils.beforeRowCreate(this, newRowIndex, relativeRowIndex, Boolean.TRUE); WriteHandlerUtils.beforeRowCreate(this, newRowIndex, relativeRowIndex, Boolean.TRUE);
Row row = WorkBookUtil.createRow(writeSheetHolder.getSheet(), i); Row row = WorkBookUtil.createRow(writeSheetHolder.getSheet(), i);
WriteHandlerUtils.afterRowCreate(this, row, relativeRowIndex, Boolean.TRUE); WriteHandlerUtils.afterRowCreate(this, row, relativeRowIndex, Boolean.TRUE);
@ -227,7 +248,7 @@ public class WriteContextImpl implements WriteContext {
Cell cell = row.createCell(columnIndex); Cell cell = row.createCell(columnIndex);
WriteHandlerUtils.afterCellCreate(this, cell, head, relativeRowIndex, Boolean.TRUE); WriteHandlerUtils.afterCellCreate(this, cell, head, relativeRowIndex, Boolean.TRUE);
cell.setCellValue(head.getHeadNameList().get(relativeRowIndex)); cell.setCellValue(head.getHeadNameList().get(relativeRowIndex));
WriteHandlerUtils.afterCellDispose(this, (CellData)null, cell, head, relativeRowIndex, Boolean.TRUE); WriteHandlerUtils.afterCellDispose(this, (CellData) null, cell, head, relativeRowIndex, Boolean.TRUE);
} }
} }
@ -251,7 +272,15 @@ public class WriteContextImpl implements WriteContext {
} }
return; return;
} }
initCurrentTableHolder(writeTable); initCurrentTableHolder(writeTable);
// Workbook and sheet handler need to supplementary execution
WriteHandlerUtils.beforeWorkbookCreate(this, true);
WriteHandlerUtils.afterWorkbookCreate(this, true);
WriteHandlerUtils.beforeSheetCreate(this, true);
WriteHandlerUtils.afterSheetCreate(this, true);
initHead(writeTableHolder.excelWriteHeadProperty()); initHead(writeTableHolder.excelWriteHeadProperty());
} }
@ -322,7 +351,7 @@ public class WriteContextImpl implements WriteContext {
try { try {
Workbook workbook = writeWorkbookHolder.getWorkbook(); Workbook workbook = writeWorkbookHolder.getWorkbook();
if (workbook instanceof SXSSFWorkbook) { if (workbook instanceof SXSSFWorkbook) {
((SXSSFWorkbook)workbook).dispose(); ((SXSSFWorkbook) workbook).dispose();
} }
} catch (Throwable t) { } catch (Throwable t) {
throwable = t; throwable = t;

8
src/main/java/com/alibaba/excel/converters/AutoConverter.java

@ -10,10 +10,10 @@ import com.alibaba.excel.metadata.property.ExcelContentProperty;
* *
* @author Jiaju Zhuang * @author Jiaju Zhuang
*/ */
public class AutoConverter implements Converter { public class AutoConverter implements Converter<Object> {
@Override @Override
public Class supportJavaTypeKey() { public Class<?> supportJavaTypeKey() {
return null; return null;
} }
@ -23,13 +23,13 @@ public class AutoConverter implements Converter {
} }
@Override @Override
public Object convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, public Object convertToJavaData(CellData<?> cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
return null; return null;
} }
@Override @Override
public CellData convertToExcelData(Object value, ExcelContentProperty contentProperty, public CellData<?> convertToExcelData(Object value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
return null; return null;
} }

78
src/main/java/com/alibaba/excel/converters/Converter.java

@ -4,12 +4,16 @@ import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.GlobalConfiguration; import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.property.ExcelContentProperty; import com.alibaba.excel.metadata.property.ExcelContentProperty;
import com.alibaba.excel.read.metadata.holder.ReadSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteHolder;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
/** /**
* Convert between Java objects and excel objects * Convert between Java objects and excel objects
* *
* @author Dan Zheng
* @param <T> * @param <T>
* @author Dan Zheng
*/ */
public interface Converter<T> { public interface Converter<T> {
@ -18,44 +22,72 @@ public interface Converter<T> {
* *
* @return Support for Java class * @return Support for Java class
*/ */
Class supportJavaTypeKey(); default Class<?> supportJavaTypeKey() {
throw new UnsupportedOperationException("The current operation is not supported by the current converter.");
}
/** /**
* Back to object enum in excel * Back to object enum in excel
* *
* @return Support for {@link CellDataTypeEnum} * @return Support for {@link CellDataTypeEnum}
*/ */
CellDataTypeEnum supportExcelTypeKey(); default CellDataTypeEnum supportExcelTypeKey() {
throw new UnsupportedOperationException("The current operation is not supported by the current converter.");
}
/**
* Convert excel objects to Java objects
*
* @param cellData Excel cell data.NotNull.
* @param contentProperty Content property.Nullable.
* @param globalConfiguration Global configuration.NotNull.
* @return Data to put into a Java object
* @throws Exception Exception.
*/
default T convertToJavaData(CellData<?> cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) throws Exception {
throw new UnsupportedOperationException("The current operation is not supported by the current converter.");
}
/** /**
* Convert excel objects to Java objects * Convert excel objects to Java objects
* *
* @param cellData * @param cellData Excel cell data.NotNull.
* Excel cell data.NotNull. * @param contentProperty Content property.Nullable.
* @param contentProperty * @param readSheetHolder .NotNull.
* Content property.Nullable.
* @param globalConfiguration
* Global configuration.NotNull.
* @return Data to put into a Java object * @return Data to put into a Java object
* @throws Exception * @throws Exception Exception.
* Exception. */
default T convertToJavaData(CellData<?> cellData,
ExcelContentProperty contentProperty, ReadSheetHolder readSheetHolder) throws Exception {
return convertToJavaData(cellData, contentProperty, readSheetHolder.globalConfiguration());
}
/**
* Convert Java objects to excel objects
*
* @param value Java Data.NotNull.
* @param contentProperty Content property.Nullable.
* @param globalConfiguration Global configuration.NotNull.
* @return Data to put into a Excel
* @throws Exception Exception.
*/ */
T convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, default CellData<?> convertToExcelData(T value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) throws Exception; GlobalConfiguration globalConfiguration) throws Exception {
throw new UnsupportedOperationException("The current operation is not supported by the current converter.");
}
/** /**
* Convert Java objects to excel objects * Convert Java objects to excel objects
* *
* @param value * @param value Java Data.NotNull.
* Java Data.NotNull. * @param contentProperty Content property.Nullable.
* @param contentProperty * @param currentWriteHolder He would be {@link WriteSheetHolder} or {@link WriteTableHolder}.NotNull.
* Content property.Nullable.
* @param globalConfiguration
* Global configuration.NotNull.
* @return Data to put into a Excel * @return Data to put into a Excel
* @throws Exception * @throws Exception Exception.
* Exception.
*/ */
CellData convertToExcelData(T value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) default CellData<?> convertToExcelData(T value, ExcelContentProperty contentProperty,
throws Exception; WriteHolder currentWriteHolder) throws Exception {
return convertToExcelData(value, contentProperty, currentWriteHolder.globalConfiguration());
}
} }

14
src/main/java/com/alibaba/excel/converters/ConverterKeyBuild.java

@ -1,9 +1,9 @@
package com.alibaba.excel.converters; package com.alibaba.excel.converters;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.util.MapUtils;
/** /**
* Converter unique key.Consider that you can just use class as the key. * Converter unique key.Consider that you can just use class as the key.
@ -12,7 +12,7 @@ import com.alibaba.excel.enums.CellDataTypeEnum;
*/ */
public class ConverterKeyBuild { public class ConverterKeyBuild {
private static final Map<String, String> BOXING_MAP = new HashMap<String, String>(16); private static final Map<String, String> BOXING_MAP = MapUtils.newHashMap();
static { static {
BOXING_MAP.put(int.class.getName(), Integer.class.getName()); BOXING_MAP.put(int.class.getName(), Integer.class.getName());
@ -25,7 +25,7 @@ public class ConverterKeyBuild {
BOXING_MAP.put(boolean.class.getName(), Boolean.class.getName()); BOXING_MAP.put(boolean.class.getName(), Boolean.class.getName());
} }
public static String buildKey(Class clazz) { public static String buildKey(Class<?> clazz) {
String className = clazz.getName(); String className = clazz.getName();
String boxingClassName = BOXING_MAP.get(clazz.getName()); String boxingClassName = BOXING_MAP.get(clazz.getName());
if (boxingClassName == null) { if (boxingClassName == null) {
@ -34,7 +34,11 @@ public class ConverterKeyBuild {
return boxingClassName; return boxingClassName;
} }
public static String buildKey(Class clazz, CellDataTypeEnum cellDataTypeEnum) { public static String buildKey(Class<?> clazz, CellDataTypeEnum cellDataTypeEnum) {
return buildKey(clazz) + "-" + cellDataTypeEnum.toString(); String key = buildKey(clazz);
if (cellDataTypeEnum == null) {
return key;
}
return key + "-" + cellDataTypeEnum.toString();
} }
} }

40
src/main/java/com/alibaba/excel/converters/DefaultConverterLoader.java

@ -1,6 +1,5 @@
package com.alibaba.excel.converters; package com.alibaba.excel.converters;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import com.alibaba.excel.converters.bigdecimal.BigDecimalBooleanConverter; import com.alibaba.excel.converters.bigdecimal.BigDecimalBooleanConverter;
@ -14,6 +13,7 @@ import com.alibaba.excel.converters.bytearray.ByteArrayImageConverter;
import com.alibaba.excel.converters.byteconverter.ByteBooleanConverter; import com.alibaba.excel.converters.byteconverter.ByteBooleanConverter;
import com.alibaba.excel.converters.byteconverter.ByteNumberConverter; import com.alibaba.excel.converters.byteconverter.ByteNumberConverter;
import com.alibaba.excel.converters.byteconverter.ByteStringConverter; import com.alibaba.excel.converters.byteconverter.ByteStringConverter;
import com.alibaba.excel.converters.date.DateDateConverter;
import com.alibaba.excel.converters.date.DateNumberConverter; import com.alibaba.excel.converters.date.DateNumberConverter;
import com.alibaba.excel.converters.date.DateStringConverter; import com.alibaba.excel.converters.date.DateStringConverter;
import com.alibaba.excel.converters.doubleconverter.DoubleBooleanConverter; import com.alibaba.excel.converters.doubleconverter.DoubleBooleanConverter;
@ -38,6 +38,7 @@ import com.alibaba.excel.converters.string.StringErrorConverter;
import com.alibaba.excel.converters.string.StringNumberConverter; import com.alibaba.excel.converters.string.StringNumberConverter;
import com.alibaba.excel.converters.string.StringStringConverter; import com.alibaba.excel.converters.string.StringStringConverter;
import com.alibaba.excel.converters.url.UrlImageConverter; import com.alibaba.excel.converters.url.UrlImageConverter;
import com.alibaba.excel.util.MapUtils;
/** /**
* Load default handler * Load default handler
@ -45,8 +46,8 @@ import com.alibaba.excel.converters.url.UrlImageConverter;
* @author Jiaju Zhuang * @author Jiaju Zhuang
*/ */
public class DefaultConverterLoader { public class DefaultConverterLoader {
private static Map<String, Converter> defaultWriteConverter; private static Map<String, Converter<?>> defaultWriteConverter;
private static Map<String, Converter> allConverter; private static Map<String, Converter<?>> allConverter;
static { static {
initDefaultWriteConverter(); initDefaultWriteConverter();
@ -54,7 +55,7 @@ public class DefaultConverterLoader {
} }
private static void initAllConverter() { private static void initAllConverter() {
allConverter = new HashMap<String, Converter>(64); allConverter = MapUtils.newHashMapWithExpectedSize(40);
putAllConverter(new BigDecimalBooleanConverter()); putAllConverter(new BigDecimalBooleanConverter());
putAllConverter(new BigDecimalNumberConverter()); putAllConverter(new BigDecimalNumberConverter());
putAllConverter(new BigDecimalStringConverter()); putAllConverter(new BigDecimalStringConverter());
@ -97,11 +98,11 @@ public class DefaultConverterLoader {
} }
private static void initDefaultWriteConverter() { private static void initDefaultWriteConverter() {
defaultWriteConverter = new HashMap<String, Converter>(32); defaultWriteConverter = MapUtils.newHashMapWithExpectedSize(40);
putWriteConverter(new BigDecimalNumberConverter()); putWriteConverter(new BigDecimalNumberConverter());
putWriteConverter(new BooleanBooleanConverter()); putWriteConverter(new BooleanBooleanConverter());
putWriteConverter(new ByteNumberConverter()); putWriteConverter(new ByteNumberConverter());
putWriteConverter(new DateStringConverter()); putWriteConverter(new DateDateConverter());
putWriteConverter(new DoubleNumberConverter()); putWriteConverter(new DoubleNumberConverter());
putWriteConverter(new FloatNumberConverter()); putWriteConverter(new FloatNumberConverter());
putWriteConverter(new IntegerNumberConverter()); putWriteConverter(new IntegerNumberConverter());
@ -113,6 +114,18 @@ public class DefaultConverterLoader {
putWriteConverter(new ByteArrayImageConverter()); putWriteConverter(new ByteArrayImageConverter());
putWriteConverter(new BoxingByteArrayImageConverter()); putWriteConverter(new BoxingByteArrayImageConverter());
putWriteConverter(new UrlImageConverter()); putWriteConverter(new UrlImageConverter());
// In some cases, it must be converted to string
putWriteStringConverter(new BigDecimalStringConverter());
putWriteStringConverter(new BooleanStringConverter());
putWriteStringConverter(new ByteStringConverter());
putWriteStringConverter(new DateStringConverter());
putWriteStringConverter(new DoubleStringConverter());
putWriteStringConverter(new FloatStringConverter());
putWriteStringConverter(new IntegerStringConverter());
putWriteStringConverter(new LongStringConverter());
putWriteStringConverter(new ShortStringConverter());
putWriteStringConverter(new StringStringConverter());
} }
/** /**
@ -120,20 +133,25 @@ public class DefaultConverterLoader {
* *
* @return * @return
*/ */
public static Map<String, Converter> loadDefaultWriteConverter() { public static Map<String, Converter<?>> loadDefaultWriteConverter() {
return defaultWriteConverter; return defaultWriteConverter;
} }
private static void putWriteConverter(Converter converter) { private static void putWriteConverter(Converter<?> converter) {
defaultWriteConverter.put(ConverterKeyBuild.buildKey(converter.supportJavaTypeKey()), converter); defaultWriteConverter.put(ConverterKeyBuild.buildKey(converter.supportJavaTypeKey()), converter);
} }
private static void putWriteStringConverter(Converter<?> converter) {
defaultWriteConverter.put(
ConverterKeyBuild.buildKey(converter.supportJavaTypeKey(), converter.supportExcelTypeKey()), converter);
}
/** /**
* Load default read converter * Load default read converter
* *
* @return * @return
*/ */
public static Map<String, Converter> loadDefaultReadConverter() { public static Map<String, Converter<?>> loadDefaultReadConverter() {
return loadAllConverter(); return loadAllConverter();
} }
@ -142,11 +160,11 @@ public class DefaultConverterLoader {
* *
* @return * @return
*/ */
public static Map<String, Converter> loadAllConverter() { public static Map<String, Converter<?>> loadAllConverter() {
return allConverter; return allConverter;
} }
private static void putAllConverter(Converter converter) { private static void putAllConverter(Converter<?> converter) {
allConverter.put(ConverterKeyBuild.buildKey(converter.supportJavaTypeKey(), converter.supportExcelTypeKey()), allConverter.put(ConverterKeyBuild.buildKey(converter.supportJavaTypeKey(), converter.supportExcelTypeKey()),
converter); converter);
} }

10
src/main/java/com/alibaba/excel/converters/bigdecimal/BigDecimalBooleanConverter.java

@ -16,7 +16,7 @@ import com.alibaba.excel.metadata.property.ExcelContentProperty;
public class BigDecimalBooleanConverter implements Converter<BigDecimal> { public class BigDecimalBooleanConverter implements Converter<BigDecimal> {
@Override @Override
public Class supportJavaTypeKey() { public Class<BigDecimal> supportJavaTypeKey() {
return BigDecimal.class; return BigDecimal.class;
} }
@ -26,7 +26,7 @@ public class BigDecimalBooleanConverter implements Converter<BigDecimal> {
} }
@Override @Override
public BigDecimal convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, public BigDecimal convertToJavaData(CellData<?> cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
if (cellData.getBooleanValue()) { if (cellData.getBooleanValue()) {
return BigDecimal.ONE; return BigDecimal.ONE;
@ -35,12 +35,12 @@ public class BigDecimalBooleanConverter implements Converter<BigDecimal> {
} }
@Override @Override
public CellData convertToExcelData(BigDecimal value, ExcelContentProperty contentProperty, public CellData<?> convertToExcelData(BigDecimal value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
if (BigDecimal.ONE.equals(value)) { if (BigDecimal.ONE.equals(value)) {
return new CellData(Boolean.TRUE); return new CellData<>(Boolean.TRUE);
} }
return new CellData(Boolean.FALSE); return new CellData<>(Boolean.FALSE);
} }
} }

12
src/main/java/com/alibaba/excel/converters/bigdecimal/BigDecimalNumberConverter.java

@ -7,6 +7,8 @@ import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.GlobalConfiguration; import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.property.ExcelContentProperty; import com.alibaba.excel.metadata.property.ExcelContentProperty;
import com.alibaba.excel.util.NumberUtils;
import com.alibaba.excel.write.metadata.holder.WriteHolder;
/** /**
* BigDecimal and number converter * BigDecimal and number converter
@ -16,7 +18,7 @@ import com.alibaba.excel.metadata.property.ExcelContentProperty;
public class BigDecimalNumberConverter implements Converter<BigDecimal> { public class BigDecimalNumberConverter implements Converter<BigDecimal> {
@Override @Override
public Class supportJavaTypeKey() { public Class<BigDecimal> supportJavaTypeKey() {
return BigDecimal.class; return BigDecimal.class;
} }
@ -26,14 +28,14 @@ public class BigDecimalNumberConverter implements Converter<BigDecimal> {
} }
@Override @Override
public BigDecimal convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, public BigDecimal convertToJavaData(CellData<?> cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
return cellData.getNumberValue(); return cellData.getNumberValue();
} }
@Override @Override
public CellData convertToExcelData(BigDecimal value, ExcelContentProperty contentProperty, public CellData<?> convertToExcelData(BigDecimal value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { WriteHolder currentWriteHolder) {
return new CellData(value); return NumberUtils.formatToCellData(value, contentProperty, currentWriteHolder);
} }
} }

8
src/main/java/com/alibaba/excel/converters/bigdecimal/BigDecimalStringConverter.java

@ -18,7 +18,7 @@ import com.alibaba.excel.util.NumberUtils;
public class BigDecimalStringConverter implements Converter<BigDecimal> { public class BigDecimalStringConverter implements Converter<BigDecimal> {
@Override @Override
public Class supportJavaTypeKey() { public Class<BigDecimal> supportJavaTypeKey() {
return BigDecimal.class; return BigDecimal.class;
} }
@ -28,14 +28,14 @@ public class BigDecimalStringConverter implements Converter<BigDecimal> {
} }
@Override @Override
public BigDecimal convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, public BigDecimal convertToJavaData(CellData<?> cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) throws ParseException { GlobalConfiguration globalConfiguration) throws ParseException {
return NumberUtils.parseBigDecimal(cellData.getStringValue(), contentProperty); return NumberUtils.parseBigDecimal(cellData.getStringValue(), contentProperty);
} }
@Override @Override
public CellData convertToExcelData(BigDecimal value, ExcelContentProperty contentProperty, public CellData<?> convertToExcelData(BigDecimal value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
return NumberUtils.formatToCellData(value, contentProperty); return NumberUtils.formatToCellDataString(value, contentProperty);
} }
} }

8
src/main/java/com/alibaba/excel/converters/booleanconverter/BooleanBooleanConverter.java

@ -14,7 +14,7 @@ import com.alibaba.excel.metadata.property.ExcelContentProperty;
public class BooleanBooleanConverter implements Converter<Boolean> { public class BooleanBooleanConverter implements Converter<Boolean> {
@Override @Override
public Class supportJavaTypeKey() { public Class<?> supportJavaTypeKey() {
return Boolean.class; return Boolean.class;
} }
@ -24,15 +24,15 @@ public class BooleanBooleanConverter implements Converter<Boolean> {
} }
@Override @Override
public Boolean convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, public Boolean convertToJavaData(CellData<?> cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
return cellData.getBooleanValue(); return cellData.getBooleanValue();
} }
@Override @Override
public CellData convertToExcelData(Boolean value, ExcelContentProperty contentProperty, public CellData<?> convertToExcelData(Boolean value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
return new CellData(value); return new CellData<>(value);
} }
} }

10
src/main/java/com/alibaba/excel/converters/booleanconverter/BooleanNumberConverter.java

@ -15,7 +15,7 @@ import com.alibaba.excel.metadata.property.ExcelContentProperty;
*/ */
public class BooleanNumberConverter implements Converter<Boolean> { public class BooleanNumberConverter implements Converter<Boolean> {
@Override @Override
public Class supportJavaTypeKey() { public Class<?> supportJavaTypeKey() {
return Boolean.class; return Boolean.class;
} }
@ -25,7 +25,7 @@ public class BooleanNumberConverter implements Converter<Boolean> {
} }
@Override @Override
public Boolean convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, public Boolean convertToJavaData(CellData<?> cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
if (BigDecimal.ONE.compareTo(cellData.getNumberValue()) == 0) { if (BigDecimal.ONE.compareTo(cellData.getNumberValue()) == 0) {
return Boolean.TRUE; return Boolean.TRUE;
@ -34,12 +34,12 @@ public class BooleanNumberConverter implements Converter<Boolean> {
} }
@Override @Override
public CellData convertToExcelData(Boolean value, ExcelContentProperty contentProperty, public CellData<?> convertToExcelData(Boolean value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
if (value) { if (value) {
return new CellData(BigDecimal.ONE); return new CellData<>(BigDecimal.ONE);
} }
return new CellData(BigDecimal.ZERO); return new CellData<>(BigDecimal.ZERO);
} }
} }

8
src/main/java/com/alibaba/excel/converters/booleanconverter/BooleanStringConverter.java

@ -14,7 +14,7 @@ import com.alibaba.excel.metadata.property.ExcelContentProperty;
public class BooleanStringConverter implements Converter<Boolean> { public class BooleanStringConverter implements Converter<Boolean> {
@Override @Override
public Class supportJavaTypeKey() { public Class<?> supportJavaTypeKey() {
return Boolean.class; return Boolean.class;
} }
@ -24,15 +24,15 @@ public class BooleanStringConverter implements Converter<Boolean> {
} }
@Override @Override
public Boolean convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, public Boolean convertToJavaData(CellData<?> cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
return Boolean.valueOf(cellData.getStringValue()); return Boolean.valueOf(cellData.getStringValue());
} }
@Override @Override
public CellData convertToExcelData(Boolean value, ExcelContentProperty contentProperty, public CellData<?> convertToExcelData(Boolean value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
return new CellData(value.toString()); return new CellData<>(value.toString());
} }
} }

6
src/main/java/com/alibaba/excel/converters/bytearray/BoxingByteArrayImageConverter.java

@ -16,7 +16,7 @@ import com.alibaba.excel.metadata.property.ExcelContentProperty;
*/ */
public class BoxingByteArrayImageConverter implements Converter<Byte[]> { public class BoxingByteArrayImageConverter implements Converter<Byte[]> {
@Override @Override
public Class supportJavaTypeKey() { public Class<?> supportJavaTypeKey() {
return Byte[].class; return Byte[].class;
} }
@ -26,13 +26,13 @@ public class BoxingByteArrayImageConverter implements Converter<Byte[]> {
} }
@Override @Override
public Byte[] convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, public Byte[] convertToJavaData(CellData<?> cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
throw new UnsupportedOperationException("Cannot convert images to byte arrays"); throw new UnsupportedOperationException("Cannot convert images to byte arrays");
} }
@Override @Override
public CellData convertToExcelData(Byte[] value, ExcelContentProperty contentProperty, public CellData<?> convertToExcelData(Byte[] value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
byte[] byteValue = new byte[value.length]; byte[] byteValue = new byte[value.length];
for (int i = 0; i < value.length; i++) { for (int i = 0; i < value.length; i++) {

5
src/main/java/com/alibaba/excel/converters/bytearray/ByteArrayImageConverter.java

@ -16,7 +16,7 @@ import com.alibaba.excel.metadata.property.ExcelContentProperty;
*/ */
public class ByteArrayImageConverter implements Converter<byte[]> { public class ByteArrayImageConverter implements Converter<byte[]> {
@Override @Override
public Class supportJavaTypeKey() { public Class<byte[]> supportJavaTypeKey() {
return byte[].class; return byte[].class;
} }
@ -26,7 +26,8 @@ public class ByteArrayImageConverter implements Converter<byte[]> {
} }
@Override @Override
public byte[] convertToJavaData(CellData cellData, ExcelContentProperty contentProperty,
public byte[] convertToJavaData(CellData<?> cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
throw new UnsupportedOperationException("Cannot convert images to byte arrays"); throw new UnsupportedOperationException("Cannot convert images to byte arrays");
} }

10
src/main/java/com/alibaba/excel/converters/byteconverter/ByteBooleanConverter.java

@ -16,7 +16,7 @@ public class ByteBooleanConverter implements Converter<Byte> {
private static final Byte ZERO = (byte)0; private static final Byte ZERO = (byte)0;
@Override @Override
public Class supportJavaTypeKey() { public Class<?> supportJavaTypeKey() {
return Byte.class; return Byte.class;
} }
@ -26,7 +26,7 @@ public class ByteBooleanConverter implements Converter<Byte> {
} }
@Override @Override
public Byte convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, public Byte convertToJavaData(CellData<?> cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
if (cellData.getBooleanValue()) { if (cellData.getBooleanValue()) {
return ONE; return ONE;
@ -35,12 +35,12 @@ public class ByteBooleanConverter implements Converter<Byte> {
} }
@Override @Override
public CellData convertToExcelData(Byte value, ExcelContentProperty contentProperty, public CellData<?> convertToExcelData(Byte value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
if (ONE.equals(value)) { if (ONE.equals(value)) {
return new CellData(Boolean.TRUE); return new CellData<>(Boolean.TRUE);
} }
return new CellData(Boolean.FALSE); return new CellData<>(Boolean.FALSE);
} }
} }

12
src/main/java/com/alibaba/excel/converters/byteconverter/ByteNumberConverter.java

@ -7,6 +7,8 @@ import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.GlobalConfiguration; import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.property.ExcelContentProperty; import com.alibaba.excel.metadata.property.ExcelContentProperty;
import com.alibaba.excel.util.NumberUtils;
import com.alibaba.excel.write.metadata.holder.WriteHolder;
/** /**
* Byte and number converter * Byte and number converter
@ -16,7 +18,7 @@ import com.alibaba.excel.metadata.property.ExcelContentProperty;
public class ByteNumberConverter implements Converter<Byte> { public class ByteNumberConverter implements Converter<Byte> {
@Override @Override
public Class supportJavaTypeKey() { public Class<?> supportJavaTypeKey() {
return Byte.class; return Byte.class;
} }
@ -26,15 +28,15 @@ public class ByteNumberConverter implements Converter<Byte> {
} }
@Override @Override
public Byte convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, public Byte convertToJavaData(CellData<?> cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
return cellData.getNumberValue().byteValue(); return cellData.getNumberValue().byteValue();
} }
@Override @Override
public CellData convertToExcelData(Byte value, ExcelContentProperty contentProperty, public CellData<?> convertToExcelData(Byte value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { WriteHolder currentWriteHolder) {
return new CellData(new BigDecimal(Byte.toString(value))); return NumberUtils.formatToCellData(value, contentProperty, currentWriteHolder);
} }
} }

8
src/main/java/com/alibaba/excel/converters/byteconverter/ByteStringConverter.java

@ -17,7 +17,7 @@ import com.alibaba.excel.util.NumberUtils;
public class ByteStringConverter implements Converter<Byte> { public class ByteStringConverter implements Converter<Byte> {
@Override @Override
public Class supportJavaTypeKey() { public Class<?> supportJavaTypeKey() {
return Byte.class; return Byte.class;
} }
@ -27,15 +27,15 @@ public class ByteStringConverter implements Converter<Byte> {
} }
@Override @Override
public Byte convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, public Byte convertToJavaData(CellData<?> cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) throws ParseException { GlobalConfiguration globalConfiguration) throws ParseException {
return NumberUtils.parseByte(cellData.getStringValue(), contentProperty); return NumberUtils.parseByte(cellData.getStringValue(), contentProperty);
} }
@Override @Override
public CellData convertToExcelData(Byte value, ExcelContentProperty contentProperty, public CellData<?> convertToExcelData(Byte value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
return NumberUtils.formatToCellData(value, contentProperty); return NumberUtils.formatToCellDataString(value, contentProperty);
} }
} }

47
src/main/java/com/alibaba/excel/converters/date/DateDateConverter.java

@ -0,0 +1,47 @@
package com.alibaba.excel.converters.date;
import java.util.Date;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
import com.alibaba.excel.util.WorkBookUtil;
import com.alibaba.excel.write.metadata.holder.WriteHolder;
/**
* Date and date converter
*
* @author Jiaju Zhuang
*/
public class DateDateConverter implements Converter<Date> {
@Override
public Class<Date> supportJavaTypeKey() {
return Date.class;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.DATE;
}
@Override
public Date convertToJavaData(CellData<?> cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
return cellData.getDateValue();
}
@Override
public CellData<?> convertToExcelData(Date value, ExcelContentProperty contentProperty,
WriteHolder currentWriteHolder) throws Exception {
CellData<?> cellData = new CellData<>(value);
if (contentProperty == null || contentProperty.getDateTimeFormatProperty() == null
|| contentProperty.getDateTimeFormatProperty().getFormat() == null) {
return cellData;
}
WorkBookUtil.fillDataFormat(cellData, currentWriteHolder,
contentProperty.getDateTimeFormatProperty().getFormat());
return cellData;
}
}

10
src/main/java/com/alibaba/excel/converters/date/DateNumberConverter.java

@ -19,7 +19,7 @@ import com.alibaba.excel.metadata.property.ExcelContentProperty;
public class DateNumberConverter implements Converter<Date> { public class DateNumberConverter implements Converter<Date> {
@Override @Override
public Class supportJavaTypeKey() { public Class<?> supportJavaTypeKey() {
return Date.class; return Date.class;
} }
@ -29,7 +29,7 @@ public class DateNumberConverter implements Converter<Date> {
} }
@Override @Override
public Date convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, public Date convertToJavaData(CellData<?> cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
if (contentProperty == null || contentProperty.getDateTimeFormatProperty() == null) { if (contentProperty == null || contentProperty.getDateTimeFormatProperty() == null) {
return DateUtil.getJavaDate(cellData.getNumberValue().doubleValue(), return DateUtil.getJavaDate(cellData.getNumberValue().doubleValue(),
@ -41,13 +41,13 @@ public class DateNumberConverter implements Converter<Date> {
} }
@Override @Override
public CellData convertToExcelData(Date value, ExcelContentProperty contentProperty, public CellData<?> convertToExcelData(Date value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
if (contentProperty == null || contentProperty.getDateTimeFormatProperty() == null) { if (contentProperty == null || contentProperty.getDateTimeFormatProperty() == null) {
return new CellData( return new CellData<>(
BigDecimal.valueOf(DateUtil.getExcelDate(value, globalConfiguration.getUse1904windowing()))); BigDecimal.valueOf(DateUtil.getExcelDate(value, globalConfiguration.getUse1904windowing())));
} else { } else {
return new CellData(BigDecimal.valueOf( return new CellData<>(BigDecimal.valueOf(
DateUtil.getExcelDate(value, contentProperty.getDateTimeFormatProperty().getUse1904windowing()))); DateUtil.getExcelDate(value, contentProperty.getDateTimeFormatProperty().getUse1904windowing())));
} }
} }

10
src/main/java/com/alibaba/excel/converters/date/DateStringConverter.java

@ -17,7 +17,7 @@ import com.alibaba.excel.util.DateUtils;
*/ */
public class DateStringConverter implements Converter<Date> { public class DateStringConverter implements Converter<Date> {
@Override @Override
public Class supportJavaTypeKey() { public Class<?> supportJavaTypeKey() {
return Date.class; return Date.class;
} }
@ -27,7 +27,7 @@ public class DateStringConverter implements Converter<Date> {
} }
@Override @Override
public Date convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, public Date convertToJavaData(CellData<?> cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) throws ParseException { GlobalConfiguration globalConfiguration) throws ParseException {
if (contentProperty == null || contentProperty.getDateTimeFormatProperty() == null) { if (contentProperty == null || contentProperty.getDateTimeFormatProperty() == null) {
return DateUtils.parseDate(cellData.getStringValue(), null); return DateUtils.parseDate(cellData.getStringValue(), null);
@ -38,12 +38,12 @@ public class DateStringConverter implements Converter<Date> {
} }
@Override @Override
public CellData convertToExcelData(Date value, ExcelContentProperty contentProperty, public CellData<?> convertToExcelData(Date value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
if (contentProperty == null || contentProperty.getDateTimeFormatProperty() == null) { if (contentProperty == null || contentProperty.getDateTimeFormatProperty() == null) {
return new CellData(DateUtils.format(value, null)); return new CellData<>(DateUtils.format(value, null));
} else { } else {
return new CellData(DateUtils.format(value, contentProperty.getDateTimeFormatProperty().getFormat())); return new CellData<>(DateUtils.format(value, contentProperty.getDateTimeFormatProperty().getFormat()));
} }
} }
} }

10
src/main/java/com/alibaba/excel/converters/doubleconverter/DoubleBooleanConverter.java

@ -16,7 +16,7 @@ public class DoubleBooleanConverter implements Converter<Double> {
private static final Double ZERO = 0.0; private static final Double ZERO = 0.0;
@Override @Override
public Class supportJavaTypeKey() { public Class<?> supportJavaTypeKey() {
return Double.class; return Double.class;
} }
@ -26,7 +26,7 @@ public class DoubleBooleanConverter implements Converter<Double> {
} }
@Override @Override
public Double convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, public Double convertToJavaData(CellData<?> cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
if (cellData.getBooleanValue()) { if (cellData.getBooleanValue()) {
return ONE; return ONE;
@ -35,12 +35,12 @@ public class DoubleBooleanConverter implements Converter<Double> {
} }
@Override @Override
public CellData convertToExcelData(Double value, ExcelContentProperty contentProperty, public CellData<?> convertToExcelData(Double value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
if (ONE.equals(value)) { if (ONE.equals(value)) {
return new CellData(Boolean.TRUE); return new CellData<>(Boolean.TRUE);
} }
return new CellData(Boolean.FALSE); return new CellData<>(Boolean.FALSE);
} }
} }

13
src/main/java/com/alibaba/excel/converters/doubleconverter/DoubleNumberConverter.java

@ -7,6 +7,8 @@ import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.GlobalConfiguration; import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.property.ExcelContentProperty; import com.alibaba.excel.metadata.property.ExcelContentProperty;
import com.alibaba.excel.util.NumberUtils;
import com.alibaba.excel.write.metadata.holder.WriteHolder;
/** /**
* Double and number converter * Double and number converter
@ -16,7 +18,7 @@ import com.alibaba.excel.metadata.property.ExcelContentProperty;
public class DoubleNumberConverter implements Converter<Double> { public class DoubleNumberConverter implements Converter<Double> {
@Override @Override
public Class supportJavaTypeKey() { public Class<?> supportJavaTypeKey() {
return Double.class; return Double.class;
} }
@ -26,15 +28,14 @@ public class DoubleNumberConverter implements Converter<Double> {
} }
@Override @Override
public Double convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, public Double convertToJavaData(CellData<?> cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
return cellData.getNumberValue().doubleValue(); return cellData.getNumberValue().doubleValue();
} }
@Override @Override
public CellData convertToExcelData(Double value, ExcelContentProperty contentProperty, public CellData<?> convertToExcelData(Double value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { WriteHolder currentWriteHolder) {
return new CellData(BigDecimal.valueOf(value)); return NumberUtils.formatToCellData(value, contentProperty, currentWriteHolder);
} }
} }

8
src/main/java/com/alibaba/excel/converters/doubleconverter/DoubleStringConverter.java

@ -17,7 +17,7 @@ import com.alibaba.excel.util.NumberUtils;
public class DoubleStringConverter implements Converter<Double> { public class DoubleStringConverter implements Converter<Double> {
@Override @Override
public Class supportJavaTypeKey() { public Class<?> supportJavaTypeKey() {
return Double.class; return Double.class;
} }
@ -27,14 +27,14 @@ public class DoubleStringConverter implements Converter<Double> {
} }
@Override @Override
public Double convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, public Double convertToJavaData(CellData<?> cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) throws ParseException { GlobalConfiguration globalConfiguration) throws ParseException {
return NumberUtils.parseDouble(cellData.getStringValue(), contentProperty); return NumberUtils.parseDouble(cellData.getStringValue(), contentProperty);
} }
@Override @Override
public CellData convertToExcelData(Double value, ExcelContentProperty contentProperty, public CellData<?> convertToExcelData(Double value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
return NumberUtils.formatToCellData(value, contentProperty); return NumberUtils.formatToCellDataString(value, contentProperty);
} }
} }

6
src/main/java/com/alibaba/excel/converters/file/FileImageConverter.java

@ -17,7 +17,7 @@ import com.alibaba.excel.util.FileUtils;
*/ */
public class FileImageConverter implements Converter<File> { public class FileImageConverter implements Converter<File> {
@Override @Override
public Class supportJavaTypeKey() { public Class<?> supportJavaTypeKey() {
return File.class; return File.class;
} }
@ -27,13 +27,13 @@ public class FileImageConverter implements Converter<File> {
} }
@Override @Override
public File convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, public File convertToJavaData(CellData<?> cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
throw new UnsupportedOperationException("Cannot convert images to file"); throw new UnsupportedOperationException("Cannot convert images to file");
} }
@Override @Override
public CellData convertToExcelData(File value, ExcelContentProperty contentProperty, public CellData<?> convertToExcelData(File value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) throws IOException { GlobalConfiguration globalConfiguration) throws IOException {
ImagePosition imagePosition = contentProperty.getField().getAnnotation(ImagePosition.class); ImagePosition imagePosition = contentProperty.getField().getAnnotation(ImagePosition.class);
if (imagePosition != null) { if (imagePosition != null) {

10
src/main/java/com/alibaba/excel/converters/floatconverter/FloatBooleanConverter.java

@ -16,7 +16,7 @@ public class FloatBooleanConverter implements Converter<Float> {
private static final Float ZERO = (float)0.0; private static final Float ZERO = (float)0.0;
@Override @Override
public Class supportJavaTypeKey() { public Class<?> supportJavaTypeKey() {
return Float.class; return Float.class;
} }
@ -26,7 +26,7 @@ public class FloatBooleanConverter implements Converter<Float> {
} }
@Override @Override
public Float convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, public Float convertToJavaData(CellData<?> cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
if (cellData.getBooleanValue()) { if (cellData.getBooleanValue()) {
return ONE; return ONE;
@ -35,12 +35,12 @@ public class FloatBooleanConverter implements Converter<Float> {
} }
@Override @Override
public CellData convertToExcelData(Float value, ExcelContentProperty contentProperty, public CellData<?> convertToExcelData(Float value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
if (ONE.equals(value)) { if (ONE.equals(value)) {
return new CellData(Boolean.TRUE); return new CellData<>(Boolean.TRUE);
} }
return new CellData(Boolean.FALSE); return new CellData<>(Boolean.FALSE);
} }
} }

15
src/main/java/com/alibaba/excel/converters/floatconverter/FloatNumberConverter.java

@ -1,12 +1,12 @@
package com.alibaba.excel.converters.floatconverter; package com.alibaba.excel.converters.floatconverter;
import java.math.BigDecimal;
import com.alibaba.excel.converters.Converter; import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.GlobalConfiguration; import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.property.ExcelContentProperty; import com.alibaba.excel.metadata.property.ExcelContentProperty;
import com.alibaba.excel.util.NumberUtils;
import com.alibaba.excel.write.metadata.holder.WriteHolder;
/** /**
* Float and number converter * Float and number converter
@ -16,7 +16,7 @@ import com.alibaba.excel.metadata.property.ExcelContentProperty;
public class FloatNumberConverter implements Converter<Float> { public class FloatNumberConverter implements Converter<Float> {
@Override @Override
public Class supportJavaTypeKey() { public Class<?> supportJavaTypeKey() {
return Float.class; return Float.class;
} }
@ -26,15 +26,14 @@ public class FloatNumberConverter implements Converter<Float> {
} }
@Override @Override
public Float convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, public Float convertToJavaData(CellData<?> cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
return cellData.getNumberValue().floatValue(); return cellData.getNumberValue().floatValue();
} }
@Override @Override
public CellData convertToExcelData(Float value, ExcelContentProperty contentProperty, public CellData<?> convertToExcelData(Float value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { WriteHolder currentWriteHolder) {
return new CellData(new BigDecimal(Float.toString(value))); return NumberUtils.formatToCellData(value, contentProperty, currentWriteHolder);
} }
} }

8
src/main/java/com/alibaba/excel/converters/floatconverter/FloatStringConverter.java

@ -17,7 +17,7 @@ import com.alibaba.excel.util.NumberUtils;
public class FloatStringConverter implements Converter<Float> { public class FloatStringConverter implements Converter<Float> {
@Override @Override
public Class supportJavaTypeKey() { public Class<?> supportJavaTypeKey() {
return Float.class; return Float.class;
} }
@ -27,14 +27,14 @@ public class FloatStringConverter implements Converter<Float> {
} }
@Override @Override
public Float convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, public Float convertToJavaData(CellData<?> cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) throws ParseException { GlobalConfiguration globalConfiguration) throws ParseException {
return NumberUtils.parseFloat(cellData.getStringValue(), contentProperty); return NumberUtils.parseFloat(cellData.getStringValue(), contentProperty);
} }
@Override @Override
public CellData convertToExcelData(Float value, ExcelContentProperty contentProperty, public CellData<?> convertToExcelData(Float value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
return NumberUtils.formatToCellData(value, contentProperty); return NumberUtils.formatToCellDataString(value, contentProperty);
} }
} }

6
src/main/java/com/alibaba/excel/converters/inputstream/InputStreamImageConverter.java

@ -20,7 +20,7 @@ import com.alibaba.excel.util.IoUtils;
*/ */
public class InputStreamImageConverter implements Converter<InputStream> { public class InputStreamImageConverter implements Converter<InputStream> {
@Override @Override
public Class supportJavaTypeKey() { public Class<?> supportJavaTypeKey() {
return InputStream.class; return InputStream.class;
} }
@ -30,13 +30,13 @@ public class InputStreamImageConverter implements Converter<InputStream> {
} }
@Override @Override
public InputStream convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, public InputStream convertToJavaData(CellData<?> cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
throw new UnsupportedOperationException("Cannot convert images to input stream"); throw new UnsupportedOperationException("Cannot convert images to input stream");
} }
@Override @Override
public CellData convertToExcelData(InputStream value, ExcelContentProperty contentProperty, public CellData<?> convertToExcelData(InputStream value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) throws IOException { GlobalConfiguration globalConfiguration) throws IOException {
ImagePosition imagePosition = contentProperty.getField().getAnnotation(ImagePosition.class); ImagePosition imagePosition = contentProperty.getField().getAnnotation(ImagePosition.class);
if (imagePosition != null) { if (imagePosition != null) {

10
src/main/java/com/alibaba/excel/converters/integer/IntegerBooleanConverter.java

@ -16,7 +16,7 @@ public class IntegerBooleanConverter implements Converter<Integer> {
private static final Integer ZERO = 0; private static final Integer ZERO = 0;
@Override @Override
public Class supportJavaTypeKey() { public Class<?> supportJavaTypeKey() {
return Integer.class; return Integer.class;
} }
@ -26,7 +26,7 @@ public class IntegerBooleanConverter implements Converter<Integer> {
} }
@Override @Override
public Integer convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, public Integer convertToJavaData(CellData<?> cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
if (cellData.getBooleanValue()) { if (cellData.getBooleanValue()) {
return ONE; return ONE;
@ -35,12 +35,12 @@ public class IntegerBooleanConverter implements Converter<Integer> {
} }
@Override @Override
public CellData convertToExcelData(Integer value, ExcelContentProperty contentProperty, public CellData<?> convertToExcelData(Integer value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
if (ONE.equals(value)) { if (ONE.equals(value)) {
return new CellData(Boolean.TRUE); return new CellData<>(Boolean.TRUE);
} }
return new CellData(Boolean.FALSE); return new CellData<>(Boolean.FALSE);
} }
} }

14
src/main/java/com/alibaba/excel/converters/integer/IntegerNumberConverter.java

@ -1,12 +1,12 @@
package com.alibaba.excel.converters.integer; package com.alibaba.excel.converters.integer;
import java.math.BigDecimal;
import com.alibaba.excel.converters.Converter; import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.GlobalConfiguration; import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.property.ExcelContentProperty; import com.alibaba.excel.metadata.property.ExcelContentProperty;
import com.alibaba.excel.util.NumberUtils;
import com.alibaba.excel.write.metadata.holder.WriteHolder;
/** /**
* Integer and number converter * Integer and number converter
@ -16,7 +16,7 @@ import com.alibaba.excel.metadata.property.ExcelContentProperty;
public class IntegerNumberConverter implements Converter<Integer> { public class IntegerNumberConverter implements Converter<Integer> {
@Override @Override
public Class supportJavaTypeKey() { public Class<?> supportJavaTypeKey() {
return Integer.class; return Integer.class;
} }
@ -26,15 +26,15 @@ public class IntegerNumberConverter implements Converter<Integer> {
} }
@Override @Override
public Integer convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, public Integer convertToJavaData(CellData<?> cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
return cellData.getNumberValue().intValue(); return cellData.getNumberValue().intValue();
} }
@Override @Override
public CellData convertToExcelData(Integer value, ExcelContentProperty contentProperty, public CellData<?> convertToExcelData(Integer value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { WriteHolder currentWriteHolder) {
return new CellData(new BigDecimal(Integer.toString(value))); return NumberUtils.formatToCellData(value, contentProperty, currentWriteHolder);
} }
} }

8
src/main/java/com/alibaba/excel/converters/integer/IntegerStringConverter.java

@ -17,7 +17,7 @@ import com.alibaba.excel.util.NumberUtils;
public class IntegerStringConverter implements Converter<Integer> { public class IntegerStringConverter implements Converter<Integer> {
@Override @Override
public Class supportJavaTypeKey() { public Class<?> supportJavaTypeKey() {
return Integer.class; return Integer.class;
} }
@ -27,14 +27,14 @@ public class IntegerStringConverter implements Converter<Integer> {
} }
@Override @Override
public Integer convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, public Integer convertToJavaData(CellData<?> cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) throws ParseException { GlobalConfiguration globalConfiguration) throws ParseException {
return NumberUtils.parseInteger(cellData.getStringValue(), contentProperty); return NumberUtils.parseInteger(cellData.getStringValue(), contentProperty);
} }
@Override @Override
public CellData convertToExcelData(Integer value, ExcelContentProperty contentProperty, public CellData<?> convertToExcelData(Integer value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
return NumberUtils.formatToCellData(value, contentProperty); return NumberUtils.formatToCellDataString(value, contentProperty);
} }
} }

10
src/main/java/com/alibaba/excel/converters/longconverter/LongBooleanConverter.java

@ -16,7 +16,7 @@ public class LongBooleanConverter implements Converter<Long> {
private static final Long ZERO = 0L; private static final Long ZERO = 0L;
@Override @Override
public Class supportJavaTypeKey() { public Class<Long> supportJavaTypeKey() {
return Long.class; return Long.class;
} }
@ -26,7 +26,7 @@ public class LongBooleanConverter implements Converter<Long> {
} }
@Override @Override
public Long convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, public Long convertToJavaData(CellData<?> cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
if (cellData.getBooleanValue()) { if (cellData.getBooleanValue()) {
return ONE; return ONE;
@ -35,12 +35,12 @@ public class LongBooleanConverter implements Converter<Long> {
} }
@Override @Override
public CellData convertToExcelData(Long value, ExcelContentProperty contentProperty, public CellData<?> convertToExcelData(Long value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
if (ONE.equals(value)) { if (ONE.equals(value)) {
return new CellData(Boolean.TRUE); return new CellData<>(Boolean.TRUE);
} }
return new CellData(Boolean.FALSE); return new CellData<>(Boolean.FALSE);
} }
} }

14
src/main/java/com/alibaba/excel/converters/longconverter/LongNumberConverter.java

@ -1,12 +1,12 @@
package com.alibaba.excel.converters.longconverter; package com.alibaba.excel.converters.longconverter;
import java.math.BigDecimal;
import com.alibaba.excel.converters.Converter; import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.GlobalConfiguration; import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.property.ExcelContentProperty; import com.alibaba.excel.metadata.property.ExcelContentProperty;
import com.alibaba.excel.util.NumberUtils;
import com.alibaba.excel.write.metadata.holder.WriteHolder;
/** /**
* Long and number converter * Long and number converter
@ -16,7 +16,7 @@ import com.alibaba.excel.metadata.property.ExcelContentProperty;
public class LongNumberConverter implements Converter<Long> { public class LongNumberConverter implements Converter<Long> {
@Override @Override
public Class supportJavaTypeKey() { public Class<Long> supportJavaTypeKey() {
return Long.class; return Long.class;
} }
@ -26,15 +26,15 @@ public class LongNumberConverter implements Converter<Long> {
} }
@Override @Override
public Long convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, public Long convertToJavaData(CellData<?> cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
return cellData.getNumberValue().longValue(); return cellData.getNumberValue().longValue();
} }
@Override @Override
public CellData convertToExcelData(Long value, ExcelContentProperty contentProperty, public CellData<?> convertToExcelData(Long value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { WriteHolder currentWriteHolder) {
return new CellData(BigDecimal.valueOf(value)); return NumberUtils.formatToCellData(value, contentProperty, currentWriteHolder);
} }
} }

8
src/main/java/com/alibaba/excel/converters/longconverter/LongStringConverter.java

@ -17,7 +17,7 @@ import com.alibaba.excel.util.NumberUtils;
public class LongStringConverter implements Converter<Long> { public class LongStringConverter implements Converter<Long> {
@Override @Override
public Class supportJavaTypeKey() { public Class<Long> supportJavaTypeKey() {
return Long.class; return Long.class;
} }
@ -27,14 +27,14 @@ public class LongStringConverter implements Converter<Long> {
} }
@Override @Override
public Long convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, public Long convertToJavaData(CellData<?> cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) throws ParseException { GlobalConfiguration globalConfiguration) throws ParseException {
return NumberUtils.parseLong(cellData.getStringValue(), contentProperty); return NumberUtils.parseLong(cellData.getStringValue(), contentProperty);
} }
@Override @Override
public CellData convertToExcelData(Long value, ExcelContentProperty contentProperty, public CellData<?> convertToExcelData(Long value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
return NumberUtils.formatToCellData(value, contentProperty); return NumberUtils.formatToCellDataString(value, contentProperty);
} }
} }

10
src/main/java/com/alibaba/excel/converters/shortconverter/ShortBooleanConverter.java

@ -16,7 +16,7 @@ public class ShortBooleanConverter implements Converter<Short> {
private static final Short ZERO = 0; private static final Short ZERO = 0;
@Override @Override
public Class supportJavaTypeKey() { public Class<Short> supportJavaTypeKey() {
return Short.class; return Short.class;
} }
@ -26,7 +26,7 @@ public class ShortBooleanConverter implements Converter<Short> {
} }
@Override @Override
public Short convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, public Short convertToJavaData(CellData<?> cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
if (cellData.getBooleanValue()) { if (cellData.getBooleanValue()) {
return ONE; return ONE;
@ -35,12 +35,12 @@ public class ShortBooleanConverter implements Converter<Short> {
} }
@Override @Override
public CellData convertToExcelData(Short value, ExcelContentProperty contentProperty, public CellData<?> convertToExcelData(Short value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
if (ONE.equals(value)) { if (ONE.equals(value)) {
return new CellData(Boolean.TRUE); return new CellData<>(Boolean.TRUE);
} }
return new CellData(Boolean.FALSE); return new CellData<>(Boolean.FALSE);
} }
} }

13
src/main/java/com/alibaba/excel/converters/shortconverter/ShortNumberConverter.java

@ -7,6 +7,8 @@ import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.GlobalConfiguration; import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.property.ExcelContentProperty; import com.alibaba.excel.metadata.property.ExcelContentProperty;
import com.alibaba.excel.util.NumberUtils;
import com.alibaba.excel.write.metadata.holder.WriteHolder;
/** /**
* Short and number converter * Short and number converter
@ -16,7 +18,7 @@ import com.alibaba.excel.metadata.property.ExcelContentProperty;
public class ShortNumberConverter implements Converter<Short> { public class ShortNumberConverter implements Converter<Short> {
@Override @Override
public Class supportJavaTypeKey() { public Class<Short> supportJavaTypeKey() {
return Short.class; return Short.class;
} }
@ -26,15 +28,14 @@ public class ShortNumberConverter implements Converter<Short> {
} }
@Override @Override
public Short convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, public Short convertToJavaData(CellData<?> cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
return cellData.getNumberValue().shortValue(); return cellData.getNumberValue().shortValue();
} }
@Override @Override
public CellData convertToExcelData(Short value, ExcelContentProperty contentProperty, public CellData<?> convertToExcelData(Short value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { WriteHolder currentWriteHolder) {
return new CellData(new BigDecimal(Short.toString(value))); return NumberUtils.formatToCellData(value, contentProperty, currentWriteHolder);
} }
} }

8
src/main/java/com/alibaba/excel/converters/shortconverter/ShortStringConverter.java

@ -17,7 +17,7 @@ import com.alibaba.excel.util.NumberUtils;
public class ShortStringConverter implements Converter<Short> { public class ShortStringConverter implements Converter<Short> {
@Override @Override
public Class supportJavaTypeKey() { public Class<?> supportJavaTypeKey() {
return Short.class; return Short.class;
} }
@ -27,14 +27,14 @@ public class ShortStringConverter implements Converter<Short> {
} }
@Override @Override
public Short convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, public Short convertToJavaData(CellData<?>cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) throws ParseException { GlobalConfiguration globalConfiguration) throws ParseException {
return NumberUtils.parseShort(cellData.getStringValue(), contentProperty); return NumberUtils.parseShort(cellData.getStringValue(), contentProperty);
} }
@Override @Override
public CellData convertToExcelData(Short value, ExcelContentProperty contentProperty, public CellData<?>convertToExcelData(Short value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
return NumberUtils.formatToCellData(value, contentProperty); return NumberUtils.formatToCellDataString(value, contentProperty);
} }
} }

8
src/main/java/com/alibaba/excel/converters/string/StringBooleanConverter.java

@ -14,7 +14,7 @@ import com.alibaba.excel.metadata.property.ExcelContentProperty;
public class StringBooleanConverter implements Converter<String> { public class StringBooleanConverter implements Converter<String> {
@Override @Override
public Class supportJavaTypeKey() { public Class<?> supportJavaTypeKey() {
return String.class; return String.class;
} }
@ -24,15 +24,15 @@ public class StringBooleanConverter implements Converter<String> {
} }
@Override @Override
public String convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, public String convertToJavaData(CellData<?> cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
return cellData.getBooleanValue().toString(); return cellData.getBooleanValue().toString();
} }
@Override @Override
public CellData convertToExcelData(String value, ExcelContentProperty contentProperty, public CellData<?> convertToExcelData(String value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
return new CellData(Boolean.valueOf(value)); return new CellData<>(Boolean.valueOf(value));
} }
} }

8
src/main/java/com/alibaba/excel/converters/string/StringErrorConverter.java

@ -13,7 +13,7 @@ import com.alibaba.excel.metadata.property.ExcelContentProperty;
*/ */
public class StringErrorConverter implements Converter<String> { public class StringErrorConverter implements Converter<String> {
@Override @Override
public Class supportJavaTypeKey() { public Class<String> supportJavaTypeKey() {
return String.class; return String.class;
} }
@ -23,15 +23,15 @@ public class StringErrorConverter implements Converter<String> {
} }
@Override @Override
public String convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, public String convertToJavaData(CellData<?> cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
return cellData.getStringValue(); return cellData.getStringValue();
} }
@Override @Override
public CellData convertToExcelData(String value, ExcelContentProperty contentProperty, public CellData<?> convertToExcelData(String value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
return new CellData(CellDataTypeEnum.ERROR, value); return new CellData<>(CellDataTypeEnum.ERROR, value);
} }
} }

6
src/main/java/com/alibaba/excel/converters/string/StringImageConverter.java

@ -20,7 +20,7 @@ import com.alibaba.excel.util.IoUtils;
*/ */
public class StringImageConverter implements Converter<String> { public class StringImageConverter implements Converter<String> {
@Override @Override
public Class supportJavaTypeKey() { public Class<?> supportJavaTypeKey() {
return String.class; return String.class;
} }
@ -30,13 +30,13 @@ public class StringImageConverter implements Converter<String> {
} }
@Override @Override
public String convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, public String convertToJavaData(CellData<?> cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
throw new UnsupportedOperationException("Cannot convert images to string"); throw new UnsupportedOperationException("Cannot convert images to string");
} }
@Override @Override
public CellData convertToExcelData(String value, ExcelContentProperty contentProperty, public CellData<?> convertToExcelData(String value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) throws IOException { GlobalConfiguration globalConfiguration) throws IOException {
ImagePosition imagePosition = contentProperty.getField().getAnnotation(ImagePosition.class); ImagePosition imagePosition = contentProperty.getField().getAnnotation(ImagePosition.class);
if (imagePosition != null) { if (imagePosition != null) {

8
src/main/java/com/alibaba/excel/converters/string/StringNumberConverter.java

@ -22,7 +22,7 @@ import com.alibaba.excel.util.StringUtils;
public class StringNumberConverter implements Converter<String> { public class StringNumberConverter implements Converter<String> {
@Override @Override
public Class supportJavaTypeKey() { public Class<?> supportJavaTypeKey() {
return String.class; return String.class;
} }
@ -32,7 +32,7 @@ public class StringNumberConverter implements Converter<String> {
} }
@Override @Override
public String convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, public String convertToJavaData(CellData<?> cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
// If there are "DateTimeFormat", read as date // If there are "DateTimeFormat", read as date
if (contentProperty != null && contentProperty.getDateTimeFormatProperty() != null) { if (contentProperty != null && contentProperty.getDateTimeFormatProperty() != null) {
@ -55,8 +55,8 @@ public class StringNumberConverter implements Converter<String> {
} }
@Override @Override
public CellData convertToExcelData(String value, ExcelContentProperty contentProperty, public CellData<?> convertToExcelData(String value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
return new CellData(new BigDecimal(value)); return new CellData<>(new BigDecimal(value));
} }
} }

8
src/main/java/com/alibaba/excel/converters/string/StringStringConverter.java

@ -13,7 +13,7 @@ import com.alibaba.excel.metadata.property.ExcelContentProperty;
*/ */
public class StringStringConverter implements Converter<String> { public class StringStringConverter implements Converter<String> {
@Override @Override
public Class supportJavaTypeKey() { public Class<?> supportJavaTypeKey() {
return String.class; return String.class;
} }
@ -23,15 +23,15 @@ public class StringStringConverter implements Converter<String> {
} }
@Override @Override
public String convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, public String convertToJavaData(CellData<?> cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
return cellData.getStringValue(); return cellData.getStringValue();
} }
@Override @Override
public CellData convertToExcelData(String value, ExcelContentProperty contentProperty, public CellData<?> convertToExcelData(String value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
return new CellData(value); return new CellData<>(value);
} }
} }

8
src/main/java/com/alibaba/excel/converters/url/UrlImageConverter.java

@ -19,7 +19,7 @@ import com.alibaba.excel.util.IoUtils;
*/ */
public class UrlImageConverter implements Converter<URL> { public class UrlImageConverter implements Converter<URL> {
@Override @Override
public Class supportJavaTypeKey() { public Class<?> supportJavaTypeKey() {
return URL.class; return URL.class;
} }
@ -29,19 +29,19 @@ public class UrlImageConverter implements Converter<URL> {
} }
@Override @Override
public URL convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, public URL convertToJavaData(CellData<?> cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
throw new UnsupportedOperationException("Cannot convert images to url."); throw new UnsupportedOperationException("Cannot convert images to url.");
} }
@Override @Override
public CellData convertToExcelData(URL value, ExcelContentProperty contentProperty, public CellData<?> convertToExcelData(URL value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) throws IOException { GlobalConfiguration globalConfiguration) throws IOException {
InputStream inputStream = null; InputStream inputStream = null;
try { try {
inputStream = value.openStream(); inputStream = value.openStream();
byte[] bytes = IoUtils.toByteArray(inputStream); byte[] bytes = IoUtils.toByteArray(inputStream);
return new CellData(bytes); return new CellData<>(bytes);
} finally { } finally {
if (inputStream != null) { if (inputStream != null) {
inputStream.close(); inputStream.close();

8
src/main/java/com/alibaba/excel/enums/CellDataTypeEnum.java

@ -39,9 +39,15 @@ public enum CellDataTypeEnum {
/** /**
* Images are currently supported only when writing * Images are currently supported only when writing
*/ */
IMAGE; IMAGE,
/**
* date.Support only when writing.
*/
DATE,
;
private static final Map<String, CellDataTypeEnum> TYPE_ROUTING_MAP = new HashMap<String, CellDataTypeEnum>(16); private static final Map<String, CellDataTypeEnum> TYPE_ROUTING_MAP = new HashMap<String, CellDataTypeEnum>(16);
static { static {
TYPE_ROUTING_MAP.put("s", STRING); TYPE_ROUTING_MAP.put("s", STRING);
TYPE_ROUTING_MAP.put("str", DIRECT_STRING); TYPE_ROUTING_MAP.put("str", DIRECT_STRING);

2
src/main/java/com/alibaba/excel/event/AnalysisEventListener.java

@ -16,7 +16,7 @@ import com.alibaba.excel.util.ConverterUtils;
public abstract class AnalysisEventListener<T> implements ReadListener<T> { public abstract class AnalysisEventListener<T> implements ReadListener<T> {
@Override @Override
public void invokeHead(Map<Integer, CellData> headMap, AnalysisContext context) { public void invokeHead(Map<Integer, CellData<?>> headMap, AnalysisContext context) {
invokeHeadMap(ConverterUtils.convertToStringMap(headMap, context), context); invokeHeadMap(ConverterUtils.convertToStringMap(headMap, context), context);
} }

38
src/main/java/com/alibaba/excel/exception/ExcelDataConvertException.java

@ -4,11 +4,16 @@ import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.property.ExcelContentProperty; import com.alibaba.excel.metadata.property.ExcelContentProperty;
import com.alibaba.excel.write.builder.ExcelWriterBuilder; import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import lombok.Getter;
import lombok.Setter;
/** /**
* Data convert exception * Data convert exception
* *
* @author Jiaju Zhuang * @author Jiaju Zhuang
*/ */
@Getter
@Setter
public class ExcelDataConvertException extends RuntimeException { public class ExcelDataConvertException extends RuntimeException {
/** /**
* NotNull. * NotNull.
@ -21,7 +26,7 @@ public class ExcelDataConvertException extends RuntimeException {
/** /**
* NotNull. * NotNull.
*/ */
private CellData cellData; private CellData<?> cellData;
/** /**
* Nullable.Only when the header is configured and when the class header is used is not null. * Nullable.Only when the header is configured and when the class header is used is not null.
* *
@ -47,35 +52,4 @@ public class ExcelDataConvertException extends RuntimeException {
this.excelContentProperty = excelContentProperty; this.excelContentProperty = excelContentProperty;
} }
public Integer getRowIndex() {
return rowIndex;
}
public void setRowIndex(Integer rowIndex) {
this.rowIndex = rowIndex;
}
public Integer getColumnIndex() {
return columnIndex;
}
public void setColumnIndex(Integer columnIndex) {
this.columnIndex = columnIndex;
}
public ExcelContentProperty getExcelContentProperty() {
return excelContentProperty;
}
public void setExcelContentProperty(ExcelContentProperty excelContentProperty) {
this.excelContentProperty = excelContentProperty;
}
public CellData getCellData() {
return cellData;
}
public void setCellData(CellData cellData) {
this.cellData = cellData;
}
} }

9
src/main/java/com/alibaba/excel/metadata/AbstractHolder.java

@ -34,7 +34,7 @@ public abstract class AbstractHolder implements ConfigurationHolder {
* <p> * <p>
* Write key: * Write key:
*/ */
private Map<String, Converter> converterMap; private Map<String, Converter<?>> converterMap;
public AbstractHolder(BasicParameter basicParameter, AbstractHolder prentAbstractHolder) { public AbstractHolder(BasicParameter basicParameter, AbstractHolder prentAbstractHolder) {
this.newInitialization = Boolean.TRUE; this.newInitialization = Boolean.TRUE;
@ -68,6 +68,7 @@ public abstract class AbstractHolder implements ConfigurationHolder {
} else { } else {
globalConfiguration.setLocale(basicParameter.getLocale()); globalConfiguration.setLocale(basicParameter.getLocale());
} }
} }
public Boolean getNewInitialization() { public Boolean getNewInitialization() {
@ -102,16 +103,16 @@ public abstract class AbstractHolder implements ConfigurationHolder {
this.globalConfiguration = globalConfiguration; this.globalConfiguration = globalConfiguration;
} }
public Map<String, Converter> getConverterMap() { public Map<String, Converter<?>> getConverterMap() {
return converterMap; return converterMap;
} }
public void setConverterMap(Map<String, Converter> converterMap) { public void setConverterMap(Map<String, Converter<?>> converterMap) {
this.converterMap = converterMap; this.converterMap = converterMap;
} }
@Override @Override
public Map<String, Converter> converterMap() { public Map<String, Converter<?>> converterMap() {
return getConverterMap(); return getConverterMap();
} }

15
src/main/java/com/alibaba/excel/metadata/BasicParameter.java

@ -41,6 +41,13 @@ public class BasicParameter {
*/ */
private Locale locale; private Locale locale;
/**
* Whether to use scientific Format.
*
* default is false
*/
private Boolean useScientificFormat;
public List<List<String>> getHead() { public List<List<String>> getHead() {
return head; return head;
} }
@ -88,4 +95,12 @@ public class BasicParameter {
public void setLocale(Locale locale) { public void setLocale(Locale locale) {
this.locale = locale; this.locale = locale;
} }
public Boolean getUseScientificFormat() {
return useScientificFormat;
}
public void setUseScientificFormat(Boolean useScientificFormat) {
this.useScientificFormat = useScientificFormat;
}
} }

157
src/main/java/com/alibaba/excel/metadata/CellData.java

@ -2,10 +2,14 @@ package com.alibaba.excel.metadata;
import java.math.BigDecimal; import java.math.BigDecimal;
import com.alibaba.excel.annotation.write.style.ImagePosition; import com.alibaba.excel.annotation.write.style.ImagePosition;
import java.util.Date;
import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.property.ImagePositionProperty; import com.alibaba.excel.metadata.property.ImagePositionProperty;
import com.alibaba.excel.util.StringUtils; import com.alibaba.excel.util.StringUtils;
import lombok.Getter;
import lombok.Setter;
/** /**
* Excel internal cell data. * Excel internal cell data.
* *
@ -13,6 +17,8 @@ import com.alibaba.excel.util.StringUtils;
* *
* @author Jiaju Zhuang * @author Jiaju Zhuang
*/ */
@Getter
@Setter
public class CellData<T> extends AbstractCell { public class CellData<T> extends AbstractCell {
private CellDataTypeEnum type; private CellDataTypeEnum type;
/** /**
@ -41,11 +47,15 @@ public class CellData<T> extends AbstractCell {
*/ */
private Boolean useImagePositionProperty = false; private Boolean useImagePositionProperty = false;
/** /**
* The number formatting.Currently only supported when reading * Support only when writing.
*/
private Date dateValue;
/**
* The number formatting.
*/ */
private Integer dataFormat; private Short dataFormat;
/** /**
* The string of number formatting.Currently only supported when reading * The string of number formatting.
*/ */
private String dataFormatString; private String dataFormatString;
/** /**
@ -66,6 +76,8 @@ public class CellData<T> extends AbstractCell {
this.dataFormat = other.dataFormat; this.dataFormat = other.dataFormat;
this.dataFormatString = other.dataFormatString; this.dataFormatString = other.dataFormatString;
this.data = other.data; this.data = other.data;
setRowIndex(other.getRowIndex());
setColumnIndex(other.getColumnIndex());
} }
public CellData() {} public CellData() {}
@ -137,108 +149,21 @@ public class CellData<T> extends AbstractCell {
this.formula = Boolean.FALSE; this.formula = Boolean.FALSE;
} }
public CellData(CellDataTypeEnum type) { public CellData(Date dateValue) {
if (type == null) { if (dateValue == null) {
throw new IllegalArgumentException("Type can not be null"); throw new IllegalArgumentException("DateValue can not be null");
} }
this.type = type; this.type = CellDataTypeEnum.DATE;
this.dateValue = dateValue;
this.formula = Boolean.FALSE; this.formula = Boolean.FALSE;
} }
public CellDataTypeEnum getType() {
return type;
}
public void setType(CellDataTypeEnum type) {
this.type = type;
}
public BigDecimal getNumberValue() {
return numberValue;
}
public void setNumberValue(BigDecimal numberValue) {
this.numberValue = numberValue;
}
public String getStringValue() {
return stringValue;
}
public void setStringValue(String stringValue) {
this.stringValue = stringValue;
}
public Boolean getBooleanValue() {
return booleanValue;
}
public void setBooleanValue(Boolean booleanValue) {
this.booleanValue = booleanValue;
}
public Boolean getFormula() {
return formula;
}
public void setFormula(Boolean formula) {
this.formula = formula;
}
public String getFormulaValue() {
return formulaValue;
}
public void setFormulaValue(String formulaValue) {
this.formulaValue = formulaValue;
}
public byte[] getImageValue() {
return imageValue;
}
public void setImageValue(byte[] imageValue) {
this.imageValue = imageValue;
}
public ImagePositionProperty getImagePositionProperty() {
return imagePositionProperty;
}
public void setImagePositionProperty(ImagePositionProperty imagePositionProperty) {
this.imagePositionProperty = imagePositionProperty;
}
public Boolean getUseImagePositionProperty() {
return useImagePositionProperty;
}
public void setUseImagePositionProperty(Boolean useImagePositionProperty) { public CellData(CellDataTypeEnum type) {
this.useImagePositionProperty = useImagePositionProperty; if (type == null) {
} throw new IllegalArgumentException("Type can not be null");
public Integer getDataFormat() {
return dataFormat;
}
public void setDataFormat(Integer dataFormat) {
this.dataFormat = dataFormat;
}
public String getDataFormatString() {
return dataFormatString;
}
public void setDataFormatString(String dataFormatString) {
this.dataFormatString = dataFormatString;
}
public T getData() {
return data;
} }
this.type = type;
public void setData(T data) {
this.data = data;
} }
/** /**
@ -269,37 +194,37 @@ public class CellData<T> extends AbstractCell {
} }
} }
public static CellData newEmptyInstance() { public static CellData<?> newEmptyInstance() {
return newEmptyInstance(null, null); return newEmptyInstance(null, null);
} }
public static CellData newEmptyInstance(Integer rowIndex, Integer columnIndex) { public static CellData<?> newEmptyInstance(Integer rowIndex, Integer columnIndex) {
CellData cellData = new CellData(CellDataTypeEnum.EMPTY); CellData<?> cellData = new CellData<>(CellDataTypeEnum.EMPTY);
cellData.setRowIndex(rowIndex); cellData.setRowIndex(rowIndex);
cellData.setColumnIndex(columnIndex); cellData.setColumnIndex(columnIndex);
return cellData; return cellData;
} }
public static CellData newInstance(Boolean booleanValue) { public static CellData<?> newInstance(Boolean booleanValue) {
return newInstance(booleanValue, null, null); return newInstance(booleanValue, null, null);
} }
public static CellData newInstance(Boolean booleanValue, Integer rowIndex, Integer columnIndex) { public static CellData<?> newInstance(Boolean booleanValue, Integer rowIndex, Integer columnIndex) {
CellData cellData = new CellData(booleanValue); CellData<?> cellData = new CellData<>(booleanValue);
cellData.setRowIndex(rowIndex); cellData.setRowIndex(rowIndex);
cellData.setColumnIndex(columnIndex); cellData.setColumnIndex(columnIndex);
return cellData; return cellData;
} }
public static CellData newInstance(String stringValue, Integer rowIndex, Integer columnIndex) { public static CellData<?> newInstance(String stringValue, Integer rowIndex, Integer columnIndex) {
CellData cellData = new CellData(stringValue); CellData<?> cellData = new CellData<>(stringValue);
cellData.setRowIndex(rowIndex); cellData.setRowIndex(rowIndex);
cellData.setColumnIndex(columnIndex); cellData.setColumnIndex(columnIndex);
return cellData; return cellData;
} }
public static CellData newInstance(BigDecimal numberValue, Integer rowIndex, Integer columnIndex) { public static CellData<?> newInstance(BigDecimal numberValue, Integer rowIndex, Integer columnIndex) {
CellData cellData = new CellData(numberValue); CellData<?> cellData = new CellData<>(numberValue);
cellData.setRowIndex(rowIndex); cellData.setRowIndex(rowIndex);
cellData.setColumnIndex(columnIndex); cellData.setColumnIndex(columnIndex);
return cellData; return cellData;
@ -312,14 +237,28 @@ public class CellData<T> extends AbstractCell {
} }
switch (type) { switch (type) {
case NUMBER: case NUMBER:
if (numberValue == null) {
return StringUtils.EMPTY;
}
return numberValue.toString(); return numberValue.toString();
case BOOLEAN: case BOOLEAN:
if (booleanValue == null) {
return StringUtils.EMPTY;
}
return booleanValue.toString(); return booleanValue.toString();
case DIRECT_STRING: case DIRECT_STRING:
case STRING: case STRING:
case ERROR: case ERROR:
return stringValue; return stringValue;
case DATE:
if (dateValue == null) {
return StringUtils.EMPTY;
}
return dateValue.toString();
case IMAGE: case IMAGE:
if (imageValue == null) {
return StringUtils.EMPTY;
}
return "image[" + imageValue.length + "]"; return "image[" + imageValue.length + "]";
default: default:
return StringUtils.EMPTY; return StringUtils.EMPTY;

2
src/main/java/com/alibaba/excel/metadata/ConfigurationHolder.java

@ -32,5 +32,5 @@ public interface ConfigurationHolder extends Holder {
* *
* @return Converter * @return Converter
*/ */
Map<String, Converter> converterMap(); Map<String, Converter<?>> converterMap();
} }

14
src/main/java/com/alibaba/excel/metadata/GlobalConfiguration.java

@ -25,6 +25,12 @@ public class GlobalConfiguration {
* used when formatting dates and numbers. * used when formatting dates and numbers.
*/ */
private Locale locale; private Locale locale;
/**
* Whether to use scientific Format.
*
* default is false
*/
private Boolean useScientificFormat;
public Boolean getUse1904windowing() { public Boolean getUse1904windowing() {
return use1904windowing; return use1904windowing;
@ -49,4 +55,12 @@ public class GlobalConfiguration {
public void setLocale(Locale locale) { public void setLocale(Locale locale) {
this.locale = locale; this.locale = locale;
} }
public Boolean getUseScientificFormat() {
return useScientificFormat;
}
public void setUseScientificFormat(Boolean useScientificFormat) {
this.useScientificFormat = useScientificFormat;
}
} }

119
src/main/java/com/alibaba/excel/metadata/DataFormatter.java → src/main/java/com/alibaba/excel/metadata/format/DataFormatter.java

@ -15,7 +15,7 @@
* can be found in svn at location root/projects/3rd-party/src * can be found in svn at location root/projects/3rd-party/src
* ==================================================================== * ====================================================================
*/ */
package com.alibaba.excel.metadata; package com.alibaba.excel.metadata.format;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode; import java.math.RoundingMode;
@ -34,13 +34,15 @@ import java.util.Map;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.apache.poi.ss.format.CellFormat;
import org.apache.poi.ss.format.CellFormatResult;
import org.apache.poi.ss.usermodel.DateUtil; import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.usermodel.ExcelGeneralNumberFormat;
import org.apache.poi.ss.usermodel.ExcelStyleDateFormatter; import org.apache.poi.ss.usermodel.ExcelStyleDateFormatter;
import org.apache.poi.ss.usermodel.FractionFormat; import org.apache.poi.ss.usermodel.FractionFormat;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.util.DateUtils; import com.alibaba.excel.util.DateUtils;
/** /**
@ -138,45 +140,92 @@ public class DataFormatter {
* @return * @return
*/ */
private Boolean use1904windowing; private Boolean use1904windowing;
/** /**
* Creates a formatter using the {@link Locale#getDefault() default locale}. * Whether to use scientific Format.
*
* default is false
*/ */
public DataFormatter() { private Boolean useScientificFormat;
this(null, null);
}
/** /**
* Creates a formatter using the given locale. * Creates a formatter using the given locale.
* *
*/ */
public DataFormatter(Locale locale, Boolean use1904windowing) { public DataFormatter(GlobalConfiguration globalConfiguration) {
this.use1904windowing = use1904windowing != null ? use1904windowing : Boolean.FALSE; if (globalConfiguration == null) {
this.locale = locale != null ? locale : Locale.getDefault(); this.use1904windowing = Boolean.FALSE;
this.locale = Locale.getDefault();
this.useScientificFormat = Boolean.FALSE;
} else {
this.use1904windowing =
globalConfiguration.getUse1904windowing() != null ? globalConfiguration.getUse1904windowing()
: Boolean.FALSE;
this.locale =
globalConfiguration.getLocale() != null ? globalConfiguration.getLocale() : Locale.getDefault();
this.useScientificFormat =
globalConfiguration.getUseScientificFormat() != null ? globalConfiguration.getUseScientificFormat()
: Boolean.FALSE;
}
this.dateSymbols = DateFormatSymbols.getInstance(this.locale); this.dateSymbols = DateFormatSymbols.getInstance(this.locale);
this.decimalSymbols = DecimalFormatSymbols.getInstance(this.locale); this.decimalSymbols = DecimalFormatSymbols.getInstance(this.locale);
} }
private Format getFormat(Integer dataFormat, String dataFormatString) { private Format getFormat(Double data,Short dataFormat, String dataFormatString) {
// Might be better to separate out the n p and z formats, falling back to p when n and z are not set.
// That however would require other code to be re factored.
// String[] formatBits = formatStrIn.split(";");
// int i = cellValue > 0.0 ? 0 : cellValue < 0.0 ? 1 : 2;
// String formatStr = (i < formatBits.length) ? formatBits[i] : formatBits[0];
String formatStr = dataFormatString;
// Excel supports 2+ part conditional data formats, eg positive/negative/zero,
// or (>1000),(>0),(0),(negative). As Java doesn't handle these kinds
// of different formats for different ranges, just +ve/-ve, we need to
// handle these ourselves in a special way.
// For now, if we detect 2+ parts, we call out to CellFormat to handle it
// TODO Going forward, we should really merge the logic between the two classes
if (formatStr.contains(";") &&
(formatStr.indexOf(';') != formatStr.lastIndexOf(';')
|| rangeConditionalPattern.matcher(formatStr).matches()
) ) {
try {
// Ask CellFormat to get a formatter for it
CellFormat cfmt = CellFormat.getInstance(locale, formatStr);
// CellFormat requires callers to identify date vs not, so do so
Object cellValueO = data;
if (DateUtil.isADateFormat(dataFormat, formatStr) &&
// don't try to handle Date value 0, let a 3 or 4-part format take care of it
data.doubleValue() != 0.0) {
cellValueO = DateUtil.getJavaDate(data, use1904windowing);
}
// Wrap and return (non-cachable - CellFormat does that)
return new CellFormatResultWrapper( cfmt.apply(cellValueO) );
} catch (Exception e) {
LOGGER.warn("Formatting failed for format {}, falling back",formatStr, e);
}
}
// See if we already have it cached // See if we already have it cached
Format format = formats.get(dataFormatString); Format format = formats.get(formatStr);
if (format != null) { if (format != null) {
return format; return format;
} }
// Is it one of the special built in types, General or @? // Is it one of the special built in types, General or @?
if ("General".equalsIgnoreCase(dataFormatString) || "@".equals(dataFormatString)) { if ("General".equalsIgnoreCase(formatStr) || "@".equals(formatStr)) {
format = getDefaultFormat(); format = getDefaultFormat();
addFormat(dataFormatString, format); addFormat(formatStr, format);
return format; return format;
} }
// Build a formatter, and cache it // Build a formatter, and cache it
format = createFormat(dataFormat, dataFormatString); format = createFormat(dataFormat, formatStr);
addFormat(dataFormatString, format); addFormat(formatStr, format);
return format; return format;
} }
private Format createFormat(Integer dataFormat, String dataFormatString) { private Format createFormat(Short dataFormat, String dataFormatString) {
String formatStr = dataFormatString; String formatStr = dataFormatString;
Format format = checkSpecialConverter(formatStr); Format format = checkSpecialConverter(formatStr);
@ -519,7 +568,7 @@ public class DataFormatter {
try { try {
return new InternalDecimalFormatWithScale(format, symbols); return new InternalDecimalFormatWithScale(format, symbols);
} catch (IllegalArgumentException iae) { } catch (IllegalArgumentException iae) {
LOGGER.debug("Formatting failed for format {}, falling back", formatStr, iae); LOGGER.error("Formatting failed for format {}, falling back", formatStr, iae);
// the pattern could not be parsed correctly, // the pattern could not be parsed correctly,
// so fall back to the default number format // so fall back to the default number format
return getDefaultFormat(); return getDefaultFormat();
@ -532,7 +581,7 @@ public class DataFormatter {
return defaultNumFormat; return defaultNumFormat;
// otherwise use general format // otherwise use general format
} }
defaultNumFormat = new ExcelGeneralNumberFormat(locale); defaultNumFormat = new ExcelGeneralNumberFormat(locale, useScientificFormat);
return defaultNumFormat; return defaultNumFormat;
} }
@ -558,8 +607,8 @@ public class DataFormatter {
* @param dataFormatString * @param dataFormatString
* @return Formatted value * @return Formatted value
*/ */
private String getFormattedDateString(Double data, Integer dataFormat, String dataFormatString) { private String getFormattedDateString(Double data, Short dataFormat, String dataFormatString) {
Format dateFormat = getFormat(dataFormat, dataFormatString); Format dateFormat = getFormat(data, dataFormat, dataFormatString);
if (dateFormat instanceof ExcelStyleDateFormatter) { if (dateFormat instanceof ExcelStyleDateFormatter) {
// Hint about the raw excel value // Hint about the raw excel value
((ExcelStyleDateFormatter)dateFormat).setDateToBeFormatted(data); ((ExcelStyleDateFormatter)dateFormat).setDateToBeFormatted(data);
@ -581,8 +630,8 @@ public class DataFormatter {
* @param dataFormatString * @param dataFormatString
* @return a formatted number string * @return a formatted number string
*/ */
private String getFormattedNumberString(Double data, Integer dataFormat, String dataFormatString) { private String getFormattedNumberString(Double data, Short dataFormat, String dataFormatString) {
Format numberFormat = getFormat(dataFormat, dataFormatString); Format numberFormat = getFormat(data, dataFormat, dataFormatString);
String formatted = numberFormat.format(data); String formatted = numberFormat.format(data);
return formatted.replaceFirst("E(\\d)", "E+$1"); // to match Excel's E-notation return formatted.replaceFirst("E(\\d)", "E+$1"); // to match Excel's E-notation
} }
@ -595,7 +644,7 @@ public class DataFormatter {
* @param dataFormatString * @param dataFormatString
* @return * @return
*/ */
public String format(Double data, Integer dataFormat, String dataFormatString) { public String format(Double data, Short dataFormat, String dataFormatString) {
if (DateUtils.isADateFormat(dataFormat, dataFormatString)) { if (DateUtils.isADateFormat(dataFormat, dataFormatString)) {
return getFormattedDateString(data, dataFormat, dataFormatString); return getFormattedDateString(data, dataFormat, dataFormatString);
} }
@ -783,4 +832,26 @@ public class DataFormatter {
} }
} }
/**
* Workaround until we merge {@link org.apache.poi.ss.usermodel.DataFormatter} with {@link CellFormat}. Constant, non-cachable wrapper around a
* {@link CellFormatResult}
*/
private final class CellFormatResultWrapper extends Format {
private final CellFormatResult result;
private CellFormatResultWrapper(CellFormatResult result) {
this.result = result;
}
@Override
public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {
return toAppendTo.append(result.text.trim());
}
@Override
public Object parseObject(String source, ParsePosition pos) {
return null; // Not supported
}
}
} }

81
src/main/java/com/alibaba/excel/metadata/format/ExcelGeneralNumberFormat.java

@ -0,0 +1,81 @@
package com.alibaba.excel.metadata.format;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.FieldPosition;
import java.text.Format;
import java.text.ParsePosition;
import java.util.Locale;
import org.apache.poi.ss.usermodel.DataFormatter;
/**
* Written with reference to {@link org.apache.poi.ss.usermodel.ExcelGeneralNumberFormat }.
* <p>
* Supported Do not use scientific notation.
*
* @author JiaJu Zhuang
**/
public class ExcelGeneralNumberFormat extends Format {
private static final long serialVersionUID = 1L;
private static final MathContext TO_10_SF = new MathContext(10, RoundingMode.HALF_UP);
private final DecimalFormatSymbols decimalSymbols;
private final DecimalFormat integerFormat;
private final DecimalFormat decimalFormat;
private final DecimalFormat scientificFormat;
public ExcelGeneralNumberFormat(final Locale locale, final boolean useScientificFormat) {
decimalSymbols = DecimalFormatSymbols.getInstance(locale);
// Supported Do not use scientific notation.
if (useScientificFormat) {
scientificFormat = new DecimalFormat("0.#####E0", decimalSymbols);
} else {
scientificFormat = new DecimalFormat("#", decimalSymbols);
}
org.apache.poi.ss.usermodel.DataFormatter.setExcelStyleRoundingMode(scientificFormat);
integerFormat = new DecimalFormat("#", decimalSymbols);
org.apache.poi.ss.usermodel.DataFormatter.setExcelStyleRoundingMode(integerFormat);
decimalFormat = new DecimalFormat("#.##########", decimalSymbols);
DataFormatter.setExcelStyleRoundingMode(decimalFormat);
}
@Override
public StringBuffer format(Object number, StringBuffer toAppendTo, FieldPosition pos) {
final double value;
if (number instanceof Number) {
value = ((Number) number).doubleValue();
if (Double.isInfinite(value) || Double.isNaN(value)) {
return integerFormat.format(number, toAppendTo, pos);
}
} else {
// testBug54786 gets here with a date, so retain previous behaviour
return integerFormat.format(number, toAppendTo, pos);
}
final double abs = Math.abs(value);
if (abs >= 1E11 || (abs <= 1E-10 && abs > 0)) {
return scientificFormat.format(number, toAppendTo, pos);
} else if (Math.floor(value) == value || abs >= 1E10) {
// integer, or integer portion uses all 11 allowed digits
return integerFormat.format(number, toAppendTo, pos);
}
// Non-integers of non-scientific magnitude are formatted as "up to 11
// numeric characters, with the decimal point counting as a numeric
// character". We know there is a decimal point, so limit to 10 digits.
// https://support.microsoft.com/en-us/kb/65903
final double rounded = new BigDecimal(value).round(TO_10_SF).doubleValue();
return decimalFormat.format(rounded, toAppendTo, pos);
}
@Override
public Object parseObject(String source, ParsePosition pos) {
throw new UnsupportedOperationException();
}
}

113
src/main/java/com/alibaba/excel/metadata/property/ExcelHeadProperty.java

@ -10,6 +10,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.TreeMap; import java.util.TreeMap;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -75,7 +76,7 @@ public class ExcelHeadProperty {
int headIndex = 0; int headIndex = 0;
for (int i = 0; i < head.size(); i++) { for (int i = 0; i < head.size(); i++) {
if (holder instanceof AbstractWriteHolder) { if (holder instanceof AbstractWriteHolder) {
if (((AbstractWriteHolder)holder).ignore(null, i)) { if (((AbstractWriteHolder) holder).ignore(null, i)) {
continue; continue;
} }
} }
@ -119,116 +120,31 @@ public class ExcelHeadProperty {
return; return;
} }
// Declared fields // Declared fields
List<Field> defaultFieldList = new ArrayList<Field>(); Map<Integer, Field> sortedAllFiledMap = new TreeMap<Integer, Field>();
Map<Integer, Field> customFieldMap = new TreeMap<Integer, Field>(); Map<Integer, Field> indexFiledMap = new TreeMap<Integer, Field>();
ClassUtils.declaredFields(headClazz, defaultFieldList, customFieldMap, ignoreMap, convertAllField);
List<Map.Entry<Field, Boolean>> exportFieldBoolPairsList = new ArrayList<Map.Entry<Field, Boolean>>(); boolean needIgnore = (holder instanceof AbstractWriteHolder) && (
int index = 0; !CollectionUtils.isEmpty(((AbstractWriteHolder) holder).getExcludeColumnFiledNames()) || !CollectionUtils
while (customFieldMap.containsKey(index)) { .isEmpty(((AbstractWriteHolder) holder).getExcludeColumnIndexes()) || !CollectionUtils
Field field = customFieldMap.get(index); .isEmpty(((AbstractWriteHolder) holder).getIncludeColumnFiledNames()) || !CollectionUtils
Map.Entry<Field, Boolean> fieldBooleanPair = .isEmpty(((AbstractWriteHolder) holder).getIncludeColumnIndexes()));
new AbstractMap.SimpleEntry<Field, Boolean>(field, Boolean.TRUE); ClassUtils.declaredFields(headClazz, sortedAllFiledMap, indexFiledMap, ignoreMap, convertAllFiled, needIgnore,
exportFieldBoolPairsList.add(fieldBooleanPair); holder);
index++;
}
for (Field field : defaultFieldList) {
Map.Entry<Field, Boolean> fieldBoolPair = new AbstractMap.SimpleEntry<Field, Boolean>(field, Boolean.FALSE);
exportFieldBoolPairsList.add(fieldBoolPair);
}
sortExportColumnFields(holder, exportFieldBoolPairsList);
initColumnProperties(holder, exportFieldBoolPairsList);
for (Map.Entry<Integer, Field> entry : customFieldMap.entrySet()) { for (Map.Entry<Integer, Field> entry : sortedAllFiledMap.entrySet()) {
initOneColumnProperty(holder, entry.getKey(), entry.getValue(), Boolean.TRUE); initOneColumnProperty(entry.getKey(), entry.getValue(), indexFiledMap.containsKey(entry.getKey()));
}
headKind = HeadKindEnum.CLASS;
}
/**
* Give the field and flag pair list and arrange them in the specified order according to the user's settings. The
* field is what the user want to export to excel, the flag indicates whether the order of the field in excel is
* specified.
*
* @param holder
* Write holder which keeps the parameters of a sheet.
* @param exportFieldBoolPairList
* Keep all the fields and the flag(which indicate whether the field order is specified) of the head
* class except the ignored. It will be modified after this function is called.
*/
private void sortExportColumnFields(Holder holder, List<Map.Entry<Field, Boolean>> exportFieldBoolPairList) {
if (holder instanceof AbstractWriteHolder) {
Collection<String> includeColumnFieldNames = ((AbstractWriteHolder)holder).getIncludeColumnFieldNames();
if (includeColumnFieldNames != null) {
Map<String, Map.Entry<Field, Boolean>> exportFieldMap =
new TreeMap<String, Map.Entry<Field, Boolean>>();
List<String> includeColumnFieldNameList = new ArrayList<String>(includeColumnFieldNames);
for (Map.Entry<Field, Boolean> fieldBoolPair : exportFieldBoolPairList) {
if (includeColumnFieldNameList.contains(fieldBoolPair.getKey().getName())) {
exportFieldMap.put(fieldBoolPair.getKey().getName(), fieldBoolPair);
}
}
exportFieldBoolPairList.clear();
for (String fieldName : includeColumnFieldNameList) {
exportFieldBoolPairList.add(exportFieldMap.get(fieldName));
}
return;
}
Collection<Integer> includeColumnIndexes = ((AbstractWriteHolder)holder).getIncludeColumnIndexes();
if (includeColumnIndexes != null) {
List<Map.Entry<Field, Boolean>> tempFieldsList = new ArrayList<Map.Entry<Field, Boolean>>();
for (Integer includeColumnIndex : includeColumnIndexes) {
tempFieldsList.add(exportFieldBoolPairList.get(includeColumnIndex));
}
exportFieldBoolPairList.clear();
exportFieldBoolPairList.addAll(tempFieldsList);
return;
}
int index = 0;
for (Map.Entry<Field, Boolean> fieldBoolPair : exportFieldBoolPairList) {
if (((AbstractWriteHolder)holder).ignore(fieldBoolPair.getKey().getName(), index)) {
exportFieldBoolPairList.remove(fieldBoolPair);
}
index++;
}
}
}
/**
* Initialize column properties.
*
* @param holder
* Write holder which keeps the parameters of a sheet.
* @param exportFieldBoolPairList
* Keep the fields which will be exported to excel and the flag which indicate whether the field order in
* excel is specified.
*/
private void initColumnProperties(Holder holder, List<Map.Entry<Field, Boolean>> exportFieldBoolPairList) {
int index = 0;
for (Map.Entry<Field, Boolean> fieldBoolPair : exportFieldBoolPairList) {
initOneColumnProperty(holder, index, fieldBoolPair.getKey(), fieldBoolPair.getValue());
index++;
} }
} }
/** /**
* Initialization column property * Initialization column property
* *
* @param holder
* @param index * @param index
* @param field * @param field
* @param forceIndex * @param forceIndex
* @return Ignore current field * @return Ignore current field
*/ */
private boolean initOneColumnProperty(Holder holder, int index, Field field, Boolean forceIndex) { private void initOneColumnProperty(int index, Field field, Boolean forceIndex) {
if (holder instanceof AbstractWriteHolder) {
if (((AbstractWriteHolder)holder).ignore(field.getName(), index)) {
return true;
}
}
ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class); ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class);
List<String> tmpHeadList = new ArrayList<String>(); List<String> tmpHeadList = new ArrayList<String>();
boolean notForceName = excelProperty == null || excelProperty.value().length <= 0 boolean notForceName = excelProperty == null || excelProperty.value().length <= 0
@ -264,7 +180,6 @@ public class ExcelHeadProperty {
headMap.put(index, head); headMap.put(index, head);
contentPropertyMap.put(index, excelContentProperty); contentPropertyMap.put(index, excelContentProperty);
fieldNameContentPropertyMap.put(field.getName(), excelContentProperty); fieldNameContentPropertyMap.put(field.getName(), excelContentProperty);
return false;
} }
public Class getHeadClazz() { public Class getHeadClazz() {

13
src/main/java/com/alibaba/excel/read/builder/AbstractExcelReaderParameterBuilder.java

@ -31,6 +31,19 @@ public abstract class AbstractExcelReaderParameterBuilder<T extends AbstractExce
return self(); return self();
} }
/**
* Whether to use scientific Format.
*
* default is false
*
* @param useScientificFormat
* @return
*/
public T useScientificFormat(Boolean useScientificFormat) {
parameter().setUseScientificFormat(useScientificFormat);
return self();
}
/** /**
* Custom type listener run after default * Custom type listener run after default
* *

51
src/main/java/com/alibaba/excel/read/listener/ModelBuildEventListener.java

@ -14,9 +14,10 @@ import com.alibaba.excel.exception.ExcelDataConvertException;
import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head; import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.property.ExcelContentProperty; import com.alibaba.excel.metadata.property.ExcelContentProperty;
import com.alibaba.excel.read.metadata.holder.ReadHolder; import com.alibaba.excel.read.metadata.holder.ReadSheetHolder;
import com.alibaba.excel.read.metadata.property.ExcelReadHeadProperty; import com.alibaba.excel.read.metadata.property.ExcelReadHeadProperty;
import com.alibaba.excel.util.ConverterUtils; import com.alibaba.excel.util.ConverterUtils;
import com.alibaba.excel.util.FieldUtils;
import net.sf.cglib.beans.BeanMap; import net.sf.cglib.beans.BeanMap;
@ -25,28 +26,28 @@ import net.sf.cglib.beans.BeanMap;
* *
* @author jipengfei * @author jipengfei
*/ */
public class ModelBuildEventListener extends AbstractIgnoreExceptionReadListener<Map<Integer, CellData>> { public class ModelBuildEventListener extends AbstractIgnoreExceptionReadListener<Map<Integer, CellData<?>>> {
@Override @Override
public void invokeHead(Map<Integer, CellData> cellDataMap, AnalysisContext context) {} public void invokeHead(Map<Integer, CellData<?>> cellDataMap, AnalysisContext context) {}
@Override @Override
public void invoke(Map<Integer, CellData> cellDataMap, AnalysisContext context) { public void invoke(Map<Integer, CellData<?>> cellDataMap, AnalysisContext context) {
ReadHolder currentReadHolder = context.currentReadHolder(); ReadSheetHolder readSheetHolder = context.readSheetHolder();
if (HeadKindEnum.CLASS.equals(currentReadHolder.excelReadHeadProperty().getHeadKind())) { if (HeadKindEnum.CLASS.equals(readSheetHolder.excelReadHeadProperty().getHeadKind())) {
context.readRowHolder() context.readRowHolder()
.setCurrentRowAnalysisResult(buildUserModel(cellDataMap, currentReadHolder, context)); .setCurrentRowAnalysisResult(buildUserModel(cellDataMap, readSheetHolder, context));
return; return;
} }
context.readRowHolder().setCurrentRowAnalysisResult(buildStringList(cellDataMap, currentReadHolder, context)); context.readRowHolder().setCurrentRowAnalysisResult(buildStringList(cellDataMap, readSheetHolder, context));
} }
private Object buildStringList(Map<Integer, CellData> cellDataMap, ReadHolder currentReadHolder, private Object buildStringList(Map<Integer, CellData<?>> cellDataMap, ReadSheetHolder readSheetHolder,
AnalysisContext context) { AnalysisContext context) {
int index = 0; int index = 0;
if (context.readWorkbookHolder().getDefaultReturnMap()) { if (context.readWorkbookHolder().getDefaultReturnMap()) {
Map<Integer, String> map = new LinkedHashMap<Integer, String>(cellDataMap.size() * 4 / 3 + 1); Map<Integer, String> map = new LinkedHashMap<Integer, String>(cellDataMap.size() * 4 / 3 + 1);
for (Map.Entry<Integer, CellData> entry : cellDataMap.entrySet()) { for (Map.Entry<Integer, CellData<?>> entry : cellDataMap.entrySet()) {
Integer key = entry.getKey(); Integer key = entry.getKey();
CellData cellData = entry.getValue(); CellData cellData = entry.getValue();
while (index < key) { while (index < key) {
@ -59,10 +60,10 @@ public class ModelBuildEventListener extends AbstractIgnoreExceptionReadListener
continue; continue;
} }
map.put(key, map.put(key,
(String)ConverterUtils.convertToJavaObject(cellData, null, null, currentReadHolder.converterMap(), (String)ConverterUtils.convertToJavaObject(cellData, null, null, readSheetHolder.converterMap(),
currentReadHolder.globalConfiguration(), context.readRowHolder().getRowIndex(), key)); readSheetHolder, context.readRowHolder().getRowIndex(), key));
} }
int headSize = currentReadHolder.excelReadHeadProperty().getHeadMap().size(); int headSize = readSheetHolder.excelReadHeadProperty().getHeadMap().size();
while (index < headSize) { while (index < headSize) {
map.put(index, null); map.put(index, null);
index++; index++;
@ -70,10 +71,10 @@ public class ModelBuildEventListener extends AbstractIgnoreExceptionReadListener
return map; return map;
} else { } else {
// Compatible with the old code the old code returns a list // Compatible with the old code the old code returns a list
List<String> list = new ArrayList<String>(); List<String> list = new ArrayList<>();
for (Map.Entry<Integer, CellData> entry : cellDataMap.entrySet()) { for (Map.Entry<Integer, CellData<?>> entry : cellDataMap.entrySet()) {
Integer key = entry.getKey(); Integer key = entry.getKey();
CellData cellData = entry.getValue(); CellData<?> cellData = entry.getValue();
while (index < key) { while (index < key) {
list.add(null); list.add(null);
index++; index++;
@ -84,10 +85,10 @@ public class ModelBuildEventListener extends AbstractIgnoreExceptionReadListener
continue; continue;
} }
list.add( list.add(
(String)ConverterUtils.convertToJavaObject(cellData, null, null, currentReadHolder.converterMap(), (String)ConverterUtils.convertToJavaObject(cellData, null, null, readSheetHolder.converterMap(),
currentReadHolder.globalConfiguration(), context.readRowHolder().getRowIndex(), key)); readSheetHolder, context.readRowHolder().getRowIndex(), key));
} }
int headSize = currentReadHolder.excelReadHeadProperty().getHeadMap().size(); int headSize = readSheetHolder.excelReadHeadProperty().getHeadMap().size();
while (index < headSize) { while (index < headSize) {
list.add(null); list.add(null);
index++; index++;
@ -96,15 +97,15 @@ public class ModelBuildEventListener extends AbstractIgnoreExceptionReadListener
} }
} }
private Object buildUserModel(Map<Integer, CellData> cellDataMap, ReadHolder currentReadHolder, private Object buildUserModel(Map<Integer, CellData<?>> cellDataMap, ReadSheetHolder readSheetHolder,
AnalysisContext context) { AnalysisContext context) {
ExcelReadHeadProperty excelReadHeadProperty = currentReadHolder.excelReadHeadProperty(); ExcelReadHeadProperty excelReadHeadProperty = readSheetHolder.excelReadHeadProperty();
Object resultModel; Object resultModel;
try { try {
resultModel = excelReadHeadProperty.getHeadClazz().newInstance(); resultModel = excelReadHeadProperty.getHeadClazz().newInstance();
} catch (Exception e) { } catch (Exception e) {
throw new ExcelDataConvertException(context.readRowHolder().getRowIndex(), 0, throw new ExcelDataConvertException(context.readRowHolder().getRowIndex(), 0,
new CellData(CellDataTypeEnum.EMPTY), null, new CellData<>(CellDataTypeEnum.EMPTY), null,
"Can not instance class: " + excelReadHeadProperty.getHeadClazz().getName(), e); "Can not instance class: " + excelReadHeadProperty.getHeadClazz().getName(), e);
} }
Map<Integer, Head> headMap = excelReadHeadProperty.getHeadMap(); Map<Integer, Head> headMap = excelReadHeadProperty.getHeadMap();
@ -115,16 +116,16 @@ public class ModelBuildEventListener extends AbstractIgnoreExceptionReadListener
if (!cellDataMap.containsKey(index)) { if (!cellDataMap.containsKey(index)) {
continue; continue;
} }
CellData cellData = cellDataMap.get(index); CellData<?> cellData = cellDataMap.get(index);
if (cellData.getType() == CellDataTypeEnum.EMPTY) { if (cellData.getType() == CellDataTypeEnum.EMPTY) {
continue; continue;
} }
ExcelContentProperty excelContentProperty = contentPropertyMap.get(index); ExcelContentProperty excelContentProperty = contentPropertyMap.get(index);
Object value = ConverterUtils.convertToJavaObject(cellData, excelContentProperty.getField(), Object value = ConverterUtils.convertToJavaObject(cellData, excelContentProperty.getField(),
excelContentProperty, currentReadHolder.converterMap(), currentReadHolder.globalConfiguration(), excelContentProperty, readSheetHolder.converterMap(), readSheetHolder,
context.readRowHolder().getRowIndex(), index); context.readRowHolder().getRowIndex(), index);
if (value != null) { if (value != null) {
map.put(excelContentProperty.getField().getName(), value); map.put(FieldUtils.resolveCglibFieldName(excelContentProperty.getField()), value);
} }
} }
BeanMap.create(resultModel).putAll(map); BeanMap.create(resultModel).putAll(map);

2
src/main/java/com/alibaba/excel/read/listener/ReadListener.java

@ -29,7 +29,7 @@ public interface ReadListener<T> extends Listener {
* @param headMap * @param headMap
* @param context * @param context
*/ */
void invokeHead(Map<Integer, CellData> headMap, AnalysisContext context); void invokeHead(Map<Integer, CellData<?>> headMap, AnalysisContext context);
/** /**
* When analysis one row trigger invoke function. * When analysis one row trigger invoke function.

29
src/main/java/com/alibaba/excel/read/metadata/holder/AbstractReadHolder.java

@ -1,12 +1,8 @@
package com.alibaba.excel.read.metadata.holder; package com.alibaba.excel.read.metadata.holder;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.excel.converters.Converter; import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.converters.ConverterKeyBuild; import com.alibaba.excel.converters.ConverterKeyBuild;
import com.alibaba.excel.converters.DefaultConverterLoader; import com.alibaba.excel.converters.DefaultConverterLoader;
@ -17,6 +13,10 @@ import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.read.metadata.ReadBasicParameter; import com.alibaba.excel.read.metadata.ReadBasicParameter;
import com.alibaba.excel.read.metadata.ReadWorkbook; import com.alibaba.excel.read.metadata.ReadWorkbook;
import com.alibaba.excel.read.metadata.property.ExcelReadHeadProperty; import com.alibaba.excel.read.metadata.property.ExcelReadHeadProperty;
import com.alibaba.excel.util.ListUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** /**
* Read Holder * Read Holder
@ -24,8 +24,6 @@ import com.alibaba.excel.read.metadata.property.ExcelReadHeadProperty;
* @author Jiaju Zhuang * @author Jiaju Zhuang
*/ */
public abstract class AbstractReadHolder extends AbstractHolder implements ReadHolder { public abstract class AbstractReadHolder extends AbstractHolder implements ReadHolder {
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractReadHolder.class);
/** /**
* Count the number of added heads when read sheet. * Count the number of added heads when read sheet.
* *
@ -56,6 +54,17 @@ public abstract class AbstractReadHolder extends AbstractHolder implements ReadH
getGlobalConfiguration().setUse1904windowing(readBasicParameter.getUse1904windowing()); getGlobalConfiguration().setUse1904windowing(readBasicParameter.getUse1904windowing());
} }
if (readBasicParameter.getUseScientificFormat() == null) {
if (parentAbstractReadHolder == null) {
getGlobalConfiguration().setUseScientificFormat(Boolean.FALSE);
} else {
getGlobalConfiguration()
.setUseScientificFormat(parentAbstractReadHolder.getGlobalConfiguration().getUseScientificFormat());
}
} else {
getGlobalConfiguration().setUseScientificFormat(readBasicParameter.getUseScientificFormat());
}
// Initialization property // Initialization property
this.excelReadHeadProperty = new ExcelReadHeadProperty(this, getClazz(), getHead(), convertAllFiled); this.excelReadHeadProperty = new ExcelReadHeadProperty(this, getClazz(), getHead(), convertAllFiled);
if (readBasicParameter.getHeadRowNumber() == null) { if (readBasicParameter.getHeadRowNumber() == null) {
@ -73,9 +82,9 @@ public abstract class AbstractReadHolder extends AbstractHolder implements ReadH
} }
if (parentAbstractReadHolder == null) { if (parentAbstractReadHolder == null) {
this.readListenerList = new ArrayList<ReadListener>(); this.readListenerList = ListUtils.newArrayList();
} else { } else {
this.readListenerList = new ArrayList<ReadListener>(parentAbstractReadHolder.getReadListenerList()); this.readListenerList = ListUtils.newArrayList(parentAbstractReadHolder.getReadListenerList());
} }
if (HolderEnum.WORKBOOK.equals(holderType())) { if (HolderEnum.WORKBOOK.equals(holderType())) {
Boolean useDefaultListener = ((ReadWorkbook)readBasicParameter).getUseDefaultListener(); Boolean useDefaultListener = ((ReadWorkbook)readBasicParameter).getUseDefaultListener();
@ -91,11 +100,11 @@ public abstract class AbstractReadHolder extends AbstractHolder implements ReadH
if (parentAbstractReadHolder == null) { if (parentAbstractReadHolder == null) {
setConverterMap(DefaultConverterLoader.loadDefaultReadConverter()); setConverterMap(DefaultConverterLoader.loadDefaultReadConverter());
} else { } else {
setConverterMap(new HashMap<String, Converter>(parentAbstractReadHolder.getConverterMap())); setConverterMap(new HashMap<>(parentAbstractReadHolder.getConverterMap()));
} }
if (readBasicParameter.getCustomConverterList() != null if (readBasicParameter.getCustomConverterList() != null
&& !readBasicParameter.getCustomConverterList().isEmpty()) { && !readBasicParameter.getCustomConverterList().isEmpty()) {
for (Converter converter : readBasicParameter.getCustomConverterList()) { for (Converter<?> converter : readBasicParameter.getCustomConverterList()) {
getConverterMap().put( getConverterMap().put(
ConverterKeyBuild.buildKey(converter.supportJavaTypeKey(), converter.supportExcelTypeKey()), ConverterKeyBuild.buildKey(converter.supportJavaTypeKey(), converter.supportExcelTypeKey()),
converter); converter);

8
src/main/java/com/alibaba/excel/read/metadata/holder/ReadSheetHolder.java

@ -15,6 +15,7 @@ import com.alibaba.excel.read.metadata.ReadSheet;
* @author Jiaju Zhuang * @author Jiaju Zhuang
*/ */
public class ReadSheetHolder extends AbstractReadHolder { public class ReadSheetHolder extends AbstractReadHolder {
/** /**
* current param * current param
*/ */
@ -50,7 +51,7 @@ public class ReadSheetHolder extends AbstractReadHolder {
/** /**
* Current CellData * Current CellData
*/ */
private CellData tempCellData; private CellData<?> tempCellData;
public ReadSheetHolder(ReadSheet readSheet, ReadWorkbookHolder readWorkbookHolder) { public ReadSheetHolder(ReadSheet readSheet, ReadWorkbookHolder readWorkbookHolder) {
super(readSheet, readWorkbookHolder, readWorkbookHolder.getReadWorkbook().getConvertAllFiled()); super(readSheet, readWorkbookHolder, readWorkbookHolder.getReadWorkbook().getConvertAllFiled());
@ -59,6 +60,7 @@ public class ReadSheetHolder extends AbstractReadHolder {
this.sheetNo = readSheet.getSheetNo(); this.sheetNo = readSheet.getSheetNo();
this.sheetName = readSheet.getSheetName(); this.sheetName = readSheet.getSheetName();
this.cellMap = new LinkedHashMap<Integer, Cell>(); this.cellMap = new LinkedHashMap<Integer, Cell>();
this.rowIndex = -1;
} }
public ReadSheet getReadSheet() { public ReadSheet getReadSheet() {
@ -133,11 +135,11 @@ public class ReadSheetHolder extends AbstractReadHolder {
this.rowIndex = rowIndex; this.rowIndex = rowIndex;
} }
public CellData getTempCellData() { public CellData<?> getTempCellData() {
return tempCellData; return tempCellData;
} }
public void setTempCellData(CellData tempCellData) { public void setTempCellData(CellData<?> tempCellData) {
this.tempCellData = tempCellData; this.tempCellData = tempCellData;
} }

12
src/main/java/com/alibaba/excel/read/metadata/holder/xls/XlsReadSheetHolder.java

@ -18,10 +18,6 @@ public class XlsReadSheetHolder extends ReadSheetHolder {
* Row type.Temporary storage, last set in <code>ReadRowHolder</code>. * Row type.Temporary storage, last set in <code>ReadRowHolder</code>.
*/ */
private RowTypeEnum tempRowType; private RowTypeEnum tempRowType;
/**
* Ignore record.
*/
private Boolean ignoreRecord;
/** /**
* Temp object index. * Temp object index.
*/ */
@ -33,7 +29,6 @@ public class XlsReadSheetHolder extends ReadSheetHolder {
public XlsReadSheetHolder(ReadSheet readSheet, ReadWorkbookHolder readWorkbookHolder) { public XlsReadSheetHolder(ReadSheet readSheet, ReadWorkbookHolder readWorkbookHolder) {
super(readSheet, readWorkbookHolder); super(readSheet, readWorkbookHolder);
ignoreRecord = Boolean.FALSE;
tempRowType = RowTypeEnum.EMPTY; tempRowType = RowTypeEnum.EMPTY;
objectCacheMap = new HashMap<Integer, String>(16); objectCacheMap = new HashMap<Integer, String>(16);
} }
@ -46,13 +41,6 @@ public class XlsReadSheetHolder extends ReadSheetHolder {
this.tempRowType = tempRowType; this.tempRowType = tempRowType;
} }
public Boolean getIgnoreRecord() {
return ignoreRecord;
}
public void setIgnoreRecord(Boolean ignoreRecord) {
this.ignoreRecord = ignoreRecord;
}
public Integer getTempObjectIndex() { public Integer getTempObjectIndex() {
return tempObjectIndex; return tempObjectIndex;

13
src/main/java/com/alibaba/excel/read/metadata/holder/xls/XlsReadWorkbookHolder.java

@ -42,6 +42,10 @@ public class XlsReadWorkbookHolder extends ReadWorkbookHolder {
* Sheet Index * Sheet Index
*/ */
private Integer readSheetIndex; private Integer readSheetIndex;
/**
* Ignore record.
*/
private Boolean ignoreRecord;
public XlsReadWorkbookHolder(ReadWorkbook readWorkbook) { public XlsReadWorkbookHolder(ReadWorkbook readWorkbook) {
super(readWorkbook); super(readWorkbook);
@ -51,6 +55,7 @@ public class XlsReadWorkbookHolder extends ReadWorkbookHolder {
if (getGlobalConfiguration().getUse1904windowing() == null) { if (getGlobalConfiguration().getUse1904windowing() == null) {
getGlobalConfiguration().setUse1904windowing(Boolean.FALSE); getGlobalConfiguration().setUse1904windowing(Boolean.FALSE);
} }
ignoreRecord = Boolean.FALSE;
} }
public POIFSFileSystem getPoifsFileSystem() { public POIFSFileSystem getPoifsFileSystem() {
@ -100,4 +105,12 @@ public class XlsReadWorkbookHolder extends ReadWorkbookHolder {
public void setReadSheetIndex(Integer readSheetIndex) { public void setReadSheetIndex(Integer readSheetIndex) {
this.readSheetIndex = readSheetIndex; this.readSheetIndex = readSheetIndex;
} }
public Boolean getIgnoreRecord() {
return ignoreRecord;
}
public void setIgnoreRecord(Boolean ignoreRecord) {
this.ignoreRecord = ignoreRecord;
}
} }

4
src/main/java/com/alibaba/excel/read/processor/DefaultAnalysisEventProcessor.java

@ -82,7 +82,7 @@ public class DefaultAnalysisEventProcessor implements AnalysisEventProcessor {
private void dealData(AnalysisContext analysisContext) { private void dealData(AnalysisContext analysisContext) {
ReadRowHolder readRowHolder = analysisContext.readRowHolder(); ReadRowHolder readRowHolder = analysisContext.readRowHolder();
Map<Integer, CellData> cellDataMap = (Map)readRowHolder.getCellMap(); Map<Integer, CellData<?>> cellDataMap = (Map)readRowHolder.getCellMap();
readRowHolder.setCurrentRowAnalysisResult(cellDataMap); readRowHolder.setCurrentRowAnalysisResult(cellDataMap);
int rowIndex = readRowHolder.getRowIndex(); int rowIndex = readRowHolder.getRowIndex();
int currentHeadRowNumber = analysisContext.readSheetHolder().getHeadRowNumber(); int currentHeadRowNumber = analysisContext.readSheetHolder().getHeadRowNumber();
@ -111,7 +111,7 @@ public class DefaultAnalysisEventProcessor implements AnalysisEventProcessor {
} }
} }
private void buildHead(AnalysisContext analysisContext, Map<Integer, CellData> cellDataMap) { private void buildHead(AnalysisContext analysisContext, Map<Integer, CellData<?>> cellDataMap) {
if (!HeadKindEnum.CLASS.equals(analysisContext.currentReadHolder().excelReadHeadProperty().getHeadKind())) { if (!HeadKindEnum.CLASS.equals(analysisContext.currentReadHolder().excelReadHeadProperty().getHeadKind())) {
return; return;
} }

75
src/main/java/com/alibaba/excel/util/BooleanUtils.java

@ -25,4 +25,79 @@ public class BooleanUtils {
} }
} }
// boolean Boolean methods
//-----------------------------------------------------------------------
/**
* <p>Checks if a {@code Boolean} value is {@code true},
* handling {@code null} by returning {@code false}.</p>
*
* <pre>
* BooleanUtils.isTrue(Boolean.TRUE) = true
* BooleanUtils.isTrue(Boolean.FALSE) = false
* BooleanUtils.isTrue(null) = false
* </pre>
*
* @param bool the boolean to check, null returns {@code false}
* @return {@code true} only if the input is non-null and true
* @since 2.1
*/
public static boolean isTrue(final Boolean bool) {
return Boolean.TRUE.equals(bool);
}
/**
* <p>Checks if a {@code Boolean} value is <i>not</i> {@code true},
* handling {@code null} by returning {@code true}.</p>
*
* <pre>
* BooleanUtils.isNotTrue(Boolean.TRUE) = false
* BooleanUtils.isNotTrue(Boolean.FALSE) = true
* BooleanUtils.isNotTrue(null) = true
* </pre>
*
* @param bool the boolean to check, null returns {@code true}
* @return {@code true} if the input is null or false
* @since 2.3
*/
public static boolean isNotTrue(final Boolean bool) {
return !isTrue(bool);
}
/**
* <p>Checks if a {@code Boolean} value is {@code false},
* handling {@code null} by returning {@code false}.</p>
*
* <pre>
* BooleanUtils.isFalse(Boolean.TRUE) = false
* BooleanUtils.isFalse(Boolean.FALSE) = true
* BooleanUtils.isFalse(null) = false
* </pre>
*
* @param bool the boolean to check, null returns {@code false}
* @return {@code true} only if the input is non-null and false
* @since 2.1
*/
public static boolean isFalse(final Boolean bool) {
return Boolean.FALSE.equals(bool);
}
/**
* <p>Checks if a {@code Boolean} value is <i>not</i> {@code false},
* handling {@code null} by returning {@code true}.</p>
*
* <pre>
* BooleanUtils.isNotFalse(Boolean.TRUE) = true
* BooleanUtils.isNotFalse(Boolean.FALSE) = false
* BooleanUtils.isNotFalse(null) = true
* </pre>
*
* @param bool the boolean to check, null returns {@code true}
* @return {@code true} if the input is null or true
* @since 2.3
*/
public static boolean isNotFalse(final Boolean bool) {
return !isFalse(bool);
}
} }

194
src/main/java/com/alibaba/excel/util/ClassUtils.java

@ -6,6 +6,8 @@ import java.lang.reflect.Modifier;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.TreeMap; import java.util.TreeMap;
@ -14,8 +16,12 @@ import java.util.concurrent.ConcurrentHashMap;
import com.alibaba.excel.annotation.ExcelIgnore; import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.event.Handler;
import com.alibaba.excel.exception.ExcelCommonException; import com.alibaba.excel.exception.ExcelCommonException;
import com.alibaba.excel.metadata.BaseRowModel; import com.alibaba.excel.metadata.BaseRowModel;
import com.alibaba.excel.metadata.Holder;
import com.alibaba.excel.write.handler.WriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteHolder;
/** /**
* Class utils * Class utils
@ -23,26 +29,54 @@ import com.alibaba.excel.metadata.BaseRowModel;
* @author Jiaju Zhuang * @author Jiaju Zhuang
**/ **/
public class ClassUtils { public class ClassUtils {
private static final Map<Class, SoftReference<FieldCache>> FIELD_CACHE = private static final Map<Class, SoftReference<FieldCache>> FIELD_CACHE =
new ConcurrentHashMap<Class, SoftReference<FieldCache>>(); new ConcurrentHashMap<Class, SoftReference<FieldCache>>();
public static void declaredFields(Class clazz, List<Field> defaultFieldList, Map<Integer, Field> customFiledMap, public static void declaredFields(Class clazz, Map<Integer, Field> sortedAllFiledMap,
Map<String, Field> ignoreMap, Boolean convertAllFiled) { Map<Integer, Field> indexFiledMap, Map<String, Field> ignoreMap, Boolean convertAllFiled,
Boolean needIgnore, Holder holder) {
FieldCache fieldCache = getFieldCache(clazz, convertAllFiled); FieldCache fieldCache = getFieldCache(clazz, convertAllFiled);
if (fieldCache != null) { if (fieldCache == null) {
defaultFieldList.addAll(fieldCache.getDefaultFieldList()); return;
customFiledMap.putAll(fieldCache.getCustomFiledMap()); }
if (ignoreMap != null) {
ignoreMap.putAll(fieldCache.getIgnoreMap()); ignoreMap.putAll(fieldCache.getIgnoreMap());
} }
Map<Integer, Field> tempIndexFildMap = indexFiledMap;
if (tempIndexFildMap == null) {
tempIndexFildMap = new TreeMap<Integer, Field>();
} }
tempIndexFildMap.putAll(fieldCache.getIndexFiledMap());
public static void declaredFields(Class clazz, List<Field> fieldList, Boolean convertAllFiled) { if (!needIgnore) {
FieldCache fieldCache = getFieldCache(clazz, convertAllFiled); sortedAllFiledMap.putAll(fieldCache.getSortedAllFiledMap());
if (fieldCache != null) { return;
fieldList.addAll(fieldCache.getAllFieldList()); }
int index = 0;
for (Map.Entry<Integer, Field> entry : fieldCache.getSortedAllFiledMap().entrySet()) {
Field field = entry.getValue();
if (((WriteHolder) holder).ignore(entry.getValue().getName(), entry.getKey())) {
if (ignoreMap != null) {
ignoreMap.put(field.getName(), field);
}
while (tempIndexFildMap.containsKey(index)) {
tempIndexFildMap.remove(index);
index++;
}
} else {
sortedAllFiledMap.put(index, field);
index++;
}
} }
} }
public static void declaredFields(Class clazz, Map<Integer, Field> sortedAllFiledMap, Boolean convertAllFiled,
Boolean needIgnore, WriteHolder writeHolder) {
declaredFields(clazz, sortedAllFiledMap, null, null, convertAllFiled, needIgnore, writeHolder);
}
private static FieldCache getFieldCache(Class clazz, Boolean convertAllFiled) { private static FieldCache getFieldCache(Class clazz, Boolean convertAllFiled) {
if (clazz == null) { if (clazz == null) {
return null; return null;
@ -72,79 +106,155 @@ public class ClassUtils {
tempClass = tempClass.getSuperclass(); tempClass = tempClass.getSuperclass();
} }
// Screening of field // Screening of field
List<Field> defaultFieldList = new ArrayList<Field>(); Map<Integer, List<Field>> orderFiledMap = new TreeMap<Integer, List<Field>>();
Map<Integer, Field> customFiledMap = new TreeMap<Integer, Field>(); Map<Integer, Field> indexFiledMap = new TreeMap<Integer, Field>();
List<Field> allFieldList = new ArrayList<Field>();
Map<String, Field> ignoreMap = new HashMap<String, Field>(16); Map<String, Field> ignoreMap = new HashMap<String, Field>(16);
ExcelIgnoreUnannotated excelIgnoreUnannotated = ExcelIgnoreUnannotated excelIgnoreUnannotated =
(ExcelIgnoreUnannotated)clazz.getAnnotation(ExcelIgnoreUnannotated.class); (ExcelIgnoreUnannotated) clazz.getAnnotation(ExcelIgnoreUnannotated.class);
for (Field field : tempFieldList) { for (Field field : tempFieldList) {
declaredOneField(field, orderFiledMap, indexFiledMap, ignoreMap, excelIgnoreUnannotated, convertAllFiled);
}
FIELD_CACHE.put(clazz, new SoftReference<FieldCache>(
new FieldCache(buildSortedAllFiledMap(orderFiledMap, indexFiledMap), indexFiledMap, ignoreMap)));
}
private static Map<Integer, Field> buildSortedAllFiledMap(Map<Integer, List<Field>> orderFiledMap,
Map<Integer, Field> indexFiledMap) {
Map<Integer, Field> sortedAllFiledMap = new HashMap<Integer, Field>(
(orderFiledMap.size() + indexFiledMap.size()) * 4 / 3 + 1);
Map<Integer, Field> tempIndexFiledMap = new HashMap<Integer, Field>(indexFiledMap);
int index = 0;
for (List<Field> fieldList : orderFiledMap.values()) {
for (Field field : fieldList) {
while (tempIndexFiledMap.containsKey(index)) {
sortedAllFiledMap.put(index, tempIndexFiledMap.get(index));
tempIndexFiledMap.remove(index);
index++;
}
sortedAllFiledMap.put(index, field);
index++;
}
}
sortedAllFiledMap.putAll(tempIndexFiledMap);
return sortedAllFiledMap;
}
private static void declaredOneField(Field field, Map<Integer, List<Field>> orderFiledMap,
Map<Integer, Field> indexFiledMap, Map<String, Field> ignoreMap, ExcelIgnoreUnannotated excelIgnoreUnannotated,
Boolean convertAllFiled) {
ExcelIgnore excelIgnore = field.getAnnotation(ExcelIgnore.class); ExcelIgnore excelIgnore = field.getAnnotation(ExcelIgnore.class);
if (excelIgnore != null) { if (excelIgnore != null) {
ignoreMap.put(field.getName(), field); ignoreMap.put(field.getName(), field);
continue; return;
} }
ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class); ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class);
boolean noExcelProperty = excelProperty == null boolean noExcelProperty = excelProperty == null
&& ((convertAllFiled != null && !convertAllFiled) || excelIgnoreUnannotated != null); && ((convertAllFiled != null && !convertAllFiled) || excelIgnoreUnannotated != null);
if (noExcelProperty) { if (noExcelProperty) {
ignoreMap.put(field.getName(), field); ignoreMap.put(field.getName(), field);
continue; return;
} }
boolean isStaticFinalOrTransient = boolean isStaticFinalOrTransient =
(Modifier.isStatic(field.getModifiers()) && Modifier.isFinal(field.getModifiers())) (Modifier.isStatic(field.getModifiers()) && Modifier.isFinal(field.getModifiers()))
|| Modifier.isTransient(field.getModifiers()); || Modifier.isTransient(field.getModifiers());
if (excelProperty == null && isStaticFinalOrTransient) { if (excelProperty == null && isStaticFinalOrTransient) {
ignoreMap.put(field.getName(), field); ignoreMap.put(field.getName(), field);
continue; return;
} }
if (excelProperty == null || excelProperty.index() < 0) { if (excelProperty != null && excelProperty.index() >= 0) {
defaultFieldList.add(field); if (indexFiledMap.containsKey(excelProperty.index())) {
allFieldList.add(field); throw new ExcelCommonException("The index of '" + indexFiledMap.get(excelProperty.index()).getName()
continue;
}
if (customFiledMap.containsKey(excelProperty.index())) {
throw new ExcelCommonException("The index of '" + customFiledMap.get(excelProperty.index()).getName()
+ "' and '" + field.getName() + "' must be inconsistent"); + "' and '" + field.getName() + "' must be inconsistent");
} }
customFiledMap.put(excelProperty.index(), field); indexFiledMap.put(excelProperty.index(), field);
allFieldList.add(field); return;
} }
FIELD_CACHE.put(clazz, int order = Integer.MAX_VALUE;
new SoftReference<FieldCache>(new FieldCache(defaultFieldList, customFiledMap, allFieldList, ignoreMap))); if (excelProperty != null) {
order = excelProperty.order();
}
List<Field> orderFiledList = orderFiledMap.get(order);
if (orderFiledList == null) {
orderFiledList = new ArrayList<Field>();
orderFiledMap.put(order, orderFiledList);
}
orderFiledList.add(field);
} }
private static class FieldCache { private static class FieldCache {
private List<Field> defaultFieldList;
private Map<Integer, Field> customFiledMap; private Map<Integer, Field> sortedAllFiledMap;
private List<Field> allFieldList; private Map<Integer, Field> indexFiledMap;
private Map<String, Field> ignoreMap; private Map<String, Field> ignoreMap;
public FieldCache(List<Field> defaultFieldList, Map<Integer, Field> customFiledMap, List<Field> allFieldList, public FieldCache(Map<Integer, Field> sortedAllFiledMap, Map<Integer, Field> indexFiledMap,
Map<String, Field> ignoreMap) { Map<String, Field> ignoreMap) {
this.defaultFieldList = defaultFieldList; this.sortedAllFiledMap = sortedAllFiledMap;
this.customFiledMap = customFiledMap; this.indexFiledMap = indexFiledMap;
this.allFieldList = allFieldList;
this.ignoreMap = ignoreMap; this.ignoreMap = ignoreMap;
} }
public List<Field> getDefaultFieldList() { public Map<Integer, Field> getSortedAllFiledMap() {
return defaultFieldList; return sortedAllFiledMap;
}
public Map<Integer, Field> getCustomFiledMap() {
return customFiledMap;
} }
public List<Field> getAllFieldList() { public Map<Integer, Field> getIndexFiledMap() {
return allFieldList; return indexFiledMap;
} }
public Map<String, Field> getIgnoreMap() { public Map<String, Field> getIgnoreMap() {
return ignoreMap; return ignoreMap;
} }
}
/**
* <p>Gets a {@code List} of all interfaces implemented by the given
* class and its superclasses.</p>
*
* <p>The order is determined by looking through each interface in turn as
* declared in the source file and following its hierarchy up. Then each
* superclass is considered in the same way. Later duplicates are ignored,
* so the order is maintained.</p>
*
* @param cls the class to look up, may be {@code null}
* @return the {@code List} of interfaces in order,
* {@code null} if null input
*/
public static List<Class<?>> getAllInterfaces(final Class<?> cls) {
if (cls == null) {
return null;
}
final LinkedHashSet<Class<?>> interfacesFound = new LinkedHashSet<>();
getAllInterfaces(cls, interfacesFound);
return new ArrayList<>(interfacesFound);
}
/**
* Gets the interfaces for the specified class.
*
* @param cls the class to look up, may be {@code null}
* @param interfacesFound the {@code Set} of interfaces for the class
*/
private static void getAllInterfaces(Class<?> cls, final HashSet<Class<?>> interfacesFound) {
while (cls != null) {
final Class<?>[] interfaces = cls.getInterfaces();
for (final Class<?> i : interfaces) {
if (interfacesFound.add(i)) {
getAllInterfaces(i, interfacesFound);
} }
}
cls = cls.getSuperclass();
}
}
} }

22
src/main/java/com/alibaba/excel/util/CollectionUtils.java

@ -1,22 +0,0 @@
package com.alibaba.excel.util;
import java.util.Collection;
import java.util.Map;
/**
* Collection utils
*
* @author jipengfei
*/
public class CollectionUtils {
private CollectionUtils() {}
public static boolean isEmpty(Collection<?> collection) {
return (collection == null || collection.isEmpty());
}
public static boolean isEmpty(Map<?, ?> map) {
return (map == null || map.isEmpty());
}
}

49
src/main/java/com/alibaba/excel/util/ConverterUtils.java

@ -3,7 +3,6 @@ package com.alibaba.excel.util;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType; import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.context.AnalysisContext;
@ -12,9 +11,9 @@ import com.alibaba.excel.converters.ConverterKeyBuild;
import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.exception.ExcelDataConvertException; import com.alibaba.excel.exception.ExcelDataConvertException;
import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.property.ExcelContentProperty; import com.alibaba.excel.metadata.property.ExcelContentProperty;
import com.alibaba.excel.read.metadata.holder.ReadHolder; import com.alibaba.excel.read.metadata.holder.ReadHolder;
import com.alibaba.excel.read.metadata.holder.ReadSheetHolder;
/** /**
* Converting objects * Converting objects
@ -32,13 +31,13 @@ public class ConverterUtils {
* @param context * @param context
* @return * @return
*/ */
public static Map<Integer, String> convertToStringMap(Map<Integer, CellData> cellDataMap, AnalysisContext context) { public static Map<Integer, String> convertToStringMap(Map<Integer, CellData<?>> cellDataMap, AnalysisContext context) {
Map<Integer, String> stringMap = new HashMap<Integer, String>(cellDataMap.size() * 4 / 3 + 1); Map<Integer, String> stringMap = MapUtils.newHashMapWithExpectedSize(cellDataMap.size());
ReadHolder currentReadHolder = context.currentReadHolder(); ReadSheetHolder readSheetHolder = context.readSheetHolder();
int index = 0; int index = 0;
for (Map.Entry<Integer, CellData> entry : cellDataMap.entrySet()) { for (Map.Entry<Integer, CellData<?>> entry : cellDataMap.entrySet()) {
Integer key = entry.getKey(); Integer key = entry.getKey();
CellData cellData = entry.getValue(); CellData<?> cellData = entry.getValue();
while (index < key) { while (index < key) {
stringMap.put(index, null); stringMap.put(index, null);
index++; index++;
@ -48,15 +47,15 @@ public class ConverterUtils {
stringMap.put(key, null); stringMap.put(key, null);
continue; continue;
} }
Converter converter = Converter<?> converter =
currentReadHolder.converterMap().get(ConverterKeyBuild.buildKey(String.class, cellData.getType())); readSheetHolder.converterMap().get(ConverterKeyBuild.buildKey(String.class, cellData.getType()));
if (converter == null) { if (converter == null) {
throw new ExcelDataConvertException(context.readRowHolder().getRowIndex(), key, cellData, null, throw new ExcelDataConvertException(context.readRowHolder().getRowIndex(), key, cellData, null,
"Converter not found, convert " + cellData.getType() + " to String"); "Converter not found, convert " + cellData.getType() + " to String");
} }
try { try {
stringMap.put(key, stringMap.put(key,
(String)(converter.convertToJavaData(cellData, null, currentReadHolder.globalConfiguration()))); (String)(converter.convertToJavaData(cellData, null, readSheetHolder)));
} catch (Exception e) { } catch (Exception e) {
throw new ExcelDataConvertException(context.readRowHolder().getRowIndex(), key, cellData, null, throw new ExcelDataConvertException(context.readRowHolder().getRowIndex(), key, cellData, null,
"Convert data " + cellData + " to String error ", e); "Convert data " + cellData + " to String error ", e);
@ -72,15 +71,15 @@ public class ConverterUtils {
* @param field * @param field
* @param contentProperty * @param contentProperty
* @param converterMap * @param converterMap
* @param globalConfiguration * @param readSheetHolder
* @param rowIndex * @param rowIndex
* @param columnIndex * @param columnIndex
* @return * @return
*/ */
public static Object convertToJavaObject(CellData cellData, Field field, ExcelContentProperty contentProperty, public static Object convertToJavaObject(CellData<?> cellData, Field field, ExcelContentProperty contentProperty,
Map<String, Converter> converterMap, GlobalConfiguration globalConfiguration, Integer rowIndex, Map<String, Converter<?>> converterMap, ReadSheetHolder readSheetHolder, Integer rowIndex,
Integer columnIndex) { Integer columnIndex) {
Class clazz; Class<?> clazz;
if (field == null) { if (field == null) {
clazz = String.class; clazz = String.class;
} else { } else {
@ -88,37 +87,37 @@ public class ConverterUtils {
} }
if (clazz == CellData.class) { if (clazz == CellData.class) {
Type type = field.getGenericType(); Type type = field.getGenericType();
Class classGeneric; Class<?> classGeneric;
if (type instanceof ParameterizedType) { if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType)type; ParameterizedType parameterizedType = (ParameterizedType)type;
classGeneric = (Class)parameterizedType.getActualTypeArguments()[0]; classGeneric = (Class<?>)parameterizedType.getActualTypeArguments()[0];
} else { } else {
classGeneric = String.class; classGeneric = String.class;
} }
CellData cellDataReturn = new CellData(cellData); CellData<Object> cellDataReturn = new CellData<Object>(cellData);
cellDataReturn.setData(doConvertToJavaObject(cellData, classGeneric, contentProperty, converterMap, cellDataReturn.setData(doConvertToJavaObject(cellData, classGeneric, contentProperty, converterMap,
globalConfiguration, rowIndex, columnIndex)); readSheetHolder, rowIndex, columnIndex));
return cellDataReturn; return cellDataReturn;
} }
return doConvertToJavaObject(cellData, clazz, contentProperty, converterMap, globalConfiguration, rowIndex, return doConvertToJavaObject(cellData, clazz, contentProperty, converterMap, readSheetHolder, rowIndex,
columnIndex); columnIndex);
} }
/** /**
*
* @param cellData * @param cellData
* @param clazz * @param clazz
* @param contentProperty * @param contentProperty
* @param converterMap * @param converterMap
* @param globalConfiguration * @param readSheetHolder
* @param rowIndex * @param rowIndex
* @param columnIndex * @param columnIndex
* @return * @return
*/ */
private static Object doConvertToJavaObject(CellData cellData, Class clazz, ExcelContentProperty contentProperty, private static Object doConvertToJavaObject(CellData<?> cellData, Class<?> clazz,
Map<String, Converter> converterMap, GlobalConfiguration globalConfiguration, Integer rowIndex, ExcelContentProperty contentProperty,
Map<String, Converter<?>> converterMap, ReadSheetHolder readSheetHolder, Integer rowIndex,
Integer columnIndex) { Integer columnIndex) {
Converter converter = null; Converter<?> converter = null;
if (contentProperty != null) { if (contentProperty != null) {
converter = contentProperty.getConverter(); converter = contentProperty.getConverter();
} }
@ -130,7 +129,7 @@ public class ConverterUtils {
"Converter not found, convert " + cellData.getType() + " to " + clazz.getName()); "Converter not found, convert " + cellData.getType() + " to " + clazz.getName());
} }
try { try {
return converter.convertToJavaData(cellData, contentProperty, globalConfiguration); return converter.convertToJavaData(cellData, contentProperty, readSheetHolder);
} catch (Exception e) { } catch (Exception e) {
throw new ExcelDataConvertException(rowIndex, columnIndex, cellData, contentProperty, throw new ExcelDataConvertException(rowIndex, columnIndex, cellData, contentProperty,
"Convert data " + cellData + " to " + clazz + " error ", e); "Convert data " + cellData + " to " + clazz + " error ", e);

32
src/main/java/com/alibaba/excel/util/DateUtils.java

@ -17,16 +17,16 @@ public class DateUtils {
/** /**
* Is a cache of dates * Is a cache of dates
*/ */
private static final ThreadLocal<Map<Integer, Boolean>> DATE_THREAD_LOCAL = private static final ThreadLocal<Map<Short, Boolean>> DATE_THREAD_LOCAL =
new ThreadLocal<Map<Integer, Boolean>>(); new ThreadLocal<>();
/** /**
* Is a cache of dates * Is a cache of dates
*/ */
private static final ThreadLocal<Map<String, SimpleDateFormat>> DATE_FORMAT_THREAD_LOCAL = private static final ThreadLocal<Map<String, SimpleDateFormat>> DATE_FORMAT_THREAD_LOCAL =
new ThreadLocal<Map<String, SimpleDateFormat>>(); new ThreadLocal<>();
/** /**
* The following patterns are used in {@link #isADateFormat(Integer, String)} * The following patterns are used in {@link #isADateFormat(Short, String)}
*/ */
private static final Pattern date_ptrn1 = Pattern.compile("^\\[\\$\\-.*?\\]"); private static final Pattern date_ptrn1 = Pattern.compile("^\\[\\$\\-.*?\\]");
private static final Pattern date_ptrn2 = Pattern.compile("^\\[[a-zA-Z]+\\]"); private static final Pattern date_ptrn2 = Pattern.compile("^\\[[a-zA-Z]+\\]");
@ -43,11 +43,15 @@ public class DateUtils {
public static final String DATE_FORMAT_10 = "yyyy-MM-dd"; public static final String DATE_FORMAT_10 = "yyyy-MM-dd";
public static final String DATE_FORMAT_14 = "yyyyMMddHHmmss"; public static final String DATE_FORMAT_14 = "yyyyMMddHHmmss";
public static final String DATE_FORMAT_16 = "yyyy-MM-dd HH:mm";
public static final String DATE_FORMAT_16_FORWARD_SLASH = "yyyy/MM/dd HH:mm";
public static final String DATE_FORMAT_17 = "yyyyMMdd HH:mm:ss"; public static final String DATE_FORMAT_17 = "yyyyMMdd HH:mm:ss";
public static final String DATE_FORMAT_19 = "yyyy-MM-dd HH:mm:ss"; public static final String DATE_FORMAT_19 = "yyyy-MM-dd HH:mm:ss";
public static final String DATE_FORMAT_19_FORWARD_SLASH = "yyyy/MM/dd HH:mm:ss"; public static final String DATE_FORMAT_19_FORWARD_SLASH = "yyyy/MM/dd HH:mm:ss";
private static final String MINUS = "-"; private static final String MINUS = "-";
public static String defaultDateFormat = DATE_FORMAT_19;
private DateUtils() {} private DateUtils() {}
/** /**
@ -91,6 +95,12 @@ public class DateUtils {
} else { } else {
return DATE_FORMAT_19_FORWARD_SLASH; return DATE_FORMAT_19_FORWARD_SLASH;
} }
case 16:
if (dateString.contains(MINUS)) {
return DATE_FORMAT_16;
} else {
return DATE_FORMAT_16_FORWARD_SLASH;
}
case 17: case 17:
return DATE_FORMAT_17; return DATE_FORMAT_17;
case 14: case 14:
@ -126,7 +136,7 @@ public class DateUtils {
return ""; return "";
} }
if (StringUtils.isEmpty(dateFormat)) { if (StringUtils.isEmpty(dateFormat)) {
dateFormat = DATE_FORMAT_19; dateFormat = defaultDateFormat;
} }
return getCacheDateFormat(dateFormat).format(date); return getCacheDateFormat(dateFormat).format(date);
} }
@ -154,13 +164,13 @@ public class DateUtils {
* @param formatString * @param formatString
* @return * @return
*/ */
public static boolean isADateFormat(Integer formatIndex, String formatString) { public static boolean isADateFormat(Short formatIndex, String formatString) {
if (formatIndex == null) { if (formatIndex == null) {
return false; return false;
} }
Map<Integer, Boolean> isDateCache = DATE_THREAD_LOCAL.get(); Map<Short, Boolean> isDateCache = DATE_THREAD_LOCAL.get();
if (isDateCache == null) { if (isDateCache == null) {
isDateCache = new HashMap<Integer, Boolean>(); isDateCache = MapUtils.newHashMap();
DATE_THREAD_LOCAL.set(isDateCache); DATE_THREAD_LOCAL.set(isDateCache);
} else { } else {
Boolean isDateCachedData = isDateCache.get(formatIndex); Boolean isDateCachedData = isDateCache.get(formatIndex);
@ -180,7 +190,7 @@ public class DateUtils {
* @param formatString * @param formatString
* @return * @return
*/ */
public static boolean isADateFormatUncached(Integer formatIndex, String formatString) { public static boolean isADateFormatUncached(Short formatIndex, String formatString) {
// First up, is this an internal date format? // First up, is this an internal date format?
if (isInternalDateFormat(formatIndex)) { if (isInternalDateFormat(formatIndex)) {
return true; return true;
@ -256,9 +266,9 @@ public class DateUtils {
/** /**
* Given a format ID this will check whether the format represents an internal excel date format or not. * Given a format ID this will check whether the format represents an internal excel date format or not.
* *
* @see #isADateFormat(Integer, String) * @see #isADateFormat(Short, String)
*/ */
public static boolean isInternalDateFormat(int format) { public static boolean isInternalDateFormat(short format) {
switch (format) { switch (format) {
// Internal Date Formats as described on page 427 in // Internal Date Formats as described on page 427 in
// Microsoft Excel Dev's Kit... // Microsoft Excel Dev's Kit...

145
src/main/java/com/alibaba/excel/util/FieldUtils.java

@ -0,0 +1,145 @@
package com.alibaba.excel.util;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
/**
* Field utils
*
* @author Jiaju Zhuang
**/
public class FieldUtils {
private static final int START_RESOLVE_FIELD_LENGTH = 2;
/**
* Parsing the name matching cglib
* <ul>
* <ul>null -> null</ul>
* <ul>string1 -> string1</ul>
* <ul>String2 -> string2</ul>
* <ul>sTring3 -> STring3</ul>
* <ul>STring4 -> STring4</ul>
* <ul>STRING5 -> STRING5</ul>
* <ul>STRing6 -> STRing6</ul>
* </ul>
*
* @param field field
* @return field name.
*/
public static String resolveCglibFieldName(Field field) {
if (field == null) {
return null;
}
String fieldName = field.getName();
if (StringUtils.isBlank(fieldName) || fieldName.length() < START_RESOLVE_FIELD_LENGTH) {
return fieldName;
}
char firstChar = fieldName.charAt(0);
char secondChar = fieldName.charAt(1);
if (Character.isUpperCase(firstChar) == Character.isUpperCase(secondChar)) {
return fieldName;
}
if (Character.isUpperCase(firstChar)) {
return buildFieldName(Character.toLowerCase(firstChar), fieldName);
}
return buildFieldName(Character.toUpperCase(firstChar), fieldName);
}
private static String buildFieldName(char firstChar, String fieldName) {
return firstChar + fieldName.substring(1);
}
/**
* Gets an accessible {@link Field} by name respecting scope. Superclasses/interfaces will be considered.
*
* @param cls
* the {@link Class} to reflect, must not be {@code null}
* @param fieldName
* the field name to obtain
* @return the Field object
* @throws IllegalArgumentException
* if the class is {@code null}, or the field name is blank or empty
*/
public static Field getField(final Class<?> cls, final String fieldName) {
final Field field = getField(cls, fieldName, false);
MemberUtils.setAccessibleWorkaround(field);
return field;
}
/**
* Gets an accessible {@link Field} by name, breaking scope if requested. Superclasses/interfaces will be
* considered.
*
* @param cls
* the {@link Class} to reflect, must not be {@code null}
* @param fieldName
* the field name to obtain
* @param forceAccess
* whether to break scope restrictions using the
* {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only
* match {@code public} fields.
* @return the Field object
* @throws NullPointerException if the class is {@code null}
* @throws IllegalArgumentException if the field name is blank or empty or is matched at multiple places
* in the inheritance hierarchy
*/
public static Field getField(final Class<?> cls, final String fieldName, final boolean forceAccess) {
Validate.isTrue(cls != null, "The class must not be null");
Validate.isTrue(StringUtils.isNotBlank(fieldName), "The field name must not be blank/empty");
// FIXME is this workaround still needed? lang requires Java 6
// Sun Java 1.3 has a bugged implementation of getField hence we write the
// code ourselves
// getField() will return the Field object with the declaring class
// set correctly to the class that declares the field. Thus requesting the
// field on a subclass will return the field from the superclass.
//
// priority order for lookup:
// searchclass private/protected/package/public
// superclass protected/package/public
// private/different package blocks access to further superclasses
// implementedinterface public
// check up the superclass hierarchy
for (Class<?> acls = cls; acls != null; acls = acls.getSuperclass()) {
try {
final Field field = acls.getDeclaredField(fieldName);
// getDeclaredField checks for non-public scopes as well
// and it returns accurate results
if (!Modifier.isPublic(field.getModifiers())) {
if (forceAccess) {
field.setAccessible(true);
} else {
continue;
}
}
return field;
} catch (final NoSuchFieldException ex) { // NOPMD
// ignore
}
}
// check the public interface case. This must be manually searched for
// incase there is a public supersuperclass field hidden by a private/package
// superclass field.
Field match = null;
for (final Class<?> class1 : ClassUtils.getAllInterfaces(cls)) {
try {
final Field test = class1.getField(fieldName);
Validate.isTrue(match == null, "Reference to field %s is ambiguous relative to %s"
+ "; a matching field exists on two or more implemented interfaces.", fieldName, cls);
match = test;
} catch (final NoSuchFieldException ex) { // NOPMD
// ignore
}
}
return match;
}
}

24
src/main/java/com/alibaba/excel/util/FileUtils.java

@ -9,12 +9,12 @@ import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.UUID; import java.util.UUID;
import org.apache.poi.util.DefaultTempFileCreationStrategy;
import org.apache.poi.util.TempFile;
import com.alibaba.excel.exception.ExcelAnalysisException; import com.alibaba.excel.exception.ExcelAnalysisException;
import com.alibaba.excel.exception.ExcelCommonException; import com.alibaba.excel.exception.ExcelCommonException;
import org.apache.poi.util.DefaultTempFileCreationStrategy;
import org.apache.poi.util.TempFile;
/** /**
* *
* @author jipengfei * @author jipengfei
@ -100,10 +100,21 @@ public class FileUtils {
/** /**
* Write inputStream to file * Write inputStream to file
* *
* @param file * @param file file
* @param inputStream * @param inputStream inputStream
*/ */
public static void writeToFile(File file, InputStream inputStream) { public static void writeToFile(File file, InputStream inputStream) {
writeToFile(file, inputStream, true);
}
/**
* Write inputStream to file
*
* @param file file
* @param inputStream inputStream
* @param closeInputStream closeInputStream
*/
public static void writeToFile(File file, InputStream inputStream, boolean closeInputStream) {
OutputStream outputStream = null; OutputStream outputStream = null;
try { try {
outputStream = new FileOutputStream(file); outputStream = new FileOutputStream(file);
@ -122,7 +133,7 @@ public class FileUtils {
throw new ExcelAnalysisException("Can not close 'outputStream'!", e); throw new ExcelAnalysisException("Can not close 'outputStream'!", e);
} }
} }
if (inputStream != null) { if (inputStream != null && closeInputStream) {
try { try {
inputStream.close(); inputStream.close();
} catch (IOException e) { } catch (IOException e) {
@ -132,6 +143,7 @@ public class FileUtils {
} }
} }
public static void createPoiFilesDirectory() { public static void createPoiFilesDirectory() {
File poiFilesPathFile = new File(poiFilesPath); File poiFilesPathFile = new File(poiFilesPath);
createDirectory(poiFilesPathFile); createDirectory(poiFilesPathFile);

39
src/main/java/com/alibaba/excel/util/IntUtils.java

@ -0,0 +1,39 @@
package com.alibaba.excel.util;
import java.util.ArrayList;
import java.util.List;
/**
* Int utils
*
* @author Jiaju Zhuang
**/
public class IntUtils {
private IntUtils() {}
/**
* The largest power of two that can be represented as an {@code int}.
*
* @since 10.0
*/
public static final int MAX_POWER_OF_TWO = 1 << (Integer.SIZE - 2);
/**
* Returns the {@code int} nearest in value to {@code value}.
*
* @param value any {@code long} value
* @return the same value cast to {@code int} if it is in the range of the {@code int} type,
* {@link Integer#MAX_VALUE} if it is too large, or {@link Integer#MIN_VALUE} if it is too
* small
*/
public static int saturatedCast(long value) {
if (value > Integer.MAX_VALUE) {
return Integer.MAX_VALUE;
}
if (value < Integer.MIN_VALUE) {
return Integer.MIN_VALUE;
}
return (int) value;
}
}

121
src/main/java/com/alibaba/excel/util/ListUtils.java

@ -0,0 +1,121 @@
package com.alibaba.excel.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import lombok.NonNull;
import org.apache.commons.compress.utils.Iterators;
/**
* List utils
*
* @author Jiaju Zhuang
**/
public class ListUtils {
private ListUtils() {}
/**
* Creates a <i>mutable</i>, empty {@code ArrayList} instance (for Java 6 and earlier).
*
* <p><b>Note for Java 7 and later:</b> this method is now unnecessary and should be treated as
* deprecated. Instead, use the {@code ArrayList} {@linkplain ArrayList#ArrayList() constructor}
* directly, taking advantage of the new <a href="http://goo.gl/iz2Wi">"diamond" syntax</a>.
*/
public static <E> ArrayList<E> newArrayList() {
return new ArrayList<>();
}
/**
* Creates a <i>mutable</i> {@code ArrayList} instance containing the given elements; a very thin
* shortcut for creating an empty list and then calling {@link Iterators#addAll}.
*
*/
public static <E> ArrayList<E> newArrayList(Iterator<? extends E> elements) {
ArrayList<E> list = newArrayList();
Iterators.addAll(list, elements);
return list;
}
/**
* Creates a <i>mutable</i> {@code ArrayList} instance containing the given elements;
*
*
* <p><b>Note for Java 7 and later:</b> if {@code elements} is a {@link Collection}, you don't
* need this method. Use the {@code ArrayList} {@linkplain ArrayList#ArrayList(Collection)
* constructor} directly, taking advantage of the new <a href="http://goo.gl/iz2Wi">"diamond"
* syntax</a>.
*/
public static <E> ArrayList<E> newArrayList(Iterable<? extends E> elements) {
checkNotNull(elements); // for GWT
// Let ArrayList's sizing logic work, if possible
return (elements instanceof Collection)
? new ArrayList<>((Collection<? extends E>)elements)
: newArrayList(elements.iterator());
}
/**
* Creates an {@code ArrayList} instance backed by an array with the specified initial size;
* simply delegates to {@link ArrayList#ArrayList(int)}.
*
* <p><b>Note for Java 7 and later:</b> this method is now unnecessary and should be treated as
* deprecated. Instead, use {@code new }{@link ArrayList#ArrayList(int) ArrayList}{@code <>(int)}
* directly, taking advantage of the new <a href="http://goo.gl/iz2Wi">"diamond" syntax</a>.
* (Unlike here, there is no risk of overload ambiguity, since the {@code ArrayList} constructors
* very wisely did not accept varargs.)
*
* @param initialArraySize the exact size of the initial backing array for the returned array list
* ({@code ArrayList} documentation calls this value the "capacity")
* @return a new, empty {@code ArrayList} which is guaranteed not to resize itself unless its size
* reaches {@code initialArraySize + 1}
* @throws IllegalArgumentException if {@code initialArraySize} is negative
*/
public static <E> ArrayList<E> newArrayListWithCapacity(int initialArraySize) {
checkNonnegative(initialArraySize, "initialArraySize");
return new ArrayList<>(initialArraySize);
}
/**
* Creates an {@code ArrayList} instance to hold {@code estimatedSize} elements, <i>plus</i> an
* unspecified amount of padding; you almost certainly mean to call {@link
* #newArrayListWithCapacity} (see that method for further advice on usage).
*
* <p><b>Note:</b> This method will soon be deprecated. Even in the rare case that you do want
* some amount of padding, it's best if you choose your desired amount explicitly.
*
* @param estimatedSize an estimate of the eventual {@link List#size()} of the new list
* @return a new, empty {@code ArrayList}, sized appropriately to hold the estimated number of
* elements
* @throws IllegalArgumentException if {@code estimatedSize} is negative
*/
public static <E> ArrayList<E> newArrayListWithExpectedSize(int estimatedSize) {
return new ArrayList<>(computeArrayListCapacity(estimatedSize));
}
static int computeArrayListCapacity(int arraySize) {
checkNonnegative(arraySize, "arraySize");
return IntUtils.saturatedCast(5L + arraySize + (arraySize / 10));
}
static int checkNonnegative(int value, String name) {
if (value < 0) {
throw new IllegalArgumentException(name + " cannot be negative but was: " + value);
}
return value;
}
/**
* Ensures that an object reference passed as a parameter to the calling method is not null.
*
* @param reference an object reference
* @return the non-null reference that was validated
* @throws NullPointerException if {@code reference} is null
*/
public static <T extends @NonNull Object> T checkNotNull(T reference) {
if (reference == null) {
throw new NullPointerException();
}
return reference;
}
}

63
src/main/java/com/alibaba/excel/util/MapUtils.java

@ -0,0 +1,63 @@
package com.alibaba.excel.util;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Map utils
*
* @author Jiaju Zhuang
**/
public class MapUtils {
private MapUtils() {}
/**
* Creates a <i>mutable</i>, empty {@code HashMap} instance.
*
* <p><b>Note:</b> if mutability is not required, use {@link ImmutableMap#of()} instead.
*
* <p><b>Note:</b> if {@code K} is an {@code enum} type, use {@link #newEnumMap} instead.
*
* <p><b>Note for Java 7 and later:</b> this method is now unnecessary and should be treated as
* deprecated. Instead, use the {@code HashMap} constructor directly, taking advantage of the new
* <a href="http://goo.gl/iz2Wi">"diamond" syntax</a>.
*
* @return a new, empty {@code HashMap}
*/
public static <K, V> HashMap<K, V> newHashMap() {
return new HashMap<>();
}
/**
* Creates a {@code HashMap} instance, with a high enough "initial capacity" that it <i>should</i>
* hold {@code expectedSize} elements without growth. This behavior cannot be broadly guaranteed,
* but it is observed to be true for OpenJDK 1.7. It also can't be guaranteed that the method
* isn't inadvertently <i>oversizing</i> the returned map.
*
* @param expectedSize the number of entries you expect to add to the returned map
* @return a new, empty {@code HashMap} with enough capacity to hold {@code expectedSize} entries
* without resizing
* @throws IllegalArgumentException if {@code expectedSize} is negative
*/
public static <K, V> HashMap<K, V> newHashMapWithExpectedSize(int expectedSize) {
return new HashMap<>(capacity(expectedSize));
}
/**
* Returns a capacity that is sufficient to keep the map from being resized as long as it grows no
* larger than expectedSize and the load factor is its default (0.75).
*/
static int capacity(int expectedSize) {
if (expectedSize < 3) {
return expectedSize + 1;
}
if (expectedSize < IntUtils.MAX_POWER_OF_TWO) {
// This is the calculation used in JDK8 to resize when a putAll
// happens; it seems to be the most conservative calculation we
// can make. 0.75 is the default load factor.
return (int) ((float) expectedSize / 0.75F + 1.0F);
}
return Integer.MAX_VALUE;
}
}

54
src/main/java/com/alibaba/excel/util/MemberUtils.java

@ -0,0 +1,54 @@
package com.alibaba.excel.util;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Member;
import java.lang.reflect.Modifier;
/**
* Member utils.
*
* @author Jiaju Zhuang
*/
public class MemberUtils {
private static final int ACCESS_TEST = Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE;
/**
* XXX Default access superclass workaround.
*
* When a {@code public} class has a default access superclass with {@code public} members,
* these members are accessible. Calling them from compiled code works fine.
* Unfortunately, on some JVMs, using reflection to invoke these members
* seems to (wrongly) prevent access even when the modifier is {@code public}.
* Calling {@code setAccessible(true)} solves the problem but will only work from
* sufficiently privileged code. Better workarounds would be gratefully
* accepted.
* @param o the AccessibleObject to set as accessible
* @return a boolean indicating whether the accessibility of the object was set to true.
*/
static boolean setAccessibleWorkaround(final AccessibleObject o) {
if (o == null || o.isAccessible()) {
return false;
}
final Member m = (Member) o;
if (!o.isAccessible() && Modifier.isPublic(m.getModifiers()) && isPackageAccess(m.getDeclaringClass().getModifiers())) {
try {
o.setAccessible(true);
return true;
} catch (final SecurityException e) { // NOPMD
// ignore in favor of subsequent IllegalAccessException
}
}
return false;
}
/**
* Returns whether a given set of modifiers implies package access.
* @param modifiers to test
* @return {@code true} unless {@code package}/{@code protected}/{@code private} modifier detected
*/
static boolean isPackageAccess(final int modifiers) {
return (modifiers & ACCESS_TEST) == 0;
}
}

15
src/main/java/com/alibaba/excel/util/NumberDataFormatterUtils.java

@ -1,6 +1,6 @@
package com.alibaba.excel.util; package com.alibaba.excel.util;
import com.alibaba.excel.metadata.DataFormatter; import com.alibaba.excel.metadata.format.DataFormatter;
import com.alibaba.excel.metadata.GlobalConfiguration; import com.alibaba.excel.metadata.GlobalConfiguration;
/** /**
@ -9,6 +9,7 @@ import com.alibaba.excel.metadata.GlobalConfiguration;
* @author Jiaju Zhuang * @author Jiaju Zhuang
**/ **/
public class NumberDataFormatterUtils { public class NumberDataFormatterUtils {
/** /**
* Cache DataFormatter. * Cache DataFormatter.
*/ */
@ -18,22 +19,16 @@ public class NumberDataFormatterUtils {
* Format number data. * Format number data.
* *
* @param data * @param data
* @param dataFormat * @param dataFormat Not null.
* Not null.
* @param dataFormatString * @param dataFormatString
* @param globalConfiguration * @param globalConfiguration
* @return * @return
*/ */
public static String format(Double data, Integer dataFormat, String dataFormatString, public static String format(Double data, Short dataFormat, String dataFormatString,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
DataFormatter dataFormatter = DATA_FORMATTER_THREAD_LOCAL.get(); DataFormatter dataFormatter = DATA_FORMATTER_THREAD_LOCAL.get();
if (dataFormatter == null) { if (dataFormatter == null) {
if (globalConfiguration != null) { dataFormatter = new DataFormatter(globalConfiguration);
dataFormatter =
new DataFormatter(globalConfiguration.getLocale(), globalConfiguration.getUse1904windowing());
} else {
dataFormatter = new DataFormatter();
}
DATA_FORMATTER_THREAD_LOCAL.set(dataFormatter); DATA_FORMATTER_THREAD_LOCAL.set(dataFormatter);
} }
return dataFormatter.format(data, dataFormat, dataFormatString); return dataFormatter.format(data, dataFormat, dataFormatString);

25
src/main/java/com/alibaba/excel/util/NumberUtils.java

@ -7,6 +7,7 @@ import java.text.ParseException;
import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.property.ExcelContentProperty; import com.alibaba.excel.metadata.property.ExcelContentProperty;
import com.alibaba.excel.write.metadata.holder.WriteHolder;
/** /**
* Number utils * Number utils
@ -46,8 +47,27 @@ public class NumberUtils {
* @param contentProperty * @param contentProperty
* @return * @return
*/ */
public static CellData formatToCellData(Number num, ExcelContentProperty contentProperty) { public static CellData<?> formatToCellDataString(Number num, ExcelContentProperty contentProperty) {
return new CellData(format(num, contentProperty)); return new CellData<>(format(num, contentProperty));
}
/**
* format
*
* @param num
* @param contentProperty
* @param currentWriteHolder
* @return
*/
public static CellData<?> formatToCellData(Number num, ExcelContentProperty contentProperty,
WriteHolder currentWriteHolder) {
CellData<?> cellData = new CellData<>(BigDecimal.valueOf(num.doubleValue()));
if (contentProperty != null && contentProperty.getNumberFormatProperty() != null
&& StringUtils.isNotBlank(contentProperty.getNumberFormatProperty().getFormat())) {
WorkBookUtil.fillDataFormat(cellData, currentWriteHolder,
contentProperty.getNumberFormatProperty().getFormat());
}
return cellData;
} }
/** /**
@ -167,6 +187,7 @@ public class NumberUtils {
RoundingMode roundingMode = contentProperty.getNumberFormatProperty().getRoundingMode(); RoundingMode roundingMode = contentProperty.getNumberFormatProperty().getRoundingMode();
DecimalFormat decimalFormat = new DecimalFormat(format); DecimalFormat decimalFormat = new DecimalFormat(format);
decimalFormat.setRoundingMode(roundingMode); decimalFormat.setRoundingMode(roundingMode);
decimalFormat.setParseBigDecimal(true);
return decimalFormat.parse(string); return decimalFormat.parse(string);
} }
} }

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save