title: CellValueFactory of a TableColumn using a generic Object type?
body: <p>Error: Type mismatch: cannot convert from <code>SimpleStringProperty</code> to <code>ObservableValue&lt;Object&gt;</code>.</p>
  
  <p>I am trying to create a TreeTableView with a column that manages various data types. This means that each row could use one of three or so types of data ( <code>String</code>, <code>int</code>, <code>StringProperty</code>, or <code>ObjectProperty&lt; LocalDate &gt;</code>.</p>
  
  <p>Given my data-type is "Object" then <code>setCellValueFactory( cellDataFeatures -&gt; { return ...; })</code> expects an <code>ObservableValue&lt; Object &gt;</code>. I am at a loss trying to get the required ObservableValue out of the Properties for the CellValueFactory callback. :(</p>
  
  <p><a href="https://stackoverflow.com/questions/30334450/cannot-convert-from-string-to-observablevaluestring" title="This post">This post</a> suggests using a <code>ReadOnlyStringWrapper</code> but I would like to keep to the value editable (in most cases). I've also found suggestions for the <code>#asObject()</code> method which is not available in a StringProperty.</p>
  
  <pre><code>        /*-------------------------+------------+ 
           | columnPeople            | columnData |
           +-------------------------+------------+ 
           |                         |            |
           | + Bob Rozz ============ | 33 ======= |
           |   + SKILLS              |            |
           |     + testskill 1       | 0.7        |
           |                         | 3/14/2017  |
           |     + testskill 2       |            |
           |                         | 0.9        |
           |                         | 3/11/2017  |
           |                         |            |
           | + Bob Dilly =========== | 34 ======= |
           |   + SKILLS              |            |
           |     + testskill 1       | 0.6        |
           |                         | 3/10/2017  |
           |     + testskill 2       |            |
           |                         | 0.5        |
           |                         | 3/17/2017  |
           +-------------------------+------------+ 
          */
  </code></pre>
  
  <p><strong>Note1</strong>: Not tackling the <code>setCellFactory(...)</code> yet.</p>
  
  <p><strong>Note2</strong>: As-presented, I realize this example is unpractical. It is completely separate from my project as an example of the desired functionality.</p>
  
  <pre><code>package testGenericTableTreeColumn;
  
  import java.text.SimpleDateFormat;
  import java.time.LocalDate;
  import java.util.ArrayList;
  import java.util.List;
  
  import javafx.application.Platform;
  import javafx.beans.property.IntegerProperty;
  import javafx.beans.property.ObjectProperty;
  import javafx.beans.property.SimpleFloatProperty;
  import javafx.beans.property.SimpleIntegerProperty;
  import javafx.beans.property.SimpleObjectProperty;
  import javafx.beans.property.SimpleStringProperty;
  import javafx.beans.property.StringProperty;
  import javafx.beans.value.ObservableValue;
  import javafx.collections.ObservableList;
  import javafx.geometry.Insets;
  import javafx.geometry.Pos;
  import javafx.scene.Group;
  import javafx.scene.Scene;
  import javafx.scene.control.ContentDisplay;
  import javafx.scene.control.DatePicker;
  import javafx.scene.control.TreeItem;
  import javafx.scene.control.TreeTableCell;
  import javafx.scene.control.TreeTableColumn;
  import javafx.scene.control.TreeTableView;
  import javafx.scene.control.cell.TextFieldTreeTableCell;
  import javafx.scene.layout.VBox;
  import javafx.stage.Stage;
  import javafx.util.Pair;
  import javafx.util.converter.DefaultStringConverter;
  
  
  
  public class testGenericTableTreeColumn extends javafx.application.Application {
  
      class Skill {
  
          private StringProperty        name = new SimpleStringProperty( "" );
          public  final String          getName(){ return this.name.get();         }
          public  final void            setName( String v ){ name.set(v); return;  }
          public  StringProperty        nameProperty(){ return this.name;          }
  
          private SimpleFloatProperty   value = new SimpleFloatProperty( 0f );
          public  final String          getValue(){ return this.name.get();        }
          public  final void            setValue( String v ){ name.set(v); return; }
          public  StringProperty        valueProperty(){ return this.name;         }
  
          private SimpleObjectProperty&lt; LocalDate &gt; date = new SimpleObjectProperty&lt; LocalDate &gt;( LocalDate.now() );//LocalDate date  = LocalDate.now();
          public  final String          getDate(){ return this.name.get();         }
          public  final void            setDate( String v ){ name.set(v); return;  }
          public  StringProperty        dateProperty(){ return this.name;          }
  
          public Skill( String name ){
              java.util.Random r = new java.util.Random();
              this.name  .set( name );                        //this.name  = name;
              this.value .set( 100 * ( r.nextFloat() ));      //this.value = 100 * ( r.nextFloat() );
              this.date  .get().minusWeeks( r.nextInt(10) );  //date.minusWeeks( r.nextInt(10) );
              return;
          }
      }
      class Person {
  
          private StringProperty  name = new SimpleStringProperty( "" );
          public final String     getName()          { return this.name.get(); }
          public final void       setName( String v ){ name.set(v); return;    }
          public StringProperty   nameProperty()     { return this.name;       }
  
          private IntegerProperty age = new SimpleIntegerProperty( 0 );
          public final int        getAge()           { return this.age.get();  }
          public final void       setAge( int v )    { age.set(v); return;     }
          public IntegerProperty  ageProperty()      { return this.age;        }
  
          public  List&lt; Skill &gt;   skills = new ArrayList&lt;&gt;();
  
          public Person( String name, int age ){
              this.name .set( name );
              this.age  .set( age  );
              skills.add( new Skill( "testskill 1" ));
              skills.add( new Skill( "testskill 2" ));
              return;
          }
      }
  
      public TreeTableView&lt; Pair&lt; Object, Object &gt;&gt; table = new TreeTableView&lt;&gt;();
  
      @Override public void start( Stage primaryStage ){
  
          TreeItem&lt; Pair&lt; Object, Object &gt;&gt; itemRoot = new TreeItem&lt;&gt;( new Pair&lt;&gt;( "PEOPLE", null ));
          this.table.setRoot( itemRoot );
  
          Person person1 = new Person( "Bob Rozz"  ,33 );
          Person person2 = new Person( "Bob Dilly" ,34 );
  
          List&lt; Person &gt; people = new ArrayList&lt;&gt;();
          people.add( person1 );
          people.add( person2 );
  
          /*-------------------------+------------+ 
           | columnPeople            | columnData |
           +-------------------------+------------+ 
           |                         |            |
           | + Bob Rozz ============ | 33 ======= |
           |   + SKILLS              |            |
           |     + testskill 1       | 0.7        |
           |                         | 3/14/2017  |
           |     + testskill 2       |            |
           |                         | 0.9        |
           |                         | 3/11/2017  |
           |                         |            |
           | + Bob Dilly =========== | 34 ======= |
           |   + SKILLS              |            |
           |     + testskill 1       | 0.6        |
           |                         | 3/10/2017  |
           |     + testskill 2       |            |
           |                         | 0.5        |
           |                         | 3/17/2017  |
           +-------------------------+------------+ 
          */
  
          for ( Person person : people ){
  
              TreeItem&lt; Pair&lt; Object, Object &gt;&gt; treeItemPerson = new TreeItem&lt;&gt;( new Pair&lt; Object, Object &gt;( person.nameProperty(), person.ageProperty() ));
              TreeItem&lt; Pair&lt; Object, Object &gt;&gt; treeItemSkills = new TreeItem&lt;&gt;( new Pair&lt; Object, Object &gt;( "Skills"             , null ));
  
              itemRoot       .getChildren().add( treeItemPerson );
              treeItemPerson .getChildren().add( treeItemSkills );
  
              for ( Skill skill : person.skills ){
  
                  TreeItem&lt; Pair&lt; Object, Object &gt;&gt; treeItemSkillName  = new TreeItem&lt;&gt;( new Pair&lt; Object, Object &gt;( null, skill.nameProperty  () ));
                  TreeItem&lt; Pair&lt; Object, Object &gt;&gt; treeItemSkillValue = new TreeItem&lt;&gt;( new Pair&lt; Object, Object &gt;( null, skill.valueProperty () ));
                  TreeItem&lt; Pair&lt; Object, Object &gt;&gt; treeItemSkillDate  = new TreeItem&lt;&gt;( new Pair&lt; Object, Object &gt;( null, skill.dateProperty  () ));
  
                  treeItemSkills    .getChildren().add( treeItemSkillName  );
                  treeItemSkillName .getChildren().add( treeItemSkillDate  );
                  treeItemSkillName .getChildren().add( treeItemSkillValue );
              }
          }
  
          TreeTableColumn&lt; Pair&lt; Object, Object&gt;, String &gt; colName = new TreeTableColumn&lt;&gt;("People"); colName.setMinWidth(100);
          colName.setCellValueFactory( cellDataFeatures -&gt; {
  
              // Could be a String, StringProperty, or ObjectProperty&lt; LocalDate &gt;
              Object item   = cellDataFeatures.getValue().getValue().getKey();
  
              //String
              if ( item instanceof String ){
                  /* ERROR */ return ( String ) item; //ERROR: Type mismatch: cannot convert from SimpleStringProperty to ObservableValue&lt; Object &gt;
              }
  
              //StringProperty
              if ( item instanceof StringProperty ){
                  /* ERROR */ return (( StringProperty ) item ); //ERROR: Type mismatch: cannot convert from SimpleStringProperty to ObservableValue&lt; Object &gt;
              }
          });
  
          TreeTableColumn&lt; Pair&lt; Object, Object&gt;, Object &gt; colData = new TreeTableColumn&lt;&gt;("Skills"); colData.setMinWidth(200);
          colData.setCellValueFactory( cellDataFeatures -&gt; {
  
              //itemKey : Could be a String, IntegerProperty, StringProperty, or ObjectProperty&lt; LocalDate &gt;
              Object item = cellDataFeatures.getValue().getValue().getValue();
  
              //String
              if ( item instanceof String ){
                  /* ERROR */ return (String) item; //ERROR: Type mismatch: cannot convert from SimpleStringProperty to ObservableValue&lt; Object &gt;
              }
  
              //IntegerProperty
              if ( item instanceof IntegerProperty ){
                  /* ERROR */ return (( IntegerProperty ) item ); //ERROR: Type mismatch: cannot convert from SimpleIntegerProperty to ObservableValue&lt; Object &gt;
              }
  
              //StringProperty
              if ( item instanceof StringProperty ){
                  /* ERROR */ return (( StringProperty ) item ); //ERROR: Type mismatch: cannot convert from SimpleStringProperty to ObservableValue&lt; Object &gt;
              }
  
              //ObjectProperty&lt; LocalDate &gt;
              if ( item instanceof ObjectProperty&lt; ? &gt;){
                  Object value = (( ObjectProperty&lt;?&gt; ) item ).getBean();
                  if ( value instanceof LocalDate ){
                      //@TODO LocalDate cell
                  }
              }
          });
  
          /*
          //colData.setCellFactory( new Callback&lt; TreeTableColumn&lt; Person, Object &gt;, TreeTableCell&lt; Person, Object &gt;&gt;());
          colData.setCellFactory( column -&gt; {
  
              TreeTableCell&lt; Object, Object &gt; cell = new TreeTableCell&lt; Object, Object &gt;(){
                  @Override protected void updateItem( Object newValue, boolean empty ){
  
                      this.setEditable( false );
  
                      super.updateItem( newValue, empty );
                      if ( empty || newValue == null ){
                          setText    ( null );
                          setGraphic ( null );
                          return;
                      }
  
                      if ( newValue instanceof String ){
                          return;
                      }
  
                      this.setEditable( true );
  
                      if ( newValue instanceof LocalDate ){
                          return;
                      }
  
                      return;
                  }   // updateItem( ... );
              };
          });
          // */
  
          // Type safety: A generic array of Table... is created for a varargs
          // parameter
          // -&gt; @SuppressWarnings("unchecked") to start method!
          table.getColumns().addAll( colName, colData );
  
          // Output in console the selected table view's cell value/class to check
          // that the data type is correct.
          //  SystemOutTreeTableViewSelectedCell.set(tableView);
          /*
          // To check that table view is correctly refreshed on data changed..
          final Button agePlusOneButton = new Button("Age +1");
          agePlusOneButton.setOnAction((ActionEvent e) -&gt; {
              Person&lt;?&gt; person = tableView.getSelectionModel().getSelectedItem();
              try {
                  person.setAge(person.getAge() + 1);
              } catch (NullPointerException npe ){
                  //
              }
          });
          */
  
          final VBox vbox = new VBox();
          vbox.setSpacing(5);
          vbox.setPadding(new Insets(10, 0, 0, 10));
          vbox.getChildren().addAll( table );
  
          Scene scene = new Scene(new Group());
          ((Group) scene.getRoot()).getChildren().addAll(vbox);
  
          primaryStage.setWidth(600);
          primaryStage.setHeight(750);
  
          primaryStage.setScene(scene);
          primaryStage.show();
      }
  
      public static void main(String[] args) {
          launch(args);
      }
  }
  </code></pre>
  
  <p>Errors:</p>
  
  <pre><code>Description Resource    Path    Location    Type
  Type mismatch: cannot convert from IntegerProperty to ObservableValue&lt;Object&gt;   testGenericTableTreeColumn.java /testGenericTableTreeColumn/src/testGenericTableTreeColumn  line 300    Java Problem
  Type mismatch: cannot convert from String to ObservableValue&lt;Object&gt;    testGenericTableTreeColumn.java /testGenericTableTreeColumn/src/testGenericTableTreeColumn  line 295    Java Problem
  Type mismatch: cannot convert from String to ObservableValue&lt;String&gt;    testGenericTableTreeColumn.java /testGenericTableTreeColumn/src/testGenericTableTreeColumn  line 278    Java Problem
  Type mismatch: cannot convert from StringProperty to ObservableValue&lt;Object&gt;    testGenericTableTreeColumn.java /testGenericTableTreeColumn/src/testGenericTableTreeColumn  line 305    Java Problem
  </code></pre>
  
  <p>Java Version:</p>
  
  <pre><code>java version "1.8.0_121" Java(TM)
  SE Runtime Environment (build 1.8.0_121-b13)
  Java HotSpot(TM) 64-Bit Server VM (build 25.121-b13, mixed mode)
  </code></pre>