cache CellStyle Properties to improve performance (#926)

* cache CellStyle Properties to improve performance

* add tests
This commit is contained in:
PJ Fanning 2025-10-29 19:47:21 +00:00 committed by GitHub
parent 67c8284f35
commit 0dc32a8596
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 219 additions and 43 deletions

View File

@ -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() {

View File

@ -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());
}
}
}

View File

@ -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();
}
/**

View File

@ -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();
}

View File

@ -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);
}

View File

@ -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());
}
}
}