1

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.

That's the error message that I get:

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

Savefile model:

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);
    }
}

SavefileJSON:

public static ObservableList<Savefile> getAllSavefiles(){
    ObjectMapper mapper = new ObjectMapper();
    File file = new File(JSONFILEPATH);
    try {
        ObservableList<Savefile> serverfiles = mapper.readValue(file, new TypeReference<ObservableList<Savefile>>(){});
        return serverfiles;
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}

and the Controller:

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<Savefile> savesTableView;

    @FXML
    private TableColumn<Savefile, String> nameColumn;

    @FXML
    private TableColumn<Savefile, String> 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<Savefile,String> nameColumn = new TableColumn<Savefile,String>("First Name");
//        nameColumn.setCellValueFactory(new PropertyValueFactory<Savefile,String>("name"));
        nameColumn.setCellValueFactory(cellData -> cellData.getValue().nameProperty());
        dataColumn.setCellValueFactory(cellData -> cellData.getValue().dateProperty());

        ObservableList<Savefile> saveFiles = SavefileJSON.getAllSavefiles();
        populateServerfiles(saveFiles);

    }

    @FXML
    private void populateAndShowUser(Savefile sf){
        if (sf != null){
            populateSavefile(sf);
        }
    }

    @FXML
    private void populateSavefile (Savefile sf){
        ObservableList<Savefile> userData = FXCollections.observableArrayList();
        userData.add(sf);
        savesTableView.setItems(userData);
    }

    @FXML
    private void populateServerfiles(ObservableList<Savefile> 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");
            }
        }
    }
}

Can somebody help me make it work? Initially I've been using List instead of ObservableList 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

Terchila Marian
  • 2,225
  • 3
  • 25
  • 48

1 Answers1

1

I think your problem is that Jackson is not able to produce an ObservableList directly (since naturally it does not have a deserializer for the JavaFX-specific ObservableList).

But in getAllSavefiles you could easily create a regular List from the JSON-File and then create an ObservableList from the items in your List.

You can use FXCollections.observableList(List<E> list) for that purpose.

Like this (from the top of my head, code untested):

public static ObservableList<Savefile> getAllSavefiles(){
    ObjectMapper mapper = new ObjectMapper();
    File file = new File(JSONFILEPATH);
    try {
        List<Savefile> serverfiles = mapper.readValue(file, new TypeReference<ArrayList<Savefile>>(){});
        return FXCollections.observableList(serverfiles);
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}
rli
  • 1,745
  • 1
  • 14
  • 25