1

I have a table view that is populated with dynamic columns that I create in the controller. The first time I create the table everything works fine, but when I try to redraw the table using new items I get a null pointer exception which seems to be caused by some nested columns I use (from reading the stack trace). When redrawing the table I take the same steps I took when I created it the first time which are:

Remove all items (first using clear then using remove all, just to be sure)

tableFullTimetable.getItems().clear();
tableFullTimetable.getItems().removeAll();

Remove all columns (same with columns)

tableFullTimetable.getColumns().clear();
tableFullTimetable.getColumns().removeAll();

I then add my dynamic nested columns using a for loop and after that, set the new items on the table

tableFullTimetable.setItems(myNewItems);

I understand that table view has refresh issues but I think this is different, the table gets cleared but when execution gets to the line of setting it throws the null pointer exception, here's the stack trace for the error:

Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
    at com.sun.javafx.scene.control.skin.NestedTableColumnHeader.dispose(NestedTableColumnHeader.java:323)
    at com.sun.javafx.scene.control.skin.NestedTableColumnHeader.updateTableColumnHeaders(NestedTableColumnHeader.java:265)
    at com.sun.javafx.scene.control.skin.NestedTableColumnHeader.checkState(NestedTableColumnHeader.java:519)
    at com.sun.javafx.scene.control.skin.NestedTableColumnHeader.computePrefHeight(NestedTableColumnHeader.java:401)
    at javafx.scene.Parent.prefHeight(Parent.java:918)
    at javafx.scene.layout.Region.prefHeight(Region.java:1438)
    at com.sun.javafx.scene.control.skin.TableHeaderRow.computePrefHeight(TableHeaderRow.java:344)
    at com.sun.javafx.scene.control.skin.TableHeaderRow.computeMinHeight(TableHeaderRow.java:339)
    at javafx.scene.Parent.minHeight(Parent.java:946)
    at javafx.scene.layout.Region.minHeight(Region.java:1404)
    at javafx.scene.control.SkinBase.computeMinHeight(SkinBase.java:254)
    at javafx.scene.control.Control.computeMinHeight(Control.java:485)
    at javafx.scene.Parent.minHeight(Parent.java:946)
    at javafx.scene.layout.Region.minHeight(Region.java:1404)
    at javafx.scene.layout.Region.computeChildMinAreaHeight(Region.java:1700)
    at javafx.scene.layout.BorderPane.getAreaHeight(BorderPane.java:618)
    at javafx.scene.layout.BorderPane.computeMinHeight(BorderPane.java:415)
    at javafx.scene.Parent.minHeight(Parent.java:946)
    at javafx.scene.layout.Region.minHeight(Region.java:1404)
    at javafx.scene.layout.Region.boundedNodeSizeWithBias(Region.java:1920)
    at javafx.scene.layout.Region.layoutInArea(Region.java:2326)
    at javafx.scene.layout.Region.layoutInArea(Region.java:2241)
    at javafx.scene.layout.Region.layoutInArea(Region.java:2182)
    at javafx.scene.layout.StackPane.layoutChildren(StackPane.java:351)
    at javafx.scene.Parent.layout(Parent.java:1076)
    at javafx.scene.Parent.layout(Parent.java:1082)
    at javafx.scene.Parent.layout(Parent.java:1082)
    at javafx.scene.Scene.doLayoutPass(Scene.java:576)
    at javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2386)
    at com.sun.javafx.tk.Toolkit$3.run(Toolkit.java:321)
    at com.sun.javafx.tk.Toolkit$3.run(Toolkit.java:319)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:319)
    at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:348)
    at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:479)
    at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:460)
    at com.sun.javafx.tk.quantum.QuantumToolkit$13.run(QuantumToolkit.java:327)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.access$300(WinApplication.java:39)
    at com.sun.glass.ui.win.WinApplication$4$1.run(WinApplication.java:112)
    at java.lang.Thread.run(Thread.java:745)

The observable collection being set to the table is an observable arraylist and it does not have any null items. I don't know what I have missed in the above process, please help thanks

Update: This was meant to show how my code works, I've not succeeded in reproducing the error in this MCVE but I hope it helps you help me :)

public class TestTable extends Application {

