1

Summary:

I am trying to populate a TableView with an ObservableList that contains objects of class "Contact" that have fields of type SimpleStringProperty.

Unfortunately it doesn't work. I get the error:

WARNING: Can not retrieve property 'firstName' in PropertyValueFactory: javafx.scene.control.cell.PropertyValueFactory@61e63bbc with provided class type: class sample.Datamodel.Contact
java.lang.RuntimeException: java.lang.IllegalAccessException: module javafx.base cannot access class sample.Datamodel.Contact (in module JavaFXChallengeContactList) because
at javafx.base/com.sun.javafx.property.PropertyReference.getProperty(PropertyReference.java:199)
at javafx.controls/javafx.scene.control.cell.PropertyValueFactory.getCellDataReflectively(PropertyValueFactory.java:182)
... and many more

I did extensive research on this topic. In many cases other people have not implemented the variableProperty() method in the class. But it is there.

I have made a method to create the columns, but other attempts (without it and putting the code directly in the initialize() method) also didn't work.

When I run the code, I get the table with the headers, but no data.

What is wrong here?

Thank you very much for your support!

Code in Contact Class:

public class Contact {

private SimpleStringProperty firstName;
private SimpleStringProperty lastName;
private SimpleStringProperty phoneNumber;
private SimpleStringProperty notes;

public Contact(SimpleStringProperty firstName, SimpleStringProperty lastName, SimpleStringProperty phoneNumber, SimpleStringProperty notes) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.phoneNumber = phoneNumber;
    this.notes = notes;
}

public String getFirstName() {
    return firstName.get();
}

public SimpleStringProperty firstNameProperty() {
    return firstName;
}

public void setFirstName(String firstName) {
    this.firstName.set(firstName);
}

... (other methods for lastName, phoneNumer and notes are identical)

Code in ContactData Class:

public class ContactData {

private ObservableList<Contact> contacts;

public ContactData() {
    this.contacts = FXCollections.observableArrayList();
}

public void addContact(String fName, String lName, String phone, String notes) {
    SimpleStringProperty firstName = new SimpleStringProperty(fName);
    SimpleStringProperty lastName = new SimpleStringProperty(lName);
    SimpleStringProperty phoneNumber = new SimpleStringProperty(phone);
    SimpleStringProperty yourNotes = new SimpleStringProperty(notes);
    this.contacts.add(new Contact(firstName, lastName, phoneNumber, yourNotes));

}

public ObservableList<Contact> getContacts() {
    return contacts;
}

Code in Controller:

public class Controller {

@FXML
private TableView table;

public void initialize() {
    ContactData contactDatabase = new ContactData();
    contactDatabase.addContact("John", "Doe", "123", "Hi John");
    contactDatabase.addContact("Peter", "Mustang", "321", "Hello Pete");
    contactDatabase.addContact("Carl", "Mueller", "555", "Hey Carl");


    TableColumn firstCol = setUpColumn("First Name","firstName");
    TableColumn secondCol = setUpColumn("Last Name","lastName");
    TableColumn thirdCol = setUpColumn("Phone Number","phoneNumber");
    TableColumn lastCol = setUpColumn("Your Notes","notes");

    table.setItems(contactDatabase.getContacts());
    table.getColumns().addAll(firstCol, secondCol, thirdCol, lastCol);

}

public TableColumn setUpColumn(String columnName, String idInContact) {
    TableColumn<Contact, SimpleStringProperty> column = new TableColumn<>(columnName);
    column.setCellValueFactory(new PropertyValueFactory<>(idInContact));
    return column;
}
kleopatra
  • 51,061
  • 28
  • 99
  • 211
CHH
  • 140
  • 1
  • 8
  • 1
    the error message is incomplete: the important part in this case is _java.lang.RuntimeException: java.lang.IllegalAccessException: module javafx.base cannot access class sample.Datamodel.Contact (in module JavaFXChallengeContactList) because_ the text __after because__ will tell you exactly what's wrong :) make sure Contact's package is exported or at least opened in your module info – kleopatra Aug 20 '20 at 11:06
  • YESSS!! Thank you so much, it worked! The solution was to add a line in module-info.java: opens sample.Datamodel; – CHH Aug 20 '20 at 11:14
  • 1
    Note a *much* better solution is to avoid using `PropertyValueFactory`. Use properly-typed table columns (i.e. `TableColumn`, not the raw type `TableColumn`) and then you can do `firstCol.setCellValueFactory(cellData -> cellData.getValue().firstNameProperty())` etc. – James_D Aug 20 '20 at 12:35

1 Answers1

3

That was solved quickly, thank you kleopatra!

a line in module-info.java was missing. The Contact class is located in the subpackage "Datamodel". It required the following line to make it work:

opens sample.Datamodel;
CHH
  • 140
  • 1
  • 8
  • 1
    glad it's working :) Just note that it's preferable to not use PropertyValueFactory at all if possible - your model class exposes properties, you can use them directly – kleopatra Aug 20 '20 at 11:32