jxls icon indicating copy to clipboard operation
jxls copied to clipboard

NullPointerException thrown when templating

Open Blackiris opened this issue 1 year ago • 0 comments

Description

A nullpointerexception is thrown when templating.

java.lang.NullPointerException
	at org.apache.poi.hssf.record.CFHeaderBase.serialize(CFHeaderBase.java:144)
	at org.apache.poi.hssf.record.StandardRecord.serialize(StandardRecord.java:56)
	at org.apache.poi.hssf.usermodel.HSSFWorkbook$SheetRecordCollector.serialize(HSSFWorkbook.java:1476)
	at org.apache.poi.hssf.usermodel.HSSFWorkbook.getBytes(HSSFWorkbook.java:1523)
	at org.apache.poi.hssf.usermodel.HSSFWorkbook.write(HSSFWorkbook.java:1418)
	at org.apache.poi.hssf.usermodel.HSSFWorkbook.write(HSSFWorkbook.java:1404)
	at org.jxls.transform.poi.PoiTransformer.writeButNotCloseStream(PoiTransformer.java:501)
	at org.jxls.transform.poi.PoiTransformer.write(PoiTransformer.java:482)
	at org.jxls.util.JxlsHelper.processTemplate(JxlsHelper.java:288)
	at org.jxls.util.JxlsHelper.processTemplate(JxlsHelper.java:253)

Reproduction code and file

    @Test
    public void processTemplate_with_good_data_expected_outputfile() throws FileNotFoundException {
        FileTemplaterExcel fileTemplaterExcel = new FileTemplaterExcel();

        Map<String, Object> data = new HashMap<>();
        DistributeSlipProcessed dist = new DistributeSlipProcessed();
        dist.setCategory("ABC");

        JtpDistributeDocument doc = new JtpDistributeDocument();
        doc.setDocumentTitle("Mon titre");
        doc.setDocumentReference("REF04846");
        doc.setDocumentVersion("1.0");
        doc.setJtpLodToClient("OUI");

        dist.setDocuments(List.of(doc, doc));

        data.put("distributes", List.of(dist));
        FileOutputStream fout = new FileOutputStream("file1.xls");
        fileTemplaterExcel.processTemplate("template3.xls", data, fout);
    }

template3.xls

Solution found

It seems that when a conditionalFormatting is not used, instead of setting an empty list of ranges, it is better to delete it.

Might not be the solution, but changing removeConditionalFormatting in PoiTransformer.java makes it works:

    // this method updates conditional formatting ranges only when the range is inside the passed areaRef
    private void removeConditionalFormatting(AreaRef areaRef) {
        Sheet destSheet = workbook.getSheet(areaRef.getSheetName());
        CellRangeAddress areaRange = CellRangeAddress.valueOf(areaRef.toString());
        SheetConditionalFormatting sheetConditionalFormatting = destSheet.getSheetConditionalFormatting();
        int numConditionalFormattings = sheetConditionalFormatting.getNumConditionalFormattings();

        for (int index = numConditionalFormattings -1; index >= 0; index--) {
            ConditionalFormatting conditionalFormatting = sheetConditionalFormatting.getConditionalFormattingAt(index);
            CellRangeAddress[] ranges = conditionalFormatting.getFormattingRanges();
            List<CellRangeAddress> newRanges = new ArrayList<>();
            for (CellRangeAddress range : ranges) {
                if (!areaRange.isInRange(range.getFirstRow(), range.getFirstColumn()) || !areaRange.isInRange(range.getLastRow(), range.getLastColumn())) {
                    newRanges.add(range);
                }
            }
            if (newRanges.isEmpty()) {
                sheetConditionalFormatting.removeConditionalFormatting(index);
            } else {
                conditionalFormatting.setFormattingRanges(newRanges.toArray(new CellRangeAddress[] {}));
            }
        }
    }

Blackiris avatar Sep 07 '23 15:09 Blackiris