This is an automated email from the ASF dual-hosted git repository.
fanningpj pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/poi.git
The following commit(s) were added to refs/heads/trunk by this push:
new 0dc32a8596 cache CellStyle Properties to improve performance (#926)
0dc32a8596 is described below
commit 0dc32a85960daaf31c79baffcfc13ac88ca579ef
Author: PJ Fanning <[email protected]>
AuthorDate: Wed Oct 29 19:47:21 2025 +0000
cache CellStyle Properties to improve performance (#926)
* cache CellStyle Properties to improve performance
* add tests
---
.../apache/poi/xssf/usermodel/XSSFCellStyle.java | 71 ++++++++++++---
.../poi/xssf/usermodel/TestXSSFCellStyle.java | 26 ++++++
.../apache/poi/hssf/usermodel/HSSFCellStyle.java | 100 +++++++++++++++------
.../org/apache/poi/ss/usermodel/CellStyle.java | 27 ++++++
.../main/java/org/apache/poi/ss/util/CellUtil.java | 9 +-
.../apache/poi/hssf/usermodel/TestCellStyle.java | 29 ++++++
6 files changed, 219 insertions(+), 43 deletions(-)
diff --git
a/poi-ooxml/src/main/java/org/apache/poi/xssf/usermodel/XSSFCellStyle.java
b/poi-ooxml/src/main/java/org/apache/poi/xssf/usermodel/XSSFCellStyle.java
index 3c4252b65e..44e12035e6 100644
--- a/poi-ooxml/src/main/java/org/apache/poi/xssf/usermodel/XSSFCellStyle.java
+++ b/poi-ooxml/src/main/java/org/apache/poi/xssf/usermodel/XSSFCellStyle.java
@@ -19,9 +19,12 @@ package org.apache.poi.xssf.usermodel;
import static org.apache.poi.ooxml.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;
+import java.util.EnumMap;
+
import org.apache.poi.common.Duplicatable;
import org.apache.poi.ooxml.POIXMLException;
import org.apache.poi.ss.usermodel.BorderStyle;
+import org.apache.poi.ss.usermodel.CellPropertyType;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.Font;
@@ -68,6 +71,7 @@ public class XSSFCellStyle implements CellStyle, Duplicatable
{
private XSSFFont _font;
private XSSFCellAlignment _cellAlignment;
private ThemesTable _theme;
+ private EnumMap<CellPropertyType, Object> _cachedProperties;
/**
* Creates a Cell Style from the supplied parts
@@ -83,6 +87,17 @@ public class XSSFCellStyle implements CellStyle,
Duplicatable {
_theme = theme;
}
+ /**
+ * Creates an empty Cell Style
+ */
+ public XSSFCellStyle(StylesTable stylesSource) {
+ _stylesSource = stylesSource;
+ // We need a new CTXf for the main styles
+ // TODO decide on a style ctxf
+ _cellXf = CTXf.Factory.newInstance();
+ _cellStyleXf = null;
+ }
+
/**
* Used so that StylesSource can figure out our location
*/
@@ -99,17 +114,6 @@ public class XSSFCellStyle implements CellStyle,
Duplicatable {
return _cellStyleXf;
}
- /**
- * Creates an empty Cell Style
- */
- public XSSFCellStyle(StylesTable stylesSource) {
- _stylesSource = stylesSource;
- // We need a new CTXf for the main styles
- // TODO decide on a style ctxf
- _cellXf = CTXf.Factory.newInstance();
- _cellStyleXf = null;
- }
-
/**
* Verifies that this style belongs to the supplied Workbook
* Styles Source.
@@ -662,6 +666,7 @@ public class XSSFCellStyle implements CellStyle,
Duplicatable {
_cellXf.setApplyAlignment(true);
getCellAlignment().setHorizontal(align);
+ invalidateCachedProperties();
}
/**
@@ -682,6 +687,7 @@ public class XSSFCellStyle implements CellStyle,
Duplicatable {
_cellXf.setBorderId(idx);
_cellXf.setApplyBorder(true);
+ invalidateCachedProperties();
}
/**
@@ -701,6 +707,7 @@ public class XSSFCellStyle implements CellStyle,
Duplicatable {
_cellXf.setBorderId(idx);
_cellXf.setApplyBorder(true);
+ invalidateCachedProperties();
}
/**
@@ -720,6 +727,7 @@ public class XSSFCellStyle implements CellStyle,
Duplicatable {
_cellXf.setBorderId(idx);
_cellXf.setApplyBorder(true);
+ invalidateCachedProperties();
}
/**
@@ -739,6 +747,7 @@ public class XSSFCellStyle implements CellStyle,
Duplicatable {
_cellXf.setBorderId(idx);
_cellXf.setApplyBorder(true);
+ invalidateCachedProperties();
}
/**
@@ -770,6 +779,7 @@ public class XSSFCellStyle implements CellStyle,
Duplicatable {
_cellXf.setBorderId(idx);
_cellXf.setApplyBorder(true);
+ invalidateCachedProperties();
}
/**
@@ -782,6 +792,7 @@ public class XSSFCellStyle implements CellStyle,
Duplicatable {
// XSSF supports >32,767 formats
setDataFormat(fmt&0xffff);
}
+
/**
* Set the index of a data format
*
@@ -790,6 +801,7 @@ public class XSSFCellStyle implements CellStyle,
Duplicatable {
public void setDataFormat(int fmt) {
_cellXf.setApplyNumberFormat(true);
_cellXf.setNumFmtId(fmt);
+ invalidateCachedProperties();
}
/**
@@ -828,6 +840,7 @@ public class XSSFCellStyle implements CellStyle,
Duplicatable {
}
addFill(ct);
+ invalidateCachedProperties();
}
/**
@@ -898,6 +911,7 @@ public class XSSFCellStyle implements CellStyle,
Duplicatable {
}
addFill(ct);
+ invalidateCachedProperties();
}
/**
@@ -954,6 +968,7 @@ public class XSSFCellStyle implements CellStyle,
Duplicatable {
*/
public void setReadingOrder(ReadingOrder order) {
getCellAlignment().setReadingOrder(order);
+ invalidateCachedProperties();
}
/**
@@ -1001,6 +1016,7 @@ public class XSSFCellStyle implements CellStyle,
Duplicatable {
}
addFill(ct);
+ invalidateCachedProperties();
}
/**
@@ -1019,6 +1035,7 @@ public class XSSFCellStyle implements CellStyle,
Duplicatable {
} else {
this._cellXf.setApplyFont(false);
}
+ invalidateCachedProperties();
}
/**
@@ -1032,6 +1049,7 @@ public class XSSFCellStyle implements CellStyle,
Duplicatable {
_cellXf.addNewProtection();
}
_cellXf.getProtection().setHidden(hidden);
+ invalidateCachedProperties();
}
/**
@@ -1042,6 +1060,7 @@ public class XSSFCellStyle implements CellStyle,
Duplicatable {
@Override
public void setIndention(short indent) {
getCellAlignment().setIndent(indent);
+ invalidateCachedProperties();
}
/**
@@ -1055,6 +1074,7 @@ public class XSSFCellStyle implements CellStyle,
Duplicatable {
XSSFColor clr = XSSFColor.from(CTColor.Factory.newInstance(),
_stylesSource.getIndexedColors());
clr.setIndexed(color);
setLeftBorderColor(clr);
+ invalidateCachedProperties();
}
/**
@@ -1074,6 +1094,7 @@ public class XSSFCellStyle implements CellStyle,
Duplicatable {
_cellXf.setBorderId(idx);
_cellXf.setApplyBorder(true);
+ invalidateCachedProperties();
}
/**
@@ -1087,6 +1108,7 @@ public class XSSFCellStyle implements CellStyle,
Duplicatable {
_cellXf.addNewProtection();
}
_cellXf.getProtection().setLocked(locked);
+ invalidateCachedProperties();
}
/**
@@ -1097,6 +1119,7 @@ public class XSSFCellStyle implements CellStyle,
Duplicatable {
@Override
public void setQuotePrefixed(boolean quotePrefix) {
_cellXf.setQuotePrefix(quotePrefix);
+ invalidateCachedProperties();
}
/**
@@ -1110,6 +1133,7 @@ public class XSSFCellStyle implements CellStyle,
Duplicatable {
XSSFColor clr = XSSFColor.from(CTColor.Factory.newInstance(),
_stylesSource.getIndexedColors());
clr.setIndexed(color);
setRightBorderColor(clr);
+ invalidateCachedProperties();
}
/**
@@ -1129,6 +1153,7 @@ public class XSSFCellStyle implements CellStyle,
Duplicatable {
_cellXf.setBorderId(idx);
_cellXf.setApplyBorder(true);
+ invalidateCachedProperties();
}
/**
@@ -1153,9 +1178,9 @@ public class XSSFCellStyle implements CellStyle,
Duplicatable {
@Override
public void setRotation(short rotation) {
getCellAlignment().setTextRotation(rotation);
+ invalidateCachedProperties();
}
-
/**
* Set the color to use for the top border
*
@@ -1167,6 +1192,7 @@ public class XSSFCellStyle implements CellStyle,
Duplicatable {
XSSFColor clr = XSSFColor.from(CTColor.Factory.newInstance(),
_stylesSource.getIndexedColors());
clr.setIndexed(color);
setTopBorderColor(clr);
+ invalidateCachedProperties();
}
/**
@@ -1186,6 +1212,7 @@ public class XSSFCellStyle implements CellStyle,
Duplicatable {
_cellXf.setBorderId(idx);
_cellXf.setApplyBorder(true);
+ invalidateCachedProperties();
}
/**
@@ -1197,6 +1224,7 @@ public class XSSFCellStyle implements CellStyle,
Duplicatable {
_cellXf.setApplyAlignment(true);
getCellAlignment().setVertical(align);
+ invalidateCachedProperties();
}
/**
@@ -1211,6 +1239,7 @@ public class XSSFCellStyle implements CellStyle,
Duplicatable {
@Override
public void setWrapText(boolean wrapped) {
getCellAlignment().setWrapText(wrapped);
+ invalidateCachedProperties();
}
/**
@@ -1260,6 +1289,24 @@ public class XSSFCellStyle implements CellStyle,
Duplicatable {
@Override
public void setShrinkToFit(boolean shrinkToFit) {
getCellAlignment().setShrinkToFit(shrinkToFit);
+ invalidateCachedProperties();
+ }
+
+ @Override
+ public EnumMap<CellPropertyType, Object> getFormatProperties() {
+ // this code is not thread safe and POI generally isn't thread safe
anyway
+ // you should not have one thread modifying styles while another reads
them
+ EnumMap<CellPropertyType, Object> props = _cachedProperties;
+ if (props == null) {
+ props = CellUtil.getFormatProperties(this);
+ _cachedProperties = props;
+ }
+ return props;
+ }
+
+ @Override
+ public void invalidateCachedProperties() {
+ _cachedProperties = null;
}
private int getFontId() {
diff --git
a/poi-ooxml/src/test/java/org/apache/poi/xssf/usermodel/TestXSSFCellStyle.java
b/poi-ooxml/src/test/java/org/apache/poi/xssf/usermodel/TestXSSFCellStyle.java
index 3b605f515f..379974443b 100644
---
a/poi-ooxml/src/test/java/org/apache/poi/xssf/usermodel/TestXSSFCellStyle.java
+++
b/poi-ooxml/src/test/java/org/apache/poi/xssf/usermodel/TestXSSFCellStyle.java
@@ -27,11 +27,13 @@ import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.IOException;
+import java.util.EnumMap;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellPropertyType;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.DataFormat;
import org.apache.poi.ss.usermodel.FillPatternType;
@@ -1153,4 +1155,28 @@ class TestXSSFCellStyle {
}
}
+ @Test
+ void cachedPropertiesInvalidation() throws IOException {
+ try (XSSFWorkbook xssfWorkbook = new XSSFWorkbook()) {
+ XSSFCellStyle cellStyle = xssfWorkbook.createCellStyle();
+ DataFormat format = xssfWorkbook.createDataFormat();
+
+ cellStyle.setDataFormat(format.getFormat("###0"));
+
+
cellStyle.setFillBackgroundColor(IndexedColors.DARK_BLUE.getIndex());
+
cellStyle.setFillForegroundColor(IndexedColors.DARK_RED.getIndex());
+ cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+
+ cellStyle.setAlignment(HorizontalAlignment.RIGHT);
+ cellStyle.setVerticalAlignment(VerticalAlignment.TOP);
+
+ EnumMap<CellPropertyType, Object> formatProperties =
cellStyle.getFormatProperties();
+ assertNotNull(formatProperties);
+ assertEquals(formatProperties, cellStyle.getFormatProperties());
+
+ cellStyle.setVerticalAlignment(VerticalAlignment.BOTTOM);
+ assertNotEquals(formatProperties, cellStyle.getFormatProperties());
+ }
+ }
+
}
diff --git a/poi/src/main/java/org/apache/poi/hssf/usermodel/HSSFCellStyle.java
b/poi/src/main/java/org/apache/poi/hssf/usermodel/HSSFCellStyle.java
index 20d3bcaf6e..080d907e6c 100644
--- a/poi/src/main/java/org/apache/poi/hssf/usermodel/HSSFCellStyle.java
+++ b/poi/src/main/java/org/apache/poi/hssf/usermodel/HSSFCellStyle.java
@@ -18,6 +18,7 @@
package org.apache.poi.hssf.usermodel;
+import java.util.EnumMap;
import java.util.List;
import java.util.Objects;
@@ -30,6 +31,7 @@ import org.apache.poi.hssf.record.StyleRecord;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.hssf.util.HSSFColor.HSSFColorPredefined;
import org.apache.poi.ss.usermodel.BorderStyle;
+import org.apache.poi.ss.usermodel.CellPropertyType;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.Font;
@@ -51,6 +53,7 @@ public final class HSSFCellStyle implements CellStyle,
Duplicatable {
private final short _index;
private final InternalWorkbook _workbook;
private final HSSFWorkbook _hssfWorkbook;
+ private EnumMap<CellPropertyType, Object> _cachedProperties;
protected HSSFCellStyle(short index, ExtendedFormatRecord rec,
HSSFWorkbook workbook)
{
@@ -114,6 +117,7 @@ public final class HSSFCellStyle implements CellStyle,
Duplicatable {
public void setDataFormat(short fmt)
{
_format.setFormatIndex(fmt);
+ invalidateCachedProperties();
}
/**
@@ -197,10 +201,12 @@ public final class HSSFCellStyle implements CellStyle,
Duplicatable {
public void setFont(Font font) {
setFont((HSSFFont)font);
}
+
public void setFont(HSSFFont font) {
_format.setIndentNotParentFont(true);
short fontindex = (short) font.getIndex();
_format.setFontIndex(fontindex);
+ invalidateCachedProperties();
}
/**
@@ -247,6 +253,7 @@ public final class HSSFCellStyle implements CellStyle,
Duplicatable {
{
_format.setIndentNotParentCellOptions(true);
_format.setHidden(hidden);
+ invalidateCachedProperties();
}
/**
@@ -268,6 +275,7 @@ public final class HSSFCellStyle implements CellStyle,
Duplicatable {
{
_format.setIndentNotParentCellOptions(true);
_format.setLocked(locked);
+ invalidateCachedProperties();
}
/**
@@ -288,6 +296,7 @@ public final class HSSFCellStyle implements CellStyle,
Duplicatable {
@Override
public void setQuotePrefixed(boolean quotePrefix) {
_format.set123Prefix(quotePrefix);
+ invalidateCachedProperties();
}
/**
@@ -307,6 +316,7 @@ public final class HSSFCellStyle implements CellStyle,
Duplicatable {
{
_format.setIndentNotParentAlignment(true);
_format.setAlignment(align.getCode());
+ invalidateCachedProperties();
}
@Override
@@ -324,6 +334,7 @@ public final class HSSFCellStyle implements CellStyle,
Duplicatable {
{
_format.setIndentNotParentAlignment(true);
_format.setWrapText(wrapped);
+ invalidateCachedProperties();
}
/**
@@ -344,6 +355,7 @@ public final class HSSFCellStyle implements CellStyle,
Duplicatable {
public void setVerticalAlignment(VerticalAlignment align)
{
_format.setVerticalAlignment(align.getCode());
+ invalidateCachedProperties();
}
@Override
@@ -364,23 +376,24 @@ public final class HSSFCellStyle implements CellStyle,
Duplicatable {
@Override
public void setRotation(short rotation)
{
- if (rotation == 0xff) {
- // Special cases for vertically aligned text
- }
- else if ((rotation < 0)&&(rotation >= -90)) {
- //Take care of the funny 4th quadrant issue
- //The 4th quadrant (-1 to -90) is stored as (91 to 180)
- rotation = (short)(90 - rotation);
- }
- else if (rotation > 90 && rotation <= 180) {
- // stay compatible with the range used by XSSF, map from ]90..180]
to ]0..-90]
- // we actually don't need to do anything here as the internal value
is stored in [0-180] anyway!
- }
- else if ((rotation < -90) || (rotation > 90)) {
- //Do not allow an incorrect rotation to be set
- throw new IllegalArgumentException("The rotation must be between -90
and 90 degrees, or 0xff");
- }
- _format.setRotation(rotation);
+ if (rotation == 0xff) {
+ // Special cases for vertically aligned text
+ }
+ else if ((rotation < 0)&&(rotation >= -90)) {
+ //Take care of the funny 4th quadrant issue
+ //The 4th quadrant (-1 to -90) is stored as (91 to 180)
+ rotation = (short)(90 - rotation);
+ }
+ else if (rotation > 90 && rotation <= 180) {
+ // stay compatible with the range used by XSSF, map from ]90..180]
to ]0..-90]
+ // we actually don't need to do anything here as the internal
value is stored in [0-180] anyway!
+ }
+ else if ((rotation < -90) || (rotation > 90)) {
+ //Do not allow an incorrect rotation to be set
+ throw new IllegalArgumentException("The rotation must be between
-90 and 90 degrees, or 0xff");
+ }
+ _format.setRotation(rotation);
+ invalidateCachedProperties();
}
/**
@@ -390,16 +403,16 @@ public final class HSSFCellStyle implements CellStyle,
Duplicatable {
@Override
public short getRotation()
{
- short rotation = _format.getRotation();
- if (rotation == 0xff) {
- // Vertical aligned special case
- return rotation;
- }
- if (rotation > 90) {
- //This is actually the 4th quadrant
- rotation = (short)(90-rotation);
- }
- return rotation;
+ short rotation = _format.getRotation();
+ if (rotation == 0xff) {
+ // Vertical aligned special case
+ return rotation;
+ }
+ if (rotation > 90) {
+ //This is actually the 4th quadrant
+ rotation = (short)(90-rotation);
+ }
+ return rotation;
}
/**
@@ -410,6 +423,7 @@ public final class HSSFCellStyle implements CellStyle,
Duplicatable {
public void setIndention(short indent)
{
_format.setIndent(indent);
+ invalidateCachedProperties();
}
/**
@@ -432,6 +446,7 @@ public final class HSSFCellStyle implements CellStyle,
Duplicatable {
{
_format.setIndentNotParentBorder(true);
_format.setBorderLeft(border.getCode());
+ invalidateCachedProperties();
}
@Override
@@ -450,6 +465,7 @@ public final class HSSFCellStyle implements CellStyle,
Duplicatable {
{
_format.setIndentNotParentBorder(true);
_format.setBorderRight(border.getCode());
+ invalidateCachedProperties();
}
@Override
@@ -468,6 +484,7 @@ public final class HSSFCellStyle implements CellStyle,
Duplicatable {
{
_format.setIndentNotParentBorder(true);
_format.setBorderTop(border.getCode());
+ invalidateCachedProperties();
}
@Override
@@ -486,6 +503,7 @@ public final class HSSFCellStyle implements CellStyle,
Duplicatable {
{
_format.setIndentNotParentBorder(true);
_format.setBorderBottom(border.getCode());
+ invalidateCachedProperties();
}
@Override
@@ -502,6 +520,7 @@ public final class HSSFCellStyle implements CellStyle,
Duplicatable {
public void setLeftBorderColor(short color)
{
_format.setLeftBorderPaletteIdx(color);
+ invalidateCachedProperties();
}
/**
@@ -523,6 +542,7 @@ public final class HSSFCellStyle implements CellStyle,
Duplicatable {
public void setRightBorderColor(short color)
{
_format.setRightBorderPaletteIdx(color);
+ invalidateCachedProperties();
}
/**
@@ -544,6 +564,7 @@ public final class HSSFCellStyle implements CellStyle,
Duplicatable {
public void setTopBorderColor(short color)
{
_format.setTopBorderPaletteIdx(color);
+ invalidateCachedProperties();
}
/**
@@ -565,6 +586,7 @@ public final class HSSFCellStyle implements CellStyle,
Duplicatable {
public void setBottomBorderColor(short color)
{
_format.setBottomBorderPaletteIdx(color);
+ invalidateCachedProperties();
}
/**
@@ -588,6 +610,7 @@ public final class HSSFCellStyle implements CellStyle,
Duplicatable {
public void setFillPattern(FillPatternType fp)
{
_format.setAdtlFillPattern(fp.getCode());
+ invalidateCachedProperties();
}
@Override
@@ -596,6 +619,23 @@ public final class HSSFCellStyle implements CellStyle,
Duplicatable {
return FillPatternType.forInt(_format.getAdtlFillPattern());
}
+ @Override
+ public EnumMap<CellPropertyType, Object> getFormatProperties() {
+ // this code is not thread safe and POI generally isn't thread safe
anyway
+ // you should not have one thread modifying styles while another reads
them
+ EnumMap<CellPropertyType, Object> props = _cachedProperties;
+ if (props == null) {
+ props = CellUtil.getFormatProperties(this);
+ _cachedProperties = props;
+ }
+ return props;
+ }
+
+ @Override
+ public void invalidateCachedProperties() {
+ _cachedProperties = null;
+ }
+
/**
* Checks if the background and foreground fills are set correctly when one
* or the other is set to the default color.
@@ -653,6 +693,7 @@ public final class HSSFCellStyle implements CellStyle,
Duplicatable {
{
_format.setFillBackground(bg);
checkDefaultBackgroundFills();
+ invalidateCachedProperties();
}
/**
@@ -712,6 +753,7 @@ public final class HSSFCellStyle implements CellStyle,
Duplicatable {
{
_format.setFillForeground(bg);
checkDefaultBackgroundFills();
+ invalidateCachedProperties();
}
/**
@@ -786,6 +828,7 @@ public final class HSSFCellStyle implements CellStyle,
Duplicatable {
throw new IllegalArgumentException("Unable to set user specified
style names for built in styles!");
}
sr.setName(styleName);
+ invalidateCachedProperties();
}
/**
@@ -795,7 +838,9 @@ public final class HSSFCellStyle implements CellStyle,
Duplicatable {
@Override
public void setShrinkToFit(boolean shrinkToFit) {
_format.setShrinkToFit(shrinkToFit);
+ invalidateCachedProperties();
}
+
/**
* Should the Cell be auto-sized by Excel to shrink
* it to fit if this text is too long?
@@ -826,6 +871,7 @@ public final class HSSFCellStyle implements CellStyle,
Duplicatable {
*/
public void setReadingOrder(short order) {
_format.setReadingOrder(order);
+ invalidateCachedProperties();
}
/**
diff --git a/poi/src/main/java/org/apache/poi/ss/usermodel/CellStyle.java
b/poi/src/main/java/org/apache/poi/ss/usermodel/CellStyle.java
index 89908b10c8..608772082a 100644
--- a/poi/src/main/java/org/apache/poi/ss/usermodel/CellStyle.java
+++ b/poi/src/main/java/org/apache/poi/ss/usermodel/CellStyle.java
@@ -17,6 +17,8 @@
package org.apache.poi.ss.usermodel;
+import java.util.EnumMap;
+
import org.apache.poi.util.Removal;
public interface CellStyle {
@@ -397,4 +399,29 @@ public interface CellStyle {
* it to fit if this text is too long?
*/
boolean getShrinkToFit();
+
+ /**
+ * Get a map of format properties (CellPropertyType -> Object).
+ * The implementations try to cache the result and
+ * return the cached value on subsequent calls. The cached value
+ * is invalidated when the CellStyle is modified. Thread-safety
+ * of the caching is not guaranteed. If you have another thread updating
+ * the CellStyle while one thread is reading the format properties, the
+ * results may be inconsistent.
+ *
+ * @return map of format properties
+ * @see org.apache.poi.ss.util.CellUtil#getFormatProperties(CellStyle)
+ * @since POI 5.5.0
+ */
+ EnumMap<CellPropertyType, Object> getFormatProperties();
+
+ /**
+ * Invalidate any cached properties. The CellStyle implementations
+ * should call this method whenever a property is changed.
+ * The API is public just in case users find that the CellStyle
implementations
+ * are not calling this method when they should.
+ *
+ * @since POI 5.5.0
+ */
+ void invalidateCachedProperties();
}
diff --git a/poi/src/main/java/org/apache/poi/ss/util/CellUtil.java
b/poi/src/main/java/org/apache/poi/ss/util/CellUtil.java
index 7c1b3ad81e..7d71f23419 100644
--- a/poi/src/main/java/org/apache/poi/ss/util/CellUtil.java
+++ b/poi/src/main/java/org/apache/poi/ss/util/CellUtil.java
@@ -614,7 +614,7 @@ public final class CellUtil {
CellStyle originalStyle = cell.getCellStyle();
CellStyle newStyle = null;
- EnumMap<CellPropertyType, Object> values =
getFormatProperties(originalStyle);
+ EnumMap<CellPropertyType, Object> values =
originalStyle.getFormatProperties();
if
(properties.containsKey(CellPropertyType.FILL_FOREGROUND_COLOR_COLOR) &&
properties.get(CellPropertyType.FILL_FOREGROUND_COLOR_COLOR) == null) {
values.remove(CellPropertyType.FILL_FOREGROUND_COLOR);
}
@@ -635,7 +635,7 @@ public final class CellUtil {
for (int i = 0; i < numberCellStyles; i++) {
CellStyle wbStyle = workbook.getCellStyleAt(i);
- EnumMap<CellPropertyType, Object> wbStyleMap =
getFormatProperties(wbStyle);
+ EnumMap<CellPropertyType, Object> wbStyleMap =
wbStyle.getFormatProperties();
// the desired style already exists in the workbook. Use the
existing style.
if (styleMapsMatch(wbStyleMap, values, disableNullColorCheck)) {
@@ -748,8 +748,9 @@ public final class CellUtil {
* @param style cell style
* @return map of format properties (CellPropertyType -> Object)
* @see #setFormatProperties(CellStyle, Workbook, Map)
+ * @since POI 5.5.0
*/
- private static EnumMap<CellPropertyType, Object>
getFormatProperties(CellStyle style) {
+ public static EnumMap<CellPropertyType, Object>
getFormatProperties(CellStyle style) {
EnumMap<CellPropertyType, Object> properties = new
EnumMap<>(CellPropertyType.class);
put(properties, CellPropertyType.ALIGNMENT, style.getAlignment());
put(properties, CellPropertyType.VERTICAL_ALIGNMENT,
style.getVerticalAlignment());
@@ -887,7 +888,7 @@ public final class CellUtil {
if (src == null || dest == null) {
throw new IllegalArgumentException("Source and destination styles
must not be null");
}
- EnumMap<CellPropertyType, Object> properties =
getFormatProperties(src);
+ EnumMap<CellPropertyType, Object> properties =
src.getFormatProperties();
setFormatProperties(dest, destWorkbook, properties);
}
diff --git a/poi/src/test/java/org/apache/poi/hssf/usermodel/TestCellStyle.java
b/poi/src/test/java/org/apache/poi/hssf/usermodel/TestCellStyle.java
index 7bfea1b3cf..cf1b39b7ab 100644
--- a/poi/src/test/java/org/apache/poi/hssf/usermodel/TestCellStyle.java
+++ b/poi/src/test/java/org/apache/poi/hssf/usermodel/TestCellStyle.java
@@ -32,19 +32,24 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Calendar;
import java.util.Date;
+import java.util.EnumMap;
import java.util.stream.Stream;
import org.apache.poi.hssf.HSSFTestDataSamples;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellPropertyType;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.CellType;
+import org.apache.poi.ss.usermodel.DataFormat;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.util.LocaleUtil;
import org.apache.poi.util.RandomSingleton;
@@ -500,4 +505,28 @@ final class TestCellStyle {
assertEquals(-90, cellStyle.getRotation());
}
}
+
+ @Test
+ void cachedPropertiesInvalidation() throws IOException {
+ try (HSSFWorkbook hssfWorkbook = new HSSFWorkbook()) {
+ HSSFCellStyle cellStyle = hssfWorkbook.createCellStyle();
+ DataFormat format = hssfWorkbook.createDataFormat();
+
+ cellStyle.setDataFormat(format.getFormat("###0"));
+
+
cellStyle.setFillBackgroundColor(IndexedColors.DARK_BLUE.getIndex());
+
cellStyle.setFillForegroundColor(IndexedColors.DARK_RED.getIndex());
+ cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+
+ cellStyle.setAlignment(HorizontalAlignment.RIGHT);
+ cellStyle.setVerticalAlignment(VerticalAlignment.TOP);
+
+ EnumMap<CellPropertyType, Object> formatProperties =
cellStyle.getFormatProperties();
+ assertNotNull(formatProperties);
+ assertEquals(formatProperties, cellStyle.getFormatProperties());
+
+ cellStyle.setVerticalAlignment(VerticalAlignment.BOTTOM);
+ assertNotEquals(formatProperties, cellStyle.getFormatProperties());
+ }
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]