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 _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 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 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 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 _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 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 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 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 values = getFormatProperties(originalStyle); + EnumMap 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 wbStyleMap = getFormatProperties(wbStyle); + EnumMap 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 getFormatProperties(CellStyle style) { + public static EnumMap getFormatProperties(CellStyle style) { EnumMap 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 properties = getFormatProperties(src); + EnumMap 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 formatProperties = cellStyle.getFormatProperties(); + assertNotNull(formatProperties); + assertEquals(formatProperties, cellStyle.getFormatProperties()); + + cellStyle.setVerticalAlignment(VerticalAlignment.BOTTOM); + assertNotEquals(formatProperties, cellStyle.getFormatProperties()); + } + } }