JSON数组作为TableView中的对象

时间:2019-03-29 14:26:47

标签: json javafx tableview

我试图基于从JSON文件检索到的一些数据在javafx中创建表视图,但是我很难显示它们。

那是我得到的错误消息:

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

保存文件模型:

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

和控制器:

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

有人可以帮我实现它吗?最初,我一直使用savefilejson中的 List 而不是 ObservableList ,并且我可以成功地从json文件中检索所有条目,但是由于我将其更改为ObservableList以便显示结果一切都坏了,我不知道如何解决

1 个答案:

答案 0 :(得分:1)

我认为您的问题是Jackson不能直接生成ObservableList(因为自然地,它没有JavaFX专用ObservableList的反序列化器)。

但是在getAllSavefiles中,您可以轻松地从JSON文件创建常规列表,然后从列表中的项目创建ObservableList。

您可以为此使用FXCollections.observableList(List<E> list)

就像这样(从我的头顶来看,未经测试的代码):

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