title: JSON Array as Objects in TableView
body: <p>I'm trying to make a table view in javafx based on some data that I retrieve from a JSON file, but I'm having a hard time trying to display them.</p>
  
  <p>That's the error message that I get:</p>
  
  <pre><code>com.fasterxml.jackson.databind.JsonMappingException: Can not find a deserializer for non-concrete Collection type [collection type; class javafx.collections.ObservableList, contains [simple type, class app.model.Savefile]]
      at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:266)
      at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:241)
      at com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:142)
      at com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:394)
      at com.fasterxml.jackson.databind.ObjectMapper._findRootDeserializer(ObjectMapper.java:3169)
      at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3062)
      at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2122)
      at app.model.SavefileJSON.getAllSavefiles(SavefileJSON.java:31)
      at app.controller.Controller.initialize(Controller.java:67)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:498)
      at sun.reflect.misc.Trampoline.invoke(MethodUtil.java:71)
      at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:498)
      at sun.reflect.misc.MethodUtil.invoke(MethodUtil.java:275)
      at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2566)
      at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2441)
      at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3214)
      at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3175)
      at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3148)
      at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3124)
      at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3104)
      at javafx.fxml.FXMLLoader.load(FXMLLoader.java:3097)
      at app.Main.start(Main.java:19)
      at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$161(LauncherImpl.java:863)
      at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$174(PlatformImpl.java:326)
      at com.sun.javafx.application.PlatformImpl.lambda$null$172(PlatformImpl.java:295)
      at java.security.AccessController.doPrivileged(Native Method)
      at com.sun.javafx.application.PlatformImpl.lambda$runLater$173(PlatformImpl.java:294)
      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.lambda$null$147(WinApplication.java:177)
      at java.lang.Thread.run(Thread.java:748)
  Caused by: java.lang.IllegalArgumentException: Can not find a deserializer for non-concrete Collection type [collection type; class javafx.collections.ObservableList, contains [simple type, class app.model.Savefile]]
      at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory.createCollectionDeserializer(BasicDeserializerFactory.java:841)
      at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer2(DeserializerCache.java:390)
      at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer(DeserializerCache.java:348)
      at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:261)
      ... 35 more
  com.fasterxml.jackson.databind.JsonMappingException: Can not find a deserializer for non-concrete Collection type [collection type; class javafx.collections.ObservableList, contains [simple type, class app.model.Savefile]]
      at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:266)
      at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:241)
      at com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:142)
      at com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:394)
      at com.fasterxml.jackson.databind.ObjectMapper._findRootDeserializer(ObjectMapper.java:3169)
      at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3062)
      at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2122)
      at app.model.SavefileJSON.getAllSavefiles(SavefileJSON.java:31)
      at app.Main.main(Main.java:40)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:498)
      at com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:389)
      at com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:328)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:498)
      at sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:767)
  Caused by: java.lang.IllegalArgumentException: Can not find a deserializer for non-concrete Collection type [collection type; class javafx.collections.ObservableList, contains [simple type, class app.model.Savefile]]
      at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory.createCollectionDeserializer(BasicDeserializerFactory.java:841)
      at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer2(DeserializerCache.java:390)
      at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer(DeserializerCache.java:348)
      at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:261)
      ... 19 more
  java.lang.reflect.InvocationTargetException
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:498)
      at com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:389)
      at com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:328)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:498)
      at sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:767)
  Caused by: java.lang.NullPointerException
      at app.Main.main(Main.java:40)
      ... 11 more
  Exception running application app.Main
  </code></pre>
  
  <p>Savefile model:</p>
  
  <pre><code>package app.model;
  
  import javafx.beans.property.SimpleIntegerProperty;
  import javafx.beans.property.SimpleStringProperty;
  import javafx.beans.property.StringProperty;
  
  import java.text.DateFormat;
  import java.text.SimpleDateFormat;
  import java.util.Date;
  
  public class Savefile {
      private StringProperty  name;
      private StringProperty date;
  
  
      @Override
      public String toString() {
          return "Savefile{" +
                  "date=" + date +
                  ", name=" + name +
                  '}';
      }
  
      public Savefile(StringProperty date, StringProperty name) {
          this.date = new SimpleStringProperty();
          this.name = new SimpleStringProperty();
      }
  
      public Savefile() {
          this.date = new SimpleStringProperty();
          this.name = new SimpleStringProperty();
      }
  
      public String getDate() {
          return date.get();
      }
  
      public StringProperty dateProperty() {
          return date;
      }
  
      public void setDate(String date) {
          this.date.set(date);
      }
  
      public String getName() {
          return name.get();
      }
  
      public StringProperty nameProperty() {
          return name;
      }
  
      public void setName(String name) {
          this.name.set(name);
      }
  }
  </code></pre>
  
  <p>SavefileJSON:</p>
  
  <pre><code>public static ObservableList&lt;Savefile&gt; getAllSavefiles(){
      ObjectMapper mapper = new ObjectMapper();
      File file = new File(JSONFILEPATH);
      try {
          ObservableList&lt;Savefile&gt; serverfiles = mapper.readValue(file, new TypeReference&lt;ObservableList&lt;Savefile&gt;&gt;(){});
          return serverfiles;
      } catch (IOException e) {
          e.printStackTrace();
      }
      return null;
  }
  </code></pre>
  
  <p>and the Controller:</p>
  
  <pre><code>package app.controller;
  
  
  import app.model.PropertiesFile;
  import app.model.Savefile;
  import app.model.SavefileJSON;
  import javafx.collections.FXCollections;
  import javafx.collections.ObservableList;
  import javafx.event.ActionEvent;
  import javafx.fxml.FXML;
  import javafx.scene.control.Button;
  import javafx.scene.control.TableColumn;
  import javafx.scene.control.TableView;
  import javafx.scene.control.TextField;
  import javafx.scene.control.cell.PropertyValueFactory;
  import jdk.jfr.events.ExceptionThrownEvent;
  
  import java.io.File;
  import java.io.IOException;
  import java.nio.file.Files;
  import java.nio.file.Path;
  import java.nio.file.Paths;
  import java.text.DateFormat;
  import java.text.SimpleDateFormat;
  import java.util.ArrayList;
  import java.util.Date;
  import java.util.List;
  
  public class Controller {
  
      public final static String CURRENT_PATH = System.getProperty("user.dir");
      public final static String SAVES_PATH = CURRENT_PATH + "\\saves";
  
      @FXML
      private TableView&lt;Savefile&gt; savesTableView;
  
      @FXML
      private TableColumn&lt;Savefile, String&gt; nameColumn;
  
      @FXML
      private TableColumn&lt;Savefile, String&gt; dataColumn;
  
      @FXML
      private Button saveButton;
  
      @FXML
      private Button loadButton;
  
      @FXML
      private Button deleteButton;
  
      @FXML
      private TextField saveFileNameText;
  
      private static void copyFile(Path sourceDirectory, Path targetDirectory) throws IOException {
          //copy source to target using Files Class
          Files.copy(sourceDirectory, targetDirectory);
      }
  
      @FXML
      private void initialize(){
  //        TableColumn&lt;Savefile,String&gt; nameColumn = new TableColumn&lt;Savefile,String&gt;("First Name");
  //        nameColumn.setCellValueFactory(new PropertyValueFactory&lt;Savefile,String&gt;("name"));
          nameColumn.setCellValueFactory(cellData -&gt; cellData.getValue().nameProperty());
          dataColumn.setCellValueFactory(cellData -&gt; cellData.getValue().dateProperty());
  
          ObservableList&lt;Savefile&gt; saveFiles = SavefileJSON.getAllSavefiles();
          populateServerfiles(saveFiles);
  
      }
  
      @FXML
      private void populateAndShowUser(Savefile sf){
          if (sf != null){
              populateSavefile(sf);
          }
      }
  
      @FXML
      private void populateSavefile (Savefile sf){
          ObservableList&lt;Savefile&gt; userData = FXCollections.observableArrayList();
          userData.add(sf);
          savesTableView.setItems(userData);
      }
  
      @FXML
      private void populateServerfiles(ObservableList&lt;Savefile&gt; savefilesData){
          savesTableView.setItems(savefilesData);
      }
  
  
      @FXML
      public void createSaveFile(ActionEvent event) {
  
          if (saveFileNameText.getText().equals("") || saveFileNameText.getText()==null){
              saveFileNameText.setStyle("-fx-border-color: #ff0000;" +
                      "-fx-border-radius: 5");
              saveFileNameText.setPromptText("Name field required");
          }else{
              String location = SAVES_PATH + "\\" + saveFileNameText.getText();
              File newSaveFileDirectory = new File(location);
              boolean result = false;
  
              //CREATING THE DIR
              try{
                  newSaveFileDirectory.mkdir();
                  SavefileJSON sfJ = new SavefileJSON();
                  DateFormat dateFormat = new SimpleDateFormat("dd/MM HH:mm");
                  Date date = new Date();
                  Savefile sf = new Savefile();
                  sf.setName(saveFileNameText.getText().toString());
                  sf.setDate(dateFormat.format(date).toString());
                  sfJ.addSavefile(sf);
  
                  //COPY THE ACTUAL SAVE FILE TO THE DIR
                  PropertiesFile pf = new PropertiesFile();
                  try{
                      copyFile(Paths.get(pf.getProp("sekiroLocation")), Paths.get(SAVES_PATH + "\\" +(saveFileNameText.getText())+ "\\S0000.sl2"));
                  }catch(IOException e){
                      System.out.println(e);
                      System.out.println("Copy sf failed");
                  }
  
                  //check if the name its unique
  
                  result = true;
              }catch(SecurityException se){
                  System.out.println(se);
              }
              if (result){
                  System.out.println("Save file directory created");
              }
          }
      }
  }
  </code></pre>
  
  <p>Can somebody help me make it work? Initially I've been using <strong>List</strong> instead of <strong>ObservableList</strong> in the savefilejson and I could successfully retrieve all the entries from the json file but since I changed it to ObservableList in order to display the results everything broke and I got no clue how to fix it</p>