• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

hazendaz / displaytag / 1753

12 Feb 2026 03:17AM UTC coverage: 77.321% (-0.01%) from 77.334%
1753

push

github

web-flow
Merge pull request #1102 from hazendaz/renovate/javax-support-logback-monorepo

Update dependency ch.qos.logback:logback-classic to v1.5.29 (javax-support)

1438 of 2003 branches covered (71.79%)

Branch coverage included in aggregate %.

4034 of 5074 relevant lines covered (79.5%)

0.8 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

72.86
/displaytag/src/main/java/org/displaytag/export/excel/ExcelHssfView.java
1
/*
2
 * SPDX-License-Identifier: MIT
3
 * See LICENSE file for details.
4
 *
5
 * Copyright 2002-2026 Fabrizio Giustina, the Displaytag team
6
 */
7
package org.displaytag.export.excel;
8

9
import java.io.OutputStream;
10
import java.util.Calendar;
11
import java.util.Date;
12
import java.util.Iterator;
13

14
import javax.servlet.jsp.JspException;
15

16
import org.apache.commons.lang3.StringUtils;
17
import org.apache.poi.hssf.usermodel.HSSFCell;
18
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
19
import org.apache.poi.hssf.usermodel.HSSFFont;
20
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
21
import org.apache.poi.hssf.usermodel.HSSFRow;
22
import org.apache.poi.hssf.usermodel.HSSFSheet;
23
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
24
import org.apache.poi.hssf.util.HSSFColor.HSSFColorPredefined;
25
import org.apache.poi.ss.usermodel.FillPatternType;
26
import org.displaytag.export.BinaryExportView;
27
import org.displaytag.model.Column;
28
import org.displaytag.model.ColumnIterator;
29
import org.displaytag.model.HeaderCell;
30
import org.displaytag.model.Row;
31
import org.displaytag.model.RowIterator;
32
import org.displaytag.model.TableModel;
33

34
/**
35
 * Excel exporter using POI HSSF.
36
 */