    private TableView<ERoom> tableFullTimetable = new TableView<>();
    private String[] days = {"monday", "tuesday", "wednesday", "thursday", "friday"};
    private Integer[] timeslots = {1, 2, 3, 4, 5};
    private List<ERoom> eRooms;

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {
        VBox rootlayout = new VBox();
        primaryStage.setWidth(895);
        primaryStage.setHeight(550);
        primaryStage.setScene(new Scene(rootlayout));
        primaryStage.show();

        eRooms = new ArrayList<>();
        eRooms.add(new ERoom("room1"));
        eRooms.add(new ERoom("room2"));

        List<ELesson> eLessons = new ArrayList<>();
        eLessons.add(new ELesson(2, "friday", eRooms.get(0)));
        eLessons.add(new ELesson(4, "wednesday", eRooms.get(1)));
        eLessons.add(new ELesson(5, "monday", eRooms.get(1)));
        eLessons.add(new ELesson(1, "tuesday", eRooms.get(0)));
        eLessons.add(new ELesson(3, "thursday", eRooms.get(1)));
        ETimetable firstTimetable = new ETimetable(eLessons, eRooms);
        //Load the first timetable
        setTimeTable(firstTimetable);

        //Button for loading a different timetable
        Button button = new Button("Load second timetable");
        rootlayout.getChildren().add(tableFullTimetable);
        button.onActionProperty().addListener(new ChangeListener<EventHandler<ActionEvent>>() {
            @Override
            public void changed(ObservableValue<? extends EventHandler<ActionEvent>> observable, EventHandler<ActionEvent> oldValue, EventHandler<ActionEvent> newValue) {
                List<ELesson> othereLessons = new ArrayList<>();
                othereLessons.add(new ELesson(3, "tuesday", eRooms.get(0)));
                othereLessons.add(new ELesson(4, "monday", eRooms.get(1)));
                othereLessons.add(new ELesson(2, "friday", eRooms.get(1)));
                othereLessons.add(new ELesson(5, "wednesday", eRooms.get(0)));
                ETimetable secondtimetable = new ETimetable(othereLessons, eRooms);
                setTimeTable(secondtimetable);
            }
        });
        rootlayout.getChildren().add(button);
    }

    private void setTimeTable(ETimetable newtimetable) {
        if (tableFullTimetable.getItems() != null) {
            tableFullTimetable.getItems().clear();
            tableFullTimetable.getItems().removeAll();
        }
        if (tableFullTimetable.getColumns() != null) {
            tableFullTimetable.getColumns().clear();
            tableFullTimetable.getColumns().removeAll();
        }
        //Nested loops for creating columns
        for (String day : days) {
            TableColumn dayTableColumn = new TableColumn(day);
            tableFullTimetable.getColumns().add(dayTableColumn);
            for (int timeslot : timeslots) {
                TableColumn<ERoom, ELesson> timeslotTableColumn = new TableColumn<>(Integer.toString(timeslot));
                timeslotTableColumn.setPrefWidth(50);
                timeslotTableColumn.setCellValueFactory(param -> {
                    for (ELesson lesson : newtimetable.getLessons()) {
                        //Return the lesson that matches this column's room and day+timeslot
                        if (lesson.getRoom().equals(param.getValue()) && lesson.getDay().equals(day) && lesson.getTimeslot() == timeslot) {
                            return new ReadOnlyObjectWrapper<ELesson>(lesson);
                        }
                    }
                    return null;
                });
                dayTableColumn.getColumns().add(timeslotTableColumn);
            }
        }
        //This is where it fails
        tableFullTimetable.setItems(FXCollections.observableArrayList(newtimetable.getRooms()));
    }

    private class ETimetable {
        private List<ELesson> lessons;
        private List<ERoom> rooms;

        private ETimetable(List<ELesson> lessons, List<ERoom> rooms) {
            this.lessons = lessons;
            this.rooms = rooms;
        }

        public List<ELesson> getLessons() {
            return lessons;
        }

        public List<ERoom> getRooms() {
            return rooms;
        }
    }

    private class ELesson {
        private int timeslot;
        private String day;
        private ERoom room;

        private ELesson(int timeslot, String day, ERoom room) {
            this.timeslot = timeslot;
            this.day = day;
            this.room = room;
        }

        public int getTimeslot() {
            return timeslot;
        }

        public String getDay() {
            return day;
        }

        public ERoom getRoom() {
            return room;
        }

        @Override
        public String toString() {
            return day + " at " + timeslot + " in " + room.getName();
        }
    }

    private class ERoom {
        String name;

        private ERoom(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }
    }
}
3
  • 1
    You'll probably need to post a MCVE to get help with this. I've done things like this many times with no issues. Also, note that calling removeAll() on an ObservableList and passing in no parameters does nothing (it removes all occurrences of the values you pass in as parameters). clear() is the method you want. Commented Aug 4, 2014 at 18:15
  • Thanks, I thought it was overloaded internally. I'll try to post some of my code Commented Aug 4, 2014 at 18:36
  • Try updating your JDK first; I think that should fix it. Commented Aug 4, 2014 at 18:43

1 Answer 1

3

This looks like a known bug.

Try updating to the latest release of Java 8 (or the prerelease of Java 8u20 if that doesn't fix it).

Sign up to request clarification or add additional context in comments.

2 Comments

I have added an MCVE, it does not reproduce the error for some reason but it shows what I intended to do. I'm using Java 8u5 let me update to the latest release and see how it goes. Thanks again for your help.
I got the same Error and updated too. But it does not change anything :/

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.