1

I am creating a Table using PDF Box API. When i try to run my code i get Null Pointer Exception. What I am doing is I am setting properties like color border width etc. of the table at different levels i.e. At Cell level, row level, table level.

Here Row, Cell, Table are different classes.

It means that if a border width is set at cell level it will be used at that cell only, if this property is set at row level then it will set border width of whole row where cell border width property is not being used, and same for table level.

Priority: Cell>Row>Table

But my code does is when the value is not set at cell level using setter, so the value will be obviously 0 (In case of primitive type). and if it is 0 then it will get value from row level. Same in the case of row.

But I am getting Null Pointer Exception when I try to get value that is inherited from row. and indirectly from table. And also getting Null Pointer exception when i try to get get Row because it is returned null.

Firstly I tried to solve Null Pointer Exception using if loop. But result is still same.

Error Message :

Exception in thread "main" java.lang.NullPointerException
    at main.Cell.getBorderWidth(Cell.java:66)
    at main.CreateTable.createSampleDocument(CreateTable.java:54)
    at main.CreateTable.main(CreateTable.java:16)

I am providing little part of code.

Table Class

public class Table {

    private List<Row> rows = new LinkedList<>();
    private float borderWidth = 0.2f;

    private Table(final List<Row> rows) {
        this.rows = rows;
    }

    public List<Row> getRows() {
        return rows;
    }

    public float getTableWidth() { 
        return tableWidth;
    }

    public void setTableWidth(final float tableWidth) {
        this.tableWidth = tableWidth;
    }


    public static class TableBuilder {
        private final List<Row> rows = new LinkedList<>();
        private Table table = new Table(rows, columns);

        public TableBuilder addRow(Row row) {
            row.setTable(table);
            rows.add(row);
            return this;
        }

        public TableBuilder setTableWidth(final float tableWidth) {
            this.tableWidth = tableWidth;
            this.table.setTableWidth(tableWidth);
            return this;
        }

        public Table build() {
            return table;
        }
    }
}

Row Class

public class Row {
    private Table table;
    private final List<Cell> cells;
    private float borderWidth;

    private Row(final List<Cell> cells) {
        super();
        this.cells = cells;
    }

    public List<Cell> getCells() {
        return this.cells;
    }

    public Table getTable() {
        return table;
    }

    void setTable(final Table table) {
        this.table = table;
    }

    public float getBorderWidth() {
        if(borderWidth == 0) {
            System.out.println(getTable().getBorderWidth());
            borderWidth = getTable().getBorderWidth();
        }
        return borderWidth;
    }

    public void setBorderWidth(float borderWidth) {
        this.borderWidth = borderWidth;
    }

    public static class RowBuilder {
        private final List<Cell> cells = new LinkedList<>();
        Row row = new Row(cells);

        public RowBuilder add(final Cell cell) {
            cell.setRow(row);
                        cells.add(cell);
                        return this;
                 }


        public RowBuilder setAllPadding(float allPadding) {
            //this.allPadding = Optional.of(allPadding);
            this.row.setAllPadding(allPadding);
            return this;
        }

        public RowBuilder setBorderWidth(float borderWidth) {
            /*this.borderWidth = Optional.of(borderWidth);
            this.borderWidth.ifPresent(row::setBorderWidth);*/
            this.row.setBorderWidth(borderWidth);
            return this;
                }
        public Row build() {

            return row;
        }
    }
}

Cell Class

public class Cell {
    private Row row;
    private final String text;
    private float borderWidth;  //To be seen afterwards

    private Cell(Object object) {
        this.text = String.valueOf(object);
    }

    public static Cell addText(Object object) {
        System.out.println(String.valueOf(object));
        return new Cell(object);
    }

    public String getText() {                    
        return text;
    }

    public Row getRow() {
        return row;
    }

    public void setRow(final Row row) {
        this.row = row;
    }