37
public class ExcelHssfView implements BinaryExportView {
38

39
    /**
40
     * TableModel to render.
41
     */
42
    private TableModel model;
43

44
    /** export full list?. */
45
    private boolean exportFull;
46

47
    /** include header in export?. */
48
    private boolean header;
49

50
    /** decorate export?. */
51
    private boolean decorated;
52

53
    /** Name of Excel Spreadsheet. */
54
    private String sheetName;
55

56
    /** Workbook. */
57
    private HSSFWorkbook wb;
58

59
    /** Worksheet. */
60
    private HSSFSheet sheet;
61

62
    /** utils. */
63
    ExcelUtils utils;
64

65
    /**
66
     * Instantiates a new excel hssf view.
67
     */
68
    public ExcelHssfView() {
1✔
69
    }
1✔
70

71
    /**
72
     * Sets the parameters.
73
     *
74
     * @param tableModel
75
     *            the table model
76
     * @param exportFullList
77
     *            the export full list
78
     * @param includeHeader
79
     *            the include header
80
     * @param decorateValues
81
     *            the decorate values
82
     *
83
     * @see org.displaytag.export.ExportView#setParameters(TableModel, boolean, boolean, boolean)
84
     */
85
    @Override
86
    public void setParameters(final TableModel tableModel, final boolean exportFullList, final boolean includeHeader,
87
            final boolean decorateValues) {
88
        this.model = tableModel;
1✔
89
        this.exportFull = exportFullList;
1✔
90
        this.header = includeHeader;
1✔
91
        this.decorated = decorateValues;
1✔
92
        this.utils = new ExcelUtils(new HSSFWorkbook());
1✔
93
        this.utils.initCellStyles(tableModel.getProperties());
1✔
94
    }
1✔
95

96
    /**
97
     * Gets the mime type.
98
     *
99
     * @return "application/vnd.ms-excel"
100
     *
101
     * @see org.displaytag.export.BaseExportView#getMimeType()
102
     */
103
    @Override
104
    public String getMimeType() {
105
        return "application/vnd.ms-excel"; //$NON-NLS-1$
1✔
106
    }
107

108
    /**
109
     * Do export.
110
     *
111
     * @param out
112
     *            the out
113
     *
114
     * @throws JspException
115
     *             the jsp exception
116
     *
117
     * @see org.displaytag.export.BinaryExportView#doExport(OutputStream)
118
     */
119
    @Override
120
    public void doExport(final OutputStream out) throws JspException {
121
        try {
122
            final String inputSheetName = this.model.getProperties().getProperty(ExcelUtils.EXCEL_SHEET_NAME);
1✔
123
            this.setSheetName(inputSheetName);
1✔
124
            this.setSheet(this.getWb().createSheet(this.getSheetName()));
1✔
125

126
            int rowNum = 0;
1✔
127
            int colNum = 0;
1✔
128

129
            if (this.header) {
1!
130
                // Create an header row
131
                final HSSFRow xlsRow = this.sheet.createRow(rowNum);
1✔
132
                rowNum++;
1✔
133

134
                final Iterator<HeaderCell> iterator = this.model.getHeaderCellList().iterator();
1✔
135

136
                while (iterator.hasNext()) {
1✔
137
                    final HeaderCell headerCell = iterator.next();
1✔
138

139
                    final HSSFCell cell = xlsRow.createCell(colNum++);
1✔
140
                    cell.setCellValue(new HSSFRichTextString(this.getHeaderCellValue(headerCell)));
1✔
141
                    cell.setCellStyle(this.createHeaderStyle(this.getWb(), headerCell));
1✔
142
                }
1✔
143
            }
144

145
            // get the correct iterator (full or partial list according to the exportFull field)
146
            final RowIterator rowIterator = this.model.getRowIterator(this.exportFull);
1✔
147

148
            // iterator on rows
149
            while (rowIterator.hasNext()) {
1✔
150
                final Row row = rowIterator.next();
1✔
151
                final HSSFRow xlsRow = this.getSheet().createRow(rowNum);
1✔
152
                rowNum++;
1✔
153
                colNum = 0;
1✔
154

155
                // iterator on columns
156
                final ColumnIterator columnIterator = row.getColumnIterator(this.model.getHeaderCellList());
1✔
157

158
                while (columnIterator.hasNext()) {
1✔
159
                    final Column column = columnIterator.nextColumn();
1✔
160

161
                    // Get the value to be displayed for the column
162
                    final Object value = column.getValue(this.decorated);
1✔
163

164
                    final HSSFCell cell = xlsRow.createCell(colNum++);
1✔
165
                    this.writeCell(value, cell);
1✔
166
                }
1✔
167
            }
1✔
168

169
            this.createTotalsRow(this.getSheet(), rowNum, this.model);
1✔
170

171
            this.autosizeColumns();
1✔
172

173
            this.getWb().write(out);
1✔
174
        } catch (final Exception e) {
×
175
            throw new ExcelUtils.ExcelGenerationException(e);
×
176
        }
1✔
177
    }
1✔
178

179
    /**
180
     * Uses POI Autosizing. WARNING. This has been known to cause performance problems and various exceptions. use at
181
     * your own risk! Overriding this method is suggested. From POI HSSF documentation for autoSizeColumn: "To calculate
182
     * column width HSSFSheet.autoSizeColumn uses Java2D classes that throw exception if graphical environment is not
183
     * available. In case if graphical environment is not available, you must tell Java that you are running in headless
184
     * mode and set the following system property: java.awt.headless=true."
185
     */
186
    protected void autosizeColumns() {
187
        for (int i = 0; i < this.getModel().getNumberOfColumns(); i++) {
1✔
188
            this.getSheet().autoSizeColumn((short) i);
1✔
189
            // since this usually creates column widths that are just too short, adjust here!
190
            // gives column width an extra character
191
            int width = this.getSheet().getColumnWidth(i);
1✔
192
            width += 256;
1✔
193
            this.getSheet().setColumnWidth(i, (short) width);
1✔
194
        }
195
    }
1✔
196

197
    /**
198
     * Write the value to the cell. Override this method if you have complex data types that may need to be exported.
199
     *
200
     * @param value
201
     *            the value of the cell
202
     * @param cell
203
     *            the cell to write it to
204
     */
205
    protected void writeCell(final Object value, final HSSFCell cell) {
206
        if (value == null) {
1!
207
            cell.setCellValue(new HSSFRichTextString(""));
×
208
        } else if (value instanceof Integer) {
1!
209
            final Integer integer = (Integer) value;
×
210
            // due to a weird bug in HSSF where it uses shorts, we need to input this as a double value :(
211
            cell.setCellValue(integer.doubleValue());
×
212
            cell.setCellStyle(this.utils.getStyle(ExcelUtils.STYLE_INTEGER));
×
213
        } else if (value instanceof Number) {
1!
214
            final Number num = (Number) value;
×
215
            if (num.equals(Double.NaN)) {
×
216
                cell.setCellValue(new HSSFRichTextString(""));
×
217
            } else {
218
                cell.setCellValue(num.doubleValue());
×
219
            }
220
            cell.setCellStyle(this.utils.getStyle(ExcelUtils.STYLE_NUMBER));
×
221
        } else if (value instanceof Date) {
1!
222
            cell.setCellValue((Date) value);
×
223
            cell.setCellStyle(this.utils.getStyle(ExcelUtils.STYLE_DATE));
×
224
        } else if (value instanceof Calendar) {
1!
225
            cell.setCellValue((Calendar) value);
×
226
            cell.setCellStyle(this.utils.getStyle(ExcelUtils.STYLE_DATE));
×
227
        } else {
228
            cell.setCellValue(new HSSFRichTextString(ExcelUtils.escapeColumnValue(value)));
1✔
229
        }
230
    }
1✔
231

232
    /**
233
     * Templated method that is called for all non-header and non-total cells.
234
     *
235
     * @param wb
236
     *            the wb
237
     * @param rowCtr
238
     *            the row ctr
239
     * @param column
240
     *            the column
241
     *
242
     * @return the HSSF cell style
243
     */
244
    public HSSFCellStyle createRowStyle(final HSSFWorkbook wb, final int rowCtr, final Column column) {
245
        return wb.createCellStyle();
×
246
    }
247

248
    /**
249
     * Gets the header cell value.
250
     *
251
     * @param headerCell
252
     *            the header cell
253
     *
254
     * @return the header cell value
255
     */
256
    public String getHeaderCellValue(final HeaderCell headerCell) {
257
        String columnHeader = headerCell.getTitle();
1✔
258

259
        if (columnHeader == null) {
1!
260
            columnHeader = StringUtils.capitalize(headerCell.getBeanPropertyName());
×
261
        }
262

263
        return columnHeader;
1✔
264
    }
265

266
    /**
267
     * Templated method that is called for all header cells.
268
     *
269
     * @param wb
270
     *            the wb
271
     * @param headerCell
272
     *            the header cell
273
     *
274
     * @return the HSSF cell style
275
     */
276
    public HSSFCellStyle createHeaderStyle(final HSSFWorkbook wb, final HeaderCell headerCell) {
277
        final HSSFCellStyle headerStyle = this.getNewCellStyle();
1✔
278

279
        headerStyle.setFillPattern(FillPatternType.FINE_DOTS);
1✔
280
        headerStyle.setFillBackgroundColor(HSSFColorPredefined.BLUE_GREY.getIndex());
1✔
281
        final HSSFFont bold = wb.createFont();
1✔
282
        bold.setBold(true);
1✔
283
        bold.setColor(HSSFColorPredefined.WHITE.getIndex());
1✔
284
        headerStyle.setFont(bold);
1✔
285

286
        return headerStyle;
1✔
287
    }
288

289
    /**
290
     * Templated method that is used if a totals row is desired.
291
     *
292
     * @param sheet
293
     *            the sheet
294
     * @param rowNum
295
     *            the row num
296
     * @param tableModel
297
     *            the table model
298
     */
299
    public void createTotalsRow(final HSSFSheet sheet, final int rowNum, final TableModel tableModel) {
300
    }
1✔
301

302
    /**
303
     * Gets the table model.
304
     *
305
     * @return the table model
306
     */
307
    public TableModel getTableModel() {
308
        return this.model;
×
309
    }
310

311
    /**
312
     * Checks if is export full.
313
     *
314
     * @return true, if is export full
315
     */
316
    public boolean isExportFull() {
317
        return this.exportFull;
×
318
    }
319

320
    /**
321
     * Checks if is include header in export.
322
     *
323
     * @return true, if is include header in export
324
     */
325
    public boolean isIncludeHeaderInExport() {
326
        return this.header;
×
327
    }
328

329
    /**
330
     * Checks if is decorate export.
331
     *
332
     * @return true, if is decorate export
333
     */
334
    public boolean isDecorateExport() {
335
        return this.decorated;
×
336
    }
337

338
    /**
339
     * Gets the sheet name.
340
     *
341
     * @return the sheet name
342
     */
343
    public String getSheetName() {
344
        return this.sheetName;
1✔
345
    }
346

347
    /**
348
     * Sets the sheet name.
349
     *
350
     * @param sheetName
351
     *            the new sheet name
352
     *
353
     * @throws JspException
354
     *             the jsp exception
355
     */
356
    public void setSheetName(String sheetName) throws JspException {
357
        // this is due to either the POI limitations or excel (I'm not sure). you get the following error if you don't
358
        // do this:
359
        // Exception: [.ExcelHssfView] !ExcelView.errorexporting! Cause: Sheet name cannot be blank, greater than 31
360
        // chars, or contain any of /\*?[]
361
        if (StringUtils.isBlank(sheetName)) {
1!
362
            throw new JspException("The sheet name property " + ExcelUtils.EXCEL_SHEET_NAME + " must not be blank.");
×
363
        }
364
        sheetName = sheetName.replaceAll("/|\\\\|\\*|\\?|\\[|\\]", "");
1✔
365
        this.sheetName = sheetName.length() <= 31 ? sheetName : sheetName.substring(0, 31 - 3) + "...";
1!
366
    }
1✔
367

368
    /**
369
     * Gets the new cell style.
370
     *
371
     * @return the new cell style
372
     */
373
    public HSSFCellStyle getNewCellStyle() {
374
        return this.getWb() == null ? null : this.getWb().createCellStyle();
1!
375
    }
376

377
    /**
378
     * Gets the wb.
379
     *
380
     * @return the wb
381
     */
382
    public HSSFWorkbook getWb() {
383
        if (this.wb == null) {
1✔
384
            this.wb = new HSSFWorkbook();
1✔
385
        }
386
        return this.wb;
1✔
387
    }
388

389
    /**
390
     * Sets the wb.
391
     *
392
     * @param wb
393
     *            the new wb
394
     */
395
    public void setWb(final HSSFWorkbook wb) {
396
        this.wb = wb;
×
397
    }
×
398

399
    /**
400
     * Gets the sheet.
401
     *
402
     * @return the sheet
403
     */
404
    public HSSFSheet getSheet() {
405
        return this.sheet;
1✔
406
    }
407

408
    /**
409
     * Sets the sheet.
410
     *
411
     * @param sheet
412
     *            the new sheet
413
     */
414
    public void setSheet(final HSSFSheet sheet) {
415
        this.sheet = sheet;
1✔
416
    }
1✔
417

418
    /**
419
     * Gets the model.
420
     *
421
     * @return the model
422
     */
423
    public TableModel getModel() {
424
        return this.model;
1✔
425
    }
426

427
    /**
428
     * Sets the model.
429
     *
430
     * @param model
431
     *            the new model
432
     */
433
    public void setModel(final TableModel model) {
434
        this.model = model;
×
435
    }
×
436

437
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc