Search code examples
javafxpropertiestableviewcoercion

How to use ObjectProperty<?> with fxml and PropertyValueFactory?


I have this TableView

<TableView fx:id="tableView">
  <columns>
    <TableColumn prefWidth="220.0" text="Source">
      <cellValueFactory>
        <PropertyValueFactory property="sourceContract" />
      </cellValueFactory>
    </TableColumn>
  </columns>
  <items>
    <FXCollections fx:factory="observableArrayList">
      <GridRowModel sourceContract="some contract" />
    </FXCollections>
  </items>
</TableView>

and these classes

public class GridRowModel {

  private ObjectProperty<ContractConfig> sourceContract = new SimpleObjectProperty<>();

  public GridRowModel() {
  }

  public ObjectProperty<ContractConfig> sourceContractProperty() {
    return sourceContract;
  }

  public ContractConfig getSourceContract() {
    return sourceContract.get();
  }

  public void setSourceContract(ContractConfig sourceContract) {
    this.sourceContract.set(sourceContract);
  }
}

public class ContractConfig {

  private String name;
  private String userFriendlyName;

  public ContractConfig() {
  }

  public ContractConfig(String name) {
    this.name = name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public void setUserFriendlyName(String userFriendlyName) {
    this.userFriendlyName = userFriendlyName;
  }

  public String getName() {
    return name;
  }

  public String getUserFriendlyName() {
    return userFriendlyName;
  }
}

I get this obvious error:

Caused by: java.lang.IllegalArgumentException: Unable to coerce some contract to class com.ui.util.ContractConfig.
    at com.sun.javafx.fxml.BeanAdapter.coerce(BeanAdapter.java:496)
    at com.sun.javafx.fxml.BeanAdapter.put(BeanAdapter.java:258)
    at com.sun.javafx.fxml.BeanAdapter.put(BeanAdapter.java:54)

I also tried this

  public void setSourceContract(String sourceContract) {
    ContractConfig cc = new ContractConfig();
    cc.setUserFriendlyName(sourceContract);
    this.sourceContract.set(cc);
  }

But I get this error

Caused by: com.sun.javafx.fxml.PropertyNotFoundException: Property "sourceContract" does not exist or is read-only.
    at com.sun.javafx.fxml.BeanAdapter.put(BeanAdapter.java:253)
    at com.sun.javafx.fxml.BeanAdapter.put(BeanAdapter.java:54)
    at javafx.fxml.FXMLLoader$Element.applyProperty(FXMLLoader.java:512) 

Is it possible to use ObjectProperty with FXML values and if so, how can I use my ContractConfig object in the FXML?


Solution

  • You use the wrong fxml code for the class structure you've created. It should look like this instead:

    <GridRowModel>
        <sourceContract>
            <ContractConfig name="some contract"/> 
        </sourceContract>
    </GridRowModel>
    

    You can also add a constructor with @NamedArg to GridRowModel and use

    <GridRowModel sourceContract="some contract" />
    
    private final ObjectProperty<ContractConfig> sourceContract;
    
    private GridRowModel(ContractConfig sourceContract) {
        this.sourceContract = new SimpleObjectProperty<>(sourceContract);
    }
    
    public GridRowModel() {
        this((ContractConfig) null);
    }
    
    public GridRowModel(@NamedArg("sourceContract") String sourceContract) {
        this(new ContractConfig(sourceContract));
    }