    public float getBorderWidth() {
        //Optional<Float> optBorderWidth = Optional.ofNullable(borderWidth);
        //return optBorderWidth.orElse(getRow().getBorderWidth());
        if(borderWidth == 0) {
            borderWidth = getRow().getTable().getBorderWidth();
        }
        return borderWidth;
    }

    public Cell setBorderWidth(float borderWidth) {
        this.borderWidth = borderWidth;
        return this;
    }
}

Edit


I just forgot to tell how this value are being used and set in memory.

Here is code

public class CreateTable {
    public static void main (String[] args) throws Exception {
        new CreateTable().createSampleDocument();
    }

    public void createSampleDocument() throws Exception {

        final Object[][] tableData = {
                {"ent",0.8, 0.5},
                {"AV",144, 51.7},
                {"Scc",0.1, 0.5}
        };

        TableBuilder tableBuilder = new TableBuilder()
                .setBorderWidth(0.2f)




        tableBuilder.addRow(new RowBuilder()
                .add(Cell.addText("P").withAllBorders().setBorderColor(Color.BLUE).setLineSpacing(2))
                .add(Cell.addText("S").withAllBorders())
                .add(Cell.addText("D").withAllBorders())
                .setBorderColor(Color.RED).setLineSpacing(1)
                .build());


        final PDDocument document = new PDDocument();
        final PDPage page = new PDPage(PDRectangle.A4);
        document.addPage(page);

        final PDPageContentStream contentStream = new PDPageContentStream(document, page);

        (new TableDrawer(contentStream, tableBuilder.build(), 300, 300)).draw();
        contentStream.close();

        document.save("C:\\Users\\sa\\Desktop\\table_pdf.pdf");
        document.close();

    }
}

Null Pointer Exception being caught at

Inside Cell class (because getRow() method is returning null)

public float getBorderWidth() {
        //Optional<Float> optBorderWidth = Optional.ofNullable(borderWidth);
        //return optBorderWidth.orElse(getRow().getBorderWidth());
        if(borderWidth == 0) {
            borderWidth = getRow().getTable().getBorderWidth();
        }
        return borderWidth;
    }
Dominique
  • 16,450
  • 15
  • 56
  • 112
Rahul Goyal
  • 121
  • 1
  • 5
  • Welcome to Stack Overflow! Please take the [tour](/tour), have a look around, and read through the [help center](/help), in particular [How do I ask a good question?](/help/how-to-ask) and [What topics can I ask about here?](/help/on-topic). Please read (and follow) the [Java Naming Conventions](http://www.oracle.com/technetwork/java/codeconventions-135099.html). Your error is `at main.Cell.getBorderWidth(Cell.java:66)`, the variable `Cell` is not initialised (early enough). – Timothy Truckle Jan 18 '19 at 09:48
  • I am not able to figure out solution getting confused. @TimothyTruckle – Rahul Goyal Jan 18 '19 at 09:59
  • 2
    from the error message the line causing the problem is `borderWidth = getRow().getTable().getBorderWidth();` (line 66) by reading this line either the getter `getRow()` returns `null` because the variable `row` is not yet initialised or the subsequent call `getTable()` retuns `null` because the *row* object is not yet configured completely. – Timothy Truckle Jan 18 '19 at 10:12
  • Yes you are right. Because this method (i.e. getBorderWidth ) is being called to early before the proper completion of row and table class. It is being called at withAllBorders() Method in Cell class in return which is being called at Create Table class while setting data. @TimothyTruckle – Rahul Goyal Jan 18 '19 at 10:22
  • Your code reminds very much of [easytable](https://github.com/vandeseer/easytable)... – mkl Jan 18 '19 at 13:20
  • Yes this code is derived from there itself. But with very new features. In fact be can perform row span over it. I didn't find any guidance over row spanning table rows. So I individually made it and some more add on (very useful) @mkl – Rahul Goyal Jan 22 '19 at 05:53

0 Answers0