Modified: poi/trunk/src/java/org/apache/poi/hssf/record/PageBreakRecord.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/PageBreakRecord.java?rev=1876433&r1=1876432&r2=1876433&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/PageBreakRecord.java 
(original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/PageBreakRecord.java Sun Apr 
12 22:03:52 2020
@@ -21,7 +21,10 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
+import java.util.function.Supplier;
 
+import org.apache.poi.common.usermodel.GenericRecord;
+import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.LittleEndianOutput;
 
 /**
@@ -47,7 +50,7 @@ public abstract class PageBreakRecord ex
      * The subs (rows or columns, don't seem to be able to set but excel sets
      * them automatically)
      */
-    public static final class Break {
+    public static final class Break implements GenericRecord {
 
         public static final int ENCODED_SIZE = 6;
         public int main;
@@ -77,6 +80,15 @@ public abstract class PageBreakRecord ex
             out.writeShort(subFrom);
             out.writeShort(subTo);
         }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return GenericRecordUtil.getGenericProperties(
+                "main", () -> main,
+                "subFrom", () -> subFrom,
+                "subTo", () -> subTo
+            );
+        }
     }
 
     protected PageBreakRecord() {}
@@ -86,7 +98,7 @@ public abstract class PageBreakRecord ex
         initMap();
     }
 
-    public PageBreakRecord(RecordInputStream in) {
+    protected PageBreakRecord(RecordInputStream in) {
         final int nBreaks = in.readShort();
         _breaks.ensureCapacity(nBreaks + 2);
         for(int k = 0; k < nBreaks; k++) {
@@ -96,7 +108,7 @@ public abstract class PageBreakRecord ex
     }
 
     private void initMap() {
-        _breaks.forEach(br -> _breakMap.put(Integer.valueOf(br.main), br));
+        _breaks.forEach(br -> _breakMap.put(br.main, br));
     }
 
     public boolean isEmpty() {
@@ -122,40 +134,6 @@ public abstract class PageBreakRecord ex
         return _breaks.iterator();
     }
 
-    public String toString() {
-        StringBuilder retval = new StringBuilder();
-
-        String label;
-        String mainLabel;
-        String subLabel;
-
-        if (getSid() == HorizontalPageBreakRecord.sid) {
-           label = "HORIZONTALPAGEBREAK";
-           mainLabel = "row";
-           subLabel = "col";
-        } else {
-           label = "VERTICALPAGEBREAK";
-           mainLabel = "column";
-           subLabel = "row";
-        }
-
-        retval.append("["+label+"]").append("\n");
-        retval.append("     .sid        =").append(getSid()).append("\n");
-        retval.append("     .numbreaks =").append(getNumBreaks()).append("\n");
-        Iterator<Break> iterator = getBreaksIterator();
-        for(int k = 0; k < getNumBreaks(); k++)
-        {
-            Break region = iterator.next();
-
-            retval.append("     .").append(mainLabel).append(" (zero-based) 
=").append(region.main).append("\n");
-            retval.append("     .").append(subLabel).append("From    
=").append(region.subFrom).append("\n");
-            retval.append("     .").append(subLabel).append("To      
=").append(region.subTo).append("\n");
-        }
-
-        retval.append("["+label+"]").append("\n");
-        return retval.toString();
-    }
-
    /**
     * Adds the page break at the specified parameters
     * @param main Depending on sid, will determine row or column to put page 
break (zero-based)
@@ -164,7 +142,7 @@ public abstract class PageBreakRecord ex
     */
     public void addBreak(int main, int subFrom, int subTo) {
 
-        Integer key = Integer.valueOf(main);
+        Integer key = main;
         Break region = _breakMap.get(key);
         if(region == null) {
             region = new Break(main, subFrom, subTo);
@@ -182,7 +160,7 @@ public abstract class PageBreakRecord ex
      * @param main (zero-based)
      */
     public final void removeBreak(int main) {
-        Integer rowKey = Integer.valueOf(main);
+        Integer rowKey = main;
         Break region = _breakMap.get(rowKey);
         _breaks.remove(region);
         _breakMap.remove(rowKey);
@@ -194,7 +172,7 @@ public abstract class PageBreakRecord ex
      * @return The Break or null if no break exists at the row/col specified.
      */
     public final Break getBreak(int main) {
-        Integer rowKey = Integer.valueOf(main);
+        Integer rowKey = main;
         return _breakMap.get(rowKey);
     }
 
@@ -213,4 +191,12 @@ public abstract class PageBreakRecord ex
 
     @Override
     public abstract PageBreakRecord copy();
+
+    @Override
+    public Map<String, Supplier<?>> getGenericProperties() {
+        return GenericRecordUtil.getGenericProperties(
+            "numBreaks", this::getNumBreaks,
+            "breaks", () -> _breaks
+        );
+    }
 }

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/PaletteRecord.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/PaletteRecord.java?rev=1876433&r1=1876432&r2=1876433&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/PaletteRecord.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/PaletteRecord.java Sun Apr 12 
22:03:52 2020
@@ -18,8 +18,12 @@
 package org.apache.poi.hssf.record;
 
 import java.util.ArrayList;
-import java.util.Collections;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.function.Supplier;
 
+import org.apache.poi.common.usermodel.GenericRecord;
+import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.LittleEndianOutput;
 
 /**
@@ -32,12 +36,20 @@ public final class PaletteRecord extends
     /** The byte index of the first color */
     public static final short FIRST_COLOR_INDEX = (short) 0x8;
 
-    private final ArrayList<PColor> _colors = new ArrayList<>();
+    private static final int[] DEFAULT_COLORS = {
+        0x000000, 0xFFFFFF, 0xFF0000, 0x00FF00, 0x0000FF, 0xFFFF00, 0xFF00FF, 
0x00FFFF,
+        0x800000, 0x008000, 0x000080, 0x808000, 0x800080, 0x008080, 0xC0C0C0, 
0x808080,
+        0x9999FF, 0x993366, 0xFFFFCC, 0xCCFFFF, 0x660066, 0xFF8080, 0x0066CC, 
0xCCCCFF,
+        0x000080, 0xFF00FF, 0xFFFF00, 0x00FFFF, 0x800080, 0x800000, 0x008080, 
0x0000FF,
+        0x00CCFF, 0xCCFFFF, 0xCCFFCC, 0xFFFF99, 0x99CCFF, 0xFF99CC, 0xCC99FF, 
0xFFCC99,
+        0x3366FF, 0x33CCCC, 0x99CC00, 0xFFCC00, 0xFF9900, 0xFF6600, 0x666699, 
0x969696,
+        0x003366, 0x339966, 0x003300, 0x333300, 0x993300, 0x993366, 0x333399, 
0x333333
+    };
+
+    private final ArrayList<PColor> _colors = new ArrayList<>(100);
 
     public PaletteRecord() {
-      PColor[] defaultPalette = createDefaultPalette();
-      _colors.ensureCapacity(defaultPalette.length);
-      Collections.addAll(_colors, defaultPalette);
+        
Arrays.stream(DEFAULT_COLORS).mapToObj(PColor::new).forEach(_colors::add);
     }
 
     public PaletteRecord(PaletteRecord other) {
@@ -55,22 +67,6 @@ public final class PaletteRecord extends
     }
 
     @Override
-    public String toString() {
-        StringBuilder buffer = new StringBuilder();
-
-        buffer.append("[PALETTE]\n");
-        buffer.append("  numcolors     = 
").append(_colors.size()).append('\n');
-        for (int i = 0; i < _colors.size(); i++) {
-            PColor c = _colors.get(i);
-            buffer.append("* colornum      = ").append(i).append('\n');
-            buffer.append(c);
-            buffer.append("/*colornum      = ").append(i).append('\n');
-        }
-        buffer.append("[/PALETTE]\n");
-        return buffer.toString();
-    }
-
-    @Override
     public void serialize(LittleEndianOutput out) {
         out.writeShort(_colors.size());
         for (PColor color : _colors) {
@@ -136,108 +132,55 @@ public final class PaletteRecord extends
         return new PaletteRecord(this);
     }
 
-    /**
-     * Creates the default palette as PaletteRecord binary data
-     */
-    private static PColor[] createDefaultPalette()
-    {
-        return new PColor[] {
-                pc(0, 0, 0),
-                pc(255, 255, 255),
-                pc(255, 0, 0),
-                pc(0, 255, 0),
-                pc(0, 0, 255),
-                pc(255, 255, 0),
-                pc(255, 0, 255),
-                pc(0, 255, 255),
-                pc(128, 0, 0),
-                pc(0, 128, 0),
-                pc(0, 0, 128),
-                pc(128, 128, 0),
-                pc(128, 0, 128),
-                pc(0, 128, 128),
-                pc(192, 192, 192),
-                pc(128, 128, 128),
-                pc(153, 153, 255),
-                pc(153, 51, 102),
-                pc(255, 255, 204),
-                pc(204, 255, 255),
-                pc(102, 0, 102),
-                pc(255, 128, 128),
-                pc(0, 102, 204),
-                pc(204, 204, 255),
-                pc(0, 0, 128),
-                pc(255, 0, 255),
-                pc(255, 255, 0),
-                pc(0, 255, 255),
-                pc(128, 0, 128),
-                pc(128, 0, 0),
-                pc(0, 128, 128),
-                pc(0, 0, 255),
-                pc(0, 204, 255),
-                pc(204, 255, 255),
-                pc(204, 255, 204),
-                pc(255, 255, 153),
-                pc(153, 204, 255),
-                pc(255, 153, 204),
-                pc(204, 153, 255),
-                pc(255, 204, 153),
-                pc(51, 102, 255),
-                pc(51, 204, 204),
-                pc(153, 204, 0),
-                pc(255, 204, 0),
-                pc(255, 153, 0),
-                pc(255, 102, 0),
-                pc(102, 102, 153),
-                pc(150, 150, 150),
-                pc(0, 51, 102),
-                pc(51, 153, 102),
-                pc(0, 51, 0),
-                pc(51, 51, 0),
-                pc(153, 51, 0),
-                pc(153, 51, 102),
-                pc(51, 51, 153),
-                pc(51, 51, 51),
-        };
+    @Override
+    public HSSFRecordTypes getGenericRecordType() {
+        return HSSFRecordTypes.PALETTE;
     }
 
-    private static PColor pc(int r, int g, int b) {
-        return new PColor(r, g, b);
+    @Override
+    public Map<String, Supplier<?>> getGenericProperties() {
+        return GenericRecordUtil.getGenericProperties("colors", () -> _colors);
     }
 
     /**
      * PColor - element in the list of colors
      */
-    private static final class PColor {
+    private static final class PColor implements GenericRecord {
         public static final short ENCODED_SIZE = 4;
         private final int _red;
         private final int _green;
         private final int _blue;
 
-        public PColor(int red, int green, int blue) {
+        PColor(int rgb) {
+            _red = (rgb >>> 16) & 0xFF;
+            _green = (rgb >>> 8) & 0xFF;
+            _blue = rgb & 0xFF;
+        }
+
+        PColor(int red, int green, int blue) {
             _red = red;
             _green = green;
             _blue = blue;
         }
 
-        public PColor(PColor other) {
+        PColor(PColor other) {
             _red = other._red;
             _green = other._green;
             _blue = other._blue;
         }
 
-        public PColor(RecordInputStream in) {
+        PColor(RecordInputStream in) {
             _red = in.readByte();
             _green = in.readByte();
             _blue = in.readByte();
             in.readByte(); // unused
         }
 
-        public byte[] getTriplet() {
+        byte[] getTriplet() {
             return new byte[] { (byte) _red, (byte) _green, (byte) _blue };
         }
 
-        public void serialize(LittleEndianOutput out) {
+        void serialize(LittleEndianOutput out) {
             out.writeByte(_red);
             out.writeByte(_green);
             out.writeByte(_blue);
@@ -245,12 +188,12 @@ public final class PaletteRecord extends
         }
 
         @Override
-        public String toString() {
-            StringBuilder buffer = new StringBuilder();
-            buffer.append("  red   = ").append(_red & 0xff).append('\n');
-            buffer.append("  green = ").append(_green & 0xff).append('\n');
-            buffer.append("  blue  = ").append(_blue & 0xff).append('\n');
-            return buffer.toString();
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return GenericRecordUtil.getGenericProperties(
+                "red", () -> _red & 0xFF,
+                "green", () -> _green & 0xFF,
+                "blue", () -> _blue & 0xFF
+            );
         }
     }
 }

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/PaneRecord.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/PaneRecord.java?rev=1876433&r1=1876432&r2=1876433&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/PaneRecord.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/PaneRecord.java Sun Apr 12 
22:03:52 2020
@@ -18,7 +18,12 @@
 package org.apache.poi.hssf.record;
 
 
-import org.apache.poi.util.HexDump;
+import static org.apache.poi.util.GenericRecordUtil.getEnumBitsAsString;
+
+import java.util.Map;
+import java.util.function.Supplier;
+
+import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.LittleEndianOutput;
 import org.apache.poi.util.Removal;
 
@@ -58,37 +63,6 @@ public final class PaneRecord extends St
     }
 
     @Override
-    public String toString()
-    {
-        StringBuilder buffer = new StringBuilder();
-
-        buffer.append("[PANE]\n");
-        buffer.append("    .x                    = ")
-            .append("0x").append(HexDump.toHex(  getX ()))
-            .append(" (").append( getX() ).append(" )");
-        buffer.append(System.getProperty("line.separator"));
-        buffer.append("    .y                    = ")
-            .append("0x").append(HexDump.toHex(  getY ()))
-            .append(" (").append( getY() ).append(" )");
-        buffer.append(System.getProperty("line.separator"));
-        buffer.append("    .topRow               = ")
-            .append("0x").append(HexDump.toHex(  getTopRow ()))
-            .append(" (").append( getTopRow() ).append(" )");
-        buffer.append(System.getProperty("line.separator"));
-        buffer.append("    .leftColumn           = ")
-            .append("0x").append(HexDump.toHex(  getLeftColumn ()))
-            .append(" (").append( getLeftColumn() ).append(" )");
-        buffer.append(System.getProperty("line.separator"));
-        buffer.append("    .activePane           = ")
-            .append("0x").append(HexDump.toHex(  getActivePane ()))
-            .append(" (").append( getActivePane() ).append(" )");
-        buffer.append(System.getProperty("line.separator"));
-
-        buffer.append("[/PANE]\n");
-        return buffer.toString();
-    }
-
-    @Override
     public void serialize(LittleEndianOutput out) {
         out.writeShort(field_1_x);
         out.writeShort(field_2_y);
@@ -109,7 +83,7 @@ public final class PaneRecord extends St
     }
 
     @Override
-    @SuppressWarnings("squid:S2975")
+    @SuppressWarnings({"squid:S2975", "MethodDoesntCallSuperMethod"})
     @Deprecated
     @Removal(version = "5.0.0")
     public PaneRecord clone() {
@@ -229,4 +203,22 @@ public final class PaneRecord extends St
     {
         this.field_5_activePane = field_5_activePane;
     }
+
+    @Override
+    public HSSFRecordTypes getGenericRecordType() {
+        return HSSFRecordTypes.PANE;
+    }
+
+    @Override
+    public Map<String, Supplier<?>> getGenericProperties() {
+        return GenericRecordUtil.getGenericProperties(
+            "x", this::getX,
+            "y", this::getY,
+            "topRow", this::getTopRow,
+            "leftColumn", this::getLeftColumn,
+            "activePane", getEnumBitsAsString(this::getActivePane,
+                new int[]{ACTIVE_PANE_LOWER_RIGHT, ACTIVE_PANE_UPPER_RIGHT, 
ACTIVE_PANE_LOWER_LEFT, ACTIVE_PANE_UPPER_LEFT},
+                new 
String[]{"LOWER_RIGHT","UPPER_RIGHT","LOWER_LEFT","UPPER_LEFT"})
+        );
+    }
 }

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/PasswordRecord.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/PasswordRecord.java?rev=1876433&r1=1876432&r2=1876433&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/PasswordRecord.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/PasswordRecord.java Sun Apr 
12 22:03:52 2020
@@ -17,7 +17,10 @@
 
 package org.apache.poi.hssf.record;
 
-import org.apache.poi.util.HexDump;
+import java.util.Map;
+import java.util.function.Supplier;
+
+import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.LittleEndianOutput;
 import org.apache.poi.util.Removal;
 
@@ -62,15 +65,6 @@ public final class PasswordRecord extend
         return field_1_password;
     }
 
-    public String toString() {
-        StringBuilder buffer = new StringBuilder();
-
-        buffer.append("[PASSWORD]\n");
-        buffer.append("    .password = 
").append(HexDump.shortToHex(field_1_password)).append("\n");
-        buffer.append("[/PASSWORD]\n");
-        return buffer.toString();
-    }
-
     public void serialize(LittleEndianOutput out) {
         out.writeShort(field_1_password);
     }
@@ -84,7 +78,7 @@ public final class PasswordRecord extend
     }
 
     @Override
-    @SuppressWarnings("squid:S2975")
+    @SuppressWarnings({"squid:S2975", "MethodDoesntCallSuperMethod"})
     @Deprecated
     @Removal(version = "5.0.0")
     public PasswordRecord clone() {
@@ -97,4 +91,14 @@ public final class PasswordRecord extend
     public PasswordRecord copy() {
         return new PasswordRecord(this);
     }
+
+    @Override
+    public HSSFRecordTypes getGenericRecordType() {
+        return HSSFRecordTypes.PASSWORD;
+    }
+
+    @Override
+    public Map<String, Supplier<?>> getGenericProperties() {
+        return GenericRecordUtil.getGenericProperties("password", 
this::getPassword);
+    }
 }

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/PasswordRev4Record.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/PasswordRev4Record.java?rev=1876433&r1=1876432&r2=1876433&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/PasswordRev4Record.java 
(original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/PasswordRev4Record.java Sun 
Apr 12 22:03:52 2020
@@ -17,7 +17,10 @@
 
 package org.apache.poi.hssf.record;
 
-import org.apache.poi.util.HexDump;
+import java.util.Map;
+import java.util.function.Supplier;
+
+import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.LittleEndianOutput;
 
 /**
@@ -50,15 +53,6 @@ public final class PasswordRev4Record ex
         field_1_password = pw;
     }
 
-    public String toString() {
-        StringBuilder buffer = new StringBuilder();
-
-        buffer.append("[PROT4REVPASSWORD]\n");
-        buffer.append("    .password = 
").append(HexDump.shortToHex(field_1_password)).append("\n");
-        buffer.append("[/PROT4REVPASSWORD]\n");
-        return buffer.toString();
-    }
-
     public void serialize(LittleEndianOutput out) {
         out.writeShort(field_1_password);
     }
@@ -75,4 +69,14 @@ public final class PasswordRev4Record ex
     public PasswordRev4Record copy() {
         return new PasswordRev4Record(this);
     }
+
+    @Override
+    public HSSFRecordTypes getGenericRecordType() {
+        return HSSFRecordTypes.PASSWORD_REV_4;
+    }
+
+    @Override
+    public Map<String, Supplier<?>> getGenericProperties() {
+        return GenericRecordUtil.getGenericProperties("password", () -> 
field_1_password);
+    }
 }

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/PrecisionRecord.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/PrecisionRecord.java?rev=1876433&r1=1876432&r2=1876433&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/PrecisionRecord.java 
(original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/PrecisionRecord.java Sun Apr 
12 22:03:52 2020
@@ -17,6 +17,10 @@
 ==================================================================== */
 package org.apache.poi.hssf.record;
 
+import java.util.Map;
+import java.util.function.Supplier;
+
+import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.LittleEndianOutput;
 
 /**
@@ -60,13 +64,6 @@ public final class PrecisionRecord exten
         return (field_1_precision == 1);
     }
 
-    public String toString() {
-        return "[PRECISION]\n" +
-                "    .precision       = " + getFullPrecision() +
-                "\n" +
-                "[/PRECISION]\n";
-    }
-
     public void serialize(LittleEndianOutput out) {
         out.writeShort(field_1_precision);
     }
@@ -84,4 +81,14 @@ public final class PrecisionRecord exten
     public PrecisionRecord copy() {
         return new PrecisionRecord(this);
     }
+
+    @Override
+    public HSSFRecordTypes getGenericRecordType() {
+        return HSSFRecordTypes.PRECISION;
+    }
+
+    @Override
+    public Map<String, Supplier<?>> getGenericProperties() {
+        return GenericRecordUtil.getGenericProperties("precision", 
this::getFullPrecision);
+    }
 }

Modified: 
poi/trunk/src/java/org/apache/poi/hssf/record/PrintGridlinesRecord.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/PrintGridlinesRecord.java?rev=1876433&r1=1876432&r2=1876433&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/PrintGridlinesRecord.java 
(original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/PrintGridlinesRecord.java Sun 
Apr 12 22:03:52 2020
@@ -16,6 +16,10 @@
 ==================================================================== */
 package org.apache.poi.hssf.record;
 
+import java.util.Map;
+import java.util.function.Supplier;
+
+import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.LittleEndianOutput;
 import org.apache.poi.util.Removal;
 
@@ -58,13 +62,6 @@ public final class PrintGridlinesRecord
         return (field_1_print_gridlines == 1);
     }
 
-    public String toString() {
-        return "[PRINTGRIDLINES]\n" +
-                "    .printgridlines = " + getPrintGridlines() +
-                "\n" +
-                "[/PRINTGRIDLINES]\n";
-    }
-
     public void serialize(LittleEndianOutput out) {
         out.writeShort(field_1_print_gridlines);
     }
@@ -79,7 +76,7 @@ public final class PrintGridlinesRecord
     }
 
     @Override
-    @SuppressWarnings("squid:S2975")
+    @SuppressWarnings({"squid:S2975", "MethodDoesntCallSuperMethod"})
     @Deprecated
     @Removal(version = "5.0.0")
     public PrintGridlinesRecord clone() {
@@ -87,6 +84,16 @@ public final class PrintGridlinesRecord
     }
 
     public PrintGridlinesRecord copy() {
-      return new PrintGridlinesRecord(this);
+        return new PrintGridlinesRecord(this);
+    }
+
+    @Override
+    public HSSFRecordTypes getGenericRecordType() {
+        return HSSFRecordTypes.PRINT_GRIDLINES;
+    }
+
+    @Override
+    public Map<String, Supplier<?>> getGenericProperties() {
+        return GenericRecordUtil.getGenericProperties("printGridlines", 
this::getPrintGridlines);
     }
 }

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/PrintHeadersRecord.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/PrintHeadersRecord.java?rev=1876433&r1=1876432&r2=1876433&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/PrintHeadersRecord.java 
(original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/PrintHeadersRecord.java Sun 
Apr 12 22:03:52 2020
@@ -17,6 +17,10 @@
 ==================================================================== */
 package org.apache.poi.hssf.record;
 
+import java.util.Map;
+import java.util.function.Supplier;
+
+import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.LittleEndianOutput;
 import org.apache.poi.util.Removal;
 
@@ -62,13 +66,6 @@ public final class PrintHeadersRecord ex
         return (field_1_print_headers == 1);
     }
 
-    public String toString() {
-        return "[PRINTHEADERS]\n" +
-                "    .printheaders   = " + getPrintHeaders() +
-                "\n" +
-                "[/PRINTHEADERS]\n";
-    }
-
     public void serialize(LittleEndianOutput out) {
         out.writeShort(field_1_print_headers);
     }
@@ -83,7 +80,7 @@ public final class PrintHeadersRecord ex
     }
 
     @Override
-    @SuppressWarnings("squid:S2975")
+    @SuppressWarnings({"squid:S2975", "MethodDoesntCallSuperMethod"})
     @Deprecated
     @Removal(version = "5.0.0")
     public PrintHeadersRecord clone() {
@@ -93,4 +90,14 @@ public final class PrintHeadersRecord ex
     public PrintHeadersRecord copy() {
       return new PrintHeadersRecord(this);
     }
+
+    @Override
+    public HSSFRecordTypes getGenericRecordType() {
+        return HSSFRecordTypes.PRINT_HEADERS;
+    }
+
+    @Override
+    public Map<String, Supplier<?>> getGenericProperties() {
+        return GenericRecordUtil.getGenericProperties("printHeaders", 
this::getPrintHeaders);
+    }
 }

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/PrintSetupRecord.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/PrintSetupRecord.java?rev=1876433&r1=1876432&r2=1876433&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/PrintSetupRecord.java 
(original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/PrintSetupRecord.java Sun Apr 
12 22:03:52 2020
@@ -17,6 +17,13 @@
 
 package org.apache.poi.hssf.record;
 
+import static org.apache.poi.util.GenericRecordUtil.getBitsAsString;
+
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.function.Supplier;
+
 import org.apache.poi.ss.usermodel.PrintSetup;
 import org.apache.poi.util.BitField;
 import org.apache.poi.util.BitFieldFactory;
@@ -286,53 +293,6 @@ public final class PrintSetupRecord exte
         return field_11_copies;
     }
 
-    public String toString()
-    {
-        StringBuilder buffer = new StringBuilder();
-
-        buffer.append("[PRINTSETUP]\n");
-        buffer.append("    .papersize      = ").append(getPaperSize())
-            .append("\n");
-        buffer.append("    .scale          = ").append(getScale())
-            .append("\n");
-        buffer.append("    .pagestart      = ").append(getPageStart())
-            .append("\n");
-        buffer.append("    .fitwidth       = ").append(getFitWidth())
-            .append("\n");
-        buffer.append("    .fitheight      = ").append(getFitHeight())
-            .append("\n");
-        buffer.append("    .options        = ").append(getOptions())
-            .append("\n");
-        buffer.append("        .ltor       = ").append(getLeftToRight())
-            .append("\n");
-        buffer.append("        .landscape  = ").append(getLandscape())
-            .append("\n");
-        buffer.append("        .valid      = ").append(getValidSettings())
-            .append("\n");
-        buffer.append("        .mono       = ").append(getNoColor())
-            .append("\n");
-        buffer.append("        .draft      = ").append(getDraft())
-            .append("\n");
-        buffer.append("        .notes      = ").append(getNotes())
-            .append("\n");
-        buffer.append("        .noOrientat = ").append(getNoOrientation())
-            .append("\n");
-        buffer.append("        .usepage    = ").append(getUsePage())
-            .append("\n");
-        buffer.append("    .hresolution    = ").append(getHResolution())
-            .append("\n");
-        buffer.append("    .vresolution    = ").append(getVResolution())
-            .append("\n");
-        buffer.append("    .headermargin   = ").append(getHeaderMargin())
-            .append("\n");
-        buffer.append("    .footermargin   = ").append(getFooterMargin())
-            .append("\n");
-        buffer.append("    .copies         = ").append(getCopies())
-            .append("\n");
-        buffer.append("[/PRINTSETUP]\n");
-        return buffer.toString();
-    }
-
     public void serialize(LittleEndianOutput out) {
         out.writeShort(getPaperSize());
         out.writeShort(getScale());
@@ -357,7 +317,7 @@ public final class PrintSetupRecord exte
     }
 
     @Override
-    @SuppressWarnings("squid:S2975")
+    @SuppressWarnings({"squid:S2975", "MethodDoesntCallSuperMethod"})
     @Deprecated
     @Removal(version = "5.0.0")
     public PrintSetupRecord clone() {
@@ -368,4 +328,28 @@ public final class PrintSetupRecord exte
     public PrintSetupRecord copy() {
       return new PrintSetupRecord(this);
     }
+
+    @Override
+    public HSSFRecordTypes getGenericRecordType() {
+        return HSSFRecordTypes.PRINT_SETUP;
+    }
+
+    @Override
+    public Map<String, Supplier<?>> getGenericProperties() {
+        final Map<String,Supplier<?>> m = new LinkedHashMap<>();
+        m.put("paperSize", this::getPaperSize);
+        m.put("scale", this::getScale);
+        m.put("pageStart",this::getPageStart);
+        m.put("fitWidth", this::getFitWidth);
+        m.put("fitHeight", this::getFitHeight);
+        m.put("options", getBitsAsString(this::getOptions,
+             new BitField[]{lefttoright, landscape, validsettings, nocolor, 
draft, notes, noOrientation, usepage},
+             new 
String[]{"lefttoright","landscape","validsettings","nocolor","draft","notes","noOrientation","usepage"}));
+        m.put("hResolution", this::getHResolution);
+        m.put("vResolution", this::getVResolution);
+        m.put("headerMargin", this::getHeaderMargin);
+        m.put("footerMargin", this::getFooterMargin);
+        m.put("copies", this::getCopies);
+        return Collections.unmodifiableMap(m);
+    }
 }

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/ProtectRecord.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/ProtectRecord.java?rev=1876433&r1=1876432&r2=1876433&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/ProtectRecord.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/ProtectRecord.java Sun Apr 12 
22:03:52 2020
@@ -17,9 +17,12 @@
 
 package org.apache.poi.hssf.record;
 
+import java.util.Map;
+import java.util.function.Supplier;
+
 import org.apache.poi.util.BitField;
 import org.apache.poi.util.BitFieldFactory;
-import org.apache.poi.util.HexDump;
+import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.LittleEndianOutput;
 import org.apache.poi.util.Removal;
 
@@ -69,15 +72,6 @@ public final class ProtectRecord extends
         return protectFlag.isSet(_options);
     }
 
-    public String toString() {
-        StringBuilder buffer = new StringBuilder();
-
-        buffer.append("[PROTECT]\n");
-        buffer.append("    .options = 
").append(HexDump.shortToHex(_options)).append("\n");
-        buffer.append("[/PROTECT]\n");
-        return buffer.toString();
-    }
-
     public void serialize(LittleEndianOutput out) {
         out.writeShort(_options);
     }
@@ -91,7 +85,7 @@ public final class ProtectRecord extends
     }
 
     @Override
-    @SuppressWarnings("squid:S2975")
+    @SuppressWarnings({"squid:S2975", "MethodDoesntCallSuperMethod"})
     @Deprecated
     @Removal(version = "5.0.0")
     public ProtectRecord clone() {
@@ -102,4 +96,17 @@ public final class ProtectRecord extends
     public ProtectRecord copy() {
         return new ProtectRecord(this);
     }
+
+    @Override
+    public HSSFRecordTypes getGenericRecordType() {
+        return HSSFRecordTypes.PROTECT;
+    }
+
+    @Override
+    public Map<String, Supplier<?>> getGenericProperties() {
+        return GenericRecordUtil.getGenericProperties(
+            "options", () -> _options,
+            "protect", this::getProtect
+        );
+    }
 }

Modified: 
poi/trunk/src/java/org/apache/poi/hssf/record/ProtectionRev4Record.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/ProtectionRev4Record.java?rev=1876433&r1=1876432&r2=1876433&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/ProtectionRev4Record.java 
(original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/ProtectionRev4Record.java Sun 
Apr 12 22:03:52 2020
@@ -17,9 +17,12 @@
 
 package org.apache.poi.hssf.record;
 
+import java.util.Map;
+import java.util.function.Supplier;
+
 import org.apache.poi.util.BitField;
 import org.apache.poi.util.BitFieldFactory;
-import org.apache.poi.util.HexDump;
+import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.LittleEndianOutput;
 
 /**
@@ -66,15 +69,6 @@ public final class ProtectionRev4Record
         return protectedFlag.isSet(_options);
     }
 
-    public String toString() {
-        StringBuilder buffer = new StringBuilder();
-
-        buffer.append("[PROT4REV]\n");
-        buffer.append("    .options = 
").append(HexDump.shortToHex(_options)).append("\n");
-        buffer.append("[/PROT4REV]\n");
-        return buffer.toString();
-    }
-
     public void serialize(LittleEndianOutput out) {
         out.writeShort(_options);
     }
@@ -91,4 +85,18 @@ public final class ProtectionRev4Record
     public ProtectionRev4Record copy() {
         return new ProtectionRev4Record(this);
     }
+
+
+    @Override
+    public HSSFRecordTypes getGenericRecordType() {
+        return HSSFRecordTypes.PROTECTION_REV_4;
+    }
+
+    @Override
+    public Map<String, Supplier<?>> getGenericProperties() {
+        return GenericRecordUtil.getGenericProperties(
+            "options", () -> _options,
+            "protect", this::getProtect
+        );
+    }
 }

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/RKRecord.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/RKRecord.java?rev=1876433&r1=1876432&r2=1876433&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/RKRecord.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/RKRecord.java Sun Apr 12 
22:03:52 2020
@@ -17,7 +17,11 @@
 
 package org.apache.poi.hssf.record;
 
+import java.util.Map;
+import java.util.function.Supplier;
+
 import org.apache.poi.hssf.util.RKUtil;
+import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.LittleEndianOutput;
 import org.apache.poi.util.Removal;
 
@@ -39,8 +43,6 @@ public final class RKRecord extends Cell
 
     private int field_4_rk_number;
 
-    private RKRecord() {}
-
     public RKRecord(RKRecord other) {
         super(other);
         field_4_rk_number = other.field_4_rk_number;
@@ -78,11 +80,6 @@ public final class RKRecord extends Cell
     }
 
     @Override
-    protected void appendValueText(StringBuilder sb) {
-       sb.append("  .value= ").append(getRKNumber());
-    }
-
-    @Override
     protected void serializeValue(LittleEndianOutput out) {
        out.writeInt(field_4_rk_number);
     }
@@ -98,7 +95,7 @@ public final class RKRecord extends Cell
     }
 
     @Override
-    @SuppressWarnings("squid:S2975")
+    @SuppressWarnings({"squid:S2975", "MethodDoesntCallSuperMethod"})
     @Deprecated
     @Removal(version = "5.0.0")
     public RKRecord clone() {
@@ -109,4 +106,17 @@ public final class RKRecord extends Cell
     public RKRecord copy() {
         return new RKRecord(this);
     }
+
+    @Override
+    public HSSFRecordTypes getGenericRecordType() {
+        return HSSFRecordTypes.RK;
+    }
+
+    @Override
+    public Map<String, Supplier<?>> getGenericProperties() {
+        return GenericRecordUtil.getGenericProperties(
+            "base", super::getGenericProperties,
+            "rkNumber", this::getRKNumber
+        );
+    }
 }

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/RecalcIdRecord.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/RecalcIdRecord.java?rev=1876433&r1=1876432&r2=1876433&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/RecalcIdRecord.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/RecalcIdRecord.java Sun Apr 
12 22:03:52 2020
@@ -17,7 +17,10 @@
 
 package org.apache.poi.hssf.record;
 
-import org.apache.poi.util.HexDump;
+import java.util.Map;
+import java.util.function.Supplier;
+
+import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.LittleEndianOutput;
 
 /**
@@ -70,16 +73,6 @@ public final class RecalcIdRecord extend
         return _engineId;
     }
 
-    public String toString() {
-        StringBuilder buffer = new StringBuilder();
-
-        buffer.append("[RECALCID]\n");
-        buffer.append("    .reserved = 
").append(HexDump.shortToHex(_reserved0)).append("\n");
-        buffer.append("    .engineId = 
").append(HexDump.intToHex(_engineId)).append("\n");
-        buffer.append("[/RECALCID]\n");
-        return buffer.toString();
-    }
-
     public void serialize(LittleEndianOutput out) {
         out.writeShort(sid); // always write 'rt' field as 0x01C1
         out.writeShort(_reserved0);
@@ -98,4 +91,17 @@ public final class RecalcIdRecord extend
     public RecalcIdRecord copy() {
         return new RecalcIdRecord(this);
     }
+
+    @Override
+    public HSSFRecordTypes getGenericRecordType() {
+        return HSSFRecordTypes.RECALC_ID;
+    }
+
+    @Override
+    public Map<String, Supplier<?>> getGenericProperties() {
+        return GenericRecordUtil.getGenericProperties(
+            "reserved0", () -> _reserved0,
+            "engineId", this::getEngineId
+        );
+    }
 }

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/Record.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/Record.java?rev=1876433&r1=1876432&r2=1876433&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/Record.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/Record.java Sun Apr 12 
22:03:52 2020
@@ -20,11 +20,13 @@ package org.apache.poi.hssf.record;
 import java.io.ByteArrayInputStream;
 
 import org.apache.poi.common.Duplicatable;
+import org.apache.poi.common.usermodel.GenericRecord;
+import org.apache.poi.util.GenericRecordJsonWriter;
 
 /**
  * All HSSF Records inherit from this class.
  */
-public abstract class Record extends RecordBase implements Duplicatable {
+public abstract class Record extends RecordBase implements Duplicatable, 
GenericRecord {
 
     protected Record() {}
 
@@ -48,8 +50,8 @@ public abstract class Record extends Rec
      * get a string representation of the record (for biffview/debugging)
      */
     @Override
-    public String toString() {
-        return super.toString();
+    public final String toString() {
+        return GenericRecordJsonWriter.marshal(this);
     }
 
     /**
@@ -85,4 +87,7 @@ public abstract class Record extends Rec
     }
 
     public abstract Record copy();
+
+    @Override
+    public abstract HSSFRecordTypes getGenericRecordType();
 }

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/RecordFactory.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/RecordFactory.java?rev=1876433&r1=1876432&r2=1876433&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/RecordFactory.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/RecordFactory.java Sun Apr 12 
22:03:52 2020
@@ -45,9 +45,9 @@ import org.apache.poi.hssf.record.chart.
 import org.apache.poi.hssf.record.chart.EndRecord;
 import org.apache.poi.hssf.record.chart.LegendRecord;
 import org.apache.poi.hssf.record.chart.LinkedDataRecord;
+import org.apache.poi.hssf.record.chart.SeriesChartGroupIndexRecord;
 import org.apache.poi.hssf.record.chart.SeriesRecord;
 import org.apache.poi.hssf.record.chart.SeriesTextRecord;
-import org.apache.poi.hssf.record.chart.SeriesToChartGroupRecord;
 import org.apache.poi.hssf.record.chart.ValueRangeRecord;
 import org.apache.poi.hssf.record.pivottable.DataItemRecord;
 import 
org.apache.poi.hssf.record.pivottable.ExtendedPivotTableViewFieldsRecord;
@@ -268,7 +268,7 @@ public final class RecordFactory {
         DataFormatRecord.class,
         EndRecord.class,
         LinkedDataRecord.class,
-        SeriesToChartGroupRecord.class,
+        SeriesChartGroupIndexRecord.class,
 
         // pivot table records
         DataItemRecord.class,

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/RefModeRecord.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/RefModeRecord.java?rev=1876433&r1=1876432&r2=1876433&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/RefModeRecord.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/RefModeRecord.java Sun Apr 12 
22:03:52 2020
@@ -19,6 +19,10 @@
 
 package org.apache.poi.hssf.record;
 
+import java.util.Map;
+import java.util.function.Supplier;
+
+import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.LittleEndianOutput;
 import org.apache.poi.util.Removal;
 
@@ -69,17 +73,6 @@ public final class RefModeRecord extends
         return field_1_mode;
     }
 
-    public String toString()
-    {
-        StringBuilder buffer = new StringBuilder();
-
-        buffer.append("[REFMODE]\n");
-        buffer.append("    .mode           = ")
-            .append(Integer.toHexString(getMode())).append("\n");
-        buffer.append("[/REFMODE]\n");
-        return buffer.toString();
-    }
-
     public void serialize(LittleEndianOutput out) {
         out.writeShort(getMode());
     }
@@ -94,7 +87,7 @@ public final class RefModeRecord extends
     }
 
     @Override
-    @SuppressWarnings("squid:S2975")
+    @SuppressWarnings({"squid:S2975", "MethodDoesntCallSuperMethod"})
     @Deprecated
     @Removal(version = "5.0.0")
     public RefModeRecord clone() {
@@ -103,6 +96,16 @@ public final class RefModeRecord extends
 
     @Override
     public RefModeRecord copy() {
-      return new RefModeRecord();
+        return new RefModeRecord();
+    }
+
+    @Override
+    public HSSFRecordTypes getGenericRecordType() {
+        return HSSFRecordTypes.REF_MODE;
+    }
+
+    @Override
+    public Map<String, Supplier<?>> getGenericProperties() {
+        return GenericRecordUtil.getGenericProperties("mode", this::getMode);
     }
 }

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/RefreshAllRecord.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/RefreshAllRecord.java?rev=1876433&r1=1876432&r2=1876433&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/RefreshAllRecord.java 
(original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/RefreshAllRecord.java Sun Apr 
12 22:03:52 2020
@@ -17,9 +17,12 @@
 
 package org.apache.poi.hssf.record;
 
+import java.util.Map;
+import java.util.function.Supplier;
+
 import org.apache.poi.util.BitField;
 import org.apache.poi.util.BitFieldFactory;
-import org.apache.poi.util.HexDump;
+import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.LittleEndianOutput;
 import org.apache.poi.util.Removal;
 
@@ -68,15 +71,6 @@ public final class RefreshAllRecord exte
         return refreshFlag.isSet(_options);
     }
 
-    public String toString() {
-        StringBuilder buffer = new StringBuilder();
-
-        buffer.append("[REFRESHALL]\n");
-        buffer.append("    .options      = 
").append(HexDump.shortToHex(_options)).append("\n");
-        buffer.append("[/REFRESHALL]\n");
-        return buffer.toString();
-    }
-
     public void serialize(LittleEndianOutput out) {
         out.writeShort(_options);
     }
@@ -90,7 +84,7 @@ public final class RefreshAllRecord exte
     }
 
     @Override
-    @SuppressWarnings("squid:S2975")
+    @SuppressWarnings({"squid:S2975", "MethodDoesntCallSuperMethod"})
     @Deprecated
     @Removal(version = "5.0.0")
     public RefreshAllRecord clone() {
@@ -101,4 +95,18 @@ public final class RefreshAllRecord exte
     public RefreshAllRecord copy() {
         return new RefreshAllRecord(this);
     }
+
+
+    @Override
+    public HSSFRecordTypes getGenericRecordType() {
+        return HSSFRecordTypes.REFRESH_ALL;
+    }
+
+    @Override
+    public Map<String, Supplier<?>> getGenericProperties() {
+        return GenericRecordUtil.getGenericProperties(
+            "options", () -> _options,
+            "refreshAll", this::getRefreshAll
+        );
+    }
 }

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/RightMarginRecord.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/RightMarginRecord.java?rev=1876433&r1=1876432&r2=1876433&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/RightMarginRecord.java 
(original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/RightMarginRecord.java Sun 
Apr 12 22:03:52 2020
@@ -17,6 +17,10 @@
 
 package org.apache.poi.hssf.record;
 
+import java.util.Map;
+import java.util.function.Supplier;
+
+import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.LittleEndianOutput;
 import org.apache.poi.util.Removal;
 
@@ -38,15 +42,6 @@ public final class RightMarginRecord ext
         field_1_margin = in.readDouble();
     }
 
-    public String toString()
-    {
-        StringBuilder buffer = new StringBuilder();
-        buffer.append( "[RightMargin]\n" );
-        buffer.append( "    .margin               = " ).append( " (" ).append( 
getMargin() ).append( " )\n" );
-        buffer.append( "[/RightMargin]\n" );
-        return buffer.toString();
-    }
-
     public void serialize(LittleEndianOutput out) {
         out.writeDouble(field_1_margin);
     }
@@ -69,7 +64,7 @@ public final class RightMarginRecord ext
     {        this.field_1_margin = field_1_margin;    }
 
     @Override
-    @SuppressWarnings("squid:S2975")
+    @SuppressWarnings({"squid:S2975", "MethodDoesntCallSuperMethod"})
     @Deprecated
     @Removal(version = "5.0.0")
     public RightMarginRecord clone() {
@@ -79,4 +74,14 @@ public final class RightMarginRecord ext
     public RightMarginRecord copy() {
         return new RightMarginRecord(this);
     }
+
+    @Override
+    public HSSFRecordTypes getGenericRecordType() {
+        return HSSFRecordTypes.RIGHT_MARGIN;
+    }
+
+    @Override
+    public Map<String, Supplier<?>> getGenericProperties() {
+        return GenericRecordUtil.getGenericProperties("margin", 
this::getMargin);
+    }
 }
\ No newline at end of file

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/RowRecord.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/RowRecord.java?rev=1876433&r1=1876432&r2=1876433&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/RowRecord.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/RowRecord.java Sun Apr 12 
22:03:52 2020
@@ -17,9 +17,15 @@
 
 package org.apache.poi.hssf.record;
 
+import static org.apache.poi.util.GenericRecordUtil.getBitsAsString;
+
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.function.Supplier;
+
 import org.apache.poi.util.BitField;
 import org.apache.poi.util.BitFieldFactory;
-import org.apache.poi.util.HexDump;
 import org.apache.poi.util.LittleEndianOutput;
 import org.apache.poi.util.Removal;
 
@@ -378,32 +384,6 @@ public final class RowRecord extends Sta
        return phoeneticGuide.isSet(field_8_option_flags);
     }
 
-    public String toString() {
-        StringBuilder sb = new StringBuilder();
-
-        sb.append("[ROW]\n");
-        sb.append("    .rownumber      = 
").append(Integer.toHexString(getRowNumber()))
-                .append("\n");
-        sb.append("    .firstcol       = 
").append(HexDump.shortToHex(getFirstCol())).append("\n");
-        sb.append("    .lastcol        = 
").append(HexDump.shortToHex(getLastCol())).append("\n");
-        sb.append("    .height         = 
").append(HexDump.shortToHex(getHeight())).append("\n");
-        sb.append("    .optimize       = 
").append(HexDump.shortToHex(getOptimize())).append("\n");
-        sb.append("    .reserved       = 
").append(HexDump.shortToHex(field_6_reserved)).append("\n");
-        sb.append("    .optionflags    = 
").append(HexDump.shortToHex(getOptionFlags())).append("\n");
-        sb.append("        .outlinelvl = 
").append(Integer.toHexString(getOutlineLevel())).append("\n");
-        sb.append("        .colapsed   = ").append(getColapsed()).append("\n");
-        sb.append("        .zeroheight = 
").append(getZeroHeight()).append("\n");
-        sb.append("        .badfontheig= 
").append(getBadFontHeight()).append("\n");
-        sb.append("        .formatted  = 
").append(getFormatted()).append("\n");
-        sb.append("    .optionsflags2  = 
").append(HexDump.shortToHex(getOptionFlags2())).append("\n");
-        sb.append("        .xfindex       = 
").append(Integer.toHexString(getXFIndex())).append("\n");
-        sb.append("        .topBorder     = 
").append(getTopBorder()).append("\n");
-        sb.append("        .bottomBorder  = 
").append(getBottomBorder()).append("\n");
-        sb.append("        .phoeneticGuide= 
").append(getPhoeneticGuide()).append("\n");
-        sb.append("[/ROW]\n");
-        return sb.toString();
-    }
-
     public void serialize(LittleEndianOutput out) {
         out.writeShort(getRowNumber());
         out.writeShort(getFirstCol() == -1 ? (short)0 : getFirstCol());
@@ -424,7 +404,7 @@ public final class RowRecord extends Sta
     }
 
     @Override
-    @SuppressWarnings("squid:S2975")
+    @SuppressWarnings({"squid:S2975", "MethodDoesntCallSuperMethod"})
     @Deprecated
     @Removal(version = "5.0.0")
     public RowRecord clone() {
@@ -435,4 +415,29 @@ public final class RowRecord extends Sta
     public RowRecord copy() {
       return new RowRecord(this);
     }
+
+    @Override
+    public HSSFRecordTypes getGenericRecordType() {
+        return HSSFRecordTypes.ROW;
+    }
+
+    @Override
+    public Map<String, Supplier<?>> getGenericProperties() {
+        final Map<String,Supplier<?>> m = new LinkedHashMap<>();
+        m.put("rowNumber", this::getRowNumber);
+        m.put("firstCol", this::getFirstCol);
+        m.put("lastCol", this::getLastCol);
+        m.put("height", this::getHeight);
+        m.put("optimized", this::getOptimize);
+        m.put("reserved", () -> field_6_reserved);
+        m.put("options", getBitsAsString(this::getOptionFlags,
+            new BitField[]{colapsed,zeroHeight,badFontHeight,formatted},
+            new 
String[]{"COLAPSED","ZERO_HEIGHT","BAD_FONT_HEIGHT","FORMATTED"}));
+        m.put("outlineLevel", this::getOutlineLevel);
+        m.put("optionFlags2", getBitsAsString(this::getOptionFlags2,
+            new BitField[]{topBorder, bottomBorder, phoeneticGuide},
+            new String[]{"TOP_BORDER","BOTTOM_BORDER","PHOENETIC_GUIDE"}));
+        m.put("xfIndex", this::getXFIndex);
+        return Collections.unmodifiableMap(m);
+    }
 }

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/SCLRecord.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/SCLRecord.java?rev=1876433&r1=1876432&r2=1876433&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/SCLRecord.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/SCLRecord.java Sun Apr 12 
22:03:52 2020
@@ -17,7 +17,10 @@
 
 package org.apache.poi.hssf.record;
 
-import org.apache.poi.util.HexDump;
+import java.util.Map;
+import java.util.function.Supplier;
+
+import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.LittleEndianOutput;
 import org.apache.poi.util.Removal;
 
@@ -45,25 +48,6 @@ public final class SCLRecord extends Sta
     }
 
     @Override
-    public String toString()
-    {
-        StringBuilder buffer = new StringBuilder();
-
-        buffer.append("[SCL]\n");
-        buffer.append("    .numerator            = ")
-            .append("0x").append(HexDump.toHex(  getNumerator ()))
-            .append(" (").append( getNumerator() ).append(" )");
-        buffer.append(System.getProperty("line.separator"));
-        buffer.append("    .denominator          = ")
-            .append("0x").append(HexDump.toHex(  getDenominator ()))
-            .append(" (").append( getDenominator() ).append(" )");
-        buffer.append(System.getProperty("line.separator"));
-
-        buffer.append("[/SCL]\n");
-        return buffer.toString();
-    }
-
-    @Override
     public void serialize(LittleEndianOutput out) {
         out.writeShort(field_1_numerator);
         out.writeShort(field_2_denominator);
@@ -81,7 +65,7 @@ public final class SCLRecord extends Sta
     }
 
     @Override
-    @SuppressWarnings("squid:S2975")
+    @SuppressWarnings({"squid:S2975", "MethodDoesntCallSuperMethod"})
     @Deprecated
     @Removal(version = "5.0.0")
     public SCLRecord clone() {
@@ -132,4 +116,17 @@ public final class SCLRecord extends Sta
     {
         this.field_2_denominator = field_2_denominator;
     }
+
+    @Override
+    public HSSFRecordTypes getGenericRecordType() {
+        return HSSFRecordTypes.SCL;
+    }
+
+    @Override
+    public Map<String, Supplier<?>> getGenericProperties() {
+        return GenericRecordUtil.getGenericProperties(
+            "numerator", this::getNumerator,
+            "denominator", this::getDenominator
+        );
+    }
 }

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/SSTRecord.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/SSTRecord.java?rev=1876433&r1=1876432&r2=1876433&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/SSTRecord.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/SSTRecord.java Sun Apr 12 
22:03:52 2020
@@ -18,10 +18,13 @@
 package org.apache.poi.hssf.record;
 
 import java.util.Iterator;
+import java.util.Map;
+import java.util.function.Supplier;
 
 import org.apache.poi.hssf.record.common.UnicodeString;
 import org.apache.poi.hssf.record.cont.ContinuableRecord;
 import org.apache.poi.hssf.record.cont.ContinuableRecordOutput;
+import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.IntMapper;
 
 /**
@@ -127,35 +130,10 @@ public final class SSTRecord extends Con
      *
      * @return the desired string
      */
-    public UnicodeString getString(int id )
-    {
+    public UnicodeString getString(int id ) {
         return field_3_strings.get( id );
     }
 
-
-    /**
-     * Return a debugging string representation
-     *
-     * @return string representation
-     */
-    public String toString() {
-        StringBuilder buffer = new StringBuilder();
-
-        buffer.append( "[SST]\n" );
-        buffer.append( "    .numstrings     = " )
-                .append( Integer.toHexString( getNumStrings() ) ).append( "\n" 
);
-        buffer.append( "    .uniquestrings  = " )
-                .append( Integer.toHexString( getNumUniqueStrings() ) 
).append( "\n" );
-        for ( int k = 0; k < field_3_strings.size(); k++ )
-        {
-          UnicodeString s = field_3_strings.get( k );
-            buffer.append("    .string_").append(k).append("      = ")
-                    .append( s.getDebugInfo() ).append( "\n" );
-        }
-        buffer.append( "[/SST]\n" );
-        return buffer.toString();
-    }
-
     public short getSid() {
         return sid;
     }
@@ -281,10 +259,6 @@ public final class SSTRecord extends Con
         bucketRelativeOffsets = serializer.getBucketRelativeOffsets();
     }
 
-    SSTDeserializer getDeserializer() {
-        return deserializer;
-    }
-
     /**
      * Creates an extended string record based on the current contents of
      * the current SST record.  The offset within the stream to the SST record
@@ -328,4 +302,20 @@ public final class SSTRecord extends Con
     public SSTRecord copy() {
         return new SSTRecord(this);
     }
+
+    @Override
+    public HSSFRecordTypes getGenericRecordType() {
+        return HSSFRecordTypes.SST;
+    }
+
+    @Override
+    public Map<String, Supplier<?>> getGenericProperties() {
+        return GenericRecordUtil.getGenericProperties(
+            "numStrings", this::getNumStrings,
+            "numUniqueStrings", this::getNumUniqueStrings,
+            "strings", () -> field_3_strings.getElements(),
+            "bucketAbsoluteOffsets", () -> bucketAbsoluteOffsets,
+            "bucketRelativeOffsets", () -> bucketRelativeOffsets
+        );
+    }
 }

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/SaveRecalcRecord.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/SaveRecalcRecord.java?rev=1876433&r1=1876432&r2=1876433&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/SaveRecalcRecord.java 
(original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/SaveRecalcRecord.java Sun Apr 
12 22:03:52 2020
@@ -17,6 +17,10 @@
 ==================================================================== */
 package org.apache.poi.hssf.record;
 
+import java.util.Map;
+import java.util.function.Supplier;
+
+import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.LittleEndianOutput;
 import org.apache.poi.util.Removal;
 
@@ -59,13 +63,6 @@ public final class SaveRecalcRecord exte
         return (field_1_recalc == 1);
     }
 
-    public String toString() {
-        return "[SAVERECALC]\n" +
-                "    .recalc         = " + getRecalc() +
-                "\n" +
-                "[/SAVERECALC]\n";
-    }
-
     public void serialize(LittleEndianOutput out) {
         out.writeShort(field_1_recalc);
     }
@@ -79,7 +76,7 @@ public final class SaveRecalcRecord exte
     }
 
     @Override
-    @SuppressWarnings("squid:S2975")
+    @SuppressWarnings({"squid:S2975", "MethodDoesntCallSuperMethod"})
     @Deprecated
     @Removal(version = "5.0.0")
     public SaveRecalcRecord clone() {
@@ -90,4 +87,14 @@ public final class SaveRecalcRecord exte
     public SaveRecalcRecord copy() {
         return new SaveRecalcRecord(this);
     }
+
+    @Override
+    public HSSFRecordTypes getGenericRecordType() {
+        return HSSFRecordTypes.SAVE_RECALC;
+    }
+
+    @Override
+    public Map<String, Supplier<?>> getGenericProperties() {
+        return GenericRecordUtil.getGenericProperties("recalc", 
this::getRecalc);
+    }
 }

Modified: 
poi/trunk/src/java/org/apache/poi/hssf/record/ScenarioProtectRecord.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/ScenarioProtectRecord.java?rev=1876433&r1=1876432&r2=1876433&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/ScenarioProtectRecord.java 
(original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/ScenarioProtectRecord.java 
Sun Apr 12 22:03:52 2020
@@ -19,6 +19,10 @@
 
 package org.apache.poi.hssf.record;
 
+import java.util.Map;
+import java.util.function.Supplier;
+
+import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.LittleEndianOutput;
 import org.apache.poi.util.Removal;
 
@@ -69,17 +73,6 @@ public final class ScenarioProtectRecord
         return (field_1_protect == 1);
     }
 
-    public String toString()
-    {
-        StringBuilder buffer = new StringBuilder();
-
-        buffer.append("[SCENARIOPROTECT]\n");
-           buffer.append("    .protect         = ").append(getProtect())
-            .append("\n");
-        buffer.append("[/SCENARIOPROTECT]\n");
-        return buffer.toString();
-    }
-
     public void serialize(LittleEndianOutput out) {
         out.writeShort(field_1_protect);
     }
@@ -94,7 +87,7 @@ public final class ScenarioProtectRecord
     }
 
     @Override
-    @SuppressWarnings("squid:S2975")
+    @SuppressWarnings({"squid:S2975", "MethodDoesntCallSuperMethod"})
     @Deprecated
     @Removal(version = "5.0.0")
     public ScenarioProtectRecord clone() {
@@ -104,4 +97,14 @@ public final class ScenarioProtectRecord
     public ScenarioProtectRecord copy() {
         return new ScenarioProtectRecord(this);
     }
+
+    @Override
+    public HSSFRecordTypes getGenericRecordType() {
+        return HSSFRecordTypes.SCENARIO_PROTECT;
+    }
+
+    @Override
+    public Map<String, Supplier<?>> getGenericProperties() {
+        return GenericRecordUtil.getGenericProperties("protect", 
this::getProtect);
+    }
 }

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/SelectionRecord.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/SelectionRecord.java?rev=1876433&r1=1876432&r2=1876433&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/SelectionRecord.java 
(original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/SelectionRecord.java Sun Apr 
12 22:03:52 2020
@@ -17,10 +17,12 @@
 
 package org.apache.poi.hssf.record;
 
+import java.util.Map;
+import java.util.function.Supplier;
 import java.util.stream.Stream;
 
 import org.apache.poi.hssf.util.CellRangeAddress8Bit;
-import org.apache.poi.util.HexDump;
+import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.LittleEndianOutput;
 import org.apache.poi.util.Removal;
 
@@ -149,17 +151,6 @@ public final class SelectionRecord exten
     }
 
     @Override
-    public String toString() {
-        return "[SELECTION]\n" +
-                "    .pane            = " + HexDump.byteToHex(getPane()) + 
"\n" +
-                "    .activecellrow   = " + 
HexDump.shortToHex(getActiveCellRow()) + "\n" +
-                "    .activecellcol   = " + 
HexDump.shortToHex(getActiveCellCol()) + "\n" +
-                "    .activecellref   = " + 
HexDump.shortToHex(getActiveCellRef()) + "\n" +
-                "    .numrefs         = " + 
HexDump.shortToHex(field_6_refs.length) + "\n" +
-                "[/SELECTION]\n";
-    }
-
-    @Override
     protected int getDataSize() {
         return 9 // 1 byte + 4 shorts
             + CellRangeAddress8Bit.getEncodedSize(field_6_refs.length);
@@ -183,7 +174,7 @@ public final class SelectionRecord exten
     }
 
     @Override
-    @SuppressWarnings("squid:S2975")
+    @SuppressWarnings({"squid:S2975", "MethodDoesntCallSuperMethod"})
     @Deprecated
     @Removal(version = "5.0.0")
     public SelectionRecord clone() {
@@ -194,4 +185,20 @@ public final class SelectionRecord exten
     public SelectionRecord copy() {
         return new SelectionRecord(this);
     }
+
+    @Override
+    public HSSFRecordTypes getGenericRecordType() {
+        return HSSFRecordTypes.SELECTION;
+    }
+
+    @Override
+    public Map<String, Supplier<?>> getGenericProperties() {
+        return GenericRecordUtil.getGenericProperties(
+            "pane", this::getPane,
+            "activeCellRow", this::getActiveCellRow,
+            "activeCellCol", this::getActiveCellCol,
+            "activeCellRef", this::getActiveCellRef,
+            "refs", () -> field_6_refs
+        );
+    }
 }

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/SharedFormulaRecord.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/SharedFormulaRecord.java?rev=1876433&r1=1876432&r2=1876433&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/SharedFormulaRecord.java 
(original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/SharedFormulaRecord.java Sun 
Apr 12 22:03:52 2020
@@ -17,12 +17,15 @@
 
 package org.apache.poi.hssf.record;
 
+import java.util.Map;
+import java.util.function.Supplier;
+
 import org.apache.poi.hssf.util.CellRangeAddress8Bit;
 import org.apache.poi.ss.SpreadsheetVersion;
 import org.apache.poi.ss.formula.Formula;
 import org.apache.poi.ss.formula.SharedFormula;
 import org.apache.poi.ss.formula.ptg.Ptg;
-import org.apache.poi.util.HexDump;
+import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.LittleEndianOutput;
 import org.apache.poi.util.Removal;
 
@@ -77,29 +80,6 @@ public final class SharedFormulaRecord e
         return 2 + field_7_parsed_expr.getEncodedSize();
     }
 
-    /**
-     * print a sort of string representation ([SHARED FORMULA RECORD] id = x 
[/SHARED FORMULA RECORD])
-     */
-
-    public String toString()
-    {
-        StringBuilder buffer = new StringBuilder();
-
-        buffer.append("[SHARED FORMULA 
(").append(HexDump.intToHex(sid)).append("]\n");
-        buffer.append("    .range      = ").append(getRange()).append("\n");
-        buffer.append("    .reserved    = 
").append(HexDump.shortToHex(field_5_reserved)).append("\n");
-
-        Ptg[] ptgs = field_7_parsed_expr.getTokens();
-        for (int k = 0; k < ptgs.length; k++ ) {
-           buffer.append("Formula[").append(k).append("]");
-           Ptg ptg = ptgs[k];
-           buffer.append(ptg).append(ptg.getRVAType()).append("\n");
-        }
-
-        buffer.append("[/SHARED FORMULA]\n");
-        return buffer.toString();
-    }
-
     public short getSid() {
         return sid;
     }
@@ -124,7 +104,7 @@ public final class SharedFormulaRecord e
     }
 
     @Override
-    @SuppressWarnings("squid:S2975")
+    @SuppressWarnings({"squid:S2975", "MethodDoesntCallSuperMethod"})
     @Deprecated
     @Removal(version = "5.0.0")
     public SharedFormulaRecord clone() {
@@ -138,4 +118,18 @@ public final class SharedFormulaRecord e
        public boolean isFormulaSame(SharedFormulaRecord other) {
                return field_7_parsed_expr.isSame(other.field_7_parsed_expr);
        }
+
+    @Override
+    public HSSFRecordTypes getGenericRecordType() {
+        return HSSFRecordTypes.SHARED_FORMULA;
+    }
+
+    @Override
+    public Map<String, Supplier<?>> getGenericProperties() {
+        return GenericRecordUtil.getGenericProperties(
+            "range", this::getRange,
+            "reserved", () -> field_5_reserved,
+            "formula", () -> field_7_parsed_expr
+        );
+    }
 }

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/StringRecord.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/StringRecord.java?rev=1876433&r1=1876432&r2=1876433&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/StringRecord.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/StringRecord.java Sun Apr 12 
22:03:52 2020
@@ -17,8 +17,12 @@
 
 package org.apache.poi.hssf.record;
 
+import java.util.Map;
+import java.util.function.Supplier;
+
 import org.apache.poi.hssf.record.cont.ContinuableRecord;
 import org.apache.poi.hssf.record.cont.ContinuableRecordOutput;
+import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.Removal;
 import org.apache.poi.util.StringUtil;
 
@@ -82,14 +86,8 @@ public final class StringRecord extends
         _is16bitUnicode = StringUtil.hasMultibyte(string);
     }
 
-    public String toString() {
-        return "[STRING]\n" +
-                "    .string            = " + _text + "\n" +
-                "[/STRING]\n";
-    }
-
     @Override
-    @SuppressWarnings("squid:S2975")
+    @SuppressWarnings({"squid:S2975", "MethodDoesntCallSuperMethod"})
     @Deprecated
     @Removal(version = "5.0.0")
     public StringRecord clone() {
@@ -99,4 +97,17 @@ public final class StringRecord extends
     public StringRecord copy() {
         return new StringRecord(this);
     }
+
+    @Override
+    public HSSFRecordTypes getGenericRecordType() {
+        return HSSFRecordTypes.STRING;
+    }
+
+    @Override
+    public Map<String, Supplier<?>> getGenericProperties() {
+        return GenericRecordUtil.getGenericProperties(
+            "is16bitUnicode", () -> _is16bitUnicode,
+            "text", this::getString
+        );
+    }
 }

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/StyleRecord.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/StyleRecord.java?rev=1876433&r1=1876432&r2=1876433&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/StyleRecord.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/StyleRecord.java Sun Apr 12 
22:03:52 2020
@@ -17,9 +17,12 @@
 
 package org.apache.poi.hssf.record;
 
+import java.util.Map;
+import java.util.function.Supplier;
+
 import org.apache.poi.util.BitField;
 import org.apache.poi.util.BitFieldFactory;
-import org.apache.poi.util.HexDump;
+import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.LittleEndianOutput;
 import org.apache.poi.util.RecordFormatException;
 import org.apache.poi.util.StringUtil;
@@ -147,25 +150,6 @@ public final class StyleRecord extends S
        }
 
        @Override
-       public String toString() {
-               StringBuilder sb = new StringBuilder();
-
-               sb.append("[STYLE]\n");
-               sb.append("    .xf_index_raw 
=").append(HexDump.shortToHex(field_1_xf_index)).append("\n");
-               sb.append("        .type     =").append(isBuiltin() ? 
"built-in" : "user-defined").append("\n");
-               sb.append("        .xf_index 
=").append(HexDump.shortToHex(getXFIndex())).append("\n");
-               if (isBuiltin()){
-                       sb.append("    
.builtin_style=").append(HexDump.byteToHex(field_2_builtin_style)).append("\n");
-                       sb.append("    
.outline_level=").append(HexDump.byteToHex(field_3_outline_style_level)).append("\n");
-               } else {
-                        sb.append("    .name        
=").append(getName()).append("\n");
-               }
-               sb.append("[/STYLE]\n");
-               return sb.toString();
-       }
-
-
-       @Override
        protected int getDataSize() {
                if (isBuiltin()) {
                        return 4; // short, byte, byte
@@ -201,4 +185,20 @@ public final class StyleRecord extends S
        public StyleRecord copy() {
                return new StyleRecord(this);
        }
+
+       @Override
+       public HSSFRecordTypes getGenericRecordType() {
+               return HSSFRecordTypes.STYLE;
+       }
+
+       @Override
+       public Map<String, Supplier<?>> getGenericProperties() {
+               return GenericRecordUtil.getGenericProperties(
+                       "xfIndex", this::getXFIndex,
+                       "type", () -> isBuiltin() ? "built-in" : "user-defined",
+                       "builtin_style", () -> field_2_builtin_style,
+                       "outline_level", () -> field_3_outline_style_level,
+                       "name", this::getName
+               );
+       }
 }

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/SubRecord.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/SubRecord.java?rev=1876433&r1=1876432&r2=1876433&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/SubRecord.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/SubRecord.java Sun Apr 12 
22:03:52 2020
@@ -18,9 +18,14 @@
 package org.apache.poi.hssf.record;
 
 import java.io.ByteArrayOutputStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Supplier;
 
 import org.apache.poi.common.Duplicatable;
-import org.apache.poi.util.HexDump;
+import org.apache.poi.common.usermodel.GenericRecord;
+import org.apache.poi.util.GenericRecordJsonWriter;
+import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.LittleEndianInput;
 import org.apache.poi.util.LittleEndianOutput;
@@ -30,7 +35,59 @@ import org.apache.poi.util.Removal;
 /**
  * Subrecords are part of the OBJ class.
  */
-public abstract class SubRecord implements Duplicatable {
+public abstract class SubRecord implements Duplicatable, GenericRecord {
+
+       public enum SubRecordTypes {
+               UNKNOWN(-1, UnknownSubRecord::new),
+               END(0x0000, EndSubRecord::new),
+               GROUP_MARKER(0x0006, GroupMarkerSubRecord::new),
+               FT_CF(0x0007, FtCfSubRecord::new),
+               FT_PIO_GRBIT(0x0008, FtPioGrbitSubRecord::new),
+               EMBEDDED_OBJECT_REF(0x0009, EmbeddedObjectRefSubRecord::new),
+               FT_CBLS(0x000C, FtCblsSubRecord::new),
+               NOTE_STRUCTURE(0x000D, NoteStructureSubRecord::new),
+               LBS_DATA(0x0013, LbsDataSubRecord::new),
+               COMMON_OBJECT_DATA(0x0015, CommonObjectDataSubRecord::new),
+               ;
+
+
+
+               @FunctionalInterface
+               public interface RecordConstructor<T extends SubRecord> {
+                       /**
+                        * read a sub-record from the supplied stream
+                        *
+                        * @param in    the stream to read from
+                        * @param cmoOt the objectType field of the containing 
CommonObjectDataSubRecord,
+                        *   we need it to propagate to next sub-records as it 
defines what data follows
+                        * @return the created sub-record
+                        */
+                       T apply(LittleEndianInput in, int size, int cmoOt);
+               }
+
+               private static final Map<Short,SubRecordTypes> LOOKUP;
+
+               static {
+                       LOOKUP = new HashMap<>();
+                       for(SubRecordTypes s : values()) {
+                               LOOKUP.put(s.sid, s);
+                       }
+               }
+
+               public final short sid;
+               public final RecordConstructor<?> recordConstructor;
+
+               SubRecordTypes(int sid, RecordConstructor<?> recordConstructor) 
{
+                       this.sid = (short)sid;
+                       this.recordConstructor = recordConstructor;
+               }
+
+               public static SubRecordTypes forTypeID(int typeID) {
+                       return LOOKUP.getOrDefault((short)typeID, UNKNOWN);
+               }
+
+       }
+
 
        //arbitrarily selected; may need to increase
        private static final int MAX_RECORD_LENGTH = 1_000_000;
@@ -74,6 +131,11 @@ public abstract class SubRecord implemen
                return new UnknownSubRecord(in, sid, secondUShort);
        }
 
+       @Override
+       public final String toString() {
+               return GenericRecordJsonWriter.marshal(this);
+       }
+
        /**
         * @return the size of the data for this record (which is always 4 
bytes less than the total
         * record size).  Note however, that ushort encoded after the record 
sid is usually but not
@@ -139,15 +201,18 @@ public abstract class SubRecord implemen
                public UnknownSubRecord copy() {
                        return this;
                }
+
                @Override
-               public String toString() {
-                       StringBuilder sb = new StringBuilder(64);
-                       sb.append(getClass().getName()).append(" [");
-                       sb.append("sid=").append(HexDump.shortToHex(_sid));
-                       sb.append(" size=").append(_data.length);
-                       sb.append(" : ").append(HexDump.toHex(_data));
-                       sb.append("]\n");
-                       return sb.toString();
+               public SubRecordTypes getGenericRecordType() {
+                       return SubRecordTypes.UNKNOWN;
+               }
+
+               @Override
+               public Map<String, Supplier<?>> getGenericProperties() {
+                       return GenericRecordUtil.getGenericProperties(
+                               "sid", () -> _sid,
+                               "data", () -> _data
+                       );
                }
        }
 
@@ -159,4 +224,7 @@ public abstract class SubRecord implemen
 
        @Override
        public abstract SubRecord copy();
+
+       @Override
+       public abstract SubRecordTypes getGenericRecordType();
 }

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/SupBookRecord.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/SupBookRecord.java?rev=1876433&r1=1876432&r2=1876433&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/SupBookRecord.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/SupBookRecord.java Sun Apr 12 
22:03:52 2020
@@ -17,6 +17,10 @@
 
 package org.apache.poi.hssf.record;
 
+import java.util.Map;
+import java.util.function.Supplier;
+
+import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.LittleEndianOutput;
 import org.apache.poi.util.POILogFactory;
 import org.apache.poi.util.POILogger;
@@ -137,27 +141,6 @@ public final class SupBookRecord extends
         }
      }
 
-    public String toString() {
-        StringBuilder sb = new StringBuilder();
-        sb.append("[SUPBOOK ");
-
-        if(isExternalReferences()) {
-            sb.append("External References]\n");
-            sb.append(" .url     = ").append(getURL()).append("\n");
-            sb.append(" .nSheets = 
").append(field_1_number_of_sheets).append("\n");
-            for (String sheetname : field_3_sheet_names) {
-                sb.append("    .name = ").append(sheetname).append("\n");
-            }
-            sb.append("[/SUPBOOK");
-        } else if(_isAddInFunctions) {
-            sb.append("Add-In Functions");
-        } else {
-            sb.append("Internal References");
-            sb.append(" nSheets=").append(field_1_number_of_sheets);
-        }
-        sb.append("]");
-        return sb.toString();
-    }
     protected int getDataSize() {
         if(!isExternalReferences()) {
             return SMALL_RECORD_SIZE;
@@ -202,7 +185,7 @@ public final class SupBookRecord extends
     }
     public String getURL() {
         String encodedUrl = field_2_encoded_url;
-        switch(encodedUrl.charAt(0)) {
+        switch(encodedUrl == null ? -1 : encodedUrl.charAt(0)) {
             case 0: // Reference to an empty workbook name
                 return encodedUrl.substring(1); // will this just be empty 
string?
             case 1: // encoded file name
@@ -254,7 +237,7 @@ public final class SupBookRecord extends
         return sb.toString();
     }
     public String[] getSheetNames() {
-        return field_3_sheet_names.clone();
+        return field_3_sheet_names == null ? null : 
field_3_sheet_names.clone();
     }
 
     public void setURL(String pUrl) {
@@ -266,4 +249,21 @@ public final class SupBookRecord extends
     public SupBookRecord copy() {
         return new SupBookRecord(this);
     }
+
+    @Override
+    public HSSFRecordTypes getGenericRecordType() {
+        return HSSFRecordTypes.SUP_BOOK;
+    }
+
+    @Override
+    public Map<String, Supplier<?>> getGenericProperties() {
+        return GenericRecordUtil.getGenericProperties(
+            "externalReferences", this::isExternalReferences,
+            "internalReferences", this::isInternalReferences,
+            "url", this::getURL,
+            "numberOfSheets", this::getNumberOfSheets,
+            "sheetNames", this::getSheetNames,
+            "addInFunctions", this::isAddInFunctions
+        );
+    }
 }

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/TabIdRecord.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/TabIdRecord.java?rev=1876433&r1=1876432&r2=1876433&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/TabIdRecord.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/TabIdRecord.java Sun Apr 12 
22:03:52 2020
@@ -17,6 +17,10 @@
 
 package org.apache.poi.hssf.record;
 
+import java.util.Map;
+import java.util.function.Supplier;
+
+import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.LittleEndianOutput;
 
 /**
@@ -53,18 +57,6 @@ public final class TabIdRecord extends S
         _tabids = array.clone();
     }
 
-    public String toString() {
-        StringBuilder buffer = new StringBuilder();
-
-        buffer.append("[TABID]\n");
-        buffer.append("    .elements        = 
").append(_tabids.length).append("\n");
-        for (int i = 0; i < _tabids.length; i++) {
-            buffer.append("    .element_").append(i).append(" = 
").append(_tabids[i]).append("\n");
-        }
-        buffer.append("[/TABID]\n");
-        return buffer.toString();
-    }
-
     public void serialize(LittleEndianOutput out) {
         for (short tabid : _tabids) {
             out.writeShort(tabid);
@@ -83,4 +75,14 @@ public final class TabIdRecord extends S
     public TabIdRecord copy() {
         return new TabIdRecord(this);
     }
+
+    @Override
+    public HSSFRecordTypes getGenericRecordType() {
+        return HSSFRecordTypes.TAB_ID;
+    }
+
+    @Override
+    public Map<String, Supplier<?>> getGenericProperties() {
+        return GenericRecordUtil.getGenericProperties("elements", () -> 
_tabids);
+    }
 }

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/TableRecord.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/TableRecord.java?rev=1876433&r1=1876432&r2=1876433&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/TableRecord.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/TableRecord.java Sun Apr 12 
22:03:52 2020
@@ -17,12 +17,17 @@
 
 package org.apache.poi.hssf.record;
 
+import static org.apache.poi.util.GenericRecordUtil.getBitsAsString;
+
+import java.util.Map;
+import java.util.function.Supplier;
+
 import org.apache.poi.hssf.util.CellRangeAddress8Bit;
 import org.apache.poi.ss.formula.ptg.TblPtg;
 import org.apache.poi.ss.util.CellReference;
 import org.apache.poi.util.BitField;
 import org.apache.poi.util.BitFieldFactory;
-import org.apache.poi.util.HexDump;
+import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.LittleEndianOutput;
 /**
  * The record specifies a data table.<p>
@@ -160,21 +165,6 @@ public final class TableRecord extends S
                out.writeShort(field_10_colInputCol);
        }
 
-       public String toString() {
-               StringBuilder buffer = new StringBuilder();
-               buffer.append("[TABLE]\n");
-               buffer.append("    .range    = 
").append(getRange()).append("\n");
-               buffer.append("    .flags    = ") 
.append(HexDump.byteToHex(field_5_flags)).append("\n");
-               buffer.append("    .alwaysClc= 
").append(isAlwaysCalc()).append("\n");
-               buffer.append("    .reserved = 
").append(HexDump.intToHex(field_6_res)).append("\n");
-               CellReference crRowInput = cr(field_7_rowInputRow, 
field_8_colInputRow);
-               CellReference crColInput = cr(field_9_rowInputCol, 
field_10_colInputCol);
-               buffer.append("    .rowInput = 
").append(crRowInput.formatAsString()).append("\n");
-               buffer.append("    .colInput = 
").append(crColInput.formatAsString()).append("\n");
-               buffer.append("[/TABLE]\n");
-               return buffer.toString();
-       }
-
        @Override
        public TableRecord copy() {
                return new TableRecord(this);
@@ -186,4 +176,22 @@ public final class TableRecord extends S
                boolean isColAbs = (colIxAndFlags & 0x4000) == 0;
                return new CellReference(rowIx, colIx, isRowAbs, isColAbs);
        }
+
+       @Override
+       public HSSFRecordTypes getGenericRecordType() {
+               return HSSFRecordTypes.TABLE;
+       }
+
+       @Override
+       public Map<String, Supplier<?>> getGenericProperties() {
+               return GenericRecordUtil.getGenericProperties(
+                       "range", this::getRange,
+                       "flags", getBitsAsString(this::getFlags,
+                               new BitField[]{alwaysCalc, calcOnOpen, 
rowOrColInpCell, oneOrTwoVar, rowDeleted, colDeleted},
+                               new 
String[]{"ALWAYS_CALC","CALC_ON_OPEN","ROW_OR_COL_INP_CELL","ONE_OR_TWO_VAR","ROW_DELETED","COL_DELETED"}),
+                       "reserved", () -> field_6_res,
+                       "rowInput", () -> cr(field_7_rowInputRow, 
field_8_colInputRow),
+                       "colInput", () -> cr(field_9_rowInputCol, 
field_10_colInputCol)
+               );
+       }
 }

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/TableStylesRecord.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/TableStylesRecord.java?rev=1876433&r1=1876432&r2=1876433&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/TableStylesRecord.java 
(original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/TableStylesRecord.java Sun 
Apr 12 22:03:52 2020
@@ -17,7 +17,10 @@
 
 package org.apache.poi.hssf.record;
 
-import org.apache.poi.util.HexDump;
+import java.util.Map;
+import java.util.function.Supplier;
+
+import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.LittleEndianOutput;
 import org.apache.poi.util.StringUtil;
 
@@ -83,25 +86,25 @@ public final class TableStylesRecord ext
                return sid;
        }
 
-
        @Override
-       public String toString() {
-               StringBuilder buffer = new StringBuilder();
-
-               buffer.append("[TABLESTYLES]\n");
-               buffer.append("    .rt      
=").append(HexDump.shortToHex(rt)).append('\n');
-               buffer.append("    
.grbitFrt=").append(HexDump.shortToHex(grbitFrt)).append('\n');
-               buffer.append("    .unused  
=").append(HexDump.toHex(unused)).append('\n');
-               buffer.append("    
.cts=").append(HexDump.intToHex(cts)).append('\n');
-               buffer.append("    
.rgchDefListStyle=").append(rgchDefListStyle).append('\n');
-               buffer.append("    
.rgchDefPivotStyle=").append(rgchDefPivotStyle).append('\n');
+       public TableStylesRecord copy() {
+               return new TableStylesRecord(this);
+       }
 
-               buffer.append("[/TABLESTYLES]\n");
-               return buffer.toString();
+       @Override
+       public HSSFRecordTypes getGenericRecordType() {
+               return HSSFRecordTypes.TABLE_STYLES;
        }
 
        @Override
-       public TableStylesRecord copy() {
-               return new TableStylesRecord(this);
+       public Map<String, Supplier<?>> getGenericProperties() {
+               return GenericRecordUtil.getGenericProperties(
+                       "rt", () -> rt,
+                       "grbitFrt", () -> grbitFrt,
+                       "unused", () -> unused,
+                       "cts", () -> cts,
+                       "rgchDefListStyle", () -> rgchDefListStyle,
+                       "rgchDefPivotStyle", () -> rgchDefPivotStyle
+               );
        }
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to