0

To explain things briefly, I have a Task object I want to convert to a JSON string using the GSON library. The object itself has String and int attributes, which I can convert to JSON just fine, however when I add a CheckBox attribute to the class, this error message appears

Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make field private javafx.beans.property.BooleanProperty javafx.scene.control.CheckBox.indeterminate accessible: module javafx.controls does not "opens javafx.scene.control" to module gson at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:349) at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:289) at java.base/java.lang.reflect.Field.checkCanSetAccessible(Field.java:174) at java.base/java.lang.reflect.Field.setAccessible(Field.java:168) at gson@2.8.2/com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:157) at gson@2.8.2/com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:100) at gson@2.8.2/com.google.gson.Gson.getAdapter(Gson.java:423) at gson@2.8.2/com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(ReflectiveTypeAdapterFactory.java:115) at gson@2.8.2/com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:164) at gson@2.8.2/com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:100) at gson@2.8.2/com.google.gson.Gson.getAdapter(Gson.java:423) at gson@2.8.2/com.google.gson.Gson.toJson(Gson.java:661) at gson@2.8.2/com.google.gson.Gson.toJson(Gson.java:648) at gson@2.8.2/com.google.gson.Gson.toJson(Gson.java:603) at gson@2.8.2/com.google.gson.Gson.toJson(Gson.java:583) at IAssessment/application.AddTaskController.addTask(AddTaskController.java:45)

I had something similar beforehand and I asked about it here (the error message was ending in does not export to gson) and the solution was to create a class module-info that looks like this

exports snippet;
exports application;
requires gson;
requires java.sql;
requires javafx.base;
requires javafx.controls;
requires javafx.fxml;
requires javafx.graphics;
opens application to gson, javafx.fxml;

This solved my previous problem but this seems to be a similar problem for which I don't know what to do. So is there a way to solve it? I appreciate any and all help.

Tomislav
  • 19
  • 6
  • 3
    Why are you trying to export a `CheckBox` to JSON in the first place? This seems like a strange thing to do, you typically only export data to JSON, not entire UI elements. – James_D Jan 25 '22 at 11:51
  • I'm not sure man. I am trying to populate a tableview with columns Name, Date and a checkbox at the end. The way I saw to add items to a tableview is thru an object. I use some setcellvaluefactory to extract the attribute values and assign them to each column. Thats why I need to keep it in my object, unless theres a way to add a checkbox to a column that isnt via an object created. I need to then save this object in a txt file as a json string for later retrieval. – Tomislav Jan 25 '22 at 12:06
  • 4
    A checkbox is a UI representation of a boolean (it’s either checked or not checked). So your data model should contain a string, date, and boolean. You should never have UI elements in the data model. – James_D Jan 25 '22 at 12:10
  • 4
    Tip: format stack traces as code. They are much easier to read that way. – jewelsea Jan 25 '22 at 12:34
  • 1
    never-ever store nodes in your data .. – kleopatra Jan 25 '22 at 12:36
  • All that said, once you fix all the design issues you have, you are still going to run into problems getting JavaFX and GSON to play nicely together. The underlying issue is that GSON assumes your data entities use a very naïve bean design ([see here](https://stackoverflow.com/questions/6203487)) in which your data classes are implemented with fields exactly matching the properties. On the other hand, JavaFX [uses a bean design](https://docs.oracle.com/javafx/2/binding/jfxpub-binding.htm) in which the fields are wrappers for the properties. – James_D Jan 25 '22 at 12:54
  • 1
    In a nutshell: you should use the `cellValueFactory` to specify what *data* ("value") each column should display. (String, date, boolean in your case.) You should use a `cellFactory` where necessary to specify *how* the column should display the data (using a `CheckBoxTableCell` for the third column). To get your check box table cell to work with the data, you'll need to use a `BooleanProperty` to represent the boolean. Because GSON *only* works with fields, it will try to serialize the `BooleanProperty` instead of its underlying boolean value. (This is a stupid design decision from GSON imo.) – James_D Jan 25 '22 at 12:58
  • 1
    So, fix your design issues, represent the table data model using JavaFX properties and set up the cell value factories and cell factories as appropriate. Then I would consider switching to a JSON library that supports Java properties instead of naïvely copying fields; Jackson works well. If you want to continue to use GSON you will have to create data transfer objects that mimic the table data model but don't use JavaFX properties, and have a layer that translates between the two data representations. – James_D Jan 25 '22 at 13:03
  • Thank you James_D , kleopatra , and jewelsea for the help. I will implement this. I am a new app dev so I appreciate the time you guys take to help me :) – Tomislav Jan 25 '22 at 13:08
  • @James_D I didn't fully understand by what you meant here. This is what I have now task.setCellValueFactory(new PropertyValueFactory<>("name")); date.setCellValueFactory(new PropertyValueFactory<>("dateString")); done.setCellValueFactory(new PropertyValueFactory<>("tickOff")); done is supposed to be the boolean property. It displays true/false in my table, how do i use cellFactory to make it represent it as a checkbox? – Tomislav Jan 25 '22 at 13:33
  • https://openjfx.io/javadoc/16/javafx.controls/javafx/scene/control/cell/CheckBoxTableCell.html#forTableColumn(javafx.scene.control.TableColumn) – James_D Jan 25 '22 at 13:39
  • @James_D sorry that didn't really clarify much to me but thanks for the explanations. – Tomislav Jan 25 '22 at 14:13
  • @Tomislav if you want to add extra info, you can edit the question instead of commenting. It is often easier to read that way, improves the question and provides superior editing and formatting capabilities. – jewelsea Jan 25 '22 at 23:21

1 Answers1

1

Figured it out

(tablecolumnname).setCellFactory(new Callback<TableColumn<(object), Boolean>, TableCell<(object), Boolean>>() {

        public TableCell<(object), Boolean> call(TableColumn<(object), Boolean> p) {
            return new CheckBoxTableCell<(object), Boolean>();
        }

    });
Tomislav
  • 19
  • 6