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]

Reply via email